mirror of
https://gitlab.com/Kwoth/nadekobot.git
synced 2025-09-10 17:28:27 -04:00
Compare commits
44 Commits
Author | SHA1 | Date | |
---|---|---|---|
|
15d4117d7f | ||
|
d7daa5f2af | ||
|
b08ff62406 | ||
|
9aa89d3be8 | ||
|
518f2e425e | ||
|
8fae6e621d | ||
|
30f3ae1ade | ||
|
ef4b1c8868 | ||
|
7f64d2661f | ||
|
ab93380d7c | ||
|
a6adf73ecf | ||
|
d9e52038ac | ||
|
be7ddc732b | ||
|
79b25c8a41 | ||
|
12fa209555 | ||
|
28a9f5682e | ||
|
06321380ee | ||
|
b51ce34190 | ||
|
317c94979a | ||
|
df2fd1b3f1 | ||
|
35f0228986 | ||
|
f391027c8c | ||
|
4e570475df | ||
|
e2066f433f | ||
|
78b328dc18 | ||
|
f0cbacd01a | ||
|
d45c39a5fe | ||
|
a6010716e8 | ||
|
d2c7563c5c | ||
|
0c167a9382 | ||
|
b9d2e4baf1 | ||
|
82e230010b | ||
|
03fb1a5ca2 | ||
|
8ac07ce6d7 | ||
|
12da9f3178 | ||
|
ae45329d2b | ||
|
f499380fe8 | ||
|
0083e9ef68 | ||
|
22b7cf5e6c | ||
|
f973766c73 | ||
|
0efdd3300d | ||
|
5016377dd1 | ||
|
2d40a35112 | ||
|
9ea6cd0b32 |
@@ -30,12 +30,17 @@ variables:
|
||||
build:
|
||||
stage: build
|
||||
script:
|
||||
- "dotnet publish -c Release -r linux-x64 --self-contained -o $LINUX_X64_OUTPUT_DIR src/NadekoBot/NadekoBot.csproj"
|
||||
- "dotnet publish -c Release -r linux-arm64 --self-contained -o $LINUX_ARM64_OUTPUT_DIR src/NadekoBot/NadekoBot.csproj"
|
||||
- "dotnet publish -c Release -r win-x64 --self-contained -o $WIN_X64_OUTPUT_DIR src/NadekoBot/NadekoBot.csproj"
|
||||
- "dotnet publish -c Release -r win-arm64 --self-contained -o $WIN_ARM64_OUTPUT_DIR src/NadekoBot/NadekoBot.csproj"
|
||||
- "dotnet publish -c Release -r osx-x64 --self-contained -o $MACOS_X64_OUTPUT_DIR src/NadekoBot/NadekoBot.csproj"
|
||||
- "dotnet publish -c Release -r osx-arm64 --self-contained -o $MACOS_ARM64_OUTPUT_DIR src/NadekoBot/NadekoBot.csproj"
|
||||
- |
|
||||
VERSION_STRING=""
|
||||
if [ -n "$CI_COMMIT_TAG" ]; then
|
||||
VERSION_STRING="-p:Version=$CI_COMMIT_TAG"
|
||||
fi
|
||||
- "dotnet publish -c Release -r linux-x64 --self-contained $VERSION_STRING -o $LINUX_X64_OUTPUT_DIR src/NadekoBot/NadekoBot.csproj"
|
||||
- "dotnet publish -c Release -r linux-arm64 --self-contained $VERSION_STRING -o $LINUX_ARM64_OUTPUT_DIR src/NadekoBot/NadekoBot.csproj"
|
||||
- "dotnet publish -c Release -r win-x64 --self-contained $VERSION_STRING -o $WIN_X64_OUTPUT_DIR src/NadekoBot/NadekoBot.csproj"
|
||||
- "dotnet publish -c Release -r win-arm64 --self-contained $VERSION_STRING -o $WIN_ARM64_OUTPUT_DIR src/NadekoBot/NadekoBot.csproj"
|
||||
- "dotnet publish -c Release -r osx-x64 --self-contained $VERSION_STRING -o $MACOS_X64_OUTPUT_DIR src/NadekoBot/NadekoBot.csproj"
|
||||
- "dotnet publish -c Release -r osx-arm64 --self-contained $VERSION_STRING -o $MACOS_ARM64_OUTPUT_DIR src/NadekoBot/NadekoBot.csproj"
|
||||
artifacts:
|
||||
paths:
|
||||
- "$LINUX_X64_OUTPUT_DIR/"
|
||||
@@ -123,6 +128,8 @@ publish-medusa-package:
|
||||
stage: publish-medusa-package
|
||||
allow_failure: true
|
||||
rules:
|
||||
- if: '$CI_PIPELINE_SOURCE == "merge_request_event"'
|
||||
when: never
|
||||
- if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH || $CI_COMMIT_TAG
|
||||
script:
|
||||
- LAST_TAG=$(git describe --tags --abbrev=0)
|
||||
|
56
CHANGELOG.md
56
CHANGELOG.md
@@ -2,6 +2,62 @@
|
||||
|
||||
Mostly based on [keepachangelog](https://keepachangelog.com/en/1.0.0/) except date format. a-c-f-r-o
|
||||
|
||||
## [5.1.0] - 25.06.2024
|
||||
|
||||
### Added
|
||||
|
||||
- Added `.prompt` command, Nadeko Ai Assistant
|
||||
- You can send natural language questions, queries or execute commands. For example "@Nadeko how's the weather in paris" and it will return `.we Paris` and run it for you.
|
||||
- In case the bot can't execute a command using your query, It will fall back to your chatter bot, in case you have it enabled in data/games.yml. (Cleverbot or chatgpt)
|
||||
- (It's far from perfect so please don't ask the bot to do dangerous things like banning or pruning)
|
||||
- Requires Patreon subscription, after which you'll be able to run it on global @Nadeko bot. If you're selfhosting, you also will need to acquire the api key from <https://dashy.nadeko.bot/api> (coming soon(ish)...)
|
||||
- Added support for `gpt-4o` in `data/games.yml`
|
||||
- Added nadekoAiToken to `creds.yml`
|
||||
|
||||
|
||||
### Changed
|
||||
|
||||
- Remind will now show a timestamp tag for durations
|
||||
- Only `Gpt35Turbo` and `Gpt4o` are valid inputs in games.yml now
|
||||
- `data/patron.yml` changed. It now has limits. The entire feature limit system has been reworked. Your previous settings will be reset
|
||||
- A lot of updates to bot strings (thanks Ene)
|
||||
- Improved cleanup command to delete a lot more data once cleanup is ran, not only guild configs (please don't use this command unless you have your database bakced up and you know 100% what you're doing)
|
||||
|
||||
### Fixed
|
||||
|
||||
- Fixed xp bg buy button not working, and possibly some other buttons too
|
||||
- Fixed shopbuy %user% placeholders and updated help text
|
||||
- All .feed overloads should now work"
|
||||
- `.xpexclude` should will now work with forums too. If you exclude a forum you won't be able to gain xp in any of the threads.
|
||||
- Fixed remind not showing correct time (thx cata)
|
||||
|
||||
### Removed
|
||||
|
||||
- Removed PoE related commands
|
||||
- dev: Removed patron quota data from the database, it will now be stored in redis
|
||||
|
||||
## [5.0.8] - 21.05.2024
|
||||
|
||||
### Added
|
||||
|
||||
- Added `.setserverbanner` and `.setservericon` commands (thx cata)
|
||||
- Added overloads section to `.h command` which will show you all versions of command usage with param names
|
||||
- You can now check commands for submodules, for example `.cmds SelfAssignedRoles` will show brief help for each of the commands in that submodule
|
||||
- Added dropdown menus for .mdls and .cmds (both module and group versions) which will give you the option to see more detailed help for each specific module, group or command respectively
|
||||
- Self-Hosters only:
|
||||
- Added a dangerous cleanup command that you don't have to know about
|
||||
|
||||
### Changed
|
||||
|
||||
- Quotes will now use alphanumerical ids (like expressions)
|
||||
|
||||
### Fixed
|
||||
|
||||
- `.verbose` will now be respected for expression errors
|
||||
- Using `.pick` will now correctly show the name of the user who picked the currency
|
||||
- Fixed `.h` not working on some commands
|
||||
- `.langset` and `.langsetd` should no longer allow unsupported languages and nonsense to be typed in
|
||||
|
||||
## [5.0.7] - 15.05.2024
|
||||
|
||||
### Fixed
|
||||
|
@@ -1,46 +1,76 @@
|
||||
# Setting up NadekoBot with Docker
|
||||
# Deploying NadekoBot with Docker: A Comprehensive Guide
|
||||
|
||||
# WORK IN PROGRESS
|
||||
## Getting Started
|
||||
|
||||
### Installation
|
||||
Ensure Docker and Docker Compose are installed on your system. If not, follow the official Docker guides for your specific operating system:
|
||||
|
||||
- [Docker Installation Guide](https://docs.docker.com/engine/install/)
|
||||
- [Docker Compose Installation Guide](https://docs.docker.com/compose/install/)
|
||||
|
||||
## Step-by-Step Installation
|
||||
|
||||
1. **Choose Your Workspace:** Select a directory where you'll set up your NadekoBot stack. Use your terminal to navigate to this directory. For the purpose of this guide, we'll use `/opt/stacks/nadekobot/` as an example, but you can choose any directory that suits your needs.
|
||||
|
||||
2. **Create a Docker Compose File:** In this directory, create a Docker Compose file named `docker-compose.yml`. You can use any text editor for this task. For instance, to use the `nano` editor, type `nano docker-compose.yml`.
|
||||
|
||||
3. **Configure Your Docker Compose File:** Populate your Docker Compose file with the following configuration:
|
||||
|
||||
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
|
||||
version: "3.7"
|
||||
services:
|
||||
nadeko:
|
||||
image: registry.gitlab.com/kwoth/nadekobot:latest
|
||||
depends_on:
|
||||
- redis
|
||||
container_name: nadeko
|
||||
restart: unless-stopped
|
||||
environment:
|
||||
TZ: Europe/Paris
|
||||
NadekoBot_RedisOptions: redis,name=nadeko
|
||||
#NadekoBot_ShardRunCommand: dotnet
|
||||
#NadekoBot_ShardRunArguments: /app/NadekoBot.dll {0} {1}
|
||||
TZ: Europe/Rome
|
||||
volumes:
|
||||
- /srv/nadeko/conf/creds.yml:/app/creds.yml:ro
|
||||
- /srv/nadeko/data:/app/data
|
||||
|
||||
redis:
|
||||
image: redis:4-alpine
|
||||
sysctls:
|
||||
- net.core.somaxconn=511
|
||||
command: redis-server --maxmemory 32M --maxmemory-policy volatile-lru
|
||||
volumes:
|
||||
- /srv/nadeko/redis-data:/data
|
||||
- /opt/stacks/nadekobot/conf/creds.yml:/app/data/creds.yml
|
||||
- /opt/stacks/nadekobot/data:/app/data
|
||||
networks: {}
|
||||
```
|
||||
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
|
||||
- `cd /srv/nadeko`
|
||||
- `docker-compose pull`
|
||||
- `docker-compose up -d`
|
||||
4. **Prepare Your Credentials File:** Before running Docker Compose, ensure the `creds.yml` file exists in the `/opt/stacks/nadekobot/conf/` directory. If it's missing, create it using `touch /opt/stacks/nadekobot/conf/creds.yml`. You may need to use `sudo`. Remember to replace `/opt/stacks/nadekobot/` with your chosen directory.
|
||||
|
||||
5. **Edit Your Credentials File:** Populate the `creds.yml` file in `/opt/stacks/nadekobot/conf/creds.yml` with your bot's credentials. You can use any text editor for this task. For instance, to use the `nano` editor, type `nano /opt/stacks/nadekobot/conf/creds.yml`. You may need to use `sudo`. Again, replace `/opt/stacks/nadekobot/` with your chosen directory.
|
||||
|
||||
6. **Launch Your Bot:** Now, you're ready to run Docker Compose. Use the following command: `docker-compose up -d`.
|
||||
|
||||
## Keeping Your Bot Up-to-Date
|
||||
|
||||
There are two methods to update your NadekoBot:
|
||||
|
||||
### Manual Update
|
||||
|
||||
1. **Navigate to Your Directory:** Use `cd /path/to/your/directory` to go to the directory containing your Docker Compose file.
|
||||
|
||||
2. **Pull the Latest Images:** Use `docker-compose pull` to fetch the latest images.
|
||||
|
||||
3. **Restart Your Containers:** Use `docker-compose up -d` to restart the containers.
|
||||
|
||||
### Automatic Update with Watchtower
|
||||
|
||||
If you prefer an automated update process, consider using Watchtower. Watchtower automatically updates your Docker containers to the latest versions.
|
||||
|
||||
To use Watchtower with NadekoBot, you need to add a specific label to the service in your Docker Compose file. Here's how your Docker Compose file should look:
|
||||
|
||||
```yml
|
||||
services:
|
||||
nadeko:
|
||||
image: registry.gitlab.com/kwoth/nadekobot:latest
|
||||
container_name: nadeko
|
||||
restart: unless-stopped
|
||||
labels:
|
||||
- com.centurylinklabs.watchtower.enable=true
|
||||
environment:
|
||||
TZ: Europe/Rome
|
||||
volumes:
|
||||
- /opt/stacks/nadekobot/conf/creds.yml:/app/data/creds.yml
|
||||
- /opt/stacks/nadekobot/data:/app/data
|
||||
networks: {}
|
||||
```
|
||||
|
||||
Remember to replace `/opt/stacks/nadekobot/` with your chosen directory in the Docker Compose file.
|
||||
|
||||
To install and run Watchtower, follow the guide provided by Containrrr:
|
||||
|
||||
- [Watchtower Installation and Usage Guide](https://containrrr.dev/watchtower/)
|
@@ -15,8 +15,8 @@
|
||||
|
||||
##### Compatible operating systems:
|
||||
|
||||
- Ubuntu: 20.04, 21.04, 21.10, 22.04
|
||||
- Mint: 19, 20
|
||||
- Ubuntu: 20.04, 22.04, 24.04
|
||||
- Mint: 19, 20, 21
|
||||
- Debian: 10, 11, 12
|
||||
- RockyLinux: 8, 9
|
||||
- AlmaLinux: 8, 9
|
||||
@@ -70,11 +70,11 @@ Open Terminal (if you're on an installation with a window manager) and navigate
|
||||
|
||||
1. (Optional) Installing Redis
|
||||
- ubuntu installation command: `sudo apt-get install redis-server`
|
||||
2. Playing music requires `ffmpeg`, `libopus`, `libsodium` and `youtube-dl` (which in turn requires python3)
|
||||
- ubuntu installation command: `sudo apt-get install ffmpeg libopus0 opus-tools libopus-dev libsodium-dev -y`
|
||||
2. Playing music requires `ffmpeg`, `libopus`, `libsodium` and `yt-dlp` (which in turn requires python3)
|
||||
- Ubuntu installation command: `sudo apt-get install ffmpeg libopus0 opus-tools libopus-dev libsodium-dev -y`
|
||||
- yt-dlp installation command: `sudo wget https://github.com/yt-dlp/yt-dlp/releases/latest/download/yt-dlp -O /usr/local/bin/yt-dlp && sudo chmod a+rx /usr/local/bin/yt-dlp`
|
||||
3. Make sure your python is version 3+ with `python --version`
|
||||
- if it's not, you can install python 3 and make it the default with: `sudo apt-get install python3.8 python-is-python3`
|
||||
|
||||
*You can use nadeko bash script [prerequisites installer](https://gitlab.com/kwoth/nadeko-bash-installer/-/blob/v5/n-prereq.sh) as a reference*
|
||||
|
||||
##### Installation Instructions
|
||||
@@ -268,7 +268,7 @@ This method is similar to the one above, but requires one extra step, with the a
|
||||
echo '#!/bin/bash'
|
||||
echo ""
|
||||
echo "echo \"Running NadekoBot in the background with auto restart\"
|
||||
youtube-dl -U
|
||||
yt-dlp -U
|
||||
|
||||
# If you want Nadeko to be compiled prior to every startup, uncomment the lines
|
||||
# below. Note that it's not necessary unless you are personally modifying the
|
||||
@@ -300,7 +300,7 @@ This method is similar to the one above, but requires one extra step, with the a
|
||||
|
||||
echo \"Waiting for 5 seconds...\"
|
||||
sleep 5
|
||||
youtube-dl -U
|
||||
yt-dlp -U
|
||||
echo \"Restarting NadekoBot...\"
|
||||
done
|
||||
|
||||
|
@@ -1,4 +1,4 @@
|
||||
dotnet ef migrations remove -c SqliteContext -f
|
||||
dotnet ef migrations remove -c PostgreSqlContext -f
|
||||
dotnet ef migrations remove -c MysqlContext -f
|
||||
dotnet ef migrations remove -c SqliteContext -f -p src/NadekoBot/NadekoBot.csproj
|
||||
dotnet ef migrations remove -c PostgreSqlContext -f -p src/NadekoBot/NadekoBot.csproj
|
||||
dotnet ef migrations remove -c MysqlContext -f -p src/NadekoBot/NadekoBot.csproj
|
||||
|
||||
|
@@ -8,7 +8,7 @@
|
||||
<ItemGroup>
|
||||
<PackageReference Include="NUnit" Version="3.13.3" />
|
||||
<PackageReference Include="NUnit3TestAdapter" Version="4.2.1" />
|
||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.2.0" />
|
||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.9.0" />
|
||||
</ItemGroup>
|
||||
|
||||
|
||||
|
@@ -3,6 +3,8 @@ namespace NadekoBot.Db.Models;
|
||||
|
||||
public class DelMsgOnCmdChannel : DbEntity
|
||||
{
|
||||
public int GuildConfigId { get; set; }
|
||||
|
||||
public ulong ChannelId { get; set; }
|
||||
public bool State { get; set; }
|
||||
|
||||
|
@@ -1,8 +0,0 @@
|
||||
#nullable disable
|
||||
namespace NadekoBot.Db.Models;
|
||||
|
||||
public class IgnoredVoicePresenceChannel : DbEntity
|
||||
{
|
||||
public LogSetting LogSetting { get; set; }
|
||||
public ulong ChannelId { get; set; }
|
||||
}
|
@@ -40,6 +40,9 @@ public class StreamRoleSettings : DbEntity
|
||||
|
||||
public class StreamRoleBlacklistedUser : DbEntity
|
||||
{
|
||||
public int StreamRoleSettingsId { get; set; }
|
||||
public StreamRoleSettings StreamRoleSettings { get; set; }
|
||||
|
||||
public ulong UserId { get; set; }
|
||||
public string Username { get; set; }
|
||||
|
||||
@@ -57,6 +60,9 @@ public class StreamRoleBlacklistedUser : DbEntity
|
||||
|
||||
public class StreamRoleWhitelistedUser : DbEntity
|
||||
{
|
||||
public int StreamRoleSettingsId { get; set; }
|
||||
public StreamRoleSettings StreamRoleSettings { get; set; }
|
||||
|
||||
public ulong UserId { get; set; }
|
||||
public string Username { get; set; }
|
||||
|
||||
|
@@ -2,8 +2,9 @@
|
||||
|
||||
public class AntiAltSetting
|
||||
{
|
||||
public int Id { get; set; }
|
||||
public int GuildConfigId { get; set; }
|
||||
|
||||
public int Id { get; set; }
|
||||
public TimeSpan MinAge { get; set; }
|
||||
public PunishmentAction Action { get; set; }
|
||||
public int ActionDurationMinutes { get; set; }
|
||||
|
@@ -1,12 +1,13 @@
|
||||
#nullable disable
|
||||
using System.ComponentModel.DataAnnotations.Schema;
|
||||
|
||||
namespace NadekoBot.Db.Models;
|
||||
|
||||
|
||||
public class AntiRaidSetting : DbEntity
|
||||
{
|
||||
public int GuildConfigId { get; set; }
|
||||
public GuildConfig GuildConfig { get; set; }
|
||||
|
||||
|
||||
public int UserThreshold { get; set; }
|
||||
public int Seconds { get; set; }
|
||||
public PunishmentAction Action { get; set; }
|
||||
|
@@ -4,8 +4,7 @@
|
||||
public class AntiSpamSetting : DbEntity
|
||||
{
|
||||
public int GuildConfigId { get; set; }
|
||||
public GuildConfig GuildConfig { get; set; }
|
||||
|
||||
|
||||
public PunishmentAction Action { get; set; }
|
||||
public int MessageThreshold { get; set; } = 3;
|
||||
public int MuteTime { get; set; }
|
||||
|
@@ -14,17 +14,3 @@ public class FilterChannelId : DbEntity
|
||||
public override int GetHashCode()
|
||||
=> ChannelId.GetHashCode();
|
||||
}
|
||||
|
||||
public class FilterWordsChannelId : DbEntity
|
||||
{
|
||||
public ulong ChannelId { get; set; }
|
||||
|
||||
public bool Equals(FilterWordsChannelId other)
|
||||
=> ChannelId == other.ChannelId;
|
||||
|
||||
public override bool Equals(object obj)
|
||||
=> obj is FilterWordsChannelId fci && Equals(fci);
|
||||
|
||||
public override int GetHashCode()
|
||||
=> ChannelId.GetHashCode();
|
||||
}
|
17
src/NadekoBot/Db/Models/filter/FilterWordsChannelId.cs
Normal file
17
src/NadekoBot/Db/Models/filter/FilterWordsChannelId.cs
Normal file
@@ -0,0 +1,17 @@
|
||||
#nullable disable
|
||||
namespace NadekoBot.Db.Models;
|
||||
|
||||
public class FilterWordsChannelId : DbEntity
|
||||
{
|
||||
public int? GuildConfigId { get; set; }
|
||||
public ulong ChannelId { get; set; }
|
||||
|
||||
public bool Equals(FilterWordsChannelId other)
|
||||
=> ChannelId == other.ChannelId;
|
||||
|
||||
public override bool Equals(object obj)
|
||||
=> obj is FilterWordsChannelId fci && Equals(fci);
|
||||
|
||||
public override int GetHashCode()
|
||||
=> ChannelId.GetHashCode();
|
||||
}
|
@@ -1,30 +1,6 @@
|
||||
#nullable disable
|
||||
namespace NadekoBot.Db.Models;
|
||||
|
||||
/// <summary>
|
||||
/// Contains data about usage of Patron-Only commands per user
|
||||
/// in order to provide support for quota limitations
|
||||
/// (allow user x who is pledging amount y to use the specified command only
|
||||
/// x amount of times in the specified time period)
|
||||
/// </summary>
|
||||
public class PatronQuota
|
||||
{
|
||||
public ulong UserId { get; set; }
|
||||
public FeatureType FeatureType { get; set; }
|
||||
public string Feature { get; set; }
|
||||
public uint HourlyCount { get; set; }
|
||||
public uint DailyCount { get; set; }
|
||||
public uint MonthlyCount { get; set; }
|
||||
}
|
||||
|
||||
public enum FeatureType
|
||||
{
|
||||
Command,
|
||||
Group,
|
||||
Module,
|
||||
Limit
|
||||
}
|
||||
|
||||
public class PatronUser
|
||||
{
|
||||
public string UniquePlatformUserId { get; set; }
|
||||
|
@@ -51,6 +51,8 @@ public class XpCurrencyReward : DbEntity
|
||||
|
||||
public class ExcludedItem : DbEntity
|
||||
{
|
||||
public XpSettings XpSettings { get; set; }
|
||||
|
||||
public ulong ItemId { get; set; }
|
||||
public ExcludedItemType ItemType { get; set; }
|
||||
|
||||
|
@@ -28,7 +28,6 @@ public abstract class NadekoContext : DbContext
|
||||
|
||||
//logging
|
||||
public DbSet<LogSetting> LogSettings { get; set; }
|
||||
public DbSet<IgnoredVoicePresenceChannel> IgnoredVoicePresenceCHannels { get; set; }
|
||||
public DbSet<IgnoredLogItem> IgnoredLogChannels { get; set; }
|
||||
|
||||
public DbSet<RotatingPlayingStatus> RotatingStatus { get; set; }
|
||||
@@ -54,15 +53,13 @@ public abstract class NadekoContext : DbContext
|
||||
|
||||
public DbSet<PatronUser> Patrons { get; set; }
|
||||
|
||||
public DbSet<PatronQuota> PatronQuotas { get; set; }
|
||||
|
||||
public DbSet<StreamOnlineMessage> StreamOnlineMessages { get; set; }
|
||||
|
||||
|
||||
public DbSet<StickyRole> StickyRoles { get; set; }
|
||||
|
||||
|
||||
public DbSet<TodoModel> Todos { get; set; }
|
||||
public DbSet<ArchivedTodoListModel> TodosArchive { get; set; }
|
||||
|
||||
|
||||
// todo add guild colors
|
||||
// public DbSet<GuildColors> GuildColors { get; set; }
|
||||
|
||||
@@ -86,15 +83,84 @@ public abstract class NadekoContext : DbContext
|
||||
#region GuildConfig
|
||||
|
||||
var configEntity = modelBuilder.Entity<GuildConfig>();
|
||||
|
||||
configEntity.HasIndex(c => c.GuildId)
|
||||
.IsUnique();
|
||||
|
||||
configEntity.Property(x => x.VerboseErrors)
|
||||
.HasDefaultValue(true);
|
||||
|
||||
modelBuilder.Entity<AntiSpamSetting>().HasOne(x => x.GuildConfig).WithOne(x => x.AntiSpamSetting);
|
||||
modelBuilder.Entity<GuildConfig>()
|
||||
.HasMany(x => x.DelMsgOnCmdChannels)
|
||||
.WithOne()
|
||||
.HasForeignKey(x => x.GuildConfigId)
|
||||
.OnDelete(DeleteBehavior.Cascade);
|
||||
|
||||
modelBuilder.Entity<AntiRaidSetting>().HasOne(x => x.GuildConfig).WithOne(x => x.AntiRaidSetting);
|
||||
modelBuilder.Entity<GuildConfig>()
|
||||
.HasMany(x => x.FollowedStreams)
|
||||
.WithOne()
|
||||
.OnDelete(DeleteBehavior.Cascade);
|
||||
|
||||
modelBuilder.Entity<GuildConfig>()
|
||||
.HasMany(x => x.GenerateCurrencyChannelIds)
|
||||
.WithOne(x => x.GuildConfig)
|
||||
.OnDelete(DeleteBehavior.Cascade);
|
||||
|
||||
modelBuilder.Entity<GuildConfig>()
|
||||
.HasMany(x => x.Permissions)
|
||||
.WithOne()
|
||||
.OnDelete(DeleteBehavior.Cascade);
|
||||
|
||||
modelBuilder.Entity<GuildConfig>()
|
||||
.HasMany(x => x.CommandCooldowns)
|
||||
.WithOne()
|
||||
.OnDelete(DeleteBehavior.Cascade);
|
||||
|
||||
modelBuilder.Entity<GuildConfig>()
|
||||
.HasMany(x => x.FilterInvitesChannelIds)
|
||||
.WithOne()
|
||||
.OnDelete(DeleteBehavior.Cascade);
|
||||
|
||||
modelBuilder.Entity<GuildConfig>()
|
||||
.HasMany(x => x.FilterLinksChannelIds)
|
||||
.WithOne()
|
||||
.OnDelete(DeleteBehavior.Cascade);
|
||||
|
||||
modelBuilder.Entity<GuildConfig>()
|
||||
.HasMany(x => x.FilteredWords)
|
||||
.WithOne()
|
||||
.OnDelete(DeleteBehavior.Cascade);
|
||||
|
||||
modelBuilder.Entity<GuildConfig>()
|
||||
.HasMany(x => x.FilterWordsChannelIds)
|
||||
.WithOne()
|
||||
.OnDelete(DeleteBehavior.Cascade);
|
||||
|
||||
modelBuilder.Entity<GuildConfig>()
|
||||
.HasMany(x => x.MutedUsers)
|
||||
.WithOne()
|
||||
.OnDelete(DeleteBehavior.Cascade);
|
||||
|
||||
modelBuilder.Entity<GuildConfig>()
|
||||
.HasOne(x => x.AntiRaidSetting)
|
||||
.WithOne()
|
||||
.HasForeignKey<AntiRaidSetting>(x => x.GuildConfigId)
|
||||
.OnDelete(DeleteBehavior.Cascade);
|
||||
|
||||
// start antispam
|
||||
|
||||
modelBuilder.Entity<GuildConfig>()
|
||||
.HasOne(x => x.AntiSpamSetting)
|
||||
.WithOne()
|
||||
.HasForeignKey<AntiSpamSetting>(x => x.GuildConfigId)
|
||||
.OnDelete(DeleteBehavior.Cascade);
|
||||
|
||||
modelBuilder.Entity<AntiSpamSetting>()
|
||||
.HasMany(x => x.IgnoredChannels)
|
||||
.WithOne()
|
||||
.OnDelete(DeleteBehavior.Cascade);
|
||||
|
||||
// end antispam
|
||||
|
||||
modelBuilder.Entity<GuildConfig>()
|
||||
.HasOne(x => x.AntiAltSetting)
|
||||
@@ -102,6 +168,98 @@ public abstract class NadekoContext : DbContext
|
||||
.HasForeignKey<AntiAltSetting>(x => x.GuildConfigId)
|
||||
.OnDelete(DeleteBehavior.Cascade);
|
||||
|
||||
modelBuilder.Entity<GuildConfig>()
|
||||
.HasMany(x => x.UnmuteTimers)
|
||||
.WithOne()
|
||||
.OnDelete(DeleteBehavior.Cascade);
|
||||
|
||||
modelBuilder.Entity<GuildConfig>()
|
||||
.HasMany(x => x.UnbanTimer)
|
||||
.WithOne()
|
||||
.OnDelete(DeleteBehavior.Cascade);
|
||||
|
||||
modelBuilder.Entity<GuildConfig>()
|
||||
.HasMany(x => x.UnroleTimer)
|
||||
.WithOne()
|
||||
.OnDelete(DeleteBehavior.Cascade);
|
||||
|
||||
modelBuilder.Entity<GuildConfig>()
|
||||
.HasMany(x => x.VcRoleInfos)
|
||||
.WithOne()
|
||||
.OnDelete(DeleteBehavior.Cascade);
|
||||
|
||||
modelBuilder.Entity<GuildConfig>()
|
||||
.HasMany(x => x.CommandAliases)
|
||||
.WithOne()
|
||||
.OnDelete(DeleteBehavior.Cascade);
|
||||
|
||||
modelBuilder.Entity<GuildConfig>()
|
||||
.HasMany(x => x.WarnPunishments)
|
||||
.WithOne()
|
||||
.OnDelete(DeleteBehavior.Cascade);
|
||||
|
||||
modelBuilder.Entity<GuildConfig>()
|
||||
.HasMany(x => x.SlowmodeIgnoredRoles)
|
||||
.WithOne()
|
||||
.OnDelete(DeleteBehavior.Cascade);
|
||||
|
||||
modelBuilder.Entity<GuildConfig>()
|
||||
.HasMany(x => x.SlowmodeIgnoredUsers)
|
||||
.WithOne()
|
||||
.OnDelete(DeleteBehavior.Cascade);
|
||||
|
||||
// start shop
|
||||
modelBuilder.Entity<GuildConfig>()
|
||||
.HasMany(x => x.ShopEntries)
|
||||
.WithOne()
|
||||
.OnDelete(DeleteBehavior.Cascade);
|
||||
|
||||
modelBuilder.Entity<ShopEntry>()
|
||||
.HasMany(x => x.Items)
|
||||
.WithOne()
|
||||
.OnDelete(DeleteBehavior.Cascade);
|
||||
|
||||
// end shop
|
||||
|
||||
// start streamrole
|
||||
|
||||
modelBuilder.Entity<GuildConfig>()
|
||||
.HasOne(x => x.StreamRole)
|
||||
.WithOne(x => x.GuildConfig)
|
||||
.HasForeignKey<StreamRoleSettings>(x => x.GuildConfigId)
|
||||
.OnDelete(DeleteBehavior.Cascade);
|
||||
|
||||
modelBuilder.Entity<StreamRoleSettings>()
|
||||
.HasMany(x => x.Whitelist)
|
||||
.WithOne(x => x.StreamRoleSettings)
|
||||
.HasForeignKey(x => x.StreamRoleSettingsId)
|
||||
.OnDelete(DeleteBehavior.Cascade);
|
||||
|
||||
modelBuilder.Entity<StreamRoleSettings>()
|
||||
.HasMany(x => x.Blacklist)
|
||||
.WithOne(x => x.StreamRoleSettings)
|
||||
.HasForeignKey(x => x.StreamRoleSettingsId)
|
||||
.OnDelete(DeleteBehavior.Cascade);
|
||||
|
||||
// end streamrole
|
||||
|
||||
modelBuilder.Entity<GuildConfig>()
|
||||
.HasOne(x => x.XpSettings)
|
||||
.WithOne(x => x.GuildConfig)
|
||||
.HasForeignKey<XpSettings>(x => x.GuildConfigId)
|
||||
.OnDelete(DeleteBehavior.Cascade);
|
||||
|
||||
modelBuilder.Entity<GuildConfig>()
|
||||
.HasMany(x => x.FeedSubs)
|
||||
.WithOne(x => x.GuildConfig)
|
||||
.HasForeignKey(x => x.GuildConfigId)
|
||||
.OnDelete(DeleteBehavior.Cascade);
|
||||
|
||||
modelBuilder.Entity<GuildConfig>()
|
||||
.HasMany(x => x.SelfAssignableRoleGroupNames)
|
||||
.WithOne()
|
||||
.OnDelete(DeleteBehavior.Cascade);
|
||||
|
||||
modelBuilder.Entity<FeedSub>()
|
||||
.HasAlternateKey(x => new
|
||||
{
|
||||
@@ -117,11 +275,6 @@ public abstract class NadekoContext : DbContext
|
||||
|
||||
#endregion
|
||||
|
||||
#region streamrole
|
||||
|
||||
modelBuilder.Entity<StreamRoleSettings>().HasOne(x => x.GuildConfig).WithOne(x => x.StreamRole);
|
||||
|
||||
#endregion
|
||||
|
||||
#region Self Assignable Roles
|
||||
|
||||
@@ -217,12 +370,6 @@ public abstract class NadekoContext : DbContext
|
||||
|
||||
#endregion
|
||||
|
||||
#region XpSettings
|
||||
|
||||
modelBuilder.Entity<XpSettings>().HasOne(x => x.GuildConfig).WithOne(x => x.XpSettings);
|
||||
|
||||
#endregion
|
||||
|
||||
#region XpRoleReward
|
||||
|
||||
modelBuilder.Entity<XpRoleReward>()
|
||||
@@ -233,6 +380,21 @@ public abstract class NadekoContext : DbContext
|
||||
})
|
||||
.IsUnique();
|
||||
|
||||
modelBuilder.Entity<XpSettings>()
|
||||
.HasMany(x => x.RoleRewards)
|
||||
.WithOne(x => x.XpSettings)
|
||||
.OnDelete(DeleteBehavior.Cascade);
|
||||
|
||||
modelBuilder.Entity<XpSettings>()
|
||||
.HasMany(x => x.CurrencyRewards)
|
||||
.WithOne(x => x.XpSettings)
|
||||
.OnDelete(DeleteBehavior.Cascade);
|
||||
|
||||
modelBuilder.Entity<XpSettings>()
|
||||
.HasMany(x => x.ExclusionList)
|
||||
.WithOne(x => x.XpSettings)
|
||||
.OnDelete(DeleteBehavior.Cascade);
|
||||
|
||||
#endregion
|
||||
|
||||
#region Club
|
||||
@@ -331,9 +493,9 @@ public abstract class NadekoContext : DbContext
|
||||
|
||||
modelBuilder.Entity<BanTemplate>().HasIndex(x => x.GuildId).IsUnique();
|
||||
modelBuilder.Entity<BanTemplate>()
|
||||
.Property(x => x.PruneDays)
|
||||
.HasDefaultValue(null)
|
||||
.IsRequired(false);
|
||||
.Property(x => x.PruneDays)
|
||||
.HasDefaultValue(null)
|
||||
.IsRequired(false);
|
||||
|
||||
#endregion
|
||||
|
||||
@@ -433,19 +595,9 @@ public abstract class NadekoContext : DbContext
|
||||
});
|
||||
|
||||
// quotes are per user id
|
||||
modelBuilder.Entity<PatronQuota>(pq =>
|
||||
{
|
||||
pq.HasIndex(x => x.UserId).IsUnique(false);
|
||||
pq.HasKey(x => new
|
||||
{
|
||||
x.UserId,
|
||||
x.FeatureType,
|
||||
x.Feature
|
||||
});
|
||||
});
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
#region Xp Item Shop
|
||||
|
||||
modelBuilder.Entity<XpShopOwnedItem>(
|
||||
@@ -453,76 +605,77 @@ public abstract class NadekoContext : DbContext
|
||||
{
|
||||
// user can own only one of each item
|
||||
x.HasIndex(model => new
|
||||
{
|
||||
model.UserId,
|
||||
model.ItemType,
|
||||
model.ItemKey
|
||||
})
|
||||
.IsUnique();
|
||||
{
|
||||
model.UserId,
|
||||
model.ItemType,
|
||||
model.ItemKey
|
||||
})
|
||||
.IsUnique();
|
||||
});
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
#region AutoPublish
|
||||
|
||||
modelBuilder.Entity<AutoPublishChannel>(apc => apc
|
||||
.HasIndex(x => x.GuildId)
|
||||
.IsUnique());
|
||||
.HasIndex(x => x.GuildId)
|
||||
.IsUnique());
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
#region GamblingStats
|
||||
|
||||
modelBuilder.Entity<GamblingStats>(gs => gs
|
||||
.HasIndex(x => x.Feature)
|
||||
.IsUnique());
|
||||
.HasIndex(x => x.Feature)
|
||||
.IsUnique());
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
#region Sticky Roles
|
||||
|
||||
|
||||
modelBuilder.Entity<StickyRole>(sr => sr.HasIndex(x => new
|
||||
{
|
||||
x.GuildId,
|
||||
x.UserId
|
||||
}).IsUnique());
|
||||
|
||||
{
|
||||
x.GuildId,
|
||||
x.UserId
|
||||
})
|
||||
.IsUnique());
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
|
||||
|
||||
#region Giveaway
|
||||
|
||||
modelBuilder.Entity<GiveawayModel>()
|
||||
.HasMany(x => x.Participants)
|
||||
.WithOne()
|
||||
.HasForeignKey(x => x.GiveawayId)
|
||||
.OnDelete(DeleteBehavior.Cascade);
|
||||
|
||||
.HasMany(x => x.Participants)
|
||||
.WithOne()
|
||||
.HasForeignKey(x => x.GiveawayId)
|
||||
.OnDelete(DeleteBehavior.Cascade);
|
||||
|
||||
modelBuilder.Entity<GiveawayUser>(gu => gu
|
||||
.HasIndex(x => new
|
||||
{
|
||||
x.GiveawayId,
|
||||
x.UserId
|
||||
})
|
||||
.IsUnique());
|
||||
|
||||
.HasIndex(x => new
|
||||
{
|
||||
x.GiveawayId,
|
||||
x.UserId
|
||||
})
|
||||
.IsUnique());
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
#region Todo
|
||||
|
||||
modelBuilder.Entity<TodoModel>()
|
||||
.HasKey(x => x.Id);
|
||||
|
||||
|
||||
modelBuilder.Entity<TodoModel>()
|
||||
.HasIndex(x => x.UserId)
|
||||
.IsUnique(false);
|
||||
|
||||
.HasIndex(x => x.UserId)
|
||||
.IsUnique(false);
|
||||
|
||||
modelBuilder.Entity<ArchivedTodoListModel>()
|
||||
.HasMany(x => x.Items)
|
||||
.WithOne()
|
||||
.HasForeignKey(x => x.ArchiveId)
|
||||
.OnDelete(DeleteBehavior.Cascade);
|
||||
|
||||
.HasMany(x => x.Items)
|
||||
.WithOne()
|
||||
.HasForeignKey(x => x.ArchiveId)
|
||||
.OnDelete(DeleteBehavior.Cascade);
|
||||
|
||||
#endregion
|
||||
}
|
||||
|
||||
|
@@ -1,5 +1,6 @@
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
using NadekoBot.Db.Models;
|
||||
|
||||
namespace NadekoBot.Migrations;
|
||||
|
||||
@@ -39,4 +40,15 @@ left join guildconfigs on reactionrolemessage.guildconfigid = guildconfigs.id;")
|
||||
throw new NotSupportedException("This database provider doesn't have an implementation for MigrateRero");
|
||||
}
|
||||
}
|
||||
|
||||
public static void GuildConfigCleanup(MigrationBuilder builder)
|
||||
{
|
||||
builder.Sql($"""
|
||||
DELETE FROM "StreamRoleBlacklistedUser" WHERE "StreamRoleSettingsId" is NULL;
|
||||
""");
|
||||
|
||||
builder.Sql($"""
|
||||
DELETE FROM "DelMsgOnCmdChannel" WHERE "GuildConfigId" is NULL;
|
||||
""");
|
||||
}
|
||||
}
|
3819
src/NadekoBot/Migrations/Mysql/20240518221440_guidlconfig-cleanup.Designer.cs
generated
Normal file
3819
src/NadekoBot/Migrations/Mysql/20240518221440_guidlconfig-cleanup.Designer.cs
generated
Normal file
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,703 @@
|
||||
using System;
|
||||
using Microsoft.EntityFrameworkCore.Metadata;
|
||||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
|
||||
#nullable disable
|
||||
|
||||
namespace NadekoBot.Migrations.Mysql
|
||||
{
|
||||
/// <inheritdoc />
|
||||
public partial class guidlconfigcleanup : Migration
|
||||
{
|
||||
/// <inheritdoc />
|
||||
protected override void Up(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.DropForeignKey(
|
||||
name: "fk_antiraidsetting_guildconfigs_guildconfigid",
|
||||
table: "antiraidsetting");
|
||||
|
||||
migrationBuilder.DropForeignKey(
|
||||
name: "fk_antispamignore_antispamsetting_antispamsettingid",
|
||||
table: "antispamignore");
|
||||
|
||||
migrationBuilder.DropForeignKey(
|
||||
name: "fk_antispamsetting_guildconfigs_guildconfigid",
|
||||
table: "antispamsetting");
|
||||
|
||||
migrationBuilder.DropForeignKey(
|
||||
name: "fk_commandalias_guildconfigs_guildconfigid",
|
||||
table: "commandalias");
|
||||
|
||||
migrationBuilder.DropForeignKey(
|
||||
name: "fk_commandcooldown_guildconfigs_guildconfigid",
|
||||
table: "commandcooldown");
|
||||
|
||||
migrationBuilder.DropForeignKey(
|
||||
name: "fk_delmsgoncmdchannel_guildconfigs_guildconfigid",
|
||||
table: "delmsgoncmdchannel");
|
||||
|
||||
migrationBuilder.DropForeignKey(
|
||||
name: "fk_excludeditem_xpsettings_xpsettingsid",
|
||||
table: "excludeditem");
|
||||
|
||||
migrationBuilder.DropForeignKey(
|
||||
name: "fk_filterchannelid_guildconfigs_guildconfigid",
|
||||
table: "filterchannelid");
|
||||
|
||||
migrationBuilder.DropForeignKey(
|
||||
name: "fk_filteredword_guildconfigs_guildconfigid",
|
||||
table: "filteredword");
|
||||
|
||||
migrationBuilder.DropForeignKey(
|
||||
name: "fk_filterlinkschannelid_guildconfigs_guildconfigid",
|
||||
table: "filterlinkschannelid");
|
||||
|
||||
migrationBuilder.DropForeignKey(
|
||||
name: "fk_filterwordschannelid_guildconfigs_guildconfigid",
|
||||
table: "filterwordschannelid");
|
||||
|
||||
migrationBuilder.DropForeignKey(
|
||||
name: "fk_followedstream_guildconfigs_guildconfigid",
|
||||
table: "followedstream");
|
||||
|
||||
migrationBuilder.DropForeignKey(
|
||||
name: "fk_gcchannelid_guildconfigs_guildconfigid",
|
||||
table: "gcchannelid");
|
||||
|
||||
migrationBuilder.DropForeignKey(
|
||||
name: "fk_muteduserid_guildconfigs_guildconfigid",
|
||||
table: "muteduserid");
|
||||
|
||||
migrationBuilder.DropForeignKey(
|
||||
name: "fk_permissions_guildconfigs_guildconfigid",
|
||||
table: "permissions");
|
||||
|
||||
migrationBuilder.DropForeignKey(
|
||||
name: "fk_shopentry_guildconfigs_guildconfigid",
|
||||
table: "shopentry");
|
||||
|
||||
migrationBuilder.DropForeignKey(
|
||||
name: "fk_shopentryitem_shopentry_shopentryid",
|
||||
table: "shopentryitem");
|
||||
|
||||
migrationBuilder.DropForeignKey(
|
||||
name: "fk_slowmodeignoredrole_guildconfigs_guildconfigid",
|
||||
table: "slowmodeignoredrole");
|
||||
|
||||
migrationBuilder.DropForeignKey(
|
||||
name: "fk_slowmodeignoreduser_guildconfigs_guildconfigid",
|
||||
table: "slowmodeignoreduser");
|
||||
|
||||
migrationBuilder.DropForeignKey(
|
||||
name: "fk_streamroleblacklisteduser_streamrolesettings_streamrolesetti~",
|
||||
table: "streamroleblacklisteduser");
|
||||
|
||||
migrationBuilder.DropForeignKey(
|
||||
name: "fk_streamrolewhitelisteduser_streamrolesettings_streamrolesetti~",
|
||||
table: "streamrolewhitelisteduser");
|
||||
|
||||
migrationBuilder.DropForeignKey(
|
||||
name: "fk_unbantimer_guildconfigs_guildconfigid",
|
||||
table: "unbantimer");
|
||||
|
||||
migrationBuilder.DropForeignKey(
|
||||
name: "fk_unmutetimer_guildconfigs_guildconfigid",
|
||||
table: "unmutetimer");
|
||||
|
||||
migrationBuilder.DropForeignKey(
|
||||
name: "fk_unroletimer_guildconfigs_guildconfigid",
|
||||
table: "unroletimer");
|
||||
|
||||
migrationBuilder.DropForeignKey(
|
||||
name: "fk_vcroleinfo_guildconfigs_guildconfigid",
|
||||
table: "vcroleinfo");
|
||||
|
||||
migrationBuilder.DropForeignKey(
|
||||
name: "fk_warningpunishment_guildconfigs_guildconfigid",
|
||||
table: "warningpunishment");
|
||||
|
||||
migrationBuilder.DropTable(
|
||||
name: "ignoredvoicepresencechannels");
|
||||
|
||||
migrationBuilder.AlterColumn<int>(
|
||||
name: "streamrolesettingsid",
|
||||
table: "streamrolewhitelisteduser",
|
||||
type: "int",
|
||||
nullable: false,
|
||||
defaultValue: 0,
|
||||
oldClrType: typeof(int),
|
||||
oldType: "int",
|
||||
oldNullable: true);
|
||||
|
||||
migrationBuilder.AlterColumn<int>(
|
||||
name: "streamrolesettingsid",
|
||||
table: "streamroleblacklisteduser",
|
||||
type: "int",
|
||||
nullable: false,
|
||||
defaultValue: 0,
|
||||
oldClrType: typeof(int),
|
||||
oldType: "int",
|
||||
oldNullable: true);
|
||||
|
||||
migrationBuilder.AlterColumn<int>(
|
||||
name: "guildconfigid",
|
||||
table: "delmsgoncmdchannel",
|
||||
type: "int",
|
||||
nullable: false,
|
||||
defaultValue: 0,
|
||||
oldClrType: typeof(int),
|
||||
oldType: "int",
|
||||
oldNullable: true);
|
||||
|
||||
migrationBuilder.AddForeignKey(
|
||||
name: "fk_antiraidsetting_guildconfigs_guildconfigid",
|
||||
table: "antiraidsetting",
|
||||
column: "guildconfigid",
|
||||
principalTable: "guildconfigs",
|
||||
principalColumn: "id",
|
||||
onDelete: ReferentialAction.Cascade);
|
||||
|
||||
migrationBuilder.AddForeignKey(
|
||||
name: "fk_antispamignore_antispamsetting_antispamsettingid",
|
||||
table: "antispamignore",
|
||||
column: "antispamsettingid",
|
||||
principalTable: "antispamsetting",
|
||||
principalColumn: "id",
|
||||
onDelete: ReferentialAction.Cascade);
|
||||
|
||||
migrationBuilder.AddForeignKey(
|
||||
name: "fk_antispamsetting_guildconfigs_guildconfigid",
|
||||
table: "antispamsetting",
|
||||
column: "guildconfigid",
|
||||
principalTable: "guildconfigs",
|
||||
principalColumn: "id",
|
||||
onDelete: ReferentialAction.Cascade);
|
||||
|
||||
migrationBuilder.AddForeignKey(
|
||||
name: "fk_commandalias_guildconfigs_guildconfigid",
|
||||
table: "commandalias",
|
||||
column: "guildconfigid",
|
||||
principalTable: "guildconfigs",
|
||||
principalColumn: "id",
|
||||
onDelete: ReferentialAction.Cascade);
|
||||
|
||||
migrationBuilder.AddForeignKey(
|
||||
name: "fk_commandcooldown_guildconfigs_guildconfigid",
|
||||
table: "commandcooldown",
|
||||
column: "guildconfigid",
|
||||
principalTable: "guildconfigs",
|
||||
principalColumn: "id",
|
||||
onDelete: ReferentialAction.Cascade);
|
||||
|
||||
migrationBuilder.AddForeignKey(
|
||||
name: "fk_delmsgoncmdchannel_guildconfigs_guildconfigid",
|
||||
table: "delmsgoncmdchannel",
|
||||
column: "guildconfigid",
|
||||
principalTable: "guildconfigs",
|
||||
principalColumn: "id",
|
||||
onDelete: ReferentialAction.Cascade);
|
||||
|
||||
migrationBuilder.AddForeignKey(
|
||||
name: "fk_excludeditem_xpsettings_xpsettingsid",
|
||||
table: "excludeditem",
|
||||
column: "xpsettingsid",
|
||||
principalTable: "xpsettings",
|
||||
principalColumn: "id",
|
||||
onDelete: ReferentialAction.Cascade);
|
||||
|
||||
migrationBuilder.AddForeignKey(
|
||||
name: "fk_filterchannelid_guildconfigs_guildconfigid",
|
||||
table: "filterchannelid",
|
||||
column: "guildconfigid",
|
||||
principalTable: "guildconfigs",
|
||||
principalColumn: "id",
|
||||
onDelete: ReferentialAction.Cascade);
|
||||
|
||||
migrationBuilder.AddForeignKey(
|
||||
name: "fk_filteredword_guildconfigs_guildconfigid",
|
||||
table: "filteredword",
|
||||
column: "guildconfigid",
|
||||
principalTable: "guildconfigs",
|
||||
principalColumn: "id",
|
||||
onDelete: ReferentialAction.Cascade);
|
||||
|
||||
migrationBuilder.AddForeignKey(
|
||||
name: "fk_filterlinkschannelid_guildconfigs_guildconfigid",
|
||||
table: "filterlinkschannelid",
|
||||
column: "guildconfigid",
|
||||
principalTable: "guildconfigs",
|
||||
principalColumn: "id",
|
||||
onDelete: ReferentialAction.Cascade);
|
||||
|
||||
migrationBuilder.AddForeignKey(
|
||||
name: "fk_filterwordschannelid_guildconfigs_guildconfigid",
|
||||
table: "filterwordschannelid",
|
||||
column: "guildconfigid",
|
||||
principalTable: "guildconfigs",
|
||||
principalColumn: "id",
|
||||
onDelete: ReferentialAction.Cascade);
|
||||
|
||||
migrationBuilder.AddForeignKey(
|
||||
name: "fk_followedstream_guildconfigs_guildconfigid",
|
||||
table: "followedstream",
|
||||
column: "guildconfigid",
|
||||
principalTable: "guildconfigs",
|
||||
principalColumn: "id",
|
||||
onDelete: ReferentialAction.Cascade);
|
||||
|
||||
migrationBuilder.AddForeignKey(
|
||||
name: "fk_gcchannelid_guildconfigs_guildconfigid",
|
||||
table: "gcchannelid",
|
||||
column: "guildconfigid",
|
||||
principalTable: "guildconfigs",
|
||||
principalColumn: "id",
|
||||
onDelete: ReferentialAction.Cascade);
|
||||
|
||||
migrationBuilder.AddForeignKey(
|
||||
name: "fk_muteduserid_guildconfigs_guildconfigid",
|
||||
table: "muteduserid",
|
||||
column: "guildconfigid",
|
||||
principalTable: "guildconfigs",
|
||||
principalColumn: "id",
|
||||
onDelete: ReferentialAction.Cascade);
|
||||
|
||||
migrationBuilder.AddForeignKey(
|
||||
name: "fk_permissions_guildconfigs_guildconfigid",
|
||||
table: "permissions",
|
||||
column: "guildconfigid",
|
||||
principalTable: "guildconfigs",
|
||||
principalColumn: "id",
|
||||
onDelete: ReferentialAction.Cascade);
|
||||
|
||||
migrationBuilder.AddForeignKey(
|
||||
name: "fk_shopentry_guildconfigs_guildconfigid",
|
||||
table: "shopentry",
|
||||
column: "guildconfigid",
|
||||
principalTable: "guildconfigs",
|
||||
principalColumn: "id",
|
||||
onDelete: ReferentialAction.Cascade);
|
||||
|
||||
migrationBuilder.AddForeignKey(
|
||||
name: "fk_shopentryitem_shopentry_shopentryid",
|
||||
table: "shopentryitem",
|
||||
column: "shopentryid",
|
||||
principalTable: "shopentry",
|
||||
principalColumn: "id",
|
||||
onDelete: ReferentialAction.Cascade);
|
||||
|
||||
migrationBuilder.AddForeignKey(
|
||||
name: "fk_slowmodeignoredrole_guildconfigs_guildconfigid",
|
||||
table: "slowmodeignoredrole",
|
||||
column: "guildconfigid",
|
||||
principalTable: "guildconfigs",
|
||||
principalColumn: "id",
|
||||
onDelete: ReferentialAction.Cascade);
|
||||
|
||||
migrationBuilder.AddForeignKey(
|
||||
name: "fk_slowmodeignoreduser_guildconfigs_guildconfigid",
|
||||
table: "slowmodeignoreduser",
|
||||
column: "guildconfigid",
|
||||
principalTable: "guildconfigs",
|
||||
principalColumn: "id",
|
||||
onDelete: ReferentialAction.Cascade);
|
||||
|
||||
migrationBuilder.AddForeignKey(
|
||||
name: "fk_streamroleblacklisteduser_streamrolesettings_streamrolesetti~",
|
||||
table: "streamroleblacklisteduser",
|
||||
column: "streamrolesettingsid",
|
||||
principalTable: "streamrolesettings",
|
||||
principalColumn: "id",
|
||||
onDelete: ReferentialAction.Cascade);
|
||||
|
||||
migrationBuilder.AddForeignKey(
|
||||
name: "fk_streamrolewhitelisteduser_streamrolesettings_streamrolesetti~",
|
||||
table: "streamrolewhitelisteduser",
|
||||
column: "streamrolesettingsid",
|
||||
principalTable: "streamrolesettings",
|
||||
principalColumn: "id",
|
||||
onDelete: ReferentialAction.Cascade);
|
||||
|
||||
migrationBuilder.AddForeignKey(
|
||||
name: "fk_unbantimer_guildconfigs_guildconfigid",
|
||||
table: "unbantimer",
|
||||
column: "guildconfigid",
|
||||
principalTable: "guildconfigs",
|
||||
principalColumn: "id",
|
||||
onDelete: ReferentialAction.Cascade);
|
||||
|
||||
migrationBuilder.AddForeignKey(
|
||||
name: "fk_unmutetimer_guildconfigs_guildconfigid",
|
||||
table: "unmutetimer",
|
||||
column: "guildconfigid",
|
||||
principalTable: "guildconfigs",
|
||||
principalColumn: "id",
|
||||
onDelete: ReferentialAction.Cascade);
|
||||
|
||||
migrationBuilder.AddForeignKey(
|
||||
name: "fk_unroletimer_guildconfigs_guildconfigid",
|
||||
table: "unroletimer",
|
||||
column: "guildconfigid",
|
||||
principalTable: "guildconfigs",
|
||||
principalColumn: "id",
|
||||
onDelete: ReferentialAction.Cascade);
|
||||
|
||||
migrationBuilder.AddForeignKey(
|
||||
name: "fk_vcroleinfo_guildconfigs_guildconfigid",
|
||||
table: "vcroleinfo",
|
||||
column: "guildconfigid",
|
||||
principalTable: "guildconfigs",
|
||||
principalColumn: "id",
|
||||
onDelete: ReferentialAction.Cascade);
|
||||
|
||||
migrationBuilder.AddForeignKey(
|
||||
name: "fk_warningpunishment_guildconfigs_guildconfigid",
|
||||
table: "warningpunishment",
|
||||
column: "guildconfigid",
|
||||
principalTable: "guildconfigs",
|
||||
principalColumn: "id",
|
||||
onDelete: ReferentialAction.Cascade);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override void Down(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.DropForeignKey(
|
||||
name: "fk_antiraidsetting_guildconfigs_guildconfigid",
|
||||
table: "antiraidsetting");
|
||||
|
||||
migrationBuilder.DropForeignKey(
|
||||
name: "fk_antispamignore_antispamsetting_antispamsettingid",
|
||||
table: "antispamignore");
|
||||
|
||||
migrationBuilder.DropForeignKey(
|
||||
name: "fk_antispamsetting_guildconfigs_guildconfigid",
|
||||
table: "antispamsetting");
|
||||
|
||||
migrationBuilder.DropForeignKey(
|
||||
name: "fk_commandalias_guildconfigs_guildconfigid",
|
||||
table: "commandalias");
|
||||
|
||||
migrationBuilder.DropForeignKey(
|
||||
name: "fk_commandcooldown_guildconfigs_guildconfigid",
|
||||
table: "commandcooldown");
|
||||
|
||||
migrationBuilder.DropForeignKey(
|
||||
name: "fk_delmsgoncmdchannel_guildconfigs_guildconfigid",
|
||||
table: "delmsgoncmdchannel");
|
||||
|
||||
migrationBuilder.DropForeignKey(
|
||||
name: "fk_excludeditem_xpsettings_xpsettingsid",
|
||||
table: "excludeditem");
|
||||
|
||||
migrationBuilder.DropForeignKey(
|
||||
name: "fk_filterchannelid_guildconfigs_guildconfigid",
|
||||
table: "filterchannelid");
|
||||
|
||||
migrationBuilder.DropForeignKey(
|
||||
name: "fk_filteredword_guildconfigs_guildconfigid",
|
||||
table: "filteredword");
|
||||
|
||||
migrationBuilder.DropForeignKey(
|
||||
name: "fk_filterlinkschannelid_guildconfigs_guildconfigid",
|
||||
table: "filterlinkschannelid");
|
||||
|
||||
migrationBuilder.DropForeignKey(
|
||||
name: "fk_filterwordschannelid_guildconfigs_guildconfigid",
|
||||
table: "filterwordschannelid");
|
||||
|
||||
migrationBuilder.DropForeignKey(
|
||||
name: "fk_followedstream_guildconfigs_guildconfigid",
|
||||
table: "followedstream");
|
||||
|
||||
migrationBuilder.DropForeignKey(
|
||||
name: "fk_gcchannelid_guildconfigs_guildconfigid",
|
||||
table: "gcchannelid");
|
||||
|
||||
migrationBuilder.DropForeignKey(
|
||||
name: "fk_muteduserid_guildconfigs_guildconfigid",
|
||||
table: "muteduserid");
|
||||
|
||||
migrationBuilder.DropForeignKey(
|
||||
name: "fk_permissions_guildconfigs_guildconfigid",
|
||||
table: "permissions");
|
||||
|
||||
migrationBuilder.DropForeignKey(
|
||||
name: "fk_shopentry_guildconfigs_guildconfigid",
|
||||
table: "shopentry");
|
||||
|
||||
migrationBuilder.DropForeignKey(
|
||||
name: "fk_shopentryitem_shopentry_shopentryid",
|
||||
table: "shopentryitem");
|
||||
|
||||
migrationBuilder.DropForeignKey(
|
||||
name: "fk_slowmodeignoredrole_guildconfigs_guildconfigid",
|
||||
table: "slowmodeignoredrole");
|
||||
|
||||
migrationBuilder.DropForeignKey(
|
||||
name: "fk_slowmodeignoreduser_guildconfigs_guildconfigid",
|
||||
table: "slowmodeignoreduser");
|
||||
|
||||
migrationBuilder.DropForeignKey(
|
||||
name: "fk_streamroleblacklisteduser_streamrolesettings_streamrolesetti~",
|
||||
table: "streamroleblacklisteduser");
|
||||
|
||||
migrationBuilder.DropForeignKey(
|
||||
name: "fk_streamrolewhitelisteduser_streamrolesettings_streamrolesetti~",
|
||||
table: "streamrolewhitelisteduser");
|
||||
|
||||
migrationBuilder.DropForeignKey(
|
||||
name: "fk_unbantimer_guildconfigs_guildconfigid",
|
||||
table: "unbantimer");
|
||||
|
||||
migrationBuilder.DropForeignKey(
|
||||
name: "fk_unmutetimer_guildconfigs_guildconfigid",
|
||||
table: "unmutetimer");
|
||||
|
||||
migrationBuilder.DropForeignKey(
|
||||
name: "fk_unroletimer_guildconfigs_guildconfigid",
|
||||
table: "unroletimer");
|
||||
|
||||
migrationBuilder.DropForeignKey(
|
||||
name: "fk_vcroleinfo_guildconfigs_guildconfigid",
|
||||
table: "vcroleinfo");
|
||||
|
||||
migrationBuilder.DropForeignKey(
|
||||
name: "fk_warningpunishment_guildconfigs_guildconfigid",
|
||||
table: "warningpunishment");
|
||||
|
||||
migrationBuilder.AlterColumn<int>(
|
||||
name: "streamrolesettingsid",
|
||||
table: "streamrolewhitelisteduser",
|
||||
type: "int",
|
||||
nullable: true,
|
||||
oldClrType: typeof(int),
|
||||
oldType: "int");
|
||||
|
||||
migrationBuilder.AlterColumn<int>(
|
||||
name: "streamrolesettingsid",
|
||||
table: "streamroleblacklisteduser",
|
||||
type: "int",
|
||||
nullable: true,
|
||||
oldClrType: typeof(int),
|
||||
oldType: "int");
|
||||
|
||||
migrationBuilder.AlterColumn<int>(
|
||||
name: "guildconfigid",
|
||||
table: "delmsgoncmdchannel",
|
||||
type: "int",
|
||||
nullable: true,
|
||||
oldClrType: typeof(int),
|
||||
oldType: "int");
|
||||
|
||||
migrationBuilder.CreateTable(
|
||||
name: "ignoredvoicepresencechannels",
|
||||
columns: table => new
|
||||
{
|
||||
id = table.Column<int>(type: "int", nullable: false)
|
||||
.Annotation("MySql:ValueGenerationStrategy", MySqlValueGenerationStrategy.IdentityColumn),
|
||||
logsettingid = table.Column<int>(type: "int", nullable: true),
|
||||
channelid = table.Column<ulong>(type: "bigint unsigned", nullable: false),
|
||||
dateadded = table.Column<DateTime>(type: "datetime(6)", nullable: true)
|
||||
},
|
||||
constraints: table =>
|
||||
{
|
||||
table.PrimaryKey("pk_ignoredvoicepresencechannels", x => x.id);
|
||||
table.ForeignKey(
|
||||
name: "fk_ignoredvoicepresencechannels_logsettings_logsettingid",
|
||||
column: x => x.logsettingid,
|
||||
principalTable: "logsettings",
|
||||
principalColumn: "id");
|
||||
})
|
||||
.Annotation("MySql:CharSet", "utf8mb4");
|
||||
|
||||
migrationBuilder.CreateIndex(
|
||||
name: "ix_ignoredvoicepresencechannels_logsettingid",
|
||||
table: "ignoredvoicepresencechannels",
|
||||
column: "logsettingid");
|
||||
|
||||
migrationBuilder.AddForeignKey(
|
||||
name: "fk_antiraidsetting_guildconfigs_guildconfigid",
|
||||
table: "antiraidsetting",
|
||||
column: "guildconfigid",
|
||||
principalTable: "guildconfigs",
|
||||
principalColumn: "id",
|
||||
onDelete: ReferentialAction.Cascade);
|
||||
|
||||
migrationBuilder.AddForeignKey(
|
||||
name: "fk_antispamignore_antispamsetting_antispamsettingid",
|
||||
table: "antispamignore",
|
||||
column: "antispamsettingid",
|
||||
principalTable: "antispamsetting",
|
||||
principalColumn: "id");
|
||||
|
||||
migrationBuilder.AddForeignKey(
|
||||
name: "fk_antispamsetting_guildconfigs_guildconfigid",
|
||||
table: "antispamsetting",
|
||||
column: "guildconfigid",
|
||||
principalTable: "guildconfigs",
|
||||
principalColumn: "id",
|
||||
onDelete: ReferentialAction.Cascade);
|
||||
|
||||
migrationBuilder.AddForeignKey(
|
||||
name: "fk_commandalias_guildconfigs_guildconfigid",
|
||||
table: "commandalias",
|
||||
column: "guildconfigid",
|
||||
principalTable: "guildconfigs",
|
||||
principalColumn: "id");
|
||||
|
||||
migrationBuilder.AddForeignKey(
|
||||
name: "fk_commandcooldown_guildconfigs_guildconfigid",
|
||||
table: "commandcooldown",
|
||||
column: "guildconfigid",
|
||||
principalTable: "guildconfigs",
|
||||
principalColumn: "id");
|
||||
|
||||
migrationBuilder.AddForeignKey(
|
||||
name: "fk_delmsgoncmdchannel_guildconfigs_guildconfigid",
|
||||
table: "delmsgoncmdchannel",
|
||||
column: "guildconfigid",
|
||||
principalTable: "guildconfigs",
|
||||
principalColumn: "id");
|
||||
|
||||
migrationBuilder.AddForeignKey(
|
||||
name: "fk_excludeditem_xpsettings_xpsettingsid",
|
||||
table: "excludeditem",
|
||||
column: "xpsettingsid",
|
||||
principalTable: "xpsettings",
|
||||
principalColumn: "id");
|
||||
|
||||
migrationBuilder.AddForeignKey(
|
||||
name: "fk_filterchannelid_guildconfigs_guildconfigid",
|
||||
table: "filterchannelid",
|
||||
column: "guildconfigid",
|
||||
principalTable: "guildconfigs",
|
||||
principalColumn: "id");
|
||||
|
||||
migrationBuilder.AddForeignKey(
|
||||
name: "fk_filteredword_guildconfigs_guildconfigid",
|
||||
table: "filteredword",
|
||||
column: "guildconfigid",
|
||||
principalTable: "guildconfigs",
|
||||
principalColumn: "id");
|
||||
|
||||
migrationBuilder.AddForeignKey(
|
||||
name: "fk_filterlinkschannelid_guildconfigs_guildconfigid",
|
||||
table: "filterlinkschannelid",
|
||||
column: "guildconfigid",
|
||||
principalTable: "guildconfigs",
|
||||
principalColumn: "id");
|
||||
|
||||
migrationBuilder.AddForeignKey(
|
||||
name: "fk_filterwordschannelid_guildconfigs_guildconfigid",
|
||||
table: "filterwordschannelid",
|
||||
column: "guildconfigid",
|
||||
principalTable: "guildconfigs",
|
||||
principalColumn: "id");
|
||||
|
||||
migrationBuilder.AddForeignKey(
|
||||
name: "fk_followedstream_guildconfigs_guildconfigid",
|
||||
table: "followedstream",
|
||||
column: "guildconfigid",
|
||||
principalTable: "guildconfigs",
|
||||
principalColumn: "id");
|
||||
|
||||
migrationBuilder.AddForeignKey(
|
||||
name: "fk_gcchannelid_guildconfigs_guildconfigid",
|
||||
table: "gcchannelid",
|
||||
column: "guildconfigid",
|
||||
principalTable: "guildconfigs",
|
||||
principalColumn: "id");
|
||||
|
||||
migrationBuilder.AddForeignKey(
|
||||
name: "fk_muteduserid_guildconfigs_guildconfigid",
|
||||
table: "muteduserid",
|
||||
column: "guildconfigid",
|
||||
principalTable: "guildconfigs",
|
||||
principalColumn: "id");
|
||||
|
||||
migrationBuilder.AddForeignKey(
|
||||
name: "fk_permissions_guildconfigs_guildconfigid",
|
||||
table: "permissions",
|
||||
column: "guildconfigid",
|
||||
principalTable: "guildconfigs",
|
||||
principalColumn: "id");
|
||||
|
||||
migrationBuilder.AddForeignKey(
|
||||
name: "fk_shopentry_guildconfigs_guildconfigid",
|
||||
table: "shopentry",
|
||||
column: "guildconfigid",
|
||||
principalTable: "guildconfigs",
|
||||
principalColumn: "id");
|
||||
|
||||
migrationBuilder.AddForeignKey(
|
||||
name: "fk_shopentryitem_shopentry_shopentryid",
|
||||
table: "shopentryitem",
|
||||
column: "shopentryid",
|
||||
principalTable: "shopentry",
|
||||
principalColumn: "id");
|
||||
|
||||
migrationBuilder.AddForeignKey(
|
||||
name: "fk_slowmodeignoredrole_guildconfigs_guildconfigid",
|
||||
table: "slowmodeignoredrole",
|
||||
column: "guildconfigid",
|
||||
principalTable: "guildconfigs",
|
||||
principalColumn: "id");
|
||||
|
||||
migrationBuilder.AddForeignKey(
|
||||
name: "fk_slowmodeignoreduser_guildconfigs_guildconfigid",
|
||||
table: "slowmodeignoreduser",
|
||||
column: "guildconfigid",
|
||||
principalTable: "guildconfigs",
|
||||
principalColumn: "id");
|
||||
|
||||
migrationBuilder.AddForeignKey(
|
||||
name: "fk_streamroleblacklisteduser_streamrolesettings_streamrolesetti~",
|
||||
table: "streamroleblacklisteduser",
|
||||
column: "streamrolesettingsid",
|
||||
principalTable: "streamrolesettings",
|
||||
principalColumn: "id");
|
||||
|
||||
migrationBuilder.AddForeignKey(
|
||||
name: "fk_streamrolewhitelisteduser_streamrolesettings_streamrolesetti~",
|
||||
table: "streamrolewhitelisteduser",
|
||||
column: "streamrolesettingsid",
|
||||
principalTable: "streamrolesettings",
|
||||
principalColumn: "id");
|
||||
|
||||
migrationBuilder.AddForeignKey(
|
||||
name: "fk_unbantimer_guildconfigs_guildconfigid",
|
||||
table: "unbantimer",
|
||||
column: "guildconfigid",
|
||||
principalTable: "guildconfigs",
|
||||
principalColumn: "id");
|
||||
|
||||
migrationBuilder.AddForeignKey(
|
||||
name: "fk_unmutetimer_guildconfigs_guildconfigid",
|
||||
table: "unmutetimer",
|
||||
column: "guildconfigid",
|
||||
principalTable: "guildconfigs",
|
||||
principalColumn: "id");
|
||||
|
||||
migrationBuilder.AddForeignKey(
|
||||
name: "fk_unroletimer_guildconfigs_guildconfigid",
|
||||
table: "unroletimer",
|
||||
column: "guildconfigid",
|
||||
principalTable: "guildconfigs",
|
||||
principalColumn: "id");
|
||||
|
||||
migrationBuilder.AddForeignKey(
|
||||
name: "fk_vcroleinfo_guildconfigs_guildconfigid",
|
||||
table: "vcroleinfo",
|
||||
column: "guildconfigid",
|
||||
principalTable: "guildconfigs",
|
||||
principalColumn: "id");
|
||||
|
||||
migrationBuilder.AddForeignKey(
|
||||
name: "fk_warningpunishment_guildconfigs_guildconfigid",
|
||||
table: "warningpunishment",
|
||||
column: "guildconfigid",
|
||||
principalTable: "guildconfigs",
|
||||
principalColumn: "id");
|
||||
}
|
||||
}
|
||||
}
|
3784
src/NadekoBot/Migrations/Mysql/20240611180516_remove-patron-limits.Designer.cs
generated
Normal file
3784
src/NadekoBot/Migrations/Mysql/20240611180516_remove-patron-limits.Designer.cs
generated
Normal file
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,44 @@
|
||||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
|
||||
#nullable disable
|
||||
|
||||
namespace NadekoBot.Migrations.Mysql
|
||||
{
|
||||
/// <inheritdoc />
|
||||
public partial class removepatronlimits : Migration
|
||||
{
|
||||
/// <inheritdoc />
|
||||
protected override void Up(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.DropTable(
|
||||
name: "patronquotas");
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override void Down(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.CreateTable(
|
||||
name: "patronquotas",
|
||||
columns: table => new
|
||||
{
|
||||
userid = table.Column<ulong>(type: "bigint unsigned", nullable: false),
|
||||
featuretype = table.Column<int>(type: "int", nullable: false),
|
||||
feature = table.Column<string>(type: "varchar(255)", nullable: false)
|
||||
.Annotation("MySql:CharSet", "utf8mb4"),
|
||||
dailycount = table.Column<uint>(type: "int unsigned", nullable: false),
|
||||
hourlycount = table.Column<uint>(type: "int unsigned", nullable: false),
|
||||
monthlycount = table.Column<uint>(type: "int unsigned", nullable: false)
|
||||
},
|
||||
constraints: table =>
|
||||
{
|
||||
table.PrimaryKey("pk_patronquotas", x => new { x.userid, x.featuretype, x.feature });
|
||||
})
|
||||
.Annotation("MySql:CharSet", "utf8mb4");
|
||||
|
||||
migrationBuilder.CreateIndex(
|
||||
name: "ix_patronquotas_userid",
|
||||
table: "patronquotas",
|
||||
column: "userid");
|
||||
}
|
||||
}
|
||||
}
|
@@ -673,7 +673,7 @@ namespace NadekoBot.Migrations.Mysql
|
||||
.HasColumnType("datetime(6)")
|
||||
.HasColumnName("dateadded");
|
||||
|
||||
b.Property<int?>("GuildConfigId")
|
||||
b.Property<int>("GuildConfigId")
|
||||
.HasColumnType("int")
|
||||
.HasColumnName("guildconfigid");
|
||||
|
||||
@@ -1423,36 +1423,6 @@ namespace NadekoBot.Migrations.Mysql
|
||||
b.ToTable("ignoredlogchannels", (string)null);
|
||||
});
|
||||
|
||||
modelBuilder.Entity("NadekoBot.Db.Models.IgnoredVoicePresenceChannel", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("int")
|
||||
.HasColumnName("id");
|
||||
|
||||
MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property<int>("Id"));
|
||||
|
||||
b.Property<ulong>("ChannelId")
|
||||
.HasColumnType("bigint unsigned")
|
||||
.HasColumnName("channelid");
|
||||
|
||||
b.Property<DateTime?>("DateAdded")
|
||||
.HasColumnType("datetime(6)")
|
||||
.HasColumnName("dateadded");
|
||||
|
||||
b.Property<int?>("LogSettingId")
|
||||
.HasColumnType("int")
|
||||
.HasColumnName("logsettingid");
|
||||
|
||||
b.HasKey("Id")
|
||||
.HasName("pk_ignoredvoicepresencechannels");
|
||||
|
||||
b.HasIndex("LogSettingId")
|
||||
.HasDatabaseName("ix_ignoredvoicepresencechannels_logsettingid");
|
||||
|
||||
b.ToTable("ignoredvoicepresencechannels", (string)null);
|
||||
});
|
||||
|
||||
modelBuilder.Entity("NadekoBot.Db.Models.ImageOnlyChannel", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
@@ -1748,41 +1718,6 @@ namespace NadekoBot.Migrations.Mysql
|
||||
b.ToTable("expressions", (string)null);
|
||||
});
|
||||
|
||||
modelBuilder.Entity("NadekoBot.Db.Models.PatronQuota", b =>
|
||||
{
|
||||
b.Property<ulong>("UserId")
|
||||
.HasColumnType("bigint unsigned")
|
||||
.HasColumnName("userid");
|
||||
|
||||
b.Property<int>("FeatureType")
|
||||
.HasColumnType("int")
|
||||
.HasColumnName("featuretype");
|
||||
|
||||
b.Property<string>("Feature")
|
||||
.HasColumnType("varchar(255)")
|
||||
.HasColumnName("feature");
|
||||
|
||||
b.Property<uint>("DailyCount")
|
||||
.HasColumnType("int unsigned")
|
||||
.HasColumnName("dailycount");
|
||||
|
||||
b.Property<uint>("HourlyCount")
|
||||
.HasColumnType("int unsigned")
|
||||
.HasColumnName("hourlycount");
|
||||
|
||||
b.Property<uint>("MonthlyCount")
|
||||
.HasColumnType("int unsigned")
|
||||
.HasColumnName("monthlycount");
|
||||
|
||||
b.HasKey("UserId", "FeatureType", "Feature")
|
||||
.HasName("pk_patronquotas");
|
||||
|
||||
b.HasIndex("UserId")
|
||||
.HasDatabaseName("ix_patronquotas_userid");
|
||||
|
||||
b.ToTable("patronquotas", (string)null);
|
||||
});
|
||||
|
||||
modelBuilder.Entity("NadekoBot.Db.Models.PatronUser", b =>
|
||||
{
|
||||
b.Property<ulong>("UserId")
|
||||
@@ -2510,7 +2445,7 @@ namespace NadekoBot.Migrations.Mysql
|
||||
.HasColumnType("datetime(6)")
|
||||
.HasColumnName("dateadded");
|
||||
|
||||
b.Property<int?>("StreamRoleSettingsId")
|
||||
b.Property<int>("StreamRoleSettingsId")
|
||||
.HasColumnType("int")
|
||||
.HasColumnName("streamrolesettingsid");
|
||||
|
||||
@@ -2587,7 +2522,7 @@ namespace NadekoBot.Migrations.Mysql
|
||||
.HasColumnType("datetime(6)")
|
||||
.HasColumnName("dateadded");
|
||||
|
||||
b.Property<int?>("StreamRoleSettingsId")
|
||||
b.Property<int>("StreamRoleSettingsId")
|
||||
.HasColumnType("int")
|
||||
.HasColumnName("streamrolesettingsid");
|
||||
|
||||
@@ -3226,14 +3161,12 @@ namespace NadekoBot.Migrations.Mysql
|
||||
|
||||
modelBuilder.Entity("NadekoBot.Db.Models.AntiRaidSetting", b =>
|
||||
{
|
||||
b.HasOne("NadekoBot.Db.Models.GuildConfig", "GuildConfig")
|
||||
b.HasOne("NadekoBot.Db.Models.GuildConfig", null)
|
||||
.WithOne("AntiRaidSetting")
|
||||
.HasForeignKey("NadekoBot.Db.Models.AntiRaidSetting", "GuildConfigId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired()
|
||||
.HasConstraintName("fk_antiraidsetting_guildconfigs_guildconfigid");
|
||||
|
||||
b.Navigation("GuildConfig");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("NadekoBot.Db.Models.AntiSpamIgnore", b =>
|
||||
@@ -3241,19 +3174,18 @@ namespace NadekoBot.Migrations.Mysql
|
||||
b.HasOne("NadekoBot.Db.Models.AntiSpamSetting", null)
|
||||
.WithMany("IgnoredChannels")
|
||||
.HasForeignKey("AntiSpamSettingId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.HasConstraintName("fk_antispamignore_antispamsetting_antispamsettingid");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("NadekoBot.Db.Models.AntiSpamSetting", b =>
|
||||
{
|
||||
b.HasOne("NadekoBot.Db.Models.GuildConfig", "GuildConfig")
|
||||
b.HasOne("NadekoBot.Db.Models.GuildConfig", null)
|
||||
.WithOne("AntiSpamSetting")
|
||||
.HasForeignKey("NadekoBot.Db.Models.AntiSpamSetting", "GuildConfigId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired()
|
||||
.HasConstraintName("fk_antispamsetting_guildconfigs_guildconfigid");
|
||||
|
||||
b.Navigation("GuildConfig");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("NadekoBot.Db.Models.AutoTranslateUser", b =>
|
||||
@@ -3326,6 +3258,7 @@ namespace NadekoBot.Migrations.Mysql
|
||||
b.HasOne("NadekoBot.Db.Models.GuildConfig", null)
|
||||
.WithMany("CommandAliases")
|
||||
.HasForeignKey("GuildConfigId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.HasConstraintName("fk_commandalias_guildconfigs_guildconfigid");
|
||||
});
|
||||
|
||||
@@ -3334,6 +3267,7 @@ namespace NadekoBot.Migrations.Mysql
|
||||
b.HasOne("NadekoBot.Db.Models.GuildConfig", null)
|
||||
.WithMany("CommandCooldowns")
|
||||
.HasForeignKey("GuildConfigId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.HasConstraintName("fk_commandcooldown_guildconfigs_guildconfigid");
|
||||
});
|
||||
|
||||
@@ -3342,6 +3276,8 @@ namespace NadekoBot.Migrations.Mysql
|
||||
b.HasOne("NadekoBot.Db.Models.GuildConfig", null)
|
||||
.WithMany("DelMsgOnCmdChannels")
|
||||
.HasForeignKey("GuildConfigId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired()
|
||||
.HasConstraintName("fk_delmsgoncmdchannel_guildconfigs_guildconfigid");
|
||||
});
|
||||
|
||||
@@ -3358,10 +3294,13 @@ namespace NadekoBot.Migrations.Mysql
|
||||
|
||||
modelBuilder.Entity("NadekoBot.Db.Models.ExcludedItem", b =>
|
||||
{
|
||||
b.HasOne("NadekoBot.Db.Models.XpSettings", null)
|
||||
b.HasOne("NadekoBot.Db.Models.XpSettings", "XpSettings")
|
||||
.WithMany("ExclusionList")
|
||||
.HasForeignKey("XpSettingsId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.HasConstraintName("fk_excludeditem_xpsettings_xpsettingsid");
|
||||
|
||||
b.Navigation("XpSettings");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("NadekoBot.Db.Models.FeedSub", b =>
|
||||
@@ -3381,6 +3320,7 @@ namespace NadekoBot.Migrations.Mysql
|
||||
b.HasOne("NadekoBot.Db.Models.GuildConfig", null)
|
||||
.WithMany("FilterInvitesChannelIds")
|
||||
.HasForeignKey("GuildConfigId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.HasConstraintName("fk_filterchannelid_guildconfigs_guildconfigid");
|
||||
});
|
||||
|
||||
@@ -3389,6 +3329,7 @@ namespace NadekoBot.Migrations.Mysql
|
||||
b.HasOne("NadekoBot.Db.Models.GuildConfig", null)
|
||||
.WithMany("FilterLinksChannelIds")
|
||||
.HasForeignKey("GuildConfigId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.HasConstraintName("fk_filterlinkschannelid_guildconfigs_guildconfigid");
|
||||
});
|
||||
|
||||
@@ -3397,6 +3338,7 @@ namespace NadekoBot.Migrations.Mysql
|
||||
b.HasOne("NadekoBot.Db.Models.GuildConfig", null)
|
||||
.WithMany("FilterWordsChannelIds")
|
||||
.HasForeignKey("GuildConfigId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.HasConstraintName("fk_filterwordschannelid_guildconfigs_guildconfigid");
|
||||
});
|
||||
|
||||
@@ -3405,6 +3347,7 @@ namespace NadekoBot.Migrations.Mysql
|
||||
b.HasOne("NadekoBot.Db.Models.GuildConfig", null)
|
||||
.WithMany("FilteredWords")
|
||||
.HasForeignKey("GuildConfigId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.HasConstraintName("fk_filteredword_guildconfigs_guildconfigid");
|
||||
});
|
||||
|
||||
@@ -3413,6 +3356,7 @@ namespace NadekoBot.Migrations.Mysql
|
||||
b.HasOne("NadekoBot.Db.Models.GuildConfig", null)
|
||||
.WithMany("FollowedStreams")
|
||||
.HasForeignKey("GuildConfigId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.HasConstraintName("fk_followedstream_guildconfigs_guildconfigid");
|
||||
});
|
||||
|
||||
@@ -3421,6 +3365,7 @@ namespace NadekoBot.Migrations.Mysql
|
||||
b.HasOne("NadekoBot.Db.Models.GuildConfig", "GuildConfig")
|
||||
.WithMany("GenerateCurrencyChannelIds")
|
||||
.HasForeignKey("GuildConfigId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.HasConstraintName("fk_gcchannelid_guildconfigs_guildconfigid");
|
||||
|
||||
b.Navigation("GuildConfig");
|
||||
@@ -3460,21 +3405,12 @@ namespace NadekoBot.Migrations.Mysql
|
||||
b.Navigation("LogSetting");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("NadekoBot.Db.Models.IgnoredVoicePresenceChannel", b =>
|
||||
{
|
||||
b.HasOne("NadekoBot.Db.Models.LogSetting", "LogSetting")
|
||||
.WithMany()
|
||||
.HasForeignKey("LogSettingId")
|
||||
.HasConstraintName("fk_ignoredvoicepresencechannels_logsettings_logsettingid");
|
||||
|
||||
b.Navigation("LogSetting");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("NadekoBot.Db.Models.MutedUserId", b =>
|
||||
{
|
||||
b.HasOne("NadekoBot.Db.Models.GuildConfig", null)
|
||||
.WithMany("MutedUsers")
|
||||
.HasForeignKey("GuildConfigId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.HasConstraintName("fk_muteduserid_guildconfigs_guildconfigid");
|
||||
});
|
||||
|
||||
@@ -3483,6 +3419,7 @@ namespace NadekoBot.Migrations.Mysql
|
||||
b.HasOne("NadekoBot.Db.Models.GuildConfig", null)
|
||||
.WithMany("Permissions")
|
||||
.HasForeignKey("GuildConfigId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.HasConstraintName("fk_permissions_guildconfigs_guildconfigid");
|
||||
});
|
||||
|
||||
@@ -3500,6 +3437,7 @@ namespace NadekoBot.Migrations.Mysql
|
||||
b.HasOne("NadekoBot.Db.Models.GuildConfig", null)
|
||||
.WithMany("ShopEntries")
|
||||
.HasForeignKey("GuildConfigId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.HasConstraintName("fk_shopentry_guildconfigs_guildconfigid");
|
||||
});
|
||||
|
||||
@@ -3508,6 +3446,7 @@ namespace NadekoBot.Migrations.Mysql
|
||||
b.HasOne("NadekoBot.Db.Models.ShopEntry", null)
|
||||
.WithMany("Items")
|
||||
.HasForeignKey("ShopEntryId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.HasConstraintName("fk_shopentryitem_shopentry_shopentryid");
|
||||
});
|
||||
|
||||
@@ -3516,6 +3455,7 @@ namespace NadekoBot.Migrations.Mysql
|
||||
b.HasOne("NadekoBot.Db.Models.GuildConfig", null)
|
||||
.WithMany("SlowmodeIgnoredRoles")
|
||||
.HasForeignKey("GuildConfigId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.HasConstraintName("fk_slowmodeignoredrole_guildconfigs_guildconfigid");
|
||||
});
|
||||
|
||||
@@ -3524,15 +3464,20 @@ namespace NadekoBot.Migrations.Mysql
|
||||
b.HasOne("NadekoBot.Db.Models.GuildConfig", null)
|
||||
.WithMany("SlowmodeIgnoredUsers")
|
||||
.HasForeignKey("GuildConfigId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.HasConstraintName("fk_slowmodeignoreduser_guildconfigs_guildconfigid");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("NadekoBot.Db.Models.StreamRoleBlacklistedUser", b =>
|
||||
{
|
||||
b.HasOne("NadekoBot.Db.Models.StreamRoleSettings", null)
|
||||
b.HasOne("NadekoBot.Db.Models.StreamRoleSettings", "StreamRoleSettings")
|
||||
.WithMany("Blacklist")
|
||||
.HasForeignKey("StreamRoleSettingsId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired()
|
||||
.HasConstraintName("fk_streamroleblacklisteduser_streamrolesettings_streamrolesetti~");
|
||||
|
||||
b.Navigation("StreamRoleSettings");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("NadekoBot.Db.Models.StreamRoleSettings", b =>
|
||||
@@ -3549,10 +3494,14 @@ namespace NadekoBot.Migrations.Mysql
|
||||
|
||||
modelBuilder.Entity("NadekoBot.Db.Models.StreamRoleWhitelistedUser", b =>
|
||||
{
|
||||
b.HasOne("NadekoBot.Db.Models.StreamRoleSettings", null)
|
||||
b.HasOne("NadekoBot.Db.Models.StreamRoleSettings", "StreamRoleSettings")
|
||||
.WithMany("Whitelist")
|
||||
.HasForeignKey("StreamRoleSettingsId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired()
|
||||
.HasConstraintName("fk_streamrolewhitelisteduser_streamrolesettings_streamrolesetti~");
|
||||
|
||||
b.Navigation("StreamRoleSettings");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("NadekoBot.Db.Models.TodoModel", b =>
|
||||
@@ -3569,6 +3518,7 @@ namespace NadekoBot.Migrations.Mysql
|
||||
b.HasOne("NadekoBot.Db.Models.GuildConfig", null)
|
||||
.WithMany("UnbanTimer")
|
||||
.HasForeignKey("GuildConfigId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.HasConstraintName("fk_unbantimer_guildconfigs_guildconfigid");
|
||||
});
|
||||
|
||||
@@ -3577,6 +3527,7 @@ namespace NadekoBot.Migrations.Mysql
|
||||
b.HasOne("NadekoBot.Db.Models.GuildConfig", null)
|
||||
.WithMany("UnmuteTimers")
|
||||
.HasForeignKey("GuildConfigId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.HasConstraintName("fk_unmutetimer_guildconfigs_guildconfigid");
|
||||
});
|
||||
|
||||
@@ -3585,6 +3536,7 @@ namespace NadekoBot.Migrations.Mysql
|
||||
b.HasOne("NadekoBot.Db.Models.GuildConfig", null)
|
||||
.WithMany("UnroleTimer")
|
||||
.HasForeignKey("GuildConfigId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.HasConstraintName("fk_unroletimer_guildconfigs_guildconfigid");
|
||||
});
|
||||
|
||||
@@ -3593,6 +3545,7 @@ namespace NadekoBot.Migrations.Mysql
|
||||
b.HasOne("NadekoBot.Db.Models.GuildConfig", null)
|
||||
.WithMany("VcRoleInfos")
|
||||
.HasForeignKey("GuildConfigId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.HasConstraintName("fk_vcroleinfo_guildconfigs_guildconfigid");
|
||||
});
|
||||
|
||||
@@ -3663,6 +3616,7 @@ namespace NadekoBot.Migrations.Mysql
|
||||
b.HasOne("NadekoBot.Db.Models.GuildConfig", null)
|
||||
.WithMany("WarnPunishments")
|
||||
.HasForeignKey("GuildConfigId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.HasConstraintName("fk_warningpunishment_guildconfigs_guildconfigid");
|
||||
});
|
||||
|
||||
|
3816
src/NadekoBot/Migrations/PostgreSql/20240518221432_guidlconfig-cleanup.Designer.cs
generated
Normal file
3816
src/NadekoBot/Migrations/PostgreSql/20240518221432_guidlconfig-cleanup.Designer.cs
generated
Normal file
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,702 @@
|
||||
using System;
|
||||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata;
|
||||
|
||||
#nullable disable
|
||||
|
||||
namespace NadekoBot.Migrations.PostgreSql
|
||||
{
|
||||
/// <inheritdoc />
|
||||
public partial class guidlconfigcleanup : Migration
|
||||
{
|
||||
/// <inheritdoc />
|
||||
protected override void Up(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.DropForeignKey(
|
||||
name: "fk_antiraidsetting_guildconfigs_guildconfigid",
|
||||
table: "antiraidsetting");
|
||||
|
||||
migrationBuilder.DropForeignKey(
|
||||
name: "fk_antispamignore_antispamsetting_antispamsettingid",
|
||||
table: "antispamignore");
|
||||
|
||||
migrationBuilder.DropForeignKey(
|
||||
name: "fk_antispamsetting_guildconfigs_guildconfigid",
|
||||
table: "antispamsetting");
|
||||
|
||||
migrationBuilder.DropForeignKey(
|
||||
name: "fk_commandalias_guildconfigs_guildconfigid",
|
||||
table: "commandalias");
|
||||
|
||||
migrationBuilder.DropForeignKey(
|
||||
name: "fk_commandcooldown_guildconfigs_guildconfigid",
|
||||
table: "commandcooldown");
|
||||
|
||||
migrationBuilder.DropForeignKey(
|
||||
name: "fk_delmsgoncmdchannel_guildconfigs_guildconfigid",
|
||||
table: "delmsgoncmdchannel");
|
||||
|
||||
migrationBuilder.DropForeignKey(
|
||||
name: "fk_excludeditem_xpsettings_xpsettingsid",
|
||||
table: "excludeditem");
|
||||
|
||||
migrationBuilder.DropForeignKey(
|
||||
name: "fk_filterchannelid_guildconfigs_guildconfigid",
|
||||
table: "filterchannelid");
|
||||
|
||||
migrationBuilder.DropForeignKey(
|
||||
name: "fk_filteredword_guildconfigs_guildconfigid",
|
||||
table: "filteredword");
|
||||
|
||||
migrationBuilder.DropForeignKey(
|
||||
name: "fk_filterlinkschannelid_guildconfigs_guildconfigid",
|
||||
table: "filterlinkschannelid");
|
||||
|
||||
migrationBuilder.DropForeignKey(
|
||||
name: "fk_filterwordschannelid_guildconfigs_guildconfigid",
|
||||
table: "filterwordschannelid");
|
||||
|
||||
migrationBuilder.DropForeignKey(
|
||||
name: "fk_followedstream_guildconfigs_guildconfigid",
|
||||
table: "followedstream");
|
||||
|
||||
migrationBuilder.DropForeignKey(
|
||||
name: "fk_gcchannelid_guildconfigs_guildconfigid",
|
||||
table: "gcchannelid");
|
||||
|
||||
migrationBuilder.DropForeignKey(
|
||||
name: "fk_muteduserid_guildconfigs_guildconfigid",
|
||||
table: "muteduserid");
|
||||
|
||||
migrationBuilder.DropForeignKey(
|
||||
name: "fk_permissions_guildconfigs_guildconfigid",
|
||||
table: "permissions");
|
||||
|
||||
migrationBuilder.DropForeignKey(
|
||||
name: "fk_shopentry_guildconfigs_guildconfigid",
|
||||
table: "shopentry");
|
||||
|
||||
migrationBuilder.DropForeignKey(
|
||||
name: "fk_shopentryitem_shopentry_shopentryid",
|
||||
table: "shopentryitem");
|
||||
|
||||
migrationBuilder.DropForeignKey(
|
||||
name: "fk_slowmodeignoredrole_guildconfigs_guildconfigid",
|
||||
table: "slowmodeignoredrole");
|
||||
|
||||
migrationBuilder.DropForeignKey(
|
||||
name: "fk_slowmodeignoreduser_guildconfigs_guildconfigid",
|
||||
table: "slowmodeignoreduser");
|
||||
|
||||
migrationBuilder.DropForeignKey(
|
||||
name: "fk_streamroleblacklisteduser_streamrolesettings_streamrolesett~",
|
||||
table: "streamroleblacklisteduser");
|
||||
|
||||
migrationBuilder.DropForeignKey(
|
||||
name: "fk_streamrolewhitelisteduser_streamrolesettings_streamrolesett~",
|
||||
table: "streamrolewhitelisteduser");
|
||||
|
||||
migrationBuilder.DropForeignKey(
|
||||
name: "fk_unbantimer_guildconfigs_guildconfigid",
|
||||
table: "unbantimer");
|
||||
|
||||
migrationBuilder.DropForeignKey(
|
||||
name: "fk_unmutetimer_guildconfigs_guildconfigid",
|
||||
table: "unmutetimer");
|
||||
|
||||
migrationBuilder.DropForeignKey(
|
||||
name: "fk_unroletimer_guildconfigs_guildconfigid",
|
||||
table: "unroletimer");
|
||||
|
||||
migrationBuilder.DropForeignKey(
|
||||
name: "fk_vcroleinfo_guildconfigs_guildconfigid",
|
||||
table: "vcroleinfo");
|
||||
|
||||
migrationBuilder.DropForeignKey(
|
||||
name: "fk_warningpunishment_guildconfigs_guildconfigid",
|
||||
table: "warningpunishment");
|
||||
|
||||
migrationBuilder.DropTable(
|
||||
name: "ignoredvoicepresencechannels");
|
||||
|
||||
migrationBuilder.AlterColumn<int>(
|
||||
name: "streamrolesettingsid",
|
||||
table: "streamrolewhitelisteduser",
|
||||
type: "integer",
|
||||
nullable: false,
|
||||
defaultValue: 0,
|
||||
oldClrType: typeof(int),
|
||||
oldType: "integer",
|
||||
oldNullable: true);
|
||||
|
||||
migrationBuilder.AlterColumn<int>(
|
||||
name: "streamrolesettingsid",
|
||||
table: "streamroleblacklisteduser",
|
||||
type: "integer",
|
||||
nullable: false,
|
||||
defaultValue: 0,
|
||||
oldClrType: typeof(int),
|
||||
oldType: "integer",
|
||||
oldNullable: true);
|
||||
|
||||
migrationBuilder.AlterColumn<int>(
|
||||
name: "guildconfigid",
|
||||
table: "delmsgoncmdchannel",
|
||||
type: "integer",
|
||||
nullable: false,
|
||||
defaultValue: 0,
|
||||
oldClrType: typeof(int),
|
||||
oldType: "integer",
|
||||
oldNullable: true);
|
||||
|
||||
migrationBuilder.AddForeignKey(
|
||||
name: "fk_antiraidsetting_guildconfigs_guildconfigid",
|
||||
table: "antiraidsetting",
|
||||
column: "guildconfigid",
|
||||
principalTable: "guildconfigs",
|
||||
principalColumn: "id",
|
||||
onDelete: ReferentialAction.Cascade);
|
||||
|
||||
migrationBuilder.AddForeignKey(
|
||||
name: "fk_antispamignore_antispamsetting_antispamsettingid",
|
||||
table: "antispamignore",
|
||||
column: "antispamsettingid",
|
||||
principalTable: "antispamsetting",
|
||||
principalColumn: "id",
|
||||
onDelete: ReferentialAction.Cascade);
|
||||
|
||||
migrationBuilder.AddForeignKey(
|
||||
name: "fk_antispamsetting_guildconfigs_guildconfigid",
|
||||
table: "antispamsetting",
|
||||
column: "guildconfigid",
|
||||
principalTable: "guildconfigs",
|
||||
principalColumn: "id",
|
||||
onDelete: ReferentialAction.Cascade);
|
||||
|
||||
migrationBuilder.AddForeignKey(
|
||||
name: "fk_commandalias_guildconfigs_guildconfigid",
|
||||
table: "commandalias",
|
||||
column: "guildconfigid",
|
||||
principalTable: "guildconfigs",
|
||||
principalColumn: "id",
|
||||
onDelete: ReferentialAction.Cascade);
|
||||
|
||||
migrationBuilder.AddForeignKey(
|
||||
name: "fk_commandcooldown_guildconfigs_guildconfigid",
|
||||
table: "commandcooldown",
|
||||
column: "guildconfigid",
|
||||
principalTable: "guildconfigs",
|
||||
principalColumn: "id",
|
||||
onDelete: ReferentialAction.Cascade);
|
||||
|
||||
migrationBuilder.AddForeignKey(
|
||||
name: "fk_delmsgoncmdchannel_guildconfigs_guildconfigid",
|
||||
table: "delmsgoncmdchannel",
|
||||
column: "guildconfigid",
|
||||
principalTable: "guildconfigs",
|
||||
principalColumn: "id",
|
||||
onDelete: ReferentialAction.Cascade);
|
||||
|
||||
migrationBuilder.AddForeignKey(
|
||||
name: "fk_excludeditem_xpsettings_xpsettingsid",
|
||||
table: "excludeditem",
|
||||
column: "xpsettingsid",
|
||||
principalTable: "xpsettings",
|
||||
principalColumn: "id",
|
||||
onDelete: ReferentialAction.Cascade);
|
||||
|
||||
migrationBuilder.AddForeignKey(
|
||||
name: "fk_filterchannelid_guildconfigs_guildconfigid",
|
||||
table: "filterchannelid",
|
||||
column: "guildconfigid",
|
||||
principalTable: "guildconfigs",
|
||||
principalColumn: "id",
|
||||
onDelete: ReferentialAction.Cascade);
|
||||
|
||||
migrationBuilder.AddForeignKey(
|
||||
name: "fk_filteredword_guildconfigs_guildconfigid",
|
||||
table: "filteredword",
|
||||
column: "guildconfigid",
|
||||
principalTable: "guildconfigs",
|
||||
principalColumn: "id",
|
||||
onDelete: ReferentialAction.Cascade);
|
||||
|
||||
migrationBuilder.AddForeignKey(
|
||||
name: "fk_filterlinkschannelid_guildconfigs_guildconfigid",
|
||||
table: "filterlinkschannelid",
|
||||
column: "guildconfigid",
|
||||
principalTable: "guildconfigs",
|
||||
principalColumn: "id",
|
||||
onDelete: ReferentialAction.Cascade);
|
||||
|
||||
migrationBuilder.AddForeignKey(
|
||||
name: "fk_filterwordschannelid_guildconfigs_guildconfigid",
|
||||
table: "filterwordschannelid",
|
||||
column: "guildconfigid",
|
||||
principalTable: "guildconfigs",
|
||||
principalColumn: "id",
|
||||
onDelete: ReferentialAction.Cascade);
|
||||
|
||||
migrationBuilder.AddForeignKey(
|
||||
name: "fk_followedstream_guildconfigs_guildconfigid",
|
||||
table: "followedstream",
|
||||
column: "guildconfigid",
|
||||
principalTable: "guildconfigs",
|
||||
principalColumn: "id",
|
||||
onDelete: ReferentialAction.Cascade);
|
||||
|
||||
migrationBuilder.AddForeignKey(
|
||||
name: "fk_gcchannelid_guildconfigs_guildconfigid",
|
||||
table: "gcchannelid",
|
||||
column: "guildconfigid",
|
||||
principalTable: "guildconfigs",
|
||||
principalColumn: "id",
|
||||
onDelete: ReferentialAction.Cascade);
|
||||
|
||||
migrationBuilder.AddForeignKey(
|
||||
name: "fk_muteduserid_guildconfigs_guildconfigid",
|
||||
table: "muteduserid",
|
||||
column: "guildconfigid",
|
||||
principalTable: "guildconfigs",
|
||||
principalColumn: "id",
|
||||
onDelete: ReferentialAction.Cascade);
|
||||
|
||||
migrationBuilder.AddForeignKey(
|
||||
name: "fk_permissions_guildconfigs_guildconfigid",
|
||||
table: "permissions",
|
||||
column: "guildconfigid",
|
||||
principalTable: "guildconfigs",
|
||||
principalColumn: "id",
|
||||
onDelete: ReferentialAction.Cascade);
|
||||
|
||||
migrationBuilder.AddForeignKey(
|
||||
name: "fk_shopentry_guildconfigs_guildconfigid",
|
||||
table: "shopentry",
|
||||
column: "guildconfigid",
|
||||
principalTable: "guildconfigs",
|
||||
principalColumn: "id",
|
||||
onDelete: ReferentialAction.Cascade);
|
||||
|
||||
migrationBuilder.AddForeignKey(
|
||||
name: "fk_shopentryitem_shopentry_shopentryid",
|
||||
table: "shopentryitem",
|
||||
column: "shopentryid",
|
||||
principalTable: "shopentry",
|
||||
principalColumn: "id",
|
||||
onDelete: ReferentialAction.Cascade);
|
||||
|
||||
migrationBuilder.AddForeignKey(
|
||||
name: "fk_slowmodeignoredrole_guildconfigs_guildconfigid",
|
||||
table: "slowmodeignoredrole",
|
||||
column: "guildconfigid",
|
||||
principalTable: "guildconfigs",
|
||||
principalColumn: "id",
|
||||
onDelete: ReferentialAction.Cascade);
|
||||
|
||||
migrationBuilder.AddForeignKey(
|
||||
name: "fk_slowmodeignoreduser_guildconfigs_guildconfigid",
|
||||
table: "slowmodeignoreduser",
|
||||
column: "guildconfigid",
|
||||
principalTable: "guildconfigs",
|
||||
principalColumn: "id",
|
||||
onDelete: ReferentialAction.Cascade);
|
||||
|
||||
migrationBuilder.AddForeignKey(
|
||||
name: "fk_streamroleblacklisteduser_streamrolesettings_streamrolesett~",
|
||||
table: "streamroleblacklisteduser",
|
||||
column: "streamrolesettingsid",
|
||||
principalTable: "streamrolesettings",
|
||||
principalColumn: "id",
|
||||
onDelete: ReferentialAction.Cascade);
|
||||
|
||||
migrationBuilder.AddForeignKey(
|
||||
name: "fk_streamrolewhitelisteduser_streamrolesettings_streamrolesett~",
|
||||
table: "streamrolewhitelisteduser",
|
||||
column: "streamrolesettingsid",
|
||||
principalTable: "streamrolesettings",
|
||||
principalColumn: "id",
|
||||
onDelete: ReferentialAction.Cascade);
|
||||
|
||||
migrationBuilder.AddForeignKey(
|
||||
name: "fk_unbantimer_guildconfigs_guildconfigid",
|
||||
table: "unbantimer",
|
||||
column: "guildconfigid",
|
||||
principalTable: "guildconfigs",
|
||||
principalColumn: "id",
|
||||
onDelete: ReferentialAction.Cascade);
|
||||
|
||||
migrationBuilder.AddForeignKey(
|
||||
name: "fk_unmutetimer_guildconfigs_guildconfigid",
|
||||
table: "unmutetimer",
|
||||
column: "guildconfigid",
|
||||
principalTable: "guildconfigs",
|
||||
principalColumn: "id",
|
||||
onDelete: ReferentialAction.Cascade);
|
||||
|
||||
migrationBuilder.AddForeignKey(
|
||||
name: "fk_unroletimer_guildconfigs_guildconfigid",
|
||||
table: "unroletimer",
|
||||
column: "guildconfigid",
|
||||
principalTable: "guildconfigs",
|
||||
principalColumn: "id",
|
||||
onDelete: ReferentialAction.Cascade);
|
||||
|
||||
migrationBuilder.AddForeignKey(
|
||||
name: "fk_vcroleinfo_guildconfigs_guildconfigid",
|
||||
table: "vcroleinfo",
|
||||
column: "guildconfigid",
|
||||
principalTable: "guildconfigs",
|
||||
principalColumn: "id",
|
||||
onDelete: ReferentialAction.Cascade);
|
||||
|
||||
migrationBuilder.AddForeignKey(
|
||||
name: "fk_warningpunishment_guildconfigs_guildconfigid",
|
||||
table: "warningpunishment",
|
||||
column: "guildconfigid",
|
||||
principalTable: "guildconfigs",
|
||||
principalColumn: "id",
|
||||
onDelete: ReferentialAction.Cascade);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override void Down(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.DropForeignKey(
|
||||
name: "fk_antiraidsetting_guildconfigs_guildconfigid",
|
||||
table: "antiraidsetting");
|
||||
|
||||
migrationBuilder.DropForeignKey(
|
||||
name: "fk_antispamignore_antispamsetting_antispamsettingid",
|
||||
table: "antispamignore");
|
||||
|
||||
migrationBuilder.DropForeignKey(
|
||||
name: "fk_antispamsetting_guildconfigs_guildconfigid",
|
||||
table: "antispamsetting");
|
||||
|
||||
migrationBuilder.DropForeignKey(
|
||||
name: "fk_commandalias_guildconfigs_guildconfigid",
|
||||
table: "commandalias");
|
||||
|
||||
migrationBuilder.DropForeignKey(
|
||||
name: "fk_commandcooldown_guildconfigs_guildconfigid",
|
||||
table: "commandcooldown");
|
||||
|
||||
migrationBuilder.DropForeignKey(
|
||||
name: "fk_delmsgoncmdchannel_guildconfigs_guildconfigid",
|
||||
table: "delmsgoncmdchannel");
|
||||
|
||||
migrationBuilder.DropForeignKey(
|
||||
name: "fk_excludeditem_xpsettings_xpsettingsid",
|
||||
table: "excludeditem");
|
||||
|
||||
migrationBuilder.DropForeignKey(
|
||||
name: "fk_filterchannelid_guildconfigs_guildconfigid",
|
||||
table: "filterchannelid");
|
||||
|
||||
migrationBuilder.DropForeignKey(
|
||||
name: "fk_filteredword_guildconfigs_guildconfigid",
|
||||
table: "filteredword");
|
||||
|
||||
migrationBuilder.DropForeignKey(
|
||||
name: "fk_filterlinkschannelid_guildconfigs_guildconfigid",
|
||||
table: "filterlinkschannelid");
|
||||
|
||||
migrationBuilder.DropForeignKey(
|
||||
name: "fk_filterwordschannelid_guildconfigs_guildconfigid",
|
||||
table: "filterwordschannelid");
|
||||
|
||||
migrationBuilder.DropForeignKey(
|
||||
name: "fk_followedstream_guildconfigs_guildconfigid",
|
||||
table: "followedstream");
|
||||
|
||||
migrationBuilder.DropForeignKey(
|
||||
name: "fk_gcchannelid_guildconfigs_guildconfigid",
|
||||
table: "gcchannelid");
|
||||
|
||||
migrationBuilder.DropForeignKey(
|
||||
name: "fk_muteduserid_guildconfigs_guildconfigid",
|
||||
table: "muteduserid");
|
||||
|
||||
migrationBuilder.DropForeignKey(
|
||||
name: "fk_permissions_guildconfigs_guildconfigid",
|
||||
table: "permissions");
|
||||
|
||||
migrationBuilder.DropForeignKey(
|
||||
name: "fk_shopentry_guildconfigs_guildconfigid",
|
||||
table: "shopentry");
|
||||
|
||||
migrationBuilder.DropForeignKey(
|
||||
name: "fk_shopentryitem_shopentry_shopentryid",
|
||||
table: "shopentryitem");
|
||||
|
||||
migrationBuilder.DropForeignKey(
|
||||
name: "fk_slowmodeignoredrole_guildconfigs_guildconfigid",
|
||||
table: "slowmodeignoredrole");
|
||||
|
||||
migrationBuilder.DropForeignKey(
|
||||
name: "fk_slowmodeignoreduser_guildconfigs_guildconfigid",
|
||||
table: "slowmodeignoreduser");
|
||||
|
||||
migrationBuilder.DropForeignKey(
|
||||
name: "fk_streamroleblacklisteduser_streamrolesettings_streamrolesett~",
|
||||
table: "streamroleblacklisteduser");
|
||||
|
||||
migrationBuilder.DropForeignKey(
|
||||
name: "fk_streamrolewhitelisteduser_streamrolesettings_streamrolesett~",
|
||||
table: "streamrolewhitelisteduser");
|
||||
|
||||
migrationBuilder.DropForeignKey(
|
||||
name: "fk_unbantimer_guildconfigs_guildconfigid",
|
||||
table: "unbantimer");
|
||||
|
||||
migrationBuilder.DropForeignKey(
|
||||
name: "fk_unmutetimer_guildconfigs_guildconfigid",
|
||||
table: "unmutetimer");
|
||||
|
||||
migrationBuilder.DropForeignKey(
|
||||
name: "fk_unroletimer_guildconfigs_guildconfigid",
|
||||
table: "unroletimer");
|
||||
|
||||
migrationBuilder.DropForeignKey(
|
||||
name: "fk_vcroleinfo_guildconfigs_guildconfigid",
|
||||
table: "vcroleinfo");
|
||||
|
||||
migrationBuilder.DropForeignKey(
|
||||
name: "fk_warningpunishment_guildconfigs_guildconfigid",
|
||||
table: "warningpunishment");
|
||||
|
||||
migrationBuilder.AlterColumn<int>(
|
||||
name: "streamrolesettingsid",
|
||||
table: "streamrolewhitelisteduser",
|
||||
type: "integer",
|
||||
nullable: true,
|
||||
oldClrType: typeof(int),
|
||||
oldType: "integer");
|
||||
|
||||
migrationBuilder.AlterColumn<int>(
|
||||
name: "streamrolesettingsid",
|
||||
table: "streamroleblacklisteduser",
|
||||
type: "integer",
|
||||
nullable: true,
|
||||
oldClrType: typeof(int),
|
||||
oldType: "integer");
|
||||
|
||||
migrationBuilder.AlterColumn<int>(
|
||||
name: "guildconfigid",
|
||||
table: "delmsgoncmdchannel",
|
||||
type: "integer",
|
||||
nullable: true,
|
||||
oldClrType: typeof(int),
|
||||
oldType: "integer");
|
||||
|
||||
migrationBuilder.CreateTable(
|
||||
name: "ignoredvoicepresencechannels",
|
||||
columns: table => new
|
||||
{
|
||||
id = table.Column<int>(type: "integer", nullable: false)
|
||||
.Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn),
|
||||
logsettingid = table.Column<int>(type: "integer", nullable: true),
|
||||
channelid = table.Column<decimal>(type: "numeric(20,0)", nullable: false),
|
||||
dateadded = table.Column<DateTime>(type: "timestamp without time zone", nullable: true)
|
||||
},
|
||||
constraints: table =>
|
||||
{
|
||||
table.PrimaryKey("pk_ignoredvoicepresencechannels", x => x.id);
|
||||
table.ForeignKey(
|
||||
name: "fk_ignoredvoicepresencechannels_logsettings_logsettingid",
|
||||
column: x => x.logsettingid,
|
||||
principalTable: "logsettings",
|
||||
principalColumn: "id");
|
||||
});
|
||||
|
||||
migrationBuilder.CreateIndex(
|
||||
name: "ix_ignoredvoicepresencechannels_logsettingid",
|
||||
table: "ignoredvoicepresencechannels",
|
||||
column: "logsettingid");
|
||||
|
||||
migrationBuilder.AddForeignKey(
|
||||
name: "fk_antiraidsetting_guildconfigs_guildconfigid",
|
||||
table: "antiraidsetting",
|
||||
column: "guildconfigid",
|
||||
principalTable: "guildconfigs",
|
||||
principalColumn: "id",
|
||||
onDelete: ReferentialAction.Cascade);
|
||||
|
||||
migrationBuilder.AddForeignKey(
|
||||
name: "fk_antispamignore_antispamsetting_antispamsettingid",
|
||||
table: "antispamignore",
|
||||
column: "antispamsettingid",
|
||||
principalTable: "antispamsetting",
|
||||
principalColumn: "id");
|
||||
|
||||
migrationBuilder.AddForeignKey(
|
||||
name: "fk_antispamsetting_guildconfigs_guildconfigid",
|
||||
table: "antispamsetting",
|
||||
column: "guildconfigid",
|
||||
principalTable: "guildconfigs",
|
||||
principalColumn: "id",
|
||||
onDelete: ReferentialAction.Cascade);
|
||||
|
||||
migrationBuilder.AddForeignKey(
|
||||
name: "fk_commandalias_guildconfigs_guildconfigid",
|
||||
table: "commandalias",
|
||||
column: "guildconfigid",
|
||||
principalTable: "guildconfigs",
|
||||
principalColumn: "id");
|
||||
|
||||
migrationBuilder.AddForeignKey(
|
||||
name: "fk_commandcooldown_guildconfigs_guildconfigid",
|
||||
table: "commandcooldown",
|
||||
column: "guildconfigid",
|
||||
principalTable: "guildconfigs",
|
||||
principalColumn: "id");
|
||||
|
||||
migrationBuilder.AddForeignKey(
|
||||
name: "fk_delmsgoncmdchannel_guildconfigs_guildconfigid",
|
||||
table: "delmsgoncmdchannel",
|
||||
column: "guildconfigid",
|
||||
principalTable: "guildconfigs",
|
||||
principalColumn: "id");
|
||||
|
||||
migrationBuilder.AddForeignKey(
|
||||
name: "fk_excludeditem_xpsettings_xpsettingsid",
|
||||
table: "excludeditem",
|
||||
column: "xpsettingsid",
|
||||
principalTable: "xpsettings",
|
||||
principalColumn: "id");
|
||||
|
||||
migrationBuilder.AddForeignKey(
|
||||
name: "fk_filterchannelid_guildconfigs_guildconfigid",
|
||||
table: "filterchannelid",
|
||||
column: "guildconfigid",
|
||||
principalTable: "guildconfigs",
|
||||
principalColumn: "id");
|
||||
|
||||
migrationBuilder.AddForeignKey(
|
||||
name: "fk_filteredword_guildconfigs_guildconfigid",
|
||||
table: "filteredword",
|
||||
column: "guildconfigid",
|
||||
principalTable: "guildconfigs",
|
||||
principalColumn: "id");
|
||||
|
||||
migrationBuilder.AddForeignKey(
|
||||
name: "fk_filterlinkschannelid_guildconfigs_guildconfigid",
|
||||
table: "filterlinkschannelid",
|
||||
column: "guildconfigid",
|
||||
principalTable: "guildconfigs",
|
||||
principalColumn: "id");
|
||||
|
||||
migrationBuilder.AddForeignKey(
|
||||
name: "fk_filterwordschannelid_guildconfigs_guildconfigid",
|
||||
table: "filterwordschannelid",
|
||||
column: "guildconfigid",
|
||||
principalTable: "guildconfigs",
|
||||
principalColumn: "id");
|
||||
|
||||
migrationBuilder.AddForeignKey(
|
||||
name: "fk_followedstream_guildconfigs_guildconfigid",
|
||||
table: "followedstream",
|
||||
column: "guildconfigid",
|
||||
principalTable: "guildconfigs",
|
||||
principalColumn: "id");
|
||||
|
||||
migrationBuilder.AddForeignKey(
|
||||
name: "fk_gcchannelid_guildconfigs_guildconfigid",
|
||||
table: "gcchannelid",
|
||||
column: "guildconfigid",
|
||||
principalTable: "guildconfigs",
|
||||
principalColumn: "id");
|
||||
|
||||
migrationBuilder.AddForeignKey(
|
||||
name: "fk_muteduserid_guildconfigs_guildconfigid",
|
||||
table: "muteduserid",
|
||||
column: "guildconfigid",
|
||||
principalTable: "guildconfigs",
|
||||
principalColumn: "id");
|
||||
|
||||
migrationBuilder.AddForeignKey(
|
||||
name: "fk_permissions_guildconfigs_guildconfigid",
|
||||
table: "permissions",
|
||||
column: "guildconfigid",
|
||||
principalTable: "guildconfigs",
|
||||
principalColumn: "id");
|
||||
|
||||
migrationBuilder.AddForeignKey(
|
||||
name: "fk_shopentry_guildconfigs_guildconfigid",
|
||||
table: "shopentry",
|
||||
column: "guildconfigid",
|
||||
principalTable: "guildconfigs",
|
||||
principalColumn: "id");
|
||||
|
||||
migrationBuilder.AddForeignKey(
|
||||
name: "fk_shopentryitem_shopentry_shopentryid",
|
||||
table: "shopentryitem",
|
||||
column: "shopentryid",
|
||||
principalTable: "shopentry",
|
||||
principalColumn: "id");
|
||||
|
||||
migrationBuilder.AddForeignKey(
|
||||
name: "fk_slowmodeignoredrole_guildconfigs_guildconfigid",
|
||||
table: "slowmodeignoredrole",
|
||||
column: "guildconfigid",
|
||||
principalTable: "guildconfigs",
|
||||
principalColumn: "id");
|
||||
|
||||
migrationBuilder.AddForeignKey(
|
||||
name: "fk_slowmodeignoreduser_guildconfigs_guildconfigid",
|
||||
table: "slowmodeignoreduser",
|
||||
column: "guildconfigid",
|
||||
principalTable: "guildconfigs",
|
||||
principalColumn: "id");
|
||||
|
||||
migrationBuilder.AddForeignKey(
|
||||
name: "fk_streamroleblacklisteduser_streamrolesettings_streamrolesett~",
|
||||
table: "streamroleblacklisteduser",
|
||||
column: "streamrolesettingsid",
|
||||
principalTable: "streamrolesettings",
|
||||
principalColumn: "id");
|
||||
|
||||
migrationBuilder.AddForeignKey(
|
||||
name: "fk_streamrolewhitelisteduser_streamrolesettings_streamrolesett~",
|
||||
table: "streamrolewhitelisteduser",
|
||||
column: "streamrolesettingsid",
|
||||
principalTable: "streamrolesettings",
|
||||
principalColumn: "id");
|
||||
|
||||
migrationBuilder.AddForeignKey(
|
||||
name: "fk_unbantimer_guildconfigs_guildconfigid",
|
||||
table: "unbantimer",
|
||||
column: "guildconfigid",
|
||||
principalTable: "guildconfigs",
|
||||
principalColumn: "id");
|
||||
|
||||
migrationBuilder.AddForeignKey(
|
||||
name: "fk_unmutetimer_guildconfigs_guildconfigid",
|
||||
table: "unmutetimer",
|
||||
column: "guildconfigid",
|
||||
principalTable: "guildconfigs",
|
||||
principalColumn: "id");
|
||||
|
||||
migrationBuilder.AddForeignKey(
|
||||
name: "fk_unroletimer_guildconfigs_guildconfigid",
|
||||
table: "unroletimer",
|
||||
column: "guildconfigid",
|
||||
principalTable: "guildconfigs",
|
||||
principalColumn: "id");
|
||||
|
||||
migrationBuilder.AddForeignKey(
|
||||
name: "fk_vcroleinfo_guildconfigs_guildconfigid",
|
||||
table: "vcroleinfo",
|
||||
column: "guildconfigid",
|
||||
principalTable: "guildconfigs",
|
||||
principalColumn: "id");
|
||||
|
||||
migrationBuilder.AddForeignKey(
|
||||
name: "fk_warningpunishment_guildconfigs_guildconfigid",
|
||||
table: "warningpunishment",
|
||||
column: "guildconfigid",
|
||||
principalTable: "guildconfigs",
|
||||
principalColumn: "id");
|
||||
}
|
||||
}
|
||||
}
|
3781
src/NadekoBot/Migrations/PostgreSql/20240611180506_remove-patron-limits.Designer.cs
generated
Normal file
3781
src/NadekoBot/Migrations/PostgreSql/20240611180506_remove-patron-limits.Designer.cs
generated
Normal file
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,42 @@
|
||||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
|
||||
#nullable disable
|
||||
|
||||
namespace NadekoBot.Migrations.PostgreSql
|
||||
{
|
||||
/// <inheritdoc />
|
||||
public partial class removepatronlimits : Migration
|
||||
{
|
||||
/// <inheritdoc />
|
||||
protected override void Up(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.DropTable(
|
||||
name: "patronquotas");
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override void Down(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.CreateTable(
|
||||
name: "patronquotas",
|
||||
columns: table => new
|
||||
{
|
||||
userid = table.Column<decimal>(type: "numeric(20,0)", nullable: false),
|
||||
featuretype = table.Column<int>(type: "integer", nullable: false),
|
||||
feature = table.Column<string>(type: "text", nullable: false),
|
||||
dailycount = table.Column<long>(type: "bigint", nullable: false),
|
||||
hourlycount = table.Column<long>(type: "bigint", nullable: false),
|
||||
monthlycount = table.Column<long>(type: "bigint", nullable: false)
|
||||
},
|
||||
constraints: table =>
|
||||
{
|
||||
table.PrimaryKey("pk_patronquotas", x => new { x.userid, x.featuretype, x.feature });
|
||||
});
|
||||
|
||||
migrationBuilder.CreateIndex(
|
||||
name: "ix_patronquotas_userid",
|
||||
table: "patronquotas",
|
||||
column: "userid");
|
||||
}
|
||||
}
|
||||
}
|
@@ -672,7 +672,7 @@ namespace NadekoBot.Migrations.PostgreSql
|
||||
.HasColumnType("timestamp without time zone")
|
||||
.HasColumnName("dateadded");
|
||||
|
||||
b.Property<int?>("GuildConfigId")
|
||||
b.Property<int>("GuildConfigId")
|
||||
.HasColumnType("integer")
|
||||
.HasColumnName("guildconfigid");
|
||||
|
||||
@@ -1422,36 +1422,6 @@ namespace NadekoBot.Migrations.PostgreSql
|
||||
b.ToTable("ignoredlogchannels", (string)null);
|
||||
});
|
||||
|
||||
modelBuilder.Entity("NadekoBot.Db.Models.IgnoredVoicePresenceChannel", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("integer")
|
||||
.HasColumnName("id");
|
||||
|
||||
NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id"));
|
||||
|
||||
b.Property<decimal>("ChannelId")
|
||||
.HasColumnType("numeric(20,0)")
|
||||
.HasColumnName("channelid");
|
||||
|
||||
b.Property<DateTime?>("DateAdded")
|
||||
.HasColumnType("timestamp without time zone")
|
||||
.HasColumnName("dateadded");
|
||||
|
||||
b.Property<int?>("LogSettingId")
|
||||
.HasColumnType("integer")
|
||||
.HasColumnName("logsettingid");
|
||||
|
||||
b.HasKey("Id")
|
||||
.HasName("pk_ignoredvoicepresencechannels");
|
||||
|
||||
b.HasIndex("LogSettingId")
|
||||
.HasDatabaseName("ix_ignoredvoicepresencechannels_logsettingid");
|
||||
|
||||
b.ToTable("ignoredvoicepresencechannels", (string)null);
|
||||
});
|
||||
|
||||
modelBuilder.Entity("NadekoBot.Db.Models.ImageOnlyChannel", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
@@ -1747,41 +1717,6 @@ namespace NadekoBot.Migrations.PostgreSql
|
||||
b.ToTable("expressions", (string)null);
|
||||
});
|
||||
|
||||
modelBuilder.Entity("NadekoBot.Db.Models.PatronQuota", b =>
|
||||
{
|
||||
b.Property<decimal>("UserId")
|
||||
.HasColumnType("numeric(20,0)")
|
||||
.HasColumnName("userid");
|
||||
|
||||
b.Property<int>("FeatureType")
|
||||
.HasColumnType("integer")
|
||||
.HasColumnName("featuretype");
|
||||
|
||||
b.Property<string>("Feature")
|
||||
.HasColumnType("text")
|
||||
.HasColumnName("feature");
|
||||
|
||||
b.Property<long>("DailyCount")
|
||||
.HasColumnType("bigint")
|
||||
.HasColumnName("dailycount");
|
||||
|
||||
b.Property<long>("HourlyCount")
|
||||
.HasColumnType("bigint")
|
||||
.HasColumnName("hourlycount");
|
||||
|
||||
b.Property<long>("MonthlyCount")
|
||||
.HasColumnType("bigint")
|
||||
.HasColumnName("monthlycount");
|
||||
|
||||
b.HasKey("UserId", "FeatureType", "Feature")
|
||||
.HasName("pk_patronquotas");
|
||||
|
||||
b.HasIndex("UserId")
|
||||
.HasDatabaseName("ix_patronquotas_userid");
|
||||
|
||||
b.ToTable("patronquotas", (string)null);
|
||||
});
|
||||
|
||||
modelBuilder.Entity("NadekoBot.Db.Models.PatronUser", b =>
|
||||
{
|
||||
b.Property<decimal>("UserId")
|
||||
@@ -2507,7 +2442,7 @@ namespace NadekoBot.Migrations.PostgreSql
|
||||
.HasColumnType("timestamp without time zone")
|
||||
.HasColumnName("dateadded");
|
||||
|
||||
b.Property<int?>("StreamRoleSettingsId")
|
||||
b.Property<int>("StreamRoleSettingsId")
|
||||
.HasColumnType("integer")
|
||||
.HasColumnName("streamrolesettingsid");
|
||||
|
||||
@@ -2584,7 +2519,7 @@ namespace NadekoBot.Migrations.PostgreSql
|
||||
.HasColumnType("timestamp without time zone")
|
||||
.HasColumnName("dateadded");
|
||||
|
||||
b.Property<int?>("StreamRoleSettingsId")
|
||||
b.Property<int>("StreamRoleSettingsId")
|
||||
.HasColumnType("integer")
|
||||
.HasColumnName("streamrolesettingsid");
|
||||
|
||||
@@ -3223,14 +3158,12 @@ namespace NadekoBot.Migrations.PostgreSql
|
||||
|
||||
modelBuilder.Entity("NadekoBot.Db.Models.AntiRaidSetting", b =>
|
||||
{
|
||||
b.HasOne("NadekoBot.Db.Models.GuildConfig", "GuildConfig")
|
||||
b.HasOne("NadekoBot.Db.Models.GuildConfig", null)
|
||||
.WithOne("AntiRaidSetting")
|
||||
.HasForeignKey("NadekoBot.Db.Models.AntiRaidSetting", "GuildConfigId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired()
|
||||
.HasConstraintName("fk_antiraidsetting_guildconfigs_guildconfigid");
|
||||
|
||||
b.Navigation("GuildConfig");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("NadekoBot.Db.Models.AntiSpamIgnore", b =>
|
||||
@@ -3238,19 +3171,18 @@ namespace NadekoBot.Migrations.PostgreSql
|
||||
b.HasOne("NadekoBot.Db.Models.AntiSpamSetting", null)
|
||||
.WithMany("IgnoredChannels")
|
||||
.HasForeignKey("AntiSpamSettingId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.HasConstraintName("fk_antispamignore_antispamsetting_antispamsettingid");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("NadekoBot.Db.Models.AntiSpamSetting", b =>
|
||||
{
|
||||
b.HasOne("NadekoBot.Db.Models.GuildConfig", "GuildConfig")
|
||||
b.HasOne("NadekoBot.Db.Models.GuildConfig", null)
|
||||
.WithOne("AntiSpamSetting")
|
||||
.HasForeignKey("NadekoBot.Db.Models.AntiSpamSetting", "GuildConfigId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired()
|
||||
.HasConstraintName("fk_antispamsetting_guildconfigs_guildconfigid");
|
||||
|
||||
b.Navigation("GuildConfig");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("NadekoBot.Db.Models.AutoTranslateUser", b =>
|
||||
@@ -3323,6 +3255,7 @@ namespace NadekoBot.Migrations.PostgreSql
|
||||
b.HasOne("NadekoBot.Db.Models.GuildConfig", null)
|
||||
.WithMany("CommandAliases")
|
||||
.HasForeignKey("GuildConfigId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.HasConstraintName("fk_commandalias_guildconfigs_guildconfigid");
|
||||
});
|
||||
|
||||
@@ -3331,6 +3264,7 @@ namespace NadekoBot.Migrations.PostgreSql
|
||||
b.HasOne("NadekoBot.Db.Models.GuildConfig", null)
|
||||
.WithMany("CommandCooldowns")
|
||||
.HasForeignKey("GuildConfigId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.HasConstraintName("fk_commandcooldown_guildconfigs_guildconfigid");
|
||||
});
|
||||
|
||||
@@ -3339,6 +3273,8 @@ namespace NadekoBot.Migrations.PostgreSql
|
||||
b.HasOne("NadekoBot.Db.Models.GuildConfig", null)
|
||||
.WithMany("DelMsgOnCmdChannels")
|
||||
.HasForeignKey("GuildConfigId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired()
|
||||
.HasConstraintName("fk_delmsgoncmdchannel_guildconfigs_guildconfigid");
|
||||
});
|
||||
|
||||
@@ -3355,10 +3291,13 @@ namespace NadekoBot.Migrations.PostgreSql
|
||||
|
||||
modelBuilder.Entity("NadekoBot.Db.Models.ExcludedItem", b =>
|
||||
{
|
||||
b.HasOne("NadekoBot.Db.Models.XpSettings", null)
|
||||
b.HasOne("NadekoBot.Db.Models.XpSettings", "XpSettings")
|
||||
.WithMany("ExclusionList")
|
||||
.HasForeignKey("XpSettingsId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.HasConstraintName("fk_excludeditem_xpsettings_xpsettingsid");
|
||||
|
||||
b.Navigation("XpSettings");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("NadekoBot.Db.Models.FeedSub", b =>
|
||||
@@ -3378,6 +3317,7 @@ namespace NadekoBot.Migrations.PostgreSql
|
||||
b.HasOne("NadekoBot.Db.Models.GuildConfig", null)
|
||||
.WithMany("FilterInvitesChannelIds")
|
||||
.HasForeignKey("GuildConfigId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.HasConstraintName("fk_filterchannelid_guildconfigs_guildconfigid");
|
||||
});
|
||||
|
||||
@@ -3386,6 +3326,7 @@ namespace NadekoBot.Migrations.PostgreSql
|
||||
b.HasOne("NadekoBot.Db.Models.GuildConfig", null)
|
||||
.WithMany("FilterLinksChannelIds")
|
||||
.HasForeignKey("GuildConfigId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.HasConstraintName("fk_filterlinkschannelid_guildconfigs_guildconfigid");
|
||||
});
|
||||
|
||||
@@ -3394,6 +3335,7 @@ namespace NadekoBot.Migrations.PostgreSql
|
||||
b.HasOne("NadekoBot.Db.Models.GuildConfig", null)
|
||||
.WithMany("FilterWordsChannelIds")
|
||||
.HasForeignKey("GuildConfigId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.HasConstraintName("fk_filterwordschannelid_guildconfigs_guildconfigid");
|
||||
});
|
||||
|
||||
@@ -3402,6 +3344,7 @@ namespace NadekoBot.Migrations.PostgreSql
|
||||
b.HasOne("NadekoBot.Db.Models.GuildConfig", null)
|
||||
.WithMany("FilteredWords")
|
||||
.HasForeignKey("GuildConfigId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.HasConstraintName("fk_filteredword_guildconfigs_guildconfigid");
|
||||
});
|
||||
|
||||
@@ -3410,6 +3353,7 @@ namespace NadekoBot.Migrations.PostgreSql
|
||||
b.HasOne("NadekoBot.Db.Models.GuildConfig", null)
|
||||
.WithMany("FollowedStreams")
|
||||
.HasForeignKey("GuildConfigId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.HasConstraintName("fk_followedstream_guildconfigs_guildconfigid");
|
||||
});
|
||||
|
||||
@@ -3418,6 +3362,7 @@ namespace NadekoBot.Migrations.PostgreSql
|
||||
b.HasOne("NadekoBot.Db.Models.GuildConfig", "GuildConfig")
|
||||
.WithMany("GenerateCurrencyChannelIds")
|
||||
.HasForeignKey("GuildConfigId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.HasConstraintName("fk_gcchannelid_guildconfigs_guildconfigid");
|
||||
|
||||
b.Navigation("GuildConfig");
|
||||
@@ -3457,21 +3402,12 @@ namespace NadekoBot.Migrations.PostgreSql
|
||||
b.Navigation("LogSetting");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("NadekoBot.Db.Models.IgnoredVoicePresenceChannel", b =>
|
||||
{
|
||||
b.HasOne("NadekoBot.Db.Models.LogSetting", "LogSetting")
|
||||
.WithMany()
|
||||
.HasForeignKey("LogSettingId")
|
||||
.HasConstraintName("fk_ignoredvoicepresencechannels_logsettings_logsettingid");
|
||||
|
||||
b.Navigation("LogSetting");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("NadekoBot.Db.Models.MutedUserId", b =>
|
||||
{
|
||||
b.HasOne("NadekoBot.Db.Models.GuildConfig", null)
|
||||
.WithMany("MutedUsers")
|
||||
.HasForeignKey("GuildConfigId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.HasConstraintName("fk_muteduserid_guildconfigs_guildconfigid");
|
||||
});
|
||||
|
||||
@@ -3480,6 +3416,7 @@ namespace NadekoBot.Migrations.PostgreSql
|
||||
b.HasOne("NadekoBot.Db.Models.GuildConfig", null)
|
||||
.WithMany("Permissions")
|
||||
.HasForeignKey("GuildConfigId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.HasConstraintName("fk_permissions_guildconfigs_guildconfigid");
|
||||
});
|
||||
|
||||
@@ -3497,6 +3434,7 @@ namespace NadekoBot.Migrations.PostgreSql
|
||||
b.HasOne("NadekoBot.Db.Models.GuildConfig", null)
|
||||
.WithMany("ShopEntries")
|
||||
.HasForeignKey("GuildConfigId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.HasConstraintName("fk_shopentry_guildconfigs_guildconfigid");
|
||||
});
|
||||
|
||||
@@ -3505,6 +3443,7 @@ namespace NadekoBot.Migrations.PostgreSql
|
||||
b.HasOne("NadekoBot.Db.Models.ShopEntry", null)
|
||||
.WithMany("Items")
|
||||
.HasForeignKey("ShopEntryId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.HasConstraintName("fk_shopentryitem_shopentry_shopentryid");
|
||||
});
|
||||
|
||||
@@ -3513,6 +3452,7 @@ namespace NadekoBot.Migrations.PostgreSql
|
||||
b.HasOne("NadekoBot.Db.Models.GuildConfig", null)
|
||||
.WithMany("SlowmodeIgnoredRoles")
|
||||
.HasForeignKey("GuildConfigId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.HasConstraintName("fk_slowmodeignoredrole_guildconfigs_guildconfigid");
|
||||
});
|
||||
|
||||
@@ -3521,15 +3461,20 @@ namespace NadekoBot.Migrations.PostgreSql
|
||||
b.HasOne("NadekoBot.Db.Models.GuildConfig", null)
|
||||
.WithMany("SlowmodeIgnoredUsers")
|
||||
.HasForeignKey("GuildConfigId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.HasConstraintName("fk_slowmodeignoreduser_guildconfigs_guildconfigid");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("NadekoBot.Db.Models.StreamRoleBlacklistedUser", b =>
|
||||
{
|
||||
b.HasOne("NadekoBot.Db.Models.StreamRoleSettings", null)
|
||||
b.HasOne("NadekoBot.Db.Models.StreamRoleSettings", "StreamRoleSettings")
|
||||
.WithMany("Blacklist")
|
||||
.HasForeignKey("StreamRoleSettingsId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired()
|
||||
.HasConstraintName("fk_streamroleblacklisteduser_streamrolesettings_streamrolesett~");
|
||||
|
||||
b.Navigation("StreamRoleSettings");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("NadekoBot.Db.Models.StreamRoleSettings", b =>
|
||||
@@ -3546,10 +3491,14 @@ namespace NadekoBot.Migrations.PostgreSql
|
||||
|
||||
modelBuilder.Entity("NadekoBot.Db.Models.StreamRoleWhitelistedUser", b =>
|
||||
{
|
||||
b.HasOne("NadekoBot.Db.Models.StreamRoleSettings", null)
|
||||
b.HasOne("NadekoBot.Db.Models.StreamRoleSettings", "StreamRoleSettings")
|
||||
.WithMany("Whitelist")
|
||||
.HasForeignKey("StreamRoleSettingsId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired()
|
||||
.HasConstraintName("fk_streamrolewhitelisteduser_streamrolesettings_streamrolesett~");
|
||||
|
||||
b.Navigation("StreamRoleSettings");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("NadekoBot.Db.Models.TodoModel", b =>
|
||||
@@ -3566,6 +3515,7 @@ namespace NadekoBot.Migrations.PostgreSql
|
||||
b.HasOne("NadekoBot.Db.Models.GuildConfig", null)
|
||||
.WithMany("UnbanTimer")
|
||||
.HasForeignKey("GuildConfigId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.HasConstraintName("fk_unbantimer_guildconfigs_guildconfigid");
|
||||
});
|
||||
|
||||
@@ -3574,6 +3524,7 @@ namespace NadekoBot.Migrations.PostgreSql
|
||||
b.HasOne("NadekoBot.Db.Models.GuildConfig", null)
|
||||
.WithMany("UnmuteTimers")
|
||||
.HasForeignKey("GuildConfigId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.HasConstraintName("fk_unmutetimer_guildconfigs_guildconfigid");
|
||||
});
|
||||
|
||||
@@ -3582,6 +3533,7 @@ namespace NadekoBot.Migrations.PostgreSql
|
||||
b.HasOne("NadekoBot.Db.Models.GuildConfig", null)
|
||||
.WithMany("UnroleTimer")
|
||||
.HasForeignKey("GuildConfigId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.HasConstraintName("fk_unroletimer_guildconfigs_guildconfigid");
|
||||
});
|
||||
|
||||
@@ -3590,6 +3542,7 @@ namespace NadekoBot.Migrations.PostgreSql
|
||||
b.HasOne("NadekoBot.Db.Models.GuildConfig", null)
|
||||
.WithMany("VcRoleInfos")
|
||||
.HasForeignKey("GuildConfigId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.HasConstraintName("fk_vcroleinfo_guildconfigs_guildconfigid");
|
||||
});
|
||||
|
||||
@@ -3660,6 +3613,7 @@ namespace NadekoBot.Migrations.PostgreSql
|
||||
b.HasOne("NadekoBot.Db.Models.GuildConfig", null)
|
||||
.WithMany("WarnPunishments")
|
||||
.HasForeignKey("GuildConfigId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.HasConstraintName("fk_warningpunishment_guildconfigs_guildconfigid");
|
||||
});
|
||||
|
||||
|
2948
src/NadekoBot/Migrations/Sqlite/20240518221424_guidlconfig-cleanup.Designer.cs
generated
Normal file
2948
src/NadekoBot/Migrations/Sqlite/20240518221424_guidlconfig-cleanup.Designer.cs
generated
Normal file
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,703 @@
|
||||
using System;
|
||||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
|
||||
#nullable disable
|
||||
|
||||
namespace NadekoBot.Migrations
|
||||
{
|
||||
/// <inheritdoc />
|
||||
public partial class guidlconfigcleanup : Migration
|
||||
{
|
||||
/// <inheritdoc />
|
||||
protected override void Up(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
MigrationQueries.GuildConfigCleanup(migrationBuilder);
|
||||
|
||||
migrationBuilder.DropForeignKey(
|
||||
name: "FK_AntiRaidSetting_GuildConfigs_GuildConfigId",
|
||||
table: "AntiRaidSetting");
|
||||
|
||||
migrationBuilder.DropForeignKey(
|
||||
name: "FK_AntiSpamIgnore_AntiSpamSetting_AntiSpamSettingId",
|
||||
table: "AntiSpamIgnore");
|
||||
|
||||
migrationBuilder.DropForeignKey(
|
||||
name: "FK_AntiSpamSetting_GuildConfigs_GuildConfigId",
|
||||
table: "AntiSpamSetting");
|
||||
|
||||
migrationBuilder.DropForeignKey(
|
||||
name: "FK_CommandAlias_GuildConfigs_GuildConfigId",
|
||||
table: "CommandAlias");
|
||||
|
||||
migrationBuilder.DropForeignKey(
|
||||
name: "FK_CommandCooldown_GuildConfigs_GuildConfigId",
|
||||
table: "CommandCooldown");
|
||||
|
||||
migrationBuilder.DropForeignKey(
|
||||
name: "FK_DelMsgOnCmdChannel_GuildConfigs_GuildConfigId",
|
||||
table: "DelMsgOnCmdChannel");
|
||||
|
||||
migrationBuilder.DropForeignKey(
|
||||
name: "FK_ExcludedItem_XpSettings_XpSettingsId",
|
||||
table: "ExcludedItem");
|
||||
|
||||
migrationBuilder.DropForeignKey(
|
||||
name: "FK_FilterChannelId_GuildConfigs_GuildConfigId",
|
||||
table: "FilterChannelId");
|
||||
|
||||
migrationBuilder.DropForeignKey(
|
||||
name: "FK_FilteredWord_GuildConfigs_GuildConfigId",
|
||||
table: "FilteredWord");
|
||||
|
||||
migrationBuilder.DropForeignKey(
|
||||
name: "FK_FilterLinksChannelId_GuildConfigs_GuildConfigId",
|
||||
table: "FilterLinksChannelId");
|
||||
|
||||
migrationBuilder.DropForeignKey(
|
||||
name: "FK_FilterWordsChannelId_GuildConfigs_GuildConfigId",
|
||||
table: "FilterWordsChannelId");
|
||||
|
||||
migrationBuilder.DropForeignKey(
|
||||
name: "FK_FollowedStream_GuildConfigs_GuildConfigId",
|
||||
table: "FollowedStream");
|
||||
|
||||
migrationBuilder.DropForeignKey(
|
||||
name: "FK_GCChannelId_GuildConfigs_GuildConfigId",
|
||||
table: "GCChannelId");
|
||||
|
||||
migrationBuilder.DropForeignKey(
|
||||
name: "FK_MutedUserId_GuildConfigs_GuildConfigId",
|
||||
table: "MutedUserId");
|
||||
|
||||
migrationBuilder.DropForeignKey(
|
||||
name: "FK_Permissions_GuildConfigs_GuildConfigId",
|
||||
table: "Permissions");
|
||||
|
||||
migrationBuilder.DropForeignKey(
|
||||
name: "FK_ShopEntry_GuildConfigs_GuildConfigId",
|
||||
table: "ShopEntry");
|
||||
|
||||
migrationBuilder.DropForeignKey(
|
||||
name: "FK_ShopEntryItem_ShopEntry_ShopEntryId",
|
||||
table: "ShopEntryItem");
|
||||
|
||||
migrationBuilder.DropForeignKey(
|
||||
name: "FK_SlowmodeIgnoredRole_GuildConfigs_GuildConfigId",
|
||||
table: "SlowmodeIgnoredRole");
|
||||
|
||||
migrationBuilder.DropForeignKey(
|
||||
name: "FK_SlowmodeIgnoredUser_GuildConfigs_GuildConfigId",
|
||||
table: "SlowmodeIgnoredUser");
|
||||
|
||||
migrationBuilder.DropForeignKey(
|
||||
name: "FK_StreamRoleBlacklistedUser_StreamRoleSettings_StreamRoleSettingsId",
|
||||
table: "StreamRoleBlacklistedUser");
|
||||
|
||||
migrationBuilder.DropForeignKey(
|
||||
name: "FK_StreamRoleWhitelistedUser_StreamRoleSettings_StreamRoleSettingsId",
|
||||
table: "StreamRoleWhitelistedUser");
|
||||
|
||||
migrationBuilder.DropForeignKey(
|
||||
name: "FK_UnbanTimer_GuildConfigs_GuildConfigId",
|
||||
table: "UnbanTimer");
|
||||
|
||||
migrationBuilder.DropForeignKey(
|
||||
name: "FK_UnmuteTimer_GuildConfigs_GuildConfigId",
|
||||
table: "UnmuteTimer");
|
||||
|
||||
migrationBuilder.DropForeignKey(
|
||||
name: "FK_UnroleTimer_GuildConfigs_GuildConfigId",
|
||||
table: "UnroleTimer");
|
||||
|
||||
migrationBuilder.DropForeignKey(
|
||||
name: "FK_VcRoleInfo_GuildConfigs_GuildConfigId",
|
||||
table: "VcRoleInfo");
|
||||
|
||||
migrationBuilder.DropForeignKey(
|
||||
name: "FK_WarningPunishment_GuildConfigs_GuildConfigId",
|
||||
table: "WarningPunishment");
|
||||
|
||||
migrationBuilder.DropTable(
|
||||
name: "IgnoredVoicePresenceCHannels");
|
||||
|
||||
migrationBuilder.AlterColumn<int>(
|
||||
name: "StreamRoleSettingsId",
|
||||
table: "StreamRoleWhitelistedUser",
|
||||
type: "INTEGER",
|
||||
nullable: false,
|
||||
defaultValue: 0,
|
||||
oldClrType: typeof(int),
|
||||
oldType: "INTEGER",
|
||||
oldNullable: true);
|
||||
|
||||
migrationBuilder.AlterColumn<int>(
|
||||
name: "StreamRoleSettingsId",
|
||||
table: "StreamRoleBlacklistedUser",
|
||||
type: "INTEGER",
|
||||
nullable: false,
|
||||
defaultValue: 0,
|
||||
oldClrType: typeof(int),
|
||||
oldType: "INTEGER",
|
||||
oldNullable: true);
|
||||
|
||||
migrationBuilder.AlterColumn<int>(
|
||||
name: "GuildConfigId",
|
||||
table: "DelMsgOnCmdChannel",
|
||||
type: "INTEGER",
|
||||
nullable: false,
|
||||
defaultValue: 0,
|
||||
oldClrType: typeof(int),
|
||||
oldType: "INTEGER",
|
||||
oldNullable: true);
|
||||
|
||||
migrationBuilder.AddForeignKey(
|
||||
name: "FK_AntiRaidSetting_GuildConfigs_GuildConfigId",
|
||||
table: "AntiRaidSetting",
|
||||
column: "GuildConfigId",
|
||||
principalTable: "GuildConfigs",
|
||||
principalColumn: "Id",
|
||||
onDelete: ReferentialAction.Cascade);
|
||||
|
||||
migrationBuilder.AddForeignKey(
|
||||
name: "FK_AntiSpamIgnore_AntiSpamSetting_AntiSpamSettingId",
|
||||
table: "AntiSpamIgnore",
|
||||
column: "AntiSpamSettingId",
|
||||
principalTable: "AntiSpamSetting",
|
||||
principalColumn: "Id",
|
||||
onDelete: ReferentialAction.Cascade);
|
||||
|
||||
migrationBuilder.AddForeignKey(
|
||||
name: "FK_AntiSpamSetting_GuildConfigs_GuildConfigId",
|
||||
table: "AntiSpamSetting",
|
||||
column: "GuildConfigId",
|
||||
principalTable: "GuildConfigs",
|
||||
principalColumn: "Id",
|
||||
onDelete: ReferentialAction.Cascade);
|
||||
|
||||
migrationBuilder.AddForeignKey(
|
||||
name: "FK_CommandAlias_GuildConfigs_GuildConfigId",
|
||||
table: "CommandAlias",
|
||||
column: "GuildConfigId",
|
||||
principalTable: "GuildConfigs",
|
||||
principalColumn: "Id",
|
||||
onDelete: ReferentialAction.Cascade);
|
||||
|
||||
migrationBuilder.AddForeignKey(
|
||||
name: "FK_CommandCooldown_GuildConfigs_GuildConfigId",
|
||||
table: "CommandCooldown",
|
||||
column: "GuildConfigId",
|
||||
principalTable: "GuildConfigs",
|
||||
principalColumn: "Id",
|
||||
onDelete: ReferentialAction.Cascade);
|
||||
|
||||
migrationBuilder.AddForeignKey(
|
||||
name: "FK_DelMsgOnCmdChannel_GuildConfigs_GuildConfigId",
|
||||
table: "DelMsgOnCmdChannel",
|
||||
column: "GuildConfigId",
|
||||
principalTable: "GuildConfigs",
|
||||
principalColumn: "Id",
|
||||
onDelete: ReferentialAction.Cascade);
|
||||
|
||||
migrationBuilder.AddForeignKey(
|
||||
name: "FK_ExcludedItem_XpSettings_XpSettingsId",
|
||||
table: "ExcludedItem",
|
||||
column: "XpSettingsId",
|
||||
principalTable: "XpSettings",
|
||||
principalColumn: "Id",
|
||||
onDelete: ReferentialAction.Cascade);
|
||||
|
||||
migrationBuilder.AddForeignKey(
|
||||
name: "FK_FilterChannelId_GuildConfigs_GuildConfigId",
|
||||
table: "FilterChannelId",
|
||||
column: "GuildConfigId",
|
||||
principalTable: "GuildConfigs",
|
||||
principalColumn: "Id",
|
||||
onDelete: ReferentialAction.Cascade);
|
||||
|
||||
migrationBuilder.AddForeignKey(
|
||||
name: "FK_FilteredWord_GuildConfigs_GuildConfigId",
|
||||
table: "FilteredWord",
|
||||
column: "GuildConfigId",
|
||||
principalTable: "GuildConfigs",
|
||||
principalColumn: "Id",
|
||||
onDelete: ReferentialAction.Cascade);
|
||||
|
||||
migrationBuilder.AddForeignKey(
|
||||
name: "FK_FilterLinksChannelId_GuildConfigs_GuildConfigId",
|
||||
table: "FilterLinksChannelId",
|
||||
column: "GuildConfigId",
|
||||
principalTable: "GuildConfigs",
|
||||
principalColumn: "Id",
|
||||
onDelete: ReferentialAction.Cascade);
|
||||
|
||||
migrationBuilder.AddForeignKey(
|
||||
name: "FK_FilterWordsChannelId_GuildConfigs_GuildConfigId",
|
||||
table: "FilterWordsChannelId",
|
||||
column: "GuildConfigId",
|
||||
principalTable: "GuildConfigs",
|
||||
principalColumn: "Id",
|
||||
onDelete: ReferentialAction.Cascade);
|
||||
|
||||
migrationBuilder.AddForeignKey(
|
||||
name: "FK_FollowedStream_GuildConfigs_GuildConfigId",
|
||||
table: "FollowedStream",
|
||||
column: "GuildConfigId",
|
||||
principalTable: "GuildConfigs",
|
||||
principalColumn: "Id",
|
||||
onDelete: ReferentialAction.Cascade);
|
||||
|
||||
migrationBuilder.AddForeignKey(
|
||||
name: "FK_GCChannelId_GuildConfigs_GuildConfigId",
|
||||
table: "GCChannelId",
|
||||
column: "GuildConfigId",
|
||||
principalTable: "GuildConfigs",
|
||||
principalColumn: "Id",
|
||||
onDelete: ReferentialAction.Cascade);
|
||||
|
||||
migrationBuilder.AddForeignKey(
|
||||
name: "FK_MutedUserId_GuildConfigs_GuildConfigId",
|
||||
table: "MutedUserId",
|
||||
column: "GuildConfigId",
|
||||
principalTable: "GuildConfigs",
|
||||
principalColumn: "Id",
|
||||
onDelete: ReferentialAction.Cascade);
|
||||
|
||||
migrationBuilder.AddForeignKey(
|
||||
name: "FK_Permissions_GuildConfigs_GuildConfigId",
|
||||
table: "Permissions",
|
||||
column: "GuildConfigId",
|
||||
principalTable: "GuildConfigs",
|
||||
principalColumn: "Id",
|
||||
onDelete: ReferentialAction.Cascade);
|
||||
|
||||
migrationBuilder.AddForeignKey(
|
||||
name: "FK_ShopEntry_GuildConfigs_GuildConfigId",
|
||||
table: "ShopEntry",
|
||||
column: "GuildConfigId",
|
||||
principalTable: "GuildConfigs",
|
||||
principalColumn: "Id",
|
||||
onDelete: ReferentialAction.Cascade);
|
||||
|
||||
migrationBuilder.AddForeignKey(
|
||||
name: "FK_ShopEntryItem_ShopEntry_ShopEntryId",
|
||||
table: "ShopEntryItem",
|
||||
column: "ShopEntryId",
|
||||
principalTable: "ShopEntry",
|
||||
principalColumn: "Id",
|
||||
onDelete: ReferentialAction.Cascade);
|
||||
|
||||
migrationBuilder.AddForeignKey(
|
||||
name: "FK_SlowmodeIgnoredRole_GuildConfigs_GuildConfigId",
|
||||
table: "SlowmodeIgnoredRole",
|
||||
column: "GuildConfigId",
|
||||
principalTable: "GuildConfigs",
|
||||
principalColumn: "Id",
|
||||
onDelete: ReferentialAction.Cascade);
|
||||
|
||||
migrationBuilder.AddForeignKey(
|
||||
name: "FK_SlowmodeIgnoredUser_GuildConfigs_GuildConfigId",
|
||||
table: "SlowmodeIgnoredUser",
|
||||
column: "GuildConfigId",
|
||||
principalTable: "GuildConfigs",
|
||||
principalColumn: "Id",
|
||||
onDelete: ReferentialAction.Cascade);
|
||||
|
||||
migrationBuilder.AddForeignKey(
|
||||
name: "FK_StreamRoleBlacklistedUser_StreamRoleSettings_StreamRoleSettingsId",
|
||||
table: "StreamRoleBlacklistedUser",
|
||||
column: "StreamRoleSettingsId",
|
||||
principalTable: "StreamRoleSettings",
|
||||
principalColumn: "Id",
|
||||
onDelete: ReferentialAction.Cascade);
|
||||
|
||||
migrationBuilder.AddForeignKey(
|
||||
name: "FK_StreamRoleWhitelistedUser_StreamRoleSettings_StreamRoleSettingsId",
|
||||
table: "StreamRoleWhitelistedUser",
|
||||
column: "StreamRoleSettingsId",
|
||||
principalTable: "StreamRoleSettings",
|
||||
principalColumn: "Id",
|
||||
onDelete: ReferentialAction.Cascade);
|
||||
|
||||
migrationBuilder.AddForeignKey(
|
||||
name: "FK_UnbanTimer_GuildConfigs_GuildConfigId",
|
||||
table: "UnbanTimer",
|
||||
column: "GuildConfigId",
|
||||
principalTable: "GuildConfigs",
|
||||
principalColumn: "Id",
|
||||
onDelete: ReferentialAction.Cascade);
|
||||
|
||||
migrationBuilder.AddForeignKey(
|
||||
name: "FK_UnmuteTimer_GuildConfigs_GuildConfigId",
|
||||
table: "UnmuteTimer",
|
||||
column: "GuildConfigId",
|
||||
principalTable: "GuildConfigs",
|
||||
principalColumn: "Id",
|
||||
onDelete: ReferentialAction.Cascade);
|
||||
|
||||
migrationBuilder.AddForeignKey(
|
||||
name: "FK_UnroleTimer_GuildConfigs_GuildConfigId",
|
||||
table: "UnroleTimer",
|
||||
column: "GuildConfigId",
|
||||
principalTable: "GuildConfigs",
|
||||
principalColumn: "Id",
|
||||
onDelete: ReferentialAction.Cascade);
|
||||
|
||||
migrationBuilder.AddForeignKey(
|
||||
name: "FK_VcRoleInfo_GuildConfigs_GuildConfigId",
|
||||
table: "VcRoleInfo",
|
||||
column: "GuildConfigId",
|
||||
principalTable: "GuildConfigs",
|
||||
principalColumn: "Id",
|
||||
onDelete: ReferentialAction.Cascade);
|
||||
|
||||
migrationBuilder.AddForeignKey(
|
||||
name: "FK_WarningPunishment_GuildConfigs_GuildConfigId",
|
||||
table: "WarningPunishment",
|
||||
column: "GuildConfigId",
|
||||
principalTable: "GuildConfigs",
|
||||
principalColumn: "Id",
|
||||
onDelete: ReferentialAction.Cascade);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override void Down(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.DropForeignKey(
|
||||
name: "FK_AntiRaidSetting_GuildConfigs_GuildConfigId",
|
||||
table: "AntiRaidSetting");
|
||||
|
||||
migrationBuilder.DropForeignKey(
|
||||
name: "FK_AntiSpamIgnore_AntiSpamSetting_AntiSpamSettingId",
|
||||
table: "AntiSpamIgnore");
|
||||
|
||||
migrationBuilder.DropForeignKey(
|
||||
name: "FK_AntiSpamSetting_GuildConfigs_GuildConfigId",
|
||||
table: "AntiSpamSetting");
|
||||
|
||||
migrationBuilder.DropForeignKey(
|
||||
name: "FK_CommandAlias_GuildConfigs_GuildConfigId",
|
||||
table: "CommandAlias");
|
||||
|
||||
migrationBuilder.DropForeignKey(
|
||||
name: "FK_CommandCooldown_GuildConfigs_GuildConfigId",
|
||||
table: "CommandCooldown");
|
||||
|
||||
migrationBuilder.DropForeignKey(
|
||||
name: "FK_DelMsgOnCmdChannel_GuildConfigs_GuildConfigId",
|
||||
table: "DelMsgOnCmdChannel");
|
||||
|
||||
migrationBuilder.DropForeignKey(
|
||||
name: "FK_ExcludedItem_XpSettings_XpSettingsId",
|
||||
table: "ExcludedItem");
|
||||
|
||||
migrationBuilder.DropForeignKey(
|
||||
name: "FK_FilterChannelId_GuildConfigs_GuildConfigId",
|
||||
table: "FilterChannelId");
|
||||
|
||||
migrationBuilder.DropForeignKey(
|
||||
name: "FK_FilteredWord_GuildConfigs_GuildConfigId",
|
||||
table: "FilteredWord");
|
||||
|
||||
migrationBuilder.DropForeignKey(
|
||||
name: "FK_FilterLinksChannelId_GuildConfigs_GuildConfigId",
|
||||
table: "FilterLinksChannelId");
|
||||
|
||||
migrationBuilder.DropForeignKey(
|
||||
name: "FK_FilterWordsChannelId_GuildConfigs_GuildConfigId",
|
||||
table: "FilterWordsChannelId");
|
||||
|
||||
migrationBuilder.DropForeignKey(
|
||||
name: "FK_FollowedStream_GuildConfigs_GuildConfigId",
|
||||
table: "FollowedStream");
|
||||
|
||||
migrationBuilder.DropForeignKey(
|
||||
name: "FK_GCChannelId_GuildConfigs_GuildConfigId",
|
||||
table: "GCChannelId");
|
||||
|
||||
migrationBuilder.DropForeignKey(
|
||||
name: "FK_MutedUserId_GuildConfigs_GuildConfigId",
|
||||
table: "MutedUserId");
|
||||
|
||||
migrationBuilder.DropForeignKey(
|
||||
name: "FK_Permissions_GuildConfigs_GuildConfigId",
|
||||
table: "Permissions");
|
||||
|
||||
migrationBuilder.DropForeignKey(
|
||||
name: "FK_ShopEntry_GuildConfigs_GuildConfigId",
|
||||
table: "ShopEntry");
|
||||
|
||||
migrationBuilder.DropForeignKey(
|
||||
name: "FK_ShopEntryItem_ShopEntry_ShopEntryId",
|
||||
table: "ShopEntryItem");
|
||||
|
||||
migrationBuilder.DropForeignKey(
|
||||
name: "FK_SlowmodeIgnoredRole_GuildConfigs_GuildConfigId",
|
||||
table: "SlowmodeIgnoredRole");
|
||||
|
||||
migrationBuilder.DropForeignKey(
|
||||
name: "FK_SlowmodeIgnoredUser_GuildConfigs_GuildConfigId",
|
||||
table: "SlowmodeIgnoredUser");
|
||||
|
||||
migrationBuilder.DropForeignKey(
|
||||
name: "FK_StreamRoleBlacklistedUser_StreamRoleSettings_StreamRoleSettingsId",
|
||||
table: "StreamRoleBlacklistedUser");
|
||||
|
||||
migrationBuilder.DropForeignKey(
|
||||
name: "FK_StreamRoleWhitelistedUser_StreamRoleSettings_StreamRoleSettingsId",
|
||||
table: "StreamRoleWhitelistedUser");
|
||||
|
||||
migrationBuilder.DropForeignKey(
|
||||
name: "FK_UnbanTimer_GuildConfigs_GuildConfigId",
|
||||
table: "UnbanTimer");
|
||||
|
||||
migrationBuilder.DropForeignKey(
|
||||
name: "FK_UnmuteTimer_GuildConfigs_GuildConfigId",
|
||||
table: "UnmuteTimer");
|
||||
|
||||
migrationBuilder.DropForeignKey(
|
||||
name: "FK_UnroleTimer_GuildConfigs_GuildConfigId",
|
||||
table: "UnroleTimer");
|
||||
|
||||
migrationBuilder.DropForeignKey(
|
||||
name: "FK_VcRoleInfo_GuildConfigs_GuildConfigId",
|
||||
table: "VcRoleInfo");
|
||||
|
||||
migrationBuilder.DropForeignKey(
|
||||
name: "FK_WarningPunishment_GuildConfigs_GuildConfigId",
|
||||
table: "WarningPunishment");
|
||||
|
||||
migrationBuilder.AlterColumn<int>(
|
||||
name: "StreamRoleSettingsId",
|
||||
table: "StreamRoleWhitelistedUser",
|
||||
type: "INTEGER",
|
||||
nullable: true,
|
||||
oldClrType: typeof(int),
|
||||
oldType: "INTEGER");
|
||||
|
||||
migrationBuilder.AlterColumn<int>(
|
||||
name: "StreamRoleSettingsId",
|
||||
table: "StreamRoleBlacklistedUser",
|
||||
type: "INTEGER",
|
||||
nullable: true,
|
||||
oldClrType: typeof(int),
|
||||
oldType: "INTEGER");
|
||||
|
||||
migrationBuilder.AlterColumn<int>(
|
||||
name: "GuildConfigId",
|
||||
table: "DelMsgOnCmdChannel",
|
||||
type: "INTEGER",
|
||||
nullable: true,
|
||||
oldClrType: typeof(int),
|
||||
oldType: "INTEGER");
|
||||
|
||||
migrationBuilder.CreateTable(
|
||||
name: "IgnoredVoicePresenceCHannels",
|
||||
columns: table => new
|
||||
{
|
||||
Id = table.Column<int>(type: "INTEGER", nullable: false)
|
||||
.Annotation("Sqlite:Autoincrement", true),
|
||||
LogSettingId = table.Column<int>(type: "INTEGER", nullable: true),
|
||||
ChannelId = table.Column<ulong>(type: "INTEGER", nullable: false),
|
||||
DateAdded = table.Column<DateTime>(type: "TEXT", nullable: true)
|
||||
},
|
||||
constraints: table =>
|
||||
{
|
||||
table.PrimaryKey("PK_IgnoredVoicePresenceCHannels", x => x.Id);
|
||||
table.ForeignKey(
|
||||
name: "FK_IgnoredVoicePresenceCHannels_LogSettings_LogSettingId",
|
||||
column: x => x.LogSettingId,
|
||||
principalTable: "LogSettings",
|
||||
principalColumn: "Id");
|
||||
});
|
||||
|
||||
migrationBuilder.CreateIndex(
|
||||
name: "IX_IgnoredVoicePresenceCHannels_LogSettingId",
|
||||
table: "IgnoredVoicePresenceCHannels",
|
||||
column: "LogSettingId");
|
||||
|
||||
migrationBuilder.AddForeignKey(
|
||||
name: "FK_AntiRaidSetting_GuildConfigs_GuildConfigId",
|
||||
table: "AntiRaidSetting",
|
||||
column: "GuildConfigId",
|
||||
principalTable: "GuildConfigs",
|
||||
principalColumn: "Id",
|
||||
onDelete: ReferentialAction.Cascade);
|
||||
|
||||
migrationBuilder.AddForeignKey(
|
||||
name: "FK_AntiSpamIgnore_AntiSpamSetting_AntiSpamSettingId",
|
||||
table: "AntiSpamIgnore",
|
||||
column: "AntiSpamSettingId",
|
||||
principalTable: "AntiSpamSetting",
|
||||
principalColumn: "Id");
|
||||
|
||||
migrationBuilder.AddForeignKey(
|
||||
name: "FK_AntiSpamSetting_GuildConfigs_GuildConfigId",
|
||||
table: "AntiSpamSetting",
|
||||
column: "GuildConfigId",
|
||||
principalTable: "GuildConfigs",
|
||||
principalColumn: "Id",
|
||||
onDelete: ReferentialAction.Cascade);
|
||||
|
||||
migrationBuilder.AddForeignKey(
|
||||
name: "FK_CommandAlias_GuildConfigs_GuildConfigId",
|
||||
table: "CommandAlias",
|
||||
column: "GuildConfigId",
|
||||
principalTable: "GuildConfigs",
|
||||
principalColumn: "Id");
|
||||
|
||||
migrationBuilder.AddForeignKey(
|
||||
name: "FK_CommandCooldown_GuildConfigs_GuildConfigId",
|
||||
table: "CommandCooldown",
|
||||
column: "GuildConfigId",
|
||||
principalTable: "GuildConfigs",
|
||||
principalColumn: "Id");
|
||||
|
||||
migrationBuilder.AddForeignKey(
|
||||
name: "FK_DelMsgOnCmdChannel_GuildConfigs_GuildConfigId",
|
||||
table: "DelMsgOnCmdChannel",
|
||||
column: "GuildConfigId",
|
||||
principalTable: "GuildConfigs",
|
||||
principalColumn: "Id");
|
||||
|
||||
migrationBuilder.AddForeignKey(
|
||||
name: "FK_ExcludedItem_XpSettings_XpSettingsId",
|
||||
table: "ExcludedItem",
|
||||
column: "XpSettingsId",
|
||||
principalTable: "XpSettings",
|
||||
principalColumn: "Id");
|
||||
|
||||
migrationBuilder.AddForeignKey(
|
||||
name: "FK_FilterChannelId_GuildConfigs_GuildConfigId",
|
||||
table: "FilterChannelId",
|
||||
column: "GuildConfigId",
|
||||
principalTable: "GuildConfigs",
|
||||
principalColumn: "Id");
|
||||
|
||||
migrationBuilder.AddForeignKey(
|
||||
name: "FK_FilteredWord_GuildConfigs_GuildConfigId",
|
||||
table: "FilteredWord",
|
||||
column: "GuildConfigId",
|
||||
principalTable: "GuildConfigs",
|
||||
principalColumn: "Id");
|
||||
|
||||
migrationBuilder.AddForeignKey(
|
||||
name: "FK_FilterLinksChannelId_GuildConfigs_GuildConfigId",
|
||||
table: "FilterLinksChannelId",
|
||||
column: "GuildConfigId",
|
||||
principalTable: "GuildConfigs",
|
||||
principalColumn: "Id");
|
||||
|
||||
migrationBuilder.AddForeignKey(
|
||||
name: "FK_FilterWordsChannelId_GuildConfigs_GuildConfigId",
|
||||
table: "FilterWordsChannelId",
|
||||
column: "GuildConfigId",
|
||||
principalTable: "GuildConfigs",
|
||||
principalColumn: "Id");
|
||||
|
||||
migrationBuilder.AddForeignKey(
|
||||
name: "FK_FollowedStream_GuildConfigs_GuildConfigId",
|
||||
table: "FollowedStream",
|
||||
column: "GuildConfigId",
|
||||
principalTable: "GuildConfigs",
|
||||
principalColumn: "Id");
|
||||
|
||||
migrationBuilder.AddForeignKey(
|
||||
name: "FK_GCChannelId_GuildConfigs_GuildConfigId",
|
||||
table: "GCChannelId",
|
||||
column: "GuildConfigId",
|
||||
principalTable: "GuildConfigs",
|
||||
principalColumn: "Id");
|
||||
|
||||
migrationBuilder.AddForeignKey(
|
||||
name: "FK_MutedUserId_GuildConfigs_GuildConfigId",
|
||||
table: "MutedUserId",
|
||||
column: "GuildConfigId",
|
||||
principalTable: "GuildConfigs",
|
||||
principalColumn: "Id");
|
||||
|
||||
migrationBuilder.AddForeignKey(
|
||||
name: "FK_Permissions_GuildConfigs_GuildConfigId",
|
||||
table: "Permissions",
|
||||
column: "GuildConfigId",
|
||||
principalTable: "GuildConfigs",
|
||||
principalColumn: "Id");
|
||||
|
||||
migrationBuilder.AddForeignKey(
|
||||
name: "FK_ShopEntry_GuildConfigs_GuildConfigId",
|
||||
table: "ShopEntry",
|
||||
column: "GuildConfigId",
|
||||
principalTable: "GuildConfigs",
|
||||
principalColumn: "Id");
|
||||
|
||||
migrationBuilder.AddForeignKey(
|
||||
name: "FK_ShopEntryItem_ShopEntry_ShopEntryId",
|
||||
table: "ShopEntryItem",
|
||||
column: "ShopEntryId",
|
||||
principalTable: "ShopEntry",
|
||||
principalColumn: "Id");
|
||||
|
||||
migrationBuilder.AddForeignKey(
|
||||
name: "FK_SlowmodeIgnoredRole_GuildConfigs_GuildConfigId",
|
||||
table: "SlowmodeIgnoredRole",
|
||||
column: "GuildConfigId",
|
||||
principalTable: "GuildConfigs",
|
||||
principalColumn: "Id");
|
||||
|
||||
migrationBuilder.AddForeignKey(
|
||||
name: "FK_SlowmodeIgnoredUser_GuildConfigs_GuildConfigId",
|
||||
table: "SlowmodeIgnoredUser",
|
||||
column: "GuildConfigId",
|
||||
principalTable: "GuildConfigs",
|
||||
principalColumn: "Id");
|
||||
|
||||
migrationBuilder.AddForeignKey(
|
||||
name: "FK_StreamRoleBlacklistedUser_StreamRoleSettings_StreamRoleSettingsId",
|
||||
table: "StreamRoleBlacklistedUser",
|
||||
column: "StreamRoleSettingsId",
|
||||
principalTable: "StreamRoleSettings",
|
||||
principalColumn: "Id");
|
||||
|
||||
migrationBuilder.AddForeignKey(
|
||||
name: "FK_StreamRoleWhitelistedUser_StreamRoleSettings_StreamRoleSettingsId",
|
||||
table: "StreamRoleWhitelistedUser",
|
||||
column: "StreamRoleSettingsId",
|
||||
principalTable: "StreamRoleSettings",
|
||||
principalColumn: "Id");
|
||||
|
||||
migrationBuilder.AddForeignKey(
|
||||
name: "FK_UnbanTimer_GuildConfigs_GuildConfigId",
|
||||
table: "UnbanTimer",
|
||||
column: "GuildConfigId",
|
||||
principalTable: "GuildConfigs",
|
||||
principalColumn: "Id");
|
||||
|
||||
migrationBuilder.AddForeignKey(
|
||||
name: "FK_UnmuteTimer_GuildConfigs_GuildConfigId",
|
||||
table: "UnmuteTimer",
|
||||
column: "GuildConfigId",
|
||||
principalTable: "GuildConfigs",
|
||||
principalColumn: "Id");
|
||||
|
||||
migrationBuilder.AddForeignKey(
|
||||
name: "FK_UnroleTimer_GuildConfigs_GuildConfigId",
|
||||
table: "UnroleTimer",
|
||||
column: "GuildConfigId",
|
||||
principalTable: "GuildConfigs",
|
||||
principalColumn: "Id");
|
||||
|
||||
migrationBuilder.AddForeignKey(
|
||||
name: "FK_VcRoleInfo_GuildConfigs_GuildConfigId",
|
||||
table: "VcRoleInfo",
|
||||
column: "GuildConfigId",
|
||||
principalTable: "GuildConfigs",
|
||||
principalColumn: "Id");
|
||||
|
||||
migrationBuilder.AddForeignKey(
|
||||
name: "FK_WarningPunishment_GuildConfigs_GuildConfigId",
|
||||
table: "WarningPunishment",
|
||||
column: "GuildConfigId",
|
||||
principalTable: "GuildConfigs",
|
||||
principalColumn: "Id");
|
||||
}
|
||||
}
|
||||
}
|
2921
src/NadekoBot/Migrations/Sqlite/20240611180456_remove-patron-limits.Designer.cs
generated
Normal file
2921
src/NadekoBot/Migrations/Sqlite/20240611180456_remove-patron-limits.Designer.cs
generated
Normal file
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,42 @@
|
||||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
|
||||
#nullable disable
|
||||
|
||||
namespace NadekoBot.Migrations
|
||||
{
|
||||
/// <inheritdoc />
|
||||
public partial class removepatronlimits : Migration
|
||||
{
|
||||
/// <inheritdoc />
|
||||
protected override void Up(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.DropTable(
|
||||
name: "PatronQuotas");
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override void Down(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.CreateTable(
|
||||
name: "PatronQuotas",
|
||||
columns: table => new
|
||||
{
|
||||
UserId = table.Column<ulong>(type: "INTEGER", nullable: false),
|
||||
FeatureType = table.Column<int>(type: "INTEGER", nullable: false),
|
||||
Feature = table.Column<string>(type: "TEXT", nullable: false),
|
||||
DailyCount = table.Column<uint>(type: "INTEGER", nullable: false),
|
||||
HourlyCount = table.Column<uint>(type: "INTEGER", nullable: false),
|
||||
MonthlyCount = table.Column<uint>(type: "INTEGER", nullable: false)
|
||||
},
|
||||
constraints: table =>
|
||||
{
|
||||
table.PrimaryKey("PK_PatronQuotas", x => new { x.UserId, x.FeatureType, x.Feature });
|
||||
});
|
||||
|
||||
migrationBuilder.CreateIndex(
|
||||
name: "IX_PatronQuotas_UserId",
|
||||
table: "PatronQuotas",
|
||||
column: "UserId");
|
||||
}
|
||||
}
|
||||
}
|
@@ -501,7 +501,7 @@ namespace NadekoBot.Migrations
|
||||
b.Property<DateTime?>("DateAdded")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<int?>("GuildConfigId")
|
||||
b.Property<int>("GuildConfigId")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<bool>("State")
|
||||
@@ -1059,28 +1059,6 @@ namespace NadekoBot.Migrations
|
||||
b.ToTable("IgnoredLogChannels");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("NadekoBot.Db.Models.IgnoredVoicePresenceChannel", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<ulong>("ChannelId")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<DateTime?>("DateAdded")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<int?>("LogSettingId")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("LogSettingId");
|
||||
|
||||
b.ToTable("IgnoredVoicePresenceCHannels");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("NadekoBot.Db.Models.ImageOnlyChannel", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
@@ -1301,33 +1279,6 @@ namespace NadekoBot.Migrations
|
||||
b.ToTable("Expressions");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("NadekoBot.Db.Models.PatronQuota", b =>
|
||||
{
|
||||
b.Property<ulong>("UserId")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<int>("FeatureType")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<string>("Feature")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<uint>("DailyCount")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<uint>("HourlyCount")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<uint>("MonthlyCount")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.HasKey("UserId", "FeatureType", "Feature");
|
||||
|
||||
b.HasIndex("UserId");
|
||||
|
||||
b.ToTable("PatronQuotas");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("NadekoBot.Db.Models.PatronUser", b =>
|
||||
{
|
||||
b.Property<ulong>("UserId")
|
||||
@@ -1867,7 +1818,7 @@ namespace NadekoBot.Migrations
|
||||
b.Property<DateTime?>("DateAdded")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<int?>("StreamRoleSettingsId")
|
||||
b.Property<int>("StreamRoleSettingsId")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<ulong>("UserId")
|
||||
@@ -1924,7 +1875,7 @@ namespace NadekoBot.Migrations
|
||||
b.Property<DateTime?>("DateAdded")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<int?>("StreamRoleSettingsId")
|
||||
b.Property<int>("StreamRoleSettingsId")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<ulong>("UserId")
|
||||
@@ -2397,31 +2348,28 @@ namespace NadekoBot.Migrations
|
||||
|
||||
modelBuilder.Entity("NadekoBot.Db.Models.AntiRaidSetting", b =>
|
||||
{
|
||||
b.HasOne("NadekoBot.Db.Models.GuildConfig", "GuildConfig")
|
||||
b.HasOne("NadekoBot.Db.Models.GuildConfig", null)
|
||||
.WithOne("AntiRaidSetting")
|
||||
.HasForeignKey("NadekoBot.Db.Models.AntiRaidSetting", "GuildConfigId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
|
||||
b.Navigation("GuildConfig");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("NadekoBot.Db.Models.AntiSpamIgnore", b =>
|
||||
{
|
||||
b.HasOne("NadekoBot.Db.Models.AntiSpamSetting", null)
|
||||
.WithMany("IgnoredChannels")
|
||||
.HasForeignKey("AntiSpamSettingId");
|
||||
.HasForeignKey("AntiSpamSettingId")
|
||||
.OnDelete(DeleteBehavior.Cascade);
|
||||
});
|
||||
|
||||
modelBuilder.Entity("NadekoBot.Db.Models.AntiSpamSetting", b =>
|
||||
{
|
||||
b.HasOne("NadekoBot.Db.Models.GuildConfig", "GuildConfig")
|
||||
b.HasOne("NadekoBot.Db.Models.GuildConfig", null)
|
||||
.WithOne("AntiSpamSetting")
|
||||
.HasForeignKey("NadekoBot.Db.Models.AntiSpamSetting", "GuildConfigId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
|
||||
b.Navigation("GuildConfig");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("NadekoBot.Db.Models.AutoTranslateUser", b =>
|
||||
@@ -2487,21 +2435,25 @@ namespace NadekoBot.Migrations
|
||||
{
|
||||
b.HasOne("NadekoBot.Db.Models.GuildConfig", null)
|
||||
.WithMany("CommandAliases")
|
||||
.HasForeignKey("GuildConfigId");
|
||||
.HasForeignKey("GuildConfigId")
|
||||
.OnDelete(DeleteBehavior.Cascade);
|
||||
});
|
||||
|
||||
modelBuilder.Entity("NadekoBot.Db.Models.CommandCooldown", b =>
|
||||
{
|
||||
b.HasOne("NadekoBot.Db.Models.GuildConfig", null)
|
||||
.WithMany("CommandCooldowns")
|
||||
.HasForeignKey("GuildConfigId");
|
||||
.HasForeignKey("GuildConfigId")
|
||||
.OnDelete(DeleteBehavior.Cascade);
|
||||
});
|
||||
|
||||
modelBuilder.Entity("NadekoBot.Db.Models.DelMsgOnCmdChannel", b =>
|
||||
{
|
||||
b.HasOne("NadekoBot.Db.Models.GuildConfig", null)
|
||||
.WithMany("DelMsgOnCmdChannels")
|
||||
.HasForeignKey("GuildConfigId");
|
||||
.HasForeignKey("GuildConfigId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
});
|
||||
|
||||
modelBuilder.Entity("NadekoBot.Db.Models.DiscordUser", b =>
|
||||
@@ -2516,9 +2468,12 @@ namespace NadekoBot.Migrations
|
||||
|
||||
modelBuilder.Entity("NadekoBot.Db.Models.ExcludedItem", b =>
|
||||
{
|
||||
b.HasOne("NadekoBot.Db.Models.XpSettings", null)
|
||||
b.HasOne("NadekoBot.Db.Models.XpSettings", "XpSettings")
|
||||
.WithMany("ExclusionList")
|
||||
.HasForeignKey("XpSettingsId");
|
||||
.HasForeignKey("XpSettingsId")
|
||||
.OnDelete(DeleteBehavior.Cascade);
|
||||
|
||||
b.Navigation("XpSettings");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("NadekoBot.Db.Models.FeedSub", b =>
|
||||
@@ -2536,42 +2491,48 @@ namespace NadekoBot.Migrations
|
||||
{
|
||||
b.HasOne("NadekoBot.Db.Models.GuildConfig", null)
|
||||
.WithMany("FilterInvitesChannelIds")
|
||||
.HasForeignKey("GuildConfigId");
|
||||
.HasForeignKey("GuildConfigId")
|
||||
.OnDelete(DeleteBehavior.Cascade);
|
||||
});
|
||||
|
||||
modelBuilder.Entity("NadekoBot.Db.Models.FilterLinksChannelId", b =>
|
||||
{
|
||||
b.HasOne("NadekoBot.Db.Models.GuildConfig", null)
|
||||
.WithMany("FilterLinksChannelIds")
|
||||
.HasForeignKey("GuildConfigId");
|
||||
.HasForeignKey("GuildConfigId")
|
||||
.OnDelete(DeleteBehavior.Cascade);
|
||||
});
|
||||
|
||||
modelBuilder.Entity("NadekoBot.Db.Models.FilterWordsChannelId", b =>
|
||||
{
|
||||
b.HasOne("NadekoBot.Db.Models.GuildConfig", null)
|
||||
.WithMany("FilterWordsChannelIds")
|
||||
.HasForeignKey("GuildConfigId");
|
||||
.HasForeignKey("GuildConfigId")
|
||||
.OnDelete(DeleteBehavior.Cascade);
|
||||
});
|
||||
|
||||
modelBuilder.Entity("NadekoBot.Db.Models.FilteredWord", b =>
|
||||
{
|
||||
b.HasOne("NadekoBot.Db.Models.GuildConfig", null)
|
||||
.WithMany("FilteredWords")
|
||||
.HasForeignKey("GuildConfigId");
|
||||
.HasForeignKey("GuildConfigId")
|
||||
.OnDelete(DeleteBehavior.Cascade);
|
||||
});
|
||||
|
||||
modelBuilder.Entity("NadekoBot.Db.Models.FollowedStream", b =>
|
||||
{
|
||||
b.HasOne("NadekoBot.Db.Models.GuildConfig", null)
|
||||
.WithMany("FollowedStreams")
|
||||
.HasForeignKey("GuildConfigId");
|
||||
.HasForeignKey("GuildConfigId")
|
||||
.OnDelete(DeleteBehavior.Cascade);
|
||||
});
|
||||
|
||||
modelBuilder.Entity("NadekoBot.Db.Models.GCChannelId", b =>
|
||||
{
|
||||
b.HasOne("NadekoBot.Db.Models.GuildConfig", "GuildConfig")
|
||||
.WithMany("GenerateCurrencyChannelIds")
|
||||
.HasForeignKey("GuildConfigId");
|
||||
.HasForeignKey("GuildConfigId")
|
||||
.OnDelete(DeleteBehavior.Cascade);
|
||||
|
||||
b.Navigation("GuildConfig");
|
||||
});
|
||||
@@ -2607,27 +2568,20 @@ namespace NadekoBot.Migrations
|
||||
b.Navigation("LogSetting");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("NadekoBot.Db.Models.IgnoredVoicePresenceChannel", b =>
|
||||
{
|
||||
b.HasOne("NadekoBot.Db.Models.LogSetting", "LogSetting")
|
||||
.WithMany()
|
||||
.HasForeignKey("LogSettingId");
|
||||
|
||||
b.Navigation("LogSetting");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("NadekoBot.Db.Models.MutedUserId", b =>
|
||||
{
|
||||
b.HasOne("NadekoBot.Db.Models.GuildConfig", null)
|
||||
.WithMany("MutedUsers")
|
||||
.HasForeignKey("GuildConfigId");
|
||||
.HasForeignKey("GuildConfigId")
|
||||
.OnDelete(DeleteBehavior.Cascade);
|
||||
});
|
||||
|
||||
modelBuilder.Entity("NadekoBot.Db.Models.Permissionv2", b =>
|
||||
{
|
||||
b.HasOne("NadekoBot.Db.Models.GuildConfig", null)
|
||||
.WithMany("Permissions")
|
||||
.HasForeignKey("GuildConfigId");
|
||||
.HasForeignKey("GuildConfigId")
|
||||
.OnDelete(DeleteBehavior.Cascade);
|
||||
});
|
||||
|
||||
modelBuilder.Entity("NadekoBot.Db.Models.PlaylistSong", b =>
|
||||
@@ -2642,35 +2596,43 @@ namespace NadekoBot.Migrations
|
||||
{
|
||||
b.HasOne("NadekoBot.Db.Models.GuildConfig", null)
|
||||
.WithMany("ShopEntries")
|
||||
.HasForeignKey("GuildConfigId");
|
||||
.HasForeignKey("GuildConfigId")
|
||||
.OnDelete(DeleteBehavior.Cascade);
|
||||
});
|
||||
|
||||
modelBuilder.Entity("NadekoBot.Db.Models.ShopEntryItem", b =>
|
||||
{
|
||||
b.HasOne("NadekoBot.Db.Models.ShopEntry", null)
|
||||
.WithMany("Items")
|
||||
.HasForeignKey("ShopEntryId");
|
||||
.HasForeignKey("ShopEntryId")
|
||||
.OnDelete(DeleteBehavior.Cascade);
|
||||
});
|
||||
|
||||
modelBuilder.Entity("NadekoBot.Db.Models.SlowmodeIgnoredRole", b =>
|
||||
{
|
||||
b.HasOne("NadekoBot.Db.Models.GuildConfig", null)
|
||||
.WithMany("SlowmodeIgnoredRoles")
|
||||
.HasForeignKey("GuildConfigId");
|
||||
.HasForeignKey("GuildConfigId")
|
||||
.OnDelete(DeleteBehavior.Cascade);
|
||||
});
|
||||
|
||||
modelBuilder.Entity("NadekoBot.Db.Models.SlowmodeIgnoredUser", b =>
|
||||
{
|
||||
b.HasOne("NadekoBot.Db.Models.GuildConfig", null)
|
||||
.WithMany("SlowmodeIgnoredUsers")
|
||||
.HasForeignKey("GuildConfigId");
|
||||
.HasForeignKey("GuildConfigId")
|
||||
.OnDelete(DeleteBehavior.Cascade);
|
||||
});
|
||||
|
||||
modelBuilder.Entity("NadekoBot.Db.Models.StreamRoleBlacklistedUser", b =>
|
||||
{
|
||||
b.HasOne("NadekoBot.Db.Models.StreamRoleSettings", null)
|
||||
b.HasOne("NadekoBot.Db.Models.StreamRoleSettings", "StreamRoleSettings")
|
||||
.WithMany("Blacklist")
|
||||
.HasForeignKey("StreamRoleSettingsId");
|
||||
.HasForeignKey("StreamRoleSettingsId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
|
||||
b.Navigation("StreamRoleSettings");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("NadekoBot.Db.Models.StreamRoleSettings", b =>
|
||||
@@ -2686,9 +2648,13 @@ namespace NadekoBot.Migrations
|
||||
|
||||
modelBuilder.Entity("NadekoBot.Db.Models.StreamRoleWhitelistedUser", b =>
|
||||
{
|
||||
b.HasOne("NadekoBot.Db.Models.StreamRoleSettings", null)
|
||||
b.HasOne("NadekoBot.Db.Models.StreamRoleSettings", "StreamRoleSettings")
|
||||
.WithMany("Whitelist")
|
||||
.HasForeignKey("StreamRoleSettingsId");
|
||||
.HasForeignKey("StreamRoleSettingsId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
|
||||
b.Navigation("StreamRoleSettings");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("NadekoBot.Db.Models.TodoModel", b =>
|
||||
@@ -2703,28 +2669,32 @@ namespace NadekoBot.Migrations
|
||||
{
|
||||
b.HasOne("NadekoBot.Db.Models.GuildConfig", null)
|
||||
.WithMany("UnbanTimer")
|
||||
.HasForeignKey("GuildConfigId");
|
||||
.HasForeignKey("GuildConfigId")
|
||||
.OnDelete(DeleteBehavior.Cascade);
|
||||
});
|
||||
|
||||
modelBuilder.Entity("NadekoBot.Db.Models.UnmuteTimer", b =>
|
||||
{
|
||||
b.HasOne("NadekoBot.Db.Models.GuildConfig", null)
|
||||
.WithMany("UnmuteTimers")
|
||||
.HasForeignKey("GuildConfigId");
|
||||
.HasForeignKey("GuildConfigId")
|
||||
.OnDelete(DeleteBehavior.Cascade);
|
||||
});
|
||||
|
||||
modelBuilder.Entity("NadekoBot.Db.Models.UnroleTimer", b =>
|
||||
{
|
||||
b.HasOne("NadekoBot.Db.Models.GuildConfig", null)
|
||||
.WithMany("UnroleTimer")
|
||||
.HasForeignKey("GuildConfigId");
|
||||
.HasForeignKey("GuildConfigId")
|
||||
.OnDelete(DeleteBehavior.Cascade);
|
||||
});
|
||||
|
||||
modelBuilder.Entity("NadekoBot.Db.Models.VcRoleInfo", b =>
|
||||
{
|
||||
b.HasOne("NadekoBot.Db.Models.GuildConfig", null)
|
||||
.WithMany("VcRoleInfos")
|
||||
.HasForeignKey("GuildConfigId");
|
||||
.HasForeignKey("GuildConfigId")
|
||||
.OnDelete(DeleteBehavior.Cascade);
|
||||
});
|
||||
|
||||
modelBuilder.Entity("NadekoBot.Db.Models.WaifuInfo", b =>
|
||||
@@ -2786,7 +2756,8 @@ namespace NadekoBot.Migrations
|
||||
{
|
||||
b.HasOne("NadekoBot.Db.Models.GuildConfig", null)
|
||||
.WithMany("WarnPunishments")
|
||||
.HasForeignKey("GuildConfigId");
|
||||
.HasForeignKey("GuildConfigId")
|
||||
.OnDelete(DeleteBehavior.Cascade);
|
||||
});
|
||||
|
||||
modelBuilder.Entity("NadekoBot.Db.Models.XpCurrencyReward", b =>
|
||||
|
@@ -1,5 +1,6 @@
|
||||
#nullable disable
|
||||
using NadekoBot.Common.TypeReaders.Models;
|
||||
using NadekoBot.Modules.Administration._common.results;
|
||||
using NadekoBot.Modules.Administration.Services;
|
||||
|
||||
namespace NadekoBot.Modules.Administration;
|
||||
@@ -405,4 +406,94 @@ public partial class Administration : NadekoModule<AdministrationService>
|
||||
await Response().Confirm(strs.autopublish_disable).SendAsync();
|
||||
}
|
||||
}
|
||||
|
||||
[Cmd]
|
||||
[UserPerm(GuildPerm.ManageNicknames)]
|
||||
[BotPerm(GuildPerm.ChangeNickname)]
|
||||
[Priority(0)]
|
||||
public async Task SetNick([Leftover] string newNick = null)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(newNick))
|
||||
return;
|
||||
var curUser = await ctx.Guild.GetCurrentUserAsync();
|
||||
await curUser.ModifyAsync(u => u.Nickname = newNick);
|
||||
|
||||
await Response().Confirm(strs.bot_nick(Format.Bold(newNick) ?? "-")).SendAsync();
|
||||
}
|
||||
|
||||
[Cmd]
|
||||
[BotPerm(GuildPerm.ManageNicknames)]
|
||||
[UserPerm(GuildPerm.ManageNicknames)]
|
||||
[Priority(1)]
|
||||
public async Task SetNick(IGuildUser gu, [Leftover] string newNick = null)
|
||||
{
|
||||
var sg = (SocketGuild)ctx.Guild;
|
||||
if (sg.OwnerId == gu.Id
|
||||
|| gu.GetRoles().Max(r => r.Position) >= sg.CurrentUser.GetRoles().Max(r => r.Position))
|
||||
{
|
||||
await Response().Error(strs.insuf_perms_i).SendAsync();
|
||||
return;
|
||||
}
|
||||
|
||||
await gu.ModifyAsync(u => u.Nickname = newNick);
|
||||
|
||||
await Response()
|
||||
.Confirm(strs.user_nick(Format.Bold(gu.ToString()), Format.Bold(newNick) ?? "-"))
|
||||
.SendAsync();
|
||||
}
|
||||
|
||||
|
||||
[Cmd]
|
||||
[RequireContext(ContextType.Guild)]
|
||||
[UserPerm(GuildPermission.ManageGuild)]
|
||||
[BotPerm(GuildPermission.ManageGuild)]
|
||||
public async Task SetServerBanner([Leftover] string img = null)
|
||||
{
|
||||
// Tier2 or higher is required to set a banner.
|
||||
if (ctx.Guild.PremiumTier is PremiumTier.Tier1 or PremiumTier.None) return;
|
||||
|
||||
var result = await _service.SetServerBannerAsync(ctx.Guild, img);
|
||||
|
||||
switch (result)
|
||||
{
|
||||
case SetServerBannerResult.Success:
|
||||
await Response().Confirm(strs.set_srvr_banner).SendAsync();
|
||||
break;
|
||||
case SetServerBannerResult.InvalidFileType:
|
||||
await Response().Error(strs.srvr_banner_invalid).SendAsync();
|
||||
break;
|
||||
case SetServerBannerResult.Toolarge:
|
||||
await Response().Error(strs.srvr_banner_too_large).SendAsync();
|
||||
break;
|
||||
case SetServerBannerResult.InvalidURL:
|
||||
await Response().Error(strs.srvr_banner_invalid_url).SendAsync();
|
||||
break;
|
||||
default:
|
||||
throw new ArgumentOutOfRangeException();
|
||||
}
|
||||
}
|
||||
|
||||
[Cmd]
|
||||
[RequireContext(ContextType.Guild)]
|
||||
[UserPerm(GuildPermission.ManageGuild)]
|
||||
[BotPerm(GuildPermission.ManageGuild)]
|
||||
public async Task SetServerIcon([Leftover] string img = null)
|
||||
{
|
||||
var result = await _service.SetServerIconAsync(ctx.Guild, img);
|
||||
|
||||
switch (result)
|
||||
{
|
||||
case SetServerIconResult.Success:
|
||||
await Response().Confirm(strs.set_srvr_icon).SendAsync();
|
||||
break;
|
||||
case SetServerIconResult.InvalidFileType:
|
||||
await Response().Error(strs.srvr_banner_invalid).SendAsync();
|
||||
break;
|
||||
case SetServerIconResult.InvalidURL:
|
||||
await Response().Error(strs.srvr_banner_invalid_url).SendAsync();
|
||||
break;
|
||||
default:
|
||||
throw new ArgumentOutOfRangeException();
|
||||
}
|
||||
}
|
||||
}
|
@@ -2,6 +2,7 @@
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using NadekoBot.Db;
|
||||
using NadekoBot.Db.Models;
|
||||
using NadekoBot.Modules.Administration._common.results;
|
||||
|
||||
namespace NadekoBot.Modules.Administration.Services;
|
||||
|
||||
@@ -13,17 +14,20 @@ public class AdministrationService : INService
|
||||
private readonly DbService _db;
|
||||
private readonly IReplacementService _repSvc;
|
||||
private readonly ILogCommandService _logService;
|
||||
private readonly IHttpClientFactory _httpFactory;
|
||||
|
||||
public AdministrationService(
|
||||
IBot bot,
|
||||
CommandHandler cmdHandler,
|
||||
DbService db,
|
||||
IReplacementService repSvc,
|
||||
ILogCommandService logService)
|
||||
ILogCommandService logService,
|
||||
IHttpClientFactory factory)
|
||||
{
|
||||
_db = db;
|
||||
_repSvc = repSvc;
|
||||
_logService = logService;
|
||||
_httpFactory = factory;
|
||||
|
||||
DeleteMessagesOnCommand = new(bot.AllGuildConfigs.Where(g => g.DeleteMessageOnCommand).Select(g => g.GuildId));
|
||||
|
||||
@@ -158,4 +162,45 @@ public class AdministrationService : INService
|
||||
|
||||
await umsg.EditAsync(text);
|
||||
}
|
||||
|
||||
public async Task<SetServerBannerResult> SetServerBannerAsync(IGuild guild, string img)
|
||||
{
|
||||
if (!IsValidUri(img)) return SetServerBannerResult.InvalidURL;
|
||||
|
||||
var uri = new Uri(img);
|
||||
|
||||
using var http = _httpFactory.CreateClient();
|
||||
using var sr = await http.GetAsync(uri, HttpCompletionOption.ResponseHeadersRead);
|
||||
|
||||
if (!sr.IsImage()) return SetServerBannerResult.InvalidFileType;
|
||||
|
||||
if (sr.GetContentLength() > 8.Megabytes())
|
||||
{
|
||||
return SetServerBannerResult.Toolarge;
|
||||
}
|
||||
|
||||
await using var imageStream = await sr.Content.ReadAsStreamAsync();
|
||||
|
||||
await guild.ModifyAsync(x => x.Banner = new Image(imageStream));
|
||||
return SetServerBannerResult.Success;
|
||||
}
|
||||
|
||||
public async Task<SetServerIconResult> SetServerIconAsync(IGuild guild, string img)
|
||||
{
|
||||
if (!IsValidUri(img)) return SetServerIconResult.InvalidURL;
|
||||
|
||||
var uri = new Uri(img);
|
||||
|
||||
using var http = _httpFactory.CreateClient();
|
||||
using var sr = await http.GetAsync(uri, HttpCompletionOption.ResponseHeadersRead);
|
||||
|
||||
if (!sr.IsImage()) return SetServerIconResult.InvalidFileType;
|
||||
|
||||
await using var imageStream = await sr.Content.ReadAsStreamAsync();
|
||||
|
||||
await guild.ModifyAsync(x => x.Icon = new Image(imageStream));
|
||||
return SetServerIconResult.Success;
|
||||
}
|
||||
|
||||
private bool IsValidUri(string img) => !string.IsNullOrWhiteSpace(img) && Uri.IsWellFormedUriString(img, UriKind.Absolute);
|
||||
}
|
@@ -0,0 +1,31 @@
|
||||
namespace NadekoBot.Modules.Administration.DangerousCommands;
|
||||
|
||||
public partial class Administration
|
||||
{
|
||||
[Group]
|
||||
public class CleanupCommands : CleanupModuleBase
|
||||
{
|
||||
private readonly ICleanupService _svc;
|
||||
|
||||
public CleanupCommands(ICleanupService svc)
|
||||
=> _svc = svc;
|
||||
|
||||
[Cmd]
|
||||
[OwnerOnly]
|
||||
[RequireContext(ContextType.DM)]
|
||||
public async Task CleanupGuildData()
|
||||
{
|
||||
var result = await _svc.DeleteMissingGuildDataAsync();
|
||||
|
||||
if (result is null)
|
||||
{
|
||||
await ctx.ErrorAsync();
|
||||
return;
|
||||
}
|
||||
|
||||
await Response()
|
||||
.Confirm($"{result.GuildCount} guilds' data remain in the database.")
|
||||
.SendAsync();
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,155 @@
|
||||
using LinqToDB;
|
||||
using LinqToDB.Data;
|
||||
using LinqToDB.EntityFrameworkCore;
|
||||
using NadekoBot.Common.ModuleBehaviors;
|
||||
using NadekoBot.Db.Models;
|
||||
|
||||
namespace NadekoBot.Modules.Administration.DangerousCommands;
|
||||
|
||||
public sealed class CleanupService : ICleanupService, IReadyExecutor, INService
|
||||
{
|
||||
private readonly IPubSub _pubSub;
|
||||
private TypedKey<KeepReport> _keepReportKey = new("cleanup:report");
|
||||
private TypedKey<bool> _keepTriggerKey = new("cleanup:trigger");
|
||||
private readonly DiscordSocketClient _client;
|
||||
private ConcurrentDictionary<int, ulong[]> guildIds = new();
|
||||
private readonly IBotCredsProvider _creds;
|
||||
private readonly DbService _db;
|
||||
|
||||
public CleanupService(
|
||||
IPubSub pubSub,
|
||||
DiscordSocketClient client,
|
||||
IBotCredsProvider creds,
|
||||
DbService db)
|
||||
{
|
||||
_pubSub = pubSub;
|
||||
_client = client;
|
||||
_creds = creds;
|
||||
_db = db;
|
||||
}
|
||||
|
||||
public async Task<KeepResult?> DeleteMissingGuildDataAsync()
|
||||
{
|
||||
guildIds = new();
|
||||
var totalShards = _creds.GetCreds().TotalShards;
|
||||
await _pubSub.Pub(_keepTriggerKey, true);
|
||||
var counter = 0;
|
||||
while (guildIds.Keys.Count < totalShards)
|
||||
{
|
||||
await Task.Delay(1000);
|
||||
counter++;
|
||||
|
||||
if (counter >= 5)
|
||||
break;
|
||||
}
|
||||
|
||||
if (guildIds.Keys.Count < totalShards)
|
||||
return default;
|
||||
|
||||
var allIds = guildIds.SelectMany(x => x.Value)
|
||||
.ToArray();
|
||||
|
||||
await using var ctx = _db.GetDbContext();
|
||||
await using var linqCtx = ctx.CreateLinqToDBContext();
|
||||
await using var tempTable = linqCtx.CreateTempTable<CleanupId>();
|
||||
|
||||
foreach (var chunk in allIds.Chunk(20000))
|
||||
{
|
||||
await tempTable.BulkCopyAsync(chunk.Select(x => new CleanupId()
|
||||
{
|
||||
GuildId = x
|
||||
}));
|
||||
}
|
||||
|
||||
// delete guild configs
|
||||
await ctx.GetTable<GuildConfig>()
|
||||
.Where(x => !tempTable.Select(x => x.GuildId)
|
||||
.Contains(x.GuildId))
|
||||
.DeleteAsync();
|
||||
|
||||
// delete guild xp
|
||||
await ctx.GetTable<UserXpStats>()
|
||||
.Where(x => !tempTable.Select(x => x.GuildId)
|
||||
.Contains(x.GuildId))
|
||||
.DeleteAsync();
|
||||
|
||||
// delete expressions
|
||||
await ctx.GetTable<NadekoExpression>()
|
||||
.Where(x => x.GuildId != null && !tempTable.Select(x => x.GuildId)
|
||||
.Contains(x.GuildId.Value))
|
||||
.DeleteAsync();
|
||||
|
||||
// delete quotes
|
||||
await ctx.GetTable<Quote>()
|
||||
.Where(x => !tempTable.Select(x => x.GuildId)
|
||||
.Contains(x.GuildId))
|
||||
.DeleteAsync();
|
||||
|
||||
// delete planted currencies
|
||||
await ctx.GetTable<PlantedCurrency>()
|
||||
.Where(x => !tempTable.Select(x => x.GuildId)
|
||||
.Contains(x.GuildId))
|
||||
.DeleteAsync();
|
||||
|
||||
// delete image only channels
|
||||
await ctx.GetTable<ImageOnlyChannel>()
|
||||
.Where(x => !tempTable.Select(x => x.GuildId)
|
||||
.Contains(x.GuildId))
|
||||
.DeleteAsync();
|
||||
|
||||
// delete reaction roles
|
||||
await ctx.GetTable<ReactionRoleV2>()
|
||||
.Where(x => !tempTable.Select(x => x.GuildId)
|
||||
.Contains(x.GuildId))
|
||||
.DeleteAsync();
|
||||
|
||||
// delete ignored users
|
||||
await ctx.GetTable<DiscordPermOverride>()
|
||||
.Where(x => x.GuildId != null && !tempTable.Select(x => x.GuildId)
|
||||
.Contains(x.GuildId.Value))
|
||||
.DeleteAsync();
|
||||
|
||||
// delete perm overrides
|
||||
await ctx.GetTable<DiscordPermOverride>()
|
||||
.Where(x => x.GuildId != null && !tempTable.Select(x => x.GuildId)
|
||||
.Contains(x.GuildId.Value))
|
||||
.DeleteAsync();
|
||||
|
||||
// delete repeaters
|
||||
await ctx.GetTable<Repeater>()
|
||||
.Where(x => !tempTable.Select(x => x.GuildId)
|
||||
.Contains(x.GuildId))
|
||||
.DeleteAsync();
|
||||
|
||||
return new()
|
||||
{
|
||||
GuildCount = guildIds.Keys.Count,
|
||||
};
|
||||
}
|
||||
|
||||
private ValueTask OnKeepReport(KeepReport report)
|
||||
{
|
||||
guildIds[report.ShardId] = report.GuildIds;
|
||||
return default;
|
||||
}
|
||||
|
||||
public async Task OnReadyAsync()
|
||||
{
|
||||
await _pubSub.Sub(_keepTriggerKey, OnKeepTrigger);
|
||||
|
||||
if (_client.ShardId == 0)
|
||||
await _pubSub.Sub(_keepReportKey, OnKeepReport);
|
||||
}
|
||||
|
||||
private ValueTask OnKeepTrigger(bool arg)
|
||||
{
|
||||
_pubSub.Pub(_keepReportKey,
|
||||
new KeepReport()
|
||||
{
|
||||
ShardId = _client.ShardId,
|
||||
GuildIds = _client.GetGuildIds(),
|
||||
});
|
||||
|
||||
return default;
|
||||
}
|
||||
}
|
@@ -0,0 +1,9 @@
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
|
||||
namespace NadekoBot.Modules.Administration.DangerousCommands;
|
||||
|
||||
public sealed class CleanupId
|
||||
{
|
||||
[Key]
|
||||
public ulong GuildId { get; set; }
|
||||
}
|
@@ -0,0 +1,6 @@
|
||||
namespace NadekoBot.Modules.Administration.DangerousCommands;
|
||||
|
||||
public interface ICleanupService
|
||||
{
|
||||
Task<KeepResult?> DeleteMissingGuildDataAsync();
|
||||
}
|
@@ -0,0 +1,7 @@
|
||||
namespace NadekoBot.Modules.Administration.DangerousCommands;
|
||||
|
||||
public sealed class KeepReport
|
||||
{
|
||||
public required int ShardId { get; init; }
|
||||
public required ulong[] GuildIds { get; init; }
|
||||
}
|
@@ -0,0 +1,6 @@
|
||||
namespace NadekoBot.Modules.Administration.DangerousCommands;
|
||||
|
||||
public sealed class KeepResult
|
||||
{
|
||||
public required int GuildCount { get; init; }
|
||||
}
|
@@ -61,7 +61,13 @@ public partial class Administration
|
||||
}
|
||||
else
|
||||
{
|
||||
ci = new(name);
|
||||
ci = new CultureInfo(name);
|
||||
if (!_supportedLocales.ContainsKey(ci.Name))
|
||||
{
|
||||
await LanguagesList();
|
||||
return;
|
||||
}
|
||||
|
||||
_localization.SetGuildCulture(ctx.Guild, ci);
|
||||
}
|
||||
|
||||
@@ -97,7 +103,12 @@ public partial class Administration
|
||||
}
|
||||
else
|
||||
{
|
||||
ci = new(name);
|
||||
ci = new CultureInfo(name);
|
||||
if (!_supportedLocales.ContainsKey(ci.Name))
|
||||
{
|
||||
await LanguagesList();
|
||||
return;
|
||||
}
|
||||
_localization.SetDefaultCulture(ci);
|
||||
}
|
||||
|
||||
|
@@ -45,23 +45,43 @@ public partial class Administration
|
||||
var progressMsg = await Response().Pending(strs.prune_progress(0, 100)).SendAsync();
|
||||
var progress = GetProgressTracker(progressMsg);
|
||||
|
||||
PruneResult result;
|
||||
if (opts.Safe)
|
||||
await _service.PruneWhere((ITextChannel)ctx.Channel,
|
||||
result = await _service.PruneWhere((ITextChannel)ctx.Channel,
|
||||
100,
|
||||
x => x.Author.Id == user.Id && !x.IsPinned,
|
||||
progress,
|
||||
opts.After);
|
||||
else
|
||||
await _service.PruneWhere((ITextChannel)ctx.Channel,
|
||||
result = await _service.PruneWhere((ITextChannel)ctx.Channel,
|
||||
100,
|
||||
x => x.Author.Id == user.Id,
|
||||
progress,
|
||||
opts.After);
|
||||
|
||||
ctx.Message.DeleteAfter(3);
|
||||
|
||||
await SendResult(result);
|
||||
await progressMsg.DeleteAsync();
|
||||
}
|
||||
|
||||
private async Task SendResult(PruneResult result)
|
||||
{
|
||||
switch (result)
|
||||
{
|
||||
case PruneResult.Success:
|
||||
break;
|
||||
case PruneResult.AlreadyRunning:
|
||||
break;
|
||||
case PruneResult.FeatureLimit:
|
||||
await Response().Pending(strs.feature_limit_reached_owner).SendAsync();
|
||||
break;
|
||||
|
||||
default:
|
||||
throw new ArgumentOutOfRangeException(nameof(result), result, null);
|
||||
}
|
||||
}
|
||||
|
||||
// prune x
|
||||
[Cmd]
|
||||
[RequireContext(ContextType.Guild)]
|
||||
@@ -83,19 +103,21 @@ public partial class Administration
|
||||
var progressMsg = await Response().Pending(strs.prune_progress(0, count)).SendAsync();
|
||||
var progress = GetProgressTracker(progressMsg);
|
||||
|
||||
PruneResult result;
|
||||
if (opts.Safe)
|
||||
await _service.PruneWhere((ITextChannel)ctx.Channel,
|
||||
result = await _service.PruneWhere((ITextChannel)ctx.Channel,
|
||||
count,
|
||||
x => !x.IsPinned && x.Id != progressMsg.Id,
|
||||
progress,
|
||||
opts.After);
|
||||
else
|
||||
await _service.PruneWhere((ITextChannel)ctx.Channel,
|
||||
result = await _service.PruneWhere((ITextChannel)ctx.Channel,
|
||||
count,
|
||||
x => x.Id != progressMsg.Id,
|
||||
progress,
|
||||
opts.After);
|
||||
|
||||
await SendResult(result);
|
||||
await progressMsg.DeleteAsync();
|
||||
}
|
||||
|
||||
@@ -155,9 +177,10 @@ public partial class Administration
|
||||
var progressMsg = await Response().Pending(strs.prune_progress(0, count)).SendAsync();
|
||||
var progress = GetProgressTracker(progressMsg);
|
||||
|
||||
PruneResult result;
|
||||
if (opts.Safe)
|
||||
{
|
||||
await _service.PruneWhere((ITextChannel)ctx.Channel,
|
||||
result = await _service.PruneWhere((ITextChannel)ctx.Channel,
|
||||
count,
|
||||
m => m.Author.Id == userId && DateTime.UtcNow - m.CreatedAt < _twoWeeks && !m.IsPinned,
|
||||
progress,
|
||||
@@ -166,7 +189,7 @@ public partial class Administration
|
||||
}
|
||||
else
|
||||
{
|
||||
await _service.PruneWhere((ITextChannel)ctx.Channel,
|
||||
result = await _service.PruneWhere((ITextChannel)ctx.Channel,
|
||||
count,
|
||||
m => m.Author.Id == userId && DateTime.UtcNow - m.CreatedAt < _twoWeeks,
|
||||
progress,
|
||||
@@ -174,6 +197,7 @@ public partial class Administration
|
||||
);
|
||||
}
|
||||
|
||||
await SendResult(result);
|
||||
await progressMsg.DeleteAsync();
|
||||
}
|
||||
|
||||
|
@@ -0,0 +1,9 @@
|
||||
#nullable disable
|
||||
namespace NadekoBot.Modules.Administration.Services;
|
||||
|
||||
public enum PruneResult
|
||||
{
|
||||
Success,
|
||||
AlreadyRunning,
|
||||
FeatureLimit,
|
||||
}
|
@@ -1,4 +1,6 @@
|
||||
#nullable disable
|
||||
using NadekoBot.Modules.Patronage;
|
||||
|
||||
namespace NadekoBot.Modules.Administration.Services;
|
||||
|
||||
public class PruneService : INService
|
||||
@@ -7,11 +9,15 @@ public class PruneService : INService
|
||||
private readonly ConcurrentDictionary<ulong, CancellationTokenSource> _pruningGuilds = new();
|
||||
private readonly TimeSpan _twoWeeks = TimeSpan.FromDays(14);
|
||||
private readonly ILogCommandService _logService;
|
||||
private readonly IPatronageService _ps;
|
||||
|
||||
public PruneService(ILogCommandService logService)
|
||||
=> _logService = logService;
|
||||
public PruneService(ILogCommandService logService, IPatronageService ps)
|
||||
{
|
||||
_logService = logService;
|
||||
_ps = ps;
|
||||
}
|
||||
|
||||
public async Task PruneWhere(
|
||||
public async Task<PruneResult> PruneWhere(
|
||||
ITextChannel channel,
|
||||
int amount,
|
||||
Func<IMessage, bool> predicate,
|
||||
@@ -26,8 +32,13 @@ public class PruneService : INService
|
||||
|
||||
using var cancelSource = new CancellationTokenSource();
|
||||
if (!_pruningGuilds.TryAdd(channel.GuildId, cancelSource))
|
||||
return;
|
||||
return PruneResult.AlreadyRunning;
|
||||
|
||||
if (!await _ps.LimitHitAsync(LimitedFeatureName.Prune, channel.Guild.OwnerId))
|
||||
{
|
||||
return PruneResult.FeatureLimit;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
var now = DateTime.UtcNow;
|
||||
@@ -47,7 +58,7 @@ public class PruneService : INService
|
||||
.ToArray();
|
||||
|
||||
if (!msgs.Any())
|
||||
return;
|
||||
return PruneResult.Success;
|
||||
|
||||
lastMessage = msgs[^1];
|
||||
|
||||
@@ -88,6 +99,8 @@ public class PruneService : INService
|
||||
{
|
||||
_pruningGuilds.TryRemove(channel.GuildId, out _);
|
||||
}
|
||||
|
||||
return PruneResult.Success;
|
||||
}
|
||||
|
||||
public async Task<bool> CancelAsync(ulong guildId)
|
||||
|
@@ -18,7 +18,7 @@ public interface IReactionRoleService
|
||||
/// <param name="group"></param>
|
||||
/// <param name="levelReq"></param>
|
||||
/// <returns>The result of the operation</returns>
|
||||
Task<OneOf<Success, FeatureLimit>> AddReactionRole(
|
||||
Task<OneOf<Success, Error>> AddReactionRole(
|
||||
IGuild guild,
|
||||
IMessage msg,
|
||||
string emote,
|
||||
|
@@ -55,12 +55,10 @@ public partial class Administration
|
||||
|
||||
await res.Match(
|
||||
_ => ctx.OkAsync(),
|
||||
fl =>
|
||||
async fl =>
|
||||
{
|
||||
_ = msg.RemoveReactionAsync(emote, ctx.Client.CurrentUser);
|
||||
return !fl.IsPatronLimit
|
||||
? Response().Error(strs.limit_reached(fl.Quota)).SendAsync()
|
||||
: Response().Pending(strs.feature_limit_reached_owner(fl.Quota, fl.Name)).SendAsync();
|
||||
await Response().Pending(strs.feature_limit_reached_owner).SendAsync();
|
||||
});
|
||||
}
|
||||
|
||||
|
@@ -21,22 +21,16 @@ public sealed class ReactionRolesService : IReadyExecutor, INService, IReactionR
|
||||
private readonly SemaphoreSlim _assignementLock = new(1, 1);
|
||||
private readonly IPatronageService _ps;
|
||||
|
||||
private static readonly FeatureLimitKey _reroFLKey = new()
|
||||
{
|
||||
Key = "rero:max_count",
|
||||
PrettyName = "Reaction Role"
|
||||
};
|
||||
|
||||
public ReactionRolesService(
|
||||
DiscordSocketClient client,
|
||||
IPatronageService ps,
|
||||
DbService db,
|
||||
IBotCredentials creds,
|
||||
IPatronageService ps)
|
||||
IBotCredentials creds)
|
||||
{
|
||||
_db = db;
|
||||
_ps = ps;
|
||||
_client = client;
|
||||
_creds = creds;
|
||||
_ps = ps;
|
||||
_cache = new();
|
||||
}
|
||||
|
||||
@@ -242,7 +236,7 @@ public sealed class ReactionRolesService : IReadyExecutor, INService, IReactionR
|
||||
/// <param name="group"></param>
|
||||
/// <param name="levelReq"></param>
|
||||
/// <returns>The result of the operation</returns>
|
||||
public async Task<OneOf<Success, FeatureLimit>> AddReactionRole(
|
||||
public async Task<OneOf<Success, Error>> AddReactionRole(
|
||||
IGuild guild,
|
||||
IMessage msg,
|
||||
string emote,
|
||||
@@ -261,9 +255,12 @@ public sealed class ReactionRolesService : IReadyExecutor, INService, IReactionR
|
||||
.Where(x => x.GuildId == guild.Id)
|
||||
.CountAsync();
|
||||
|
||||
var result = await _ps.TryGetFeatureLimitAsync(_reroFLKey, guild.OwnerId, 50);
|
||||
if (result.Quota != -1 && activeReactionRoles >= result.Quota)
|
||||
return result;
|
||||
var limit = await _ps.GetUserLimit(LimitedFeatureName.ReactionRole, guild.OwnerId);
|
||||
|
||||
if (!_creds.IsOwner(guild.OwnerId) && (activeReactionRoles >= limit.Quota && limit.Quota >= 0))
|
||||
{
|
||||
return new Error();
|
||||
}
|
||||
|
||||
await ctx.GetTable<ReactionRoleV2>()
|
||||
.InsertOrUpdateAsync(() => new()
|
||||
|
@@ -459,42 +459,7 @@ public partial class Administration
|
||||
|
||||
await Response().Confirm(strs.bot_name(Format.Bold(newName))).SendAsync();
|
||||
}
|
||||
|
||||
[Cmd]
|
||||
[UserPerm(GuildPerm.ManageNicknames)]
|
||||
[BotPerm(GuildPerm.ChangeNickname)]
|
||||
[Priority(0)]
|
||||
public async Task SetNick([Leftover] string newNick = null)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(newNick))
|
||||
return;
|
||||
var curUser = await ctx.Guild.GetCurrentUserAsync();
|
||||
await curUser.ModifyAsync(u => u.Nickname = newNick);
|
||||
|
||||
await Response().Confirm(strs.bot_nick(Format.Bold(newNick) ?? "-")).SendAsync();
|
||||
}
|
||||
|
||||
[Cmd]
|
||||
[BotPerm(GuildPerm.ManageNicknames)]
|
||||
[UserPerm(GuildPerm.ManageNicknames)]
|
||||
[Priority(1)]
|
||||
public async Task SetNick(IGuildUser gu, [Leftover] string newNick = null)
|
||||
{
|
||||
var sg = (SocketGuild)ctx.Guild;
|
||||
if (sg.OwnerId == gu.Id
|
||||
|| gu.GetRoles().Max(r => r.Position) >= sg.CurrentUser.GetRoles().Max(r => r.Position))
|
||||
{
|
||||
await Response().Error(strs.insuf_perms_i).SendAsync();
|
||||
return;
|
||||
}
|
||||
|
||||
await gu.ModifyAsync(u => u.Nickname = newNick);
|
||||
|
||||
await Response()
|
||||
.Confirm(strs.user_nick(Format.Bold(gu.ToString()), Format.Bold(newNick) ?? "-"))
|
||||
.SendAsync();
|
||||
}
|
||||
|
||||
|
||||
[Cmd]
|
||||
[OwnerOnly]
|
||||
public async Task SetStatus([Leftover] SettableUserStatus status)
|
||||
|
@@ -0,0 +1,9 @@
|
||||
namespace NadekoBot.Modules.Administration._common.results;
|
||||
|
||||
public enum SetServerBannerResult
|
||||
{
|
||||
Success,
|
||||
InvalidFileType,
|
||||
Toolarge,
|
||||
InvalidURL
|
||||
}
|
@@ -0,0 +1,8 @@
|
||||
namespace NadekoBot.Modules.Administration._common.results;
|
||||
|
||||
public enum SetServerIconResult
|
||||
{
|
||||
Success,
|
||||
InvalidFileType,
|
||||
InvalidURL
|
||||
}
|
@@ -1,5 +1,7 @@
|
||||
#nullable disable
|
||||
|
||||
using NadekoBot.Db.Models;
|
||||
|
||||
namespace NadekoBot.Modules.NadekoExpressions;
|
||||
|
||||
[Name("Expressions")]
|
||||
@@ -34,12 +36,12 @@ public partial class NadekoExpressions : NadekoModule<NadekoExpressionsService>
|
||||
|
||||
await Response()
|
||||
.Embed(_sender.CreateEmbed()
|
||||
.WithOkColor()
|
||||
.WithTitle(GetText(strs.expr_new))
|
||||
.WithDescription($"#{new kwum(ex.Id)}")
|
||||
.AddField(GetText(strs.trigger), key)
|
||||
.AddField(GetText(strs.response),
|
||||
message.Length > 1024 ? GetText(strs.redacted_too_long) : message))
|
||||
.WithOkColor()
|
||||
.WithTitle(GetText(strs.expr_new))
|
||||
.WithDescription($"#{new kwum(ex.Id)}")
|
||||
.AddField(GetText(strs.trigger), key)
|
||||
.AddField(GetText(strs.response),
|
||||
message.Length > 1024 ? GetText(strs.redacted_too_long) : message))
|
||||
.SendAsync();
|
||||
}
|
||||
|
||||
@@ -68,9 +70,9 @@ public partial class NadekoExpressions : NadekoModule<NadekoExpressionsService>
|
||||
|
||||
|
||||
[Cmd]
|
||||
public async Task ExprAdd(string key, [Leftover] string message)
|
||||
public async Task ExprAdd(string trigger, [Leftover] string response)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(message) || string.IsNullOrWhiteSpace(key))
|
||||
if (string.IsNullOrWhiteSpace(response) || string.IsNullOrWhiteSpace(trigger))
|
||||
{
|
||||
return;
|
||||
}
|
||||
@@ -81,7 +83,7 @@ public partial class NadekoExpressions : NadekoModule<NadekoExpressionsService>
|
||||
return;
|
||||
}
|
||||
|
||||
await ExprAddInternalAsync(key, message);
|
||||
await ExprAddInternalAsync(trigger, response);
|
||||
}
|
||||
|
||||
[Cmd]
|
||||
@@ -93,8 +95,7 @@ public partial class NadekoExpressions : NadekoModule<NadekoExpressionsService>
|
||||
return;
|
||||
}
|
||||
|
||||
if ((channel is null && !_creds.IsOwner(ctx.User))
|
||||
|| (channel is not null && !((IGuildUser)ctx.User).GuildPermissions.Administrator))
|
||||
if (!IsValidExprEditor())
|
||||
{
|
||||
await Response().Error(strs.expr_insuff_perms).SendAsync();
|
||||
return;
|
||||
@@ -105,12 +106,12 @@ public partial class NadekoExpressions : NadekoModule<NadekoExpressionsService>
|
||||
{
|
||||
await Response()
|
||||
.Embed(_sender.CreateEmbed()
|
||||
.WithOkColor()
|
||||
.WithTitle(GetText(strs.expr_edited))
|
||||
.WithDescription($"#{id}")
|
||||
.AddField(GetText(strs.trigger), ex.Trigger)
|
||||
.AddField(GetText(strs.response),
|
||||
message.Length > 1024 ? GetText(strs.redacted_too_long) : message))
|
||||
.WithOkColor()
|
||||
.WithTitle(GetText(strs.expr_edited))
|
||||
.WithDescription($"#{id}")
|
||||
.AddField(GetText(strs.trigger), ex.Trigger)
|
||||
.AddField(GetText(strs.response),
|
||||
message.Length > 1024 ? GetText(strs.redacted_too_long) : message))
|
||||
.SendAsync();
|
||||
}
|
||||
else
|
||||
@@ -119,6 +120,10 @@ public partial class NadekoExpressions : NadekoModule<NadekoExpressionsService>
|
||||
}
|
||||
}
|
||||
|
||||
private bool IsValidExprEditor()
|
||||
=> (ctx.Guild is not null && ((IGuildUser)ctx.User).GuildPermissions.Administrator)
|
||||
|| (ctx.Guild is null && _creds.IsOwner(ctx.User));
|
||||
|
||||
[Cmd]
|
||||
[Priority(1)]
|
||||
public async Task ExprList(int page = 1)
|
||||
@@ -132,7 +137,7 @@ public partial class NadekoExpressions : NadekoModule<NadekoExpressionsService>
|
||||
.OrderBy(x => x.Trigger)
|
||||
.ToArray();
|
||||
|
||||
if (allExpressions is null || !allExpressions.Any())
|
||||
if (!allExpressions.Any())
|
||||
{
|
||||
await Response().Error(strs.expr_no_found).SendAsync();
|
||||
return;
|
||||
@@ -171,16 +176,48 @@ public partial class NadekoExpressions : NadekoModule<NadekoExpressionsService>
|
||||
return;
|
||||
}
|
||||
|
||||
var inter = CreateEditInteraction(id, found);
|
||||
|
||||
await Response()
|
||||
.Interaction(IsValidExprEditor() ? inter : null)
|
||||
.Embed(_sender.CreateEmbed()
|
||||
.WithOkColor()
|
||||
.WithDescription($"#{id}")
|
||||
.AddField(GetText(strs.trigger), found.Trigger.TrimTo(1024))
|
||||
.AddField(GetText(strs.response),
|
||||
found.Response.TrimTo(1000).Replace("](", "]\\(")))
|
||||
.WithOkColor()
|
||||
.WithDescription($"#{id}")
|
||||
.AddField(GetText(strs.trigger), found.Trigger.TrimTo(1024))
|
||||
.AddField(GetText(strs.response),
|
||||
found.Response.TrimTo(1000).Replace("](", "]\\(")))
|
||||
.SendAsync();
|
||||
}
|
||||
|
||||
private NadekoInteractionBase CreateEditInteraction(kwum id, NadekoExpression found)
|
||||
{
|
||||
var modal = new ModalBuilder()
|
||||
.WithCustomId("expr:edit_modal")
|
||||
.WithTitle($"Edit expression {id}")
|
||||
.AddTextInput(new TextInputBuilder()
|
||||
.WithLabel(GetText(strs.response))
|
||||
.WithValue(found.Response)
|
||||
.WithMinLength(1)
|
||||
.WithCustomId("expr:edit_modal:response")
|
||||
.WithStyle(TextInputStyle.Paragraph));
|
||||
|
||||
var inter = _inter.Create(ctx.User.Id,
|
||||
new ButtonBuilder()
|
||||
.WithEmote(Emoji.Parse("📝"))
|
||||
.WithLabel("Edit")
|
||||
.WithStyle(ButtonStyle.Primary)
|
||||
.WithCustomId("test"),
|
||||
modal,
|
||||
async (sm) =>
|
||||
{
|
||||
var msg = sm.Data.Components.FirstOrDefault()?.Value;
|
||||
|
||||
await ExprEdit(id, msg);
|
||||
}
|
||||
);
|
||||
return inter;
|
||||
}
|
||||
|
||||
public async Task ExprDeleteInternalAsync(kwum id)
|
||||
{
|
||||
var ex = await _service.DeleteAsync(ctx.Guild?.Id, id);
|
||||
@@ -189,11 +226,11 @@ public partial class NadekoExpressions : NadekoModule<NadekoExpressionsService>
|
||||
{
|
||||
await Response()
|
||||
.Embed(_sender.CreateEmbed()
|
||||
.WithOkColor()
|
||||
.WithTitle(GetText(strs.expr_deleted))
|
||||
.WithDescription($"#{id}")
|
||||
.AddField(GetText(strs.trigger), ex.Trigger.TrimTo(1024))
|
||||
.AddField(GetText(strs.response), ex.Response.TrimTo(1024)))
|
||||
.WithOkColor()
|
||||
.WithTitle(GetText(strs.expr_deleted))
|
||||
.WithDescription($"#{id}")
|
||||
.AddField(GetText(strs.trigger), ex.Trigger.TrimTo(1024))
|
||||
.AddField(GetText(strs.response), ex.Response.TrimTo(1024)))
|
||||
.SendAsync();
|
||||
}
|
||||
else
|
||||
@@ -340,8 +377,8 @@ public partial class NadekoExpressions : NadekoModule<NadekoExpressionsService>
|
||||
public async Task ExprClear()
|
||||
{
|
||||
if (await PromptUserConfirmAsync(_sender.CreateEmbed()
|
||||
.WithTitle("Expression clear")
|
||||
.WithDescription("This will delete all expressions on this server.")))
|
||||
.WithTitle("Expression clear")
|
||||
.WithDescription("This will delete all expressions on this server.")))
|
||||
{
|
||||
var count = _service.DeleteAllExpressions(ctx.Guild.Id);
|
||||
await Response().Confirm(strs.exprs_cleared(count)).SendAsync();
|
||||
|
@@ -6,6 +6,7 @@ using NadekoBot.Db;
|
||||
using NadekoBot.Db.Models;
|
||||
using System.Runtime.CompilerServices;
|
||||
using LinqToDB.EntityFrameworkCore;
|
||||
using NadekoBot.Modules.Permissions.Services;
|
||||
using YamlDotNet.Serialization;
|
||||
using YamlDotNet.Serialization.NamingConventions;
|
||||
|
||||
@@ -77,6 +78,7 @@ public sealed class NadekoExpressionsService : IExecOnMessage, IReadyExecutor
|
||||
|
||||
private bool ready;
|
||||
private ConcurrentHashSet<ulong> _disabledGlobalExpressionGuilds;
|
||||
private readonly PermissionService _pc;
|
||||
|
||||
public NadekoExpressionsService(
|
||||
DbService db,
|
||||
@@ -87,7 +89,8 @@ public sealed class NadekoExpressionsService : IExecOnMessage, IReadyExecutor
|
||||
IPubSub pubSub,
|
||||
IMessageSenderService sender,
|
||||
IReplacementService repSvc,
|
||||
IPermissionChecker permChecker)
|
||||
IPermissionChecker permChecker,
|
||||
PermissionService pc)
|
||||
{
|
||||
_db = db;
|
||||
_client = client;
|
||||
@@ -98,6 +101,7 @@ public sealed class NadekoExpressionsService : IExecOnMessage, IReadyExecutor
|
||||
_sender = sender;
|
||||
_repSvc = repSvc;
|
||||
_permChecker = permChecker;
|
||||
_pc = pc;
|
||||
_rng = new NadekoRandom();
|
||||
|
||||
_pubSub.Sub(_exprsReloadedKey, OnExprsShouldReload);
|
||||
@@ -138,6 +142,7 @@ public sealed class NadekoExpressionsService : IExecOnMessage, IReadyExecutor
|
||||
var globalItems = uow.Set<NadekoExpression>()
|
||||
.AsNoTracking()
|
||||
.Where(x => x.GuildId == null || x.GuildId == 0)
|
||||
.Where(x => x.Trigger != null)
|
||||
.AsEnumerable()
|
||||
.Select(x =>
|
||||
{
|
||||
@@ -254,26 +259,30 @@ public sealed class NadekoExpressionsService : IExecOnMessage, IReadyExecutor
|
||||
"ACTUALEXPRESSIONS",
|
||||
expr.Trigger
|
||||
);
|
||||
|
||||
|
||||
if (!result.IsAllowed)
|
||||
{
|
||||
if (result.TryPickT3(out var disallowed, out _))
|
||||
var cache = _pc.GetCacheFor(guild.Id);
|
||||
if (cache.Verbose)
|
||||
{
|
||||
var permissionMessage = _strings.GetText(strs.perm_prevent(disallowed.PermIndex + 1,
|
||||
Format.Bold(disallowed.PermText)),
|
||||
sg.Id);
|
||||
|
||||
try
|
||||
if (result.TryPickT3(out var disallowed, out _))
|
||||
{
|
||||
await _sender.Response(msg.Channel)
|
||||
.Error(permissionMessage)
|
||||
.SendAsync();
|
||||
}
|
||||
catch
|
||||
{
|
||||
}
|
||||
var permissionMessage = _strings.GetText(strs.perm_prevent(disallowed.PermIndex + 1,
|
||||
Format.Bold(disallowed.PermText)),
|
||||
sg.Id);
|
||||
|
||||
Log.Information("{PermissionMessage}", permissionMessage);
|
||||
try
|
||||
{
|
||||
await _sender.Response(msg.Channel)
|
||||
.Error(permissionMessage)
|
||||
.SendAsync();
|
||||
}
|
||||
catch
|
||||
{
|
||||
}
|
||||
|
||||
Log.Information("{PermissionMessage}", permissionMessage);
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
|
@@ -3,6 +3,7 @@ using NadekoBot.Common.TypeReaders;
|
||||
using NadekoBot.Modules.Gambling.Common;
|
||||
using NadekoBot.Modules.Gambling.Common.Blackjack;
|
||||
using NadekoBot.Modules.Gambling.Services;
|
||||
using NadekoBot.Modules.Utility;
|
||||
|
||||
namespace NadekoBot.Modules.Gambling;
|
||||
|
||||
|
@@ -1,7 +1,6 @@
|
||||
#nullable disable
|
||||
using LinqToDB;
|
||||
using LinqToDB.EntityFrameworkCore;
|
||||
using NadekoBot.Db;
|
||||
using NadekoBot.Db.Models;
|
||||
using NadekoBot.Modules.Gambling.Bank;
|
||||
using NadekoBot.Modules.Gambling.Common;
|
||||
@@ -14,6 +13,7 @@ using System.Text;
|
||||
using NadekoBot.Modules.Gambling.Rps;
|
||||
using NadekoBot.Common.TypeReaders;
|
||||
using NadekoBot.Modules.Patronage;
|
||||
using NadekoBot.Modules.Utility;
|
||||
|
||||
namespace NadekoBot.Modules.Gambling;
|
||||
|
||||
@@ -27,9 +27,9 @@ public partial class Gambling : GamblingModule<GamblingService>
|
||||
private readonly DownloadTracker _tracker;
|
||||
private readonly GamblingConfigService _configService;
|
||||
private readonly IBankService _bank;
|
||||
private readonly IPatronageService _ps;
|
||||
private readonly IRemindService _remind;
|
||||
private readonly GamblingTxTracker _gamblingTxTracker;
|
||||
private readonly IPatronageService _ps;
|
||||
|
||||
private IUserMessage rdMsg;
|
||||
|
||||
@@ -41,8 +41,8 @@ public partial class Gambling : GamblingModule<GamblingService>
|
||||
DownloadTracker tracker,
|
||||
GamblingConfigService configService,
|
||||
IBankService bank,
|
||||
IPatronageService ps,
|
||||
IRemindService remind,
|
||||
IPatronageService patronage,
|
||||
GamblingTxTracker gamblingTxTracker)
|
||||
: base(configService)
|
||||
{
|
||||
@@ -51,9 +51,9 @@ public partial class Gambling : GamblingModule<GamblingService>
|
||||
_cs = currency;
|
||||
_client = client;
|
||||
_bank = bank;
|
||||
_ps = ps;
|
||||
_remind = remind;
|
||||
_gamblingTxTracker = gamblingTxTracker;
|
||||
_ps = patronage;
|
||||
|
||||
_enUsCulture = new CultureInfo("en-US", false).NumberFormat;
|
||||
_enUsCulture.NumberDecimalDigits = 0;
|
||||
@@ -74,7 +74,7 @@ public partial class Gambling : GamblingModule<GamblingService>
|
||||
var stats = await _gamblingTxTracker.GetAllAsync();
|
||||
|
||||
var eb = _sender.CreateEmbed()
|
||||
.WithOkColor();
|
||||
.WithOkColor();
|
||||
|
||||
var str = "` Feature `|` Bet `|`Paid Out`|` RoI `\n";
|
||||
str += "――――――――――――――――――――\n";
|
||||
@@ -119,26 +119,20 @@ public partial class Gambling : GamblingModule<GamblingService>
|
||||
|
||||
// [21:03] Bob Page: Kinda remids me of US economy
|
||||
var embed = _sender.CreateEmbed()
|
||||
.WithTitle(GetText(strs.economy_state))
|
||||
.AddField(GetText(strs.currency_owned), N(ec.Cash - ec.Bot))
|
||||
.AddField(GetText(strs.currency_one_percent), (onePercent * 100).ToString("F2") + "%")
|
||||
.AddField(GetText(strs.currency_planted), N(ec.Planted))
|
||||
.AddField(GetText(strs.owned_waifus_total), N(ec.Waifus))
|
||||
.AddField(GetText(strs.bot_currency), N(ec.Bot))
|
||||
.AddField(GetText(strs.bank_accounts), N(ec.Bank))
|
||||
.AddField(GetText(strs.total), N(ec.Cash + ec.Planted + ec.Waifus + ec.Bank))
|
||||
.WithOkColor();
|
||||
.WithTitle(GetText(strs.economy_state))
|
||||
.AddField(GetText(strs.currency_owned), N(ec.Cash - ec.Bot))
|
||||
.AddField(GetText(strs.currency_one_percent), (onePercent * 100).ToString("F2") + "%")
|
||||
.AddField(GetText(strs.currency_planted), N(ec.Planted))
|
||||
.AddField(GetText(strs.owned_waifus_total), N(ec.Waifus))
|
||||
.AddField(GetText(strs.bot_currency), N(ec.Bot))
|
||||
.AddField(GetText(strs.bank_accounts), N(ec.Bank))
|
||||
.AddField(GetText(strs.total), N(ec.Cash + ec.Planted + ec.Waifus + ec.Bank))
|
||||
.WithOkColor();
|
||||
|
||||
// ec.Cash already contains ec.Bot as it's the total of all values in the CurrencyAmount column of the DiscordUser table
|
||||
await Response().Embed(embed).SendAsync();
|
||||
}
|
||||
|
||||
private static readonly FeatureLimitKey _timelyKey = new FeatureLimitKey()
|
||||
{
|
||||
Key = "timely:extra_percent",
|
||||
PrettyName = "Timely"
|
||||
};
|
||||
|
||||
private async Task RemindTimelyAction(SocketMessageComponent smc, DateTime when)
|
||||
{
|
||||
var tt = TimestampTag.FromDateTime(when, TimestampTagStyles.Relative);
|
||||
@@ -154,18 +148,27 @@ public partial class Gambling : GamblingModule<GamblingService>
|
||||
await smc.RespondConfirmAsync(_sender, GetText(strs.remind_timely(tt)), ephemeral: true);
|
||||
}
|
||||
|
||||
private NadekoInteraction CreateRemindMeInteraction(int period)
|
||||
{
|
||||
return _inter
|
||||
// Creates timely reminder button, parameter in hours.
|
||||
private NadekoInteractionBase CreateRemindMeInteraction(int period)
|
||||
=> _inter
|
||||
.Create(ctx.User.Id,
|
||||
new SimpleInteraction<DateTime>(
|
||||
new ButtonBuilder(
|
||||
label: "Remind me",
|
||||
emote: Emoji.Parse("⏰"),
|
||||
customId: "timely:remind_me"),
|
||||
RemindTimelyAction,
|
||||
DateTime.UtcNow.Add(TimeSpan.FromHours(period))));
|
||||
}
|
||||
new ButtonBuilder(
|
||||
label: "Remind me",
|
||||
emote: Emoji.Parse("⏰"),
|
||||
customId: "timely:remind_me"),
|
||||
(smc) => RemindTimelyAction(smc, DateTime.UtcNow.Add(TimeSpan.FromHours(period)))
|
||||
);
|
||||
|
||||
// Creates timely reminder button, parameter in milliseconds.
|
||||
private NadekoInteractionBase CreateRemindMeInteraction(double ms)
|
||||
=> _inter
|
||||
.Create(ctx.User.Id,
|
||||
new ButtonBuilder(
|
||||
label: "Remind me",
|
||||
emote: Emoji.Parse("⏰"),
|
||||
customId: "timely:remind_me"),
|
||||
(smc) => RemindTimelyAction(smc, DateTime.UtcNow.Add(TimeSpan.FromMilliseconds(ms)))
|
||||
);
|
||||
|
||||
[Cmd]
|
||||
public async Task Timely()
|
||||
@@ -178,25 +181,31 @@ public partial class Gambling : GamblingModule<GamblingService>
|
||||
return;
|
||||
}
|
||||
|
||||
var inter = CreateRemindMeInteraction(period);
|
||||
|
||||
if (await _service.ClaimTimelyAsync(ctx.User.Id, period) is { } rem)
|
||||
if (await _service.ClaimTimelyAsync(ctx.User.Id, period) is { } remainder)
|
||||
{
|
||||
// Get correct time form remainder
|
||||
var interaction = CreateRemindMeInteraction(remainder.TotalMilliseconds);
|
||||
|
||||
// Removes timely button if there is a timely reminder in DB
|
||||
if (_service.UserHasTimelyReminder(ctx.User.Id))
|
||||
{
|
||||
inter = null;
|
||||
interaction = null;
|
||||
}
|
||||
|
||||
var now = DateTime.UtcNow;
|
||||
var relativeTag = TimestampTag.FromDateTime(now.Add(rem), TimestampTagStyles.Relative);
|
||||
await Response().Pending(strs.timely_already_claimed(relativeTag)).Interaction(inter).SendAsync();
|
||||
var relativeTag = TimestampTag.FromDateTime(now.Add(remainder), TimestampTagStyles.Relative);
|
||||
await Response().Pending(strs.timely_already_claimed(relativeTag)).Interaction(interaction).SendAsync();
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
var result = await _ps.TryGetFeatureLimitAsync(_timelyKey, ctx.User.Id, 0);
|
||||
var patron = await _ps.GetPatronAsync(ctx.User.Id);
|
||||
|
||||
val = (int)(val * (1 + (result.Quota! * 0.01f)));
|
||||
var percentBonus = (_ps.PercentBonus(patron) / 100f);
|
||||
|
||||
val += (int)(val * percentBonus);
|
||||
|
||||
var inter = CreateRemindMeInteraction(period);
|
||||
|
||||
await _cs.AddAsync(ctx.User.Id, val, new("timely", "claim"));
|
||||
|
||||
@@ -311,9 +320,9 @@ public partial class Gambling : GamblingModule<GamblingService>
|
||||
}
|
||||
|
||||
var embed = _sender.CreateEmbed()
|
||||
.WithTitle(GetText(strs.transactions(((SocketGuild)ctx.Guild)?.GetUser(userId)?.ToString()
|
||||
?? $"{userId}")))
|
||||
.WithOkColor();
|
||||
.WithTitle(GetText(strs.transactions(((SocketGuild)ctx.Guild)?.GetUser(userId)?.ToString()
|
||||
?? $"{userId}")))
|
||||
.WithOkColor();
|
||||
|
||||
var sb = new StringBuilder();
|
||||
foreach (var tr in trs)
|
||||
@@ -408,7 +417,7 @@ public partial class Gambling : GamblingModule<GamblingService>
|
||||
await Response().Confirm(strs.has(Format.Code(userId.ToString()), cur)).SendAsync();
|
||||
}
|
||||
|
||||
private async Task BankAction(SocketMessageComponent smc, object _)
|
||||
private async Task BankAction(SocketMessageComponent smc)
|
||||
{
|
||||
var balance = await _bank.GetBalanceAsync(ctx.User.Id);
|
||||
|
||||
@@ -418,12 +427,12 @@ public partial class Gambling : GamblingModule<GamblingService>
|
||||
.Pipe(text => smc.RespondConfirmAsync(_sender, text, ephemeral: true));
|
||||
}
|
||||
|
||||
private NadekoInteraction CreateCashInteraction()
|
||||
=> _inter.Create<object>(ctx.User.Id,
|
||||
new(new(
|
||||
customId: "cash:bank_show_balance",
|
||||
emote: new Emoji("🏦")),
|
||||
BankAction));
|
||||
private NadekoInteractionBase CreateCashInteraction()
|
||||
=> _inter.Create(ctx.User.Id,
|
||||
new ButtonBuilder(
|
||||
customId: "cash:bank_show_balance",
|
||||
emote: new Emoji("🏦")),
|
||||
BankAction);
|
||||
|
||||
[Cmd]
|
||||
[Priority(1)]
|
||||
@@ -732,10 +741,10 @@ public partial class Gambling : GamblingModule<GamblingService>
|
||||
}
|
||||
|
||||
var eb = _sender.CreateEmbed()
|
||||
.WithAuthor(ctx.User)
|
||||
.WithDescription(Format.Bold(str))
|
||||
.AddField(GetText(strs.roll2), result.Roll.ToString(CultureInfo.InvariantCulture))
|
||||
.WithOkColor();
|
||||
.WithAuthor(ctx.User)
|
||||
.WithDescription(Format.Bold(str))
|
||||
.AddField(GetText(strs.roll2), result.Roll.ToString(CultureInfo.InvariantCulture))
|
||||
.WithOkColor();
|
||||
|
||||
await Response().Embed(eb).SendAsync();
|
||||
}
|
||||
@@ -787,7 +796,7 @@ public partial class Gambling : GamblingModule<GamblingService>
|
||||
return await uow.Set<DiscordUser>().GetTopRichest(_client.CurrentUser.Id, curPage);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
var res = Response()
|
||||
.Paginated();
|
||||
|
||||
@@ -799,8 +808,9 @@ public partial class Gambling : GamblingModule<GamblingService>
|
||||
.CurrentPage(page)
|
||||
.Page((toSend, curPage) =>
|
||||
{
|
||||
var embed = _sender.CreateEmbed().WithOkColor()
|
||||
.WithTitle(CurrencySign + " " + GetText(strs.leaderboard));
|
||||
var embed = _sender.CreateEmbed()
|
||||
.WithOkColor()
|
||||
.WithTitle(CurrencySign + " " + GetText(strs.leaderboard));
|
||||
|
||||
if (!toSend.Any())
|
||||
{
|
||||
@@ -894,6 +904,7 @@ public partial class Gambling : GamblingModule<GamblingService>
|
||||
private static readonly ImmutableArray<string> _emojis =
|
||||
new[] { "⬆", "↖", "⬅", "↙", "⬇", "↘", "➡", "↗" }.ToImmutableArray();
|
||||
|
||||
|
||||
[Cmd]
|
||||
public async Task LuckyLadder([OverrideTypeReader(typeof(BalanceTypeReader))] long amount)
|
||||
{
|
||||
@@ -923,11 +934,11 @@ public partial class Gambling : GamblingModule<GamblingService>
|
||||
}
|
||||
|
||||
var eb = _sender.CreateEmbed()
|
||||
.WithOkColor()
|
||||
.WithDescription(sb.ToString())
|
||||
.AddField(GetText(strs.multiplier), $"{result.Multiplier:0.##}x", true)
|
||||
.AddField(GetText(strs.won), $"{(long)result.Won}", true)
|
||||
.WithAuthor(ctx.User);
|
||||
.WithOkColor()
|
||||
.WithDescription(sb.ToString())
|
||||
.AddField(GetText(strs.multiplier), $"{result.Multiplier:0.##}x", true)
|
||||
.AddField(GetText(strs.won), $"{(long)result.Won}", true)
|
||||
.WithAuthor(ctx.User);
|
||||
|
||||
|
||||
await Response().Embed(eb).SendAsync();
|
||||
|
@@ -27,7 +27,7 @@ public partial class Gambling
|
||||
|
||||
if (picked > 0)
|
||||
{
|
||||
var msg = await Response().NoReply().Confirm(strs.picked(N(picked))).SendAsync();
|
||||
var msg = await Response().NoReply().Confirm(strs.picked(N(picked), ctx.User)).SendAsync();
|
||||
msg.DeleteAfter(10);
|
||||
}
|
||||
|
||||
|
@@ -247,7 +247,14 @@ public partial class Gambling
|
||||
}
|
||||
else
|
||||
{
|
||||
var cmd = entry.Command.Replace("%you%", ctx.User.Id.ToString());
|
||||
var buyer = (IGuildUser)ctx.User;
|
||||
var cmd = entry.Command
|
||||
.Replace("%you%", buyer.Mention)
|
||||
.Replace("%you.mention%", buyer.Mention)
|
||||
.Replace("%you.username%", buyer.Username)
|
||||
.Replace("%you.name%", buyer.GlobalName ?? buyer.Username)
|
||||
.Replace("%you.nick%", buyer.DisplayName);
|
||||
|
||||
var eb = _sender.CreateEmbed()
|
||||
.WithPendingColor()
|
||||
.WithTitle("Executing shop command")
|
||||
@@ -259,6 +266,7 @@ public partial class Gambling
|
||||
GetProfitAmount(entry.Price),
|
||||
new("shop", "sell", entry.Name));
|
||||
|
||||
await Task.Delay(250);
|
||||
await _cmdHandler.TryRunCommand(guild,
|
||||
channel,
|
||||
new DoAsUserMessage(
|
||||
|
@@ -9,6 +9,7 @@ using SixLabors.ImageSharp.PixelFormats;
|
||||
using SixLabors.ImageSharp.Processing;
|
||||
using NadekoBot.Modules.Gambling;
|
||||
using NadekoBot.Common.TypeReaders;
|
||||
using NadekoBot.Modules.Utility;
|
||||
using Color = SixLabors.ImageSharp.Color;
|
||||
using Image = SixLabors.ImageSharp.Image;
|
||||
|
||||
@@ -76,9 +77,12 @@ public partial class Gambling
|
||||
.WithOkColor();
|
||||
|
||||
var bb = new ButtonBuilder(emote: Emoji.Parse("🔁"), customId: "slot:again", label: "Pull Again");
|
||||
var si = new SimpleInteraction<long>(bb, (_, amount) => Slot(amount), amount);
|
||||
var inter = _inter.Create(ctx.User.Id, bb, smc =>
|
||||
{
|
||||
smc.DeferAsync();
|
||||
return Slot(amount);
|
||||
});
|
||||
|
||||
var inter = _inter.Create(ctx.User.Id, si);
|
||||
var msg = await ctx.Channel.SendFileAsync(imgStream,
|
||||
"result.png",
|
||||
embed: eb.Build(),
|
||||
|
@@ -18,7 +18,8 @@ public partial class Games
|
||||
[Cmd]
|
||||
[RequireContext(ContextType.Guild)]
|
||||
[UserPerm(GuildPerm.ManageMessages)]
|
||||
public async Task Cleverbot()
|
||||
[NoPublicBot]
|
||||
public async Task CleverBot()
|
||||
{
|
||||
var channel = (ITextChannel)ctx.Channel;
|
||||
|
||||
@@ -30,7 +31,7 @@ public partial class Games
|
||||
await uow.SaveChangesAsync();
|
||||
}
|
||||
|
||||
await Response().Confirm(strs.cleverbot_disabled).SendAsync();
|
||||
await Response().Confirm(strs.chatbot_disabled).SendAsync();
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -42,7 +43,7 @@ public partial class Games
|
||||
await uow.SaveChangesAsync();
|
||||
}
|
||||
|
||||
await Response().Confirm(strs.cleverbot_enabled).SendAsync();
|
||||
await Response().Confirm(strs.chatbot_enabled).SendAsync();
|
||||
}
|
||||
}
|
||||
}
|
@@ -15,43 +15,32 @@ public class ChatterBotService : IExecOnMessage
|
||||
public int Priority
|
||||
=> 1;
|
||||
|
||||
private readonly FeatureLimitKey _flKey;
|
||||
|
||||
private readonly DiscordSocketClient _client;
|
||||
private readonly IPermissionChecker _perms;
|
||||
private readonly CommandHandler _cmd;
|
||||
private readonly IBotCredentials _creds;
|
||||
private readonly IHttpClientFactory _httpFactory;
|
||||
private readonly IPatronageService _ps;
|
||||
private readonly GamesConfigService _gcs;
|
||||
private readonly IMessageSenderService _sender;
|
||||
public readonly IPatronageService _ps;
|
||||
|
||||
public ChatterBotService(
|
||||
DiscordSocketClient client,
|
||||
IPermissionChecker perms,
|
||||
IBot bot,
|
||||
CommandHandler cmd,
|
||||
IPatronageService ps,
|
||||
IHttpClientFactory factory,
|
||||
IBotCredentials creds,
|
||||
IPatronageService ps,
|
||||
GamesConfigService gcs,
|
||||
IMessageSenderService sender)
|
||||
{
|
||||
_client = client;
|
||||
_perms = perms;
|
||||
_cmd = cmd;
|
||||
_creds = creds;
|
||||
_sender = sender;
|
||||
_httpFactory = factory;
|
||||
_ps = ps;
|
||||
_perms = perms;
|
||||
_gcs = gcs;
|
||||
|
||||
_flKey = new FeatureLimitKey()
|
||||
{
|
||||
Key = CleverBotResponseStr.CLEVERBOT_RESPONSE,
|
||||
PrettyName = "Cleverbot Replies"
|
||||
};
|
||||
_ps = ps;
|
||||
|
||||
ChatterBotGuilds = new(bot.AllGuildConfigs
|
||||
.Where(gc => gc.CleverbotEnabled)
|
||||
@@ -69,9 +58,9 @@ public class ChatterBotService : IExecOnMessage
|
||||
|
||||
Log.Information("Cleverbot will not work as the api key is missing");
|
||||
return null;
|
||||
case ChatBotImplementation.Gpt3:
|
||||
case ChatBotImplementation.Gpt:
|
||||
if (!string.IsNullOrWhiteSpace(_creds.Gpt3ApiKey))
|
||||
return new OfficialGpt3Session(_creds.Gpt3ApiKey,
|
||||
return new OfficialGptSession(_creds.Gpt3ApiKey,
|
||||
_gcs.Data.ChatGpt.ModelName,
|
||||
_gcs.Data.ChatGpt.ChatHistory,
|
||||
_gcs.Data.ChatGpt.MaxTokens,
|
||||
@@ -87,19 +76,18 @@ public class ChatterBotService : IExecOnMessage
|
||||
}
|
||||
}
|
||||
|
||||
public string PrepareMessage(IUserMessage msg, out IChatterBotSession cleverbot)
|
||||
public IChatterBotSession GetOrCreateSession(ulong guildId)
|
||||
{
|
||||
var channel = msg.Channel as ITextChannel;
|
||||
cleverbot = null;
|
||||
if (ChatterBotGuilds.TryGetValue(guildId, out var lazyChatBot))
|
||||
return lazyChatBot.Value;
|
||||
|
||||
if (channel is null)
|
||||
return null;
|
||||
|
||||
if (!ChatterBotGuilds.TryGetValue(channel.Guild.Id, out var lazyCleverbot))
|
||||
return null;
|
||||
|
||||
cleverbot = lazyCleverbot.Value;
|
||||
lazyChatBot = new(() => CreateSession(), true);
|
||||
ChatterBotGuilds.TryAdd(guildId, lazyChatBot);
|
||||
return lazyChatBot.Value;
|
||||
}
|
||||
|
||||
public string PrepareMessage(IUserMessage msg)
|
||||
{
|
||||
var nadekoId = _client.CurrentUser.Id;
|
||||
var normalMention = $"<@{nadekoId}> ";
|
||||
var nickMention = $"<@!{nadekoId}> ";
|
||||
@@ -119,13 +107,31 @@ public class ChatterBotService : IExecOnMessage
|
||||
if (guild is not SocketGuild sg)
|
||||
return false;
|
||||
|
||||
var channel = usrMsg.Channel as ITextChannel;
|
||||
if (channel is null)
|
||||
return false;
|
||||
|
||||
if (!ChatterBotGuilds.TryGetValue(channel.Guild.Id, out var lazyChatBot))
|
||||
return false;
|
||||
|
||||
var chatBot = lazyChatBot.Value;
|
||||
var message = PrepareMessage(usrMsg);
|
||||
if (message is null)
|
||||
return false;
|
||||
|
||||
return await RunChatterBot(sg, usrMsg, channel, chatBot, message);
|
||||
}
|
||||
|
||||
public async Task<bool> RunChatterBot(
|
||||
SocketGuild guild,
|
||||
IUserMessage usrMsg,
|
||||
ITextChannel channel,
|
||||
IChatterBotSession chatBot,
|
||||
string message)
|
||||
{
|
||||
try
|
||||
{
|
||||
var message = PrepareMessage(usrMsg, out var cbs);
|
||||
if (message is null || cbs is null)
|
||||
return false;
|
||||
|
||||
var res = await _perms.CheckPermsAsync(sg,
|
||||
var res = await _perms.CheckPermsAsync(guild,
|
||||
usrMsg.Channel,
|
||||
usrMsg.Author,
|
||||
CleverBotResponseStr.CLEVERBOT_RESPONSE,
|
||||
@@ -134,59 +140,33 @@ public class ChatterBotService : IExecOnMessage
|
||||
if (!res.IsAllowed)
|
||||
return false;
|
||||
|
||||
var channel = (ITextChannel)usrMsg.Channel;
|
||||
var conf = _ps.GetConfig();
|
||||
if (!_creds.IsOwner(sg.OwnerId) && conf.IsEnabled)
|
||||
if (!await _ps.LimitHitAsync(LimitedFeatureName.ChatBot, usrMsg.Author.Id, 2048 / 2))
|
||||
{
|
||||
var quota = await _ps.TryGetFeatureLimitAsync(_flKey, sg.OwnerId, 0);
|
||||
|
||||
uint? daily = quota.Quota is int dVal and < 0
|
||||
? (uint)-dVal
|
||||
: null;
|
||||
|
||||
uint? monthly = quota.Quota is int mVal and >= 0
|
||||
? (uint)mVal
|
||||
: null;
|
||||
|
||||
var maybeLimit = await _ps.TryIncrementQuotaCounterAsync(sg.OwnerId,
|
||||
sg.OwnerId == usrMsg.Author.Id,
|
||||
FeatureType.Limit,
|
||||
_flKey.Key,
|
||||
null,
|
||||
daily,
|
||||
monthly);
|
||||
|
||||
if (maybeLimit.TryPickT1(out var ql, out var counters))
|
||||
{
|
||||
if (ql.Quota == 0)
|
||||
{
|
||||
await _sender.Response(channel)
|
||||
.Error(null,
|
||||
text:
|
||||
"In order to use the cleverbot feature, the owner of this server should be [Patron Tier X](https://patreon.com/join/nadekobot) on patreon.",
|
||||
footer:
|
||||
"You may disable the cleverbot feature, and this message via '.cleverbot' command")
|
||||
.SendAsync();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
await _sender.Response(channel)
|
||||
.Error(
|
||||
null!,
|
||||
$"You've reached your quota limit of **{ql.Quota}** responses {ql.QuotaPeriod.ToFullName()} for the cleverbot feature.",
|
||||
footer: "You may wait for the quota reset or .")
|
||||
.SendAsync();
|
||||
|
||||
return true;
|
||||
}
|
||||
// limit exceeded
|
||||
return false;
|
||||
}
|
||||
|
||||
_ = channel.TriggerTypingAsync();
|
||||
var response = await cbs.Think(message, usrMsg.Author.ToString());
|
||||
await _sender.Response(channel)
|
||||
.Confirm(response)
|
||||
.SendAsync();
|
||||
var response = await chatBot.Think(message, usrMsg.Author.ToString());
|
||||
|
||||
if (response.TryPickT0(out var result, out var error))
|
||||
{
|
||||
// calculate the diff in case we overestimated user's usage
|
||||
var inTokens = (result.TokensIn - 2048) / 2;
|
||||
|
||||
// add the output tokens to the limit
|
||||
await _ps.LimitForceHit(LimitedFeatureName.ChatBot,
|
||||
usrMsg.Author.Id,
|
||||
(inTokens) + (result.TokensOut / 2 * 3));
|
||||
|
||||
await _sender.Response(channel)
|
||||
.Confirm(result.Text)
|
||||
.SendAsync();
|
||||
}
|
||||
else
|
||||
{
|
||||
Log.Warning("Error in chatterbot: {Error}", error);
|
||||
}
|
||||
|
||||
Log.Information("""
|
||||
CleverBot Executed
|
@@ -3,10 +3,25 @@ using System.Text.Json.Serialization;
|
||||
|
||||
namespace NadekoBot.Modules.Games.Common.ChatterBot;
|
||||
|
||||
public class Gpt3Response
|
||||
public class OpenAiCompletionResponse
|
||||
{
|
||||
[JsonPropertyName("choices")]
|
||||
public Choice[] Choices { get; set; }
|
||||
|
||||
[JsonPropertyName("usage")]
|
||||
public OpenAiUsageData Usage { get; set; }
|
||||
}
|
||||
|
||||
public class OpenAiUsageData
|
||||
{
|
||||
[JsonPropertyName("prompt_tokens")]
|
||||
public int PromptTokens { get; set; }
|
||||
|
||||
[JsonPropertyName("completion_tokens")]
|
||||
public int CompletionTokens { get; set; }
|
||||
|
||||
[JsonPropertyName("total_tokens")]
|
||||
public int TotalTokens { get; set; }
|
||||
}
|
||||
|
||||
public class Choice
|
||||
|
@@ -1,7 +1,10 @@
|
||||
#nullable disable
|
||||
using OneOf;
|
||||
using OneOf.Types;
|
||||
|
||||
namespace NadekoBot.Modules.Games.Common.ChatterBot;
|
||||
|
||||
public interface IChatterBotSession
|
||||
{
|
||||
Task<string> Think(string input, string username);
|
||||
Task<OneOf<ThinkResult, Error<string>>> Think(string input, string username);
|
||||
}
|
@@ -1,5 +1,7 @@
|
||||
#nullable disable
|
||||
using Newtonsoft.Json;
|
||||
using OneOf;
|
||||
using OneOf.Types;
|
||||
|
||||
namespace NadekoBot.Modules.Games.Common.ChatterBot;
|
||||
|
||||
@@ -18,7 +20,7 @@ public class OfficialCleverbotSession : IChatterBotSession
|
||||
_httpFactory = factory;
|
||||
}
|
||||
|
||||
public async Task<string> Think(string input, string username)
|
||||
public async Task<OneOf<ThinkResult, Error<string>>> Think(string input, string username)
|
||||
{
|
||||
using var http = _httpFactory.CreateClient();
|
||||
var dataString = await http.GetStringAsync(string.Format(QueryString, input, cs ?? ""));
|
||||
@@ -27,12 +29,17 @@ public class OfficialCleverbotSession : IChatterBotSession
|
||||
var data = JsonConvert.DeserializeObject<CleverbotResponse>(dataString);
|
||||
|
||||
cs = data?.Cs;
|
||||
return data?.Output;
|
||||
return new ThinkResult
|
||||
{
|
||||
Text = data?.Output,
|
||||
TokensIn = 2,
|
||||
TokensOut = 1
|
||||
};
|
||||
}
|
||||
catch
|
||||
{
|
||||
Log.Warning("Unexpected cleverbot response received: {ResponseString}", dataString);
|
||||
return null;
|
||||
Log.Warning("Unexpected response from CleverBot: {ResponseString}", dataString);
|
||||
return new Error<string>("Unexpected CleverBot response received");
|
||||
}
|
||||
}
|
||||
}
|
@@ -1,105 +0,0 @@
|
||||
#nullable disable
|
||||
using Newtonsoft.Json;
|
||||
using System.Net.Http.Json;
|
||||
using SharpToken;
|
||||
|
||||
namespace NadekoBot.Modules.Games.Common.ChatterBot;
|
||||
|
||||
public class OfficialGpt3Session : IChatterBotSession
|
||||
{
|
||||
private string Uri
|
||||
=> $"https://api.openai.com/v1/chat/completions";
|
||||
|
||||
private readonly string _apiKey;
|
||||
private readonly string _model;
|
||||
private readonly int _maxHistory;
|
||||
private readonly int _maxTokens;
|
||||
private readonly int _minTokens;
|
||||
private readonly string _nadekoUsername;
|
||||
private readonly GptEncoding _encoding;
|
||||
private List<GPTMessage> messages = new();
|
||||
private readonly IHttpClientFactory _httpFactory;
|
||||
|
||||
|
||||
|
||||
public OfficialGpt3Session(
|
||||
string apiKey,
|
||||
ChatGptModel model,
|
||||
int chatHistory,
|
||||
int maxTokens,
|
||||
int minTokens,
|
||||
string personality,
|
||||
string nadekoUsername,
|
||||
IHttpClientFactory factory)
|
||||
{
|
||||
_apiKey = apiKey;
|
||||
_httpFactory = factory;
|
||||
switch (model)
|
||||
{
|
||||
case ChatGptModel.Gpt35Turbo:
|
||||
_model = "gpt-3.5-turbo";
|
||||
break;
|
||||
case ChatGptModel.Gpt4:
|
||||
_model = "gpt-4";
|
||||
break;
|
||||
case ChatGptModel.Gpt432k:
|
||||
_model = "gpt-4-32k";
|
||||
break;
|
||||
}
|
||||
_maxHistory = chatHistory;
|
||||
_maxTokens = maxTokens;
|
||||
_minTokens = minTokens;
|
||||
_nadekoUsername = nadekoUsername;
|
||||
_encoding = GptEncoding.GetEncodingForModel(_model);
|
||||
messages.Add(new GPTMessage(){Role = "user", Content = personality, Name = _nadekoUsername});
|
||||
}
|
||||
|
||||
public async Task<string> Think(string input, string username)
|
||||
{
|
||||
messages.Add(new GPTMessage(){Role = "user", Content = input, Name = username});
|
||||
while(messages.Count > _maxHistory + 2){
|
||||
messages.RemoveAt(1);
|
||||
}
|
||||
int tokensUsed = 0;
|
||||
foreach(GPTMessage message in messages){
|
||||
tokensUsed += _encoding.Encode(message.Content).Count;
|
||||
}
|
||||
tokensUsed *= 2; //Unsure why this is the case, but the token count chatgpt reports back is double what I calculate.
|
||||
//check if we have the minimum number of tokens available to use. Remove messages until we have enough, otherwise exit out and inform the user why.
|
||||
while(_maxTokens - tokensUsed <= _minTokens){
|
||||
if(messages.Count > 2){
|
||||
int tokens = _encoding.Encode(messages[1].Content).Count * 2;
|
||||
tokensUsed -= tokens;
|
||||
messages.RemoveAt(1);
|
||||
}
|
||||
else{
|
||||
return "Token count exceeded, please increase the number of tokens in the bot config and restart.";
|
||||
}
|
||||
}
|
||||
using var http = _httpFactory.CreateClient();
|
||||
http.DefaultRequestHeaders.Authorization = new("Bearer", _apiKey);
|
||||
var data = await http.PostAsJsonAsync(Uri, new Gpt3ApiRequest()
|
||||
{
|
||||
Model = _model,
|
||||
Messages = messages,
|
||||
MaxTokens = _maxTokens - tokensUsed,
|
||||
Temperature = 1,
|
||||
});
|
||||
var dataString = await data.Content.ReadAsStringAsync();
|
||||
try
|
||||
{
|
||||
var response = JsonConvert.DeserializeObject<Gpt3Response>(dataString);
|
||||
string message = response?.Choices[0]?.Message?.Content;
|
||||
//Can't rely on the return to except, now that we need to add it to the messages list.
|
||||
_ = message ?? throw new ArgumentNullException(nameof(message));
|
||||
messages.Add(new GPTMessage(){Role = "assistant", Content = message, Name = _nadekoUsername});
|
||||
return message;
|
||||
}
|
||||
catch
|
||||
{
|
||||
Log.Warning("Unexpected GPT-3 response received: {ResponseString}", dataString);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -0,0 +1,141 @@
|
||||
#nullable disable
|
||||
using Newtonsoft.Json;
|
||||
using OneOf.Types;
|
||||
using System.Net.Http.Json;
|
||||
using SharpToken;
|
||||
|
||||
namespace NadekoBot.Modules.Games.Common.ChatterBot;
|
||||
|
||||
public class OfficialGptSession : IChatterBotSession
|
||||
{
|
||||
private string Uri
|
||||
=> $"https://api.openai.com/v1/chat/completions";
|
||||
|
||||
private readonly string _apiKey;
|
||||
private readonly string _model;
|
||||
private readonly int _maxHistory;
|
||||
private readonly int _maxTokens;
|
||||
private readonly int _minTokens;
|
||||
private readonly string _nadekoUsername;
|
||||
private readonly GptEncoding _encoding;
|
||||
private List<GPTMessage> messages = new();
|
||||
private readonly IHttpClientFactory _httpFactory;
|
||||
|
||||
|
||||
public OfficialGptSession(
|
||||
string apiKey,
|
||||
ChatGptModel model,
|
||||
int chatHistory,
|
||||
int maxTokens,
|
||||
int minTokens,
|
||||
string personality,
|
||||
string nadekoUsername,
|
||||
IHttpClientFactory factory)
|
||||
{
|
||||
_apiKey = apiKey;
|
||||
_httpFactory = factory;
|
||||
|
||||
_model = model switch
|
||||
{
|
||||
ChatGptModel.Gpt35Turbo => "gpt-3.5-turbo",
|
||||
ChatGptModel.Gpt4o => "gpt-4o",
|
||||
_ => throw new ArgumentException("Unknown, unsupported or obsolete model", nameof(model))
|
||||
};
|
||||
|
||||
_maxHistory = chatHistory;
|
||||
_maxTokens = maxTokens;
|
||||
_minTokens = minTokens;
|
||||
_nadekoUsername = nadekoUsername;
|
||||
_encoding = GptEncoding.GetEncodingForModel(_model);
|
||||
messages.Add(new()
|
||||
{
|
||||
Role = "system",
|
||||
Content = personality,
|
||||
Name = _nadekoUsername
|
||||
});
|
||||
}
|
||||
|
||||
public async Task<OneOf.OneOf<ThinkResult, Error<string>>> Think(string input, string username)
|
||||
{
|
||||
messages.Add(new()
|
||||
{
|
||||
Role = "user",
|
||||
Content = input,
|
||||
Name = username
|
||||
});
|
||||
while (messages.Count > _maxHistory + 2)
|
||||
{
|
||||
messages.RemoveAt(1);
|
||||
}
|
||||
|
||||
var tokensUsed = messages.Sum(message => _encoding.Encode(message.Content).Count);
|
||||
|
||||
tokensUsed *= 2;
|
||||
|
||||
//check if we have the minimum number of tokens available to use. Remove messages until we have enough, otherwise exit out and inform the user why.
|
||||
while (_maxTokens - tokensUsed <= _minTokens)
|
||||
{
|
||||
if (messages.Count > 2)
|
||||
{
|
||||
var tokens = _encoding.Encode(messages[1].Content).Count * 2;
|
||||
tokensUsed -= tokens;
|
||||
messages.RemoveAt(1);
|
||||
}
|
||||
else
|
||||
{
|
||||
return new Error<string>("Token count exceeded, please increase the number of tokens in the bot config and restart.");
|
||||
}
|
||||
}
|
||||
|
||||
using var http = _httpFactory.CreateClient();
|
||||
http.DefaultRequestHeaders.Authorization = new("Bearer", _apiKey);
|
||||
|
||||
var data = await http.PostAsJsonAsync(Uri,
|
||||
new Gpt3ApiRequest()
|
||||
{
|
||||
Model = _model,
|
||||
Messages = messages,
|
||||
MaxTokens = _maxTokens - tokensUsed,
|
||||
Temperature = 1,
|
||||
});
|
||||
|
||||
var dataString = await data.Content.ReadAsStringAsync();
|
||||
try
|
||||
{
|
||||
var response = JsonConvert.DeserializeObject<OpenAiCompletionResponse>(dataString);
|
||||
var res = response?.Choices?[0];
|
||||
var message = res?.Message?.Content;
|
||||
|
||||
if (message is null)
|
||||
{
|
||||
return new Error<string>("ChatGpt: Received no response.");
|
||||
}
|
||||
|
||||
messages.Add(new()
|
||||
{
|
||||
Role = "assistant",
|
||||
Content = message,
|
||||
Name = _nadekoUsername
|
||||
});
|
||||
|
||||
return new ThinkResult()
|
||||
{
|
||||
Text = message,
|
||||
TokensIn = response.Usage.PromptTokens,
|
||||
TokensOut = response.Usage.CompletionTokens
|
||||
};
|
||||
}
|
||||
catch
|
||||
{
|
||||
Log.Warning("Unexpected response received from OpenAI: {ResponseString}", dataString);
|
||||
return new Error<string>("Unexpected response received");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public sealed class ThinkResult
|
||||
{
|
||||
public string Text { get; set; }
|
||||
public int TokensIn { get; set; }
|
||||
public int TokensOut { get; set; }
|
||||
}
|
@@ -8,7 +8,7 @@ namespace NadekoBot.Modules.Games.Common;
|
||||
public sealed partial class GamesConfig : ICloneable<GamesConfig>
|
||||
{
|
||||
[Comment("DO NOT CHANGE")]
|
||||
public int Version { get; set; } = 3;
|
||||
public int Version { get; set; } = 4;
|
||||
|
||||
[Comment("Hangman related settings (.hangman command)")]
|
||||
public HangmanConfig Hangman { get; set; } = new()
|
||||
@@ -105,8 +105,8 @@ public sealed partial class GamesConfig : ICloneable<GamesConfig>
|
||||
|
||||
[Comment(@"Which chatbot API should bot use.
|
||||
'cleverbot' - bot will use Cleverbot API.
|
||||
'gpt3' - bot will use GPT-3 API")]
|
||||
public ChatBotImplementation ChatBot { get; set; } = ChatBotImplementation.Gpt3;
|
||||
'gpt' - bot will use GPT API")]
|
||||
public ChatBotImplementation ChatBot { get; set; } = ChatBotImplementation.Gpt;
|
||||
|
||||
public ChatGptConfig ChatGpt { get; set; } = new();
|
||||
}
|
||||
@@ -114,10 +114,10 @@ public sealed partial class GamesConfig : ICloneable<GamesConfig>
|
||||
[Cloneable]
|
||||
public sealed partial class ChatGptConfig
|
||||
{
|
||||
[Comment(@"Which GPT-3 Model should bot use.
|
||||
[Comment(@"Which GPT Model should bot use.
|
||||
gpt35turbo - cheapest
|
||||
gpt4 - 30x more expensive, higher quality
|
||||
gp432k - same model as above, but with a 32k token limit")]
|
||||
gpt4o - more expensive, higher quality
|
||||
")]
|
||||
public ChatGptModel ModelName { get; set; } = ChatGptModel.Gpt35Turbo;
|
||||
|
||||
[Comment(@"How should the chat bot behave, what's its personality? (Usage of this counts towards the max tokens)")]
|
||||
@@ -126,10 +126,10 @@ public sealed partial class ChatGptConfig
|
||||
[Comment(@"The maximum number of messages in a conversation that can be remembered. (This will increase the number of tokens used)")]
|
||||
public int ChatHistory { get; set; } = 5;
|
||||
|
||||
[Comment(@"The maximum number of tokens to use per GPT-3 API call")]
|
||||
[Comment(@"The maximum number of tokens to use per GPT API call")]
|
||||
public int MaxTokens { get; set; } = 100;
|
||||
|
||||
[Comment(@"The minimum number of tokens to use per GPT-3 API call, such that chat history is removed to make room.")]
|
||||
[Comment(@"The minimum number of tokens to use per GPT API call, such that chat history is removed to make room.")]
|
||||
public int MinTokens { get; set; } = 30;
|
||||
}
|
||||
|
||||
@@ -163,12 +163,18 @@ public sealed partial class RaceAnimal
|
||||
public enum ChatBotImplementation
|
||||
{
|
||||
Cleverbot,
|
||||
Gpt3
|
||||
Gpt = 1,
|
||||
[Obsolete]
|
||||
Gpt3 = 1,
|
||||
}
|
||||
|
||||
public enum ChatGptModel
|
||||
{
|
||||
Gpt35Turbo,
|
||||
[Obsolete]
|
||||
Gpt4,
|
||||
Gpt432k
|
||||
[Obsolete]
|
||||
Gpt432k,
|
||||
|
||||
Gpt35Turbo,
|
||||
Gpt4o,
|
||||
}
|
@@ -73,15 +73,6 @@ public sealed class GamesConfigService : ConfigServiceBase<GamesConfig>
|
||||
});
|
||||
}
|
||||
|
||||
if (data.Version < 2)
|
||||
{
|
||||
ModifyConfig(c =>
|
||||
{
|
||||
c.Version = 2;
|
||||
c.ChatBot = ChatBotImplementation.Cleverbot;
|
||||
});
|
||||
}
|
||||
|
||||
if (data.Version < 3)
|
||||
{
|
||||
ModifyConfig(c =>
|
||||
@@ -90,5 +81,19 @@ public sealed class GamesConfigService : ConfigServiceBase<GamesConfig>
|
||||
c.ChatGpt.ModelName = ChatGptModel.Gpt35Turbo;
|
||||
});
|
||||
}
|
||||
|
||||
if (data.Version < 4)
|
||||
{
|
||||
ModifyConfig(c =>
|
||||
{
|
||||
c.Version = 4;
|
||||
#pragma warning disable CS0612 // Type or member is obsolete
|
||||
c.ChatGpt.ModelName =
|
||||
c.ChatGpt.ModelName == ChatGptModel.Gpt4 || c.ChatGpt.ModelName == ChatGptModel.Gpt432k
|
||||
? ChatGptModel.Gpt4o
|
||||
: c.ChatGpt.ModelName;
|
||||
#pragma warning restore CS0612 // Type or member is obsolete
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
@@ -86,11 +86,31 @@ public sealed partial class Help : NadekoModule<HelpService>
|
||||
topLevelModules.Add(m);
|
||||
}
|
||||
|
||||
var menu = new SelectMenuBuilder()
|
||||
.WithPlaceholder("Select a module to see its commands")
|
||||
.WithCustomId("cmds:modules_select");
|
||||
|
||||
foreach (var m in topLevelModules)
|
||||
menu.AddOption(m.Name, m.Name, GetModuleEmoji(m.Name));
|
||||
|
||||
var inter = _inter.Create(ctx.User.Id,
|
||||
menu,
|
||||
async (smc) =>
|
||||
{
|
||||
await smc.DeferAsync();
|
||||
var val = smc.Data.Values.FirstOrDefault();
|
||||
if (val is null)
|
||||
return;
|
||||
|
||||
await Commands(val);
|
||||
});
|
||||
|
||||
await Response()
|
||||
.Paginated()
|
||||
.Items(topLevelModules)
|
||||
.PageSize(12)
|
||||
.CurrentPage(page)
|
||||
.Interaction(inter)
|
||||
.AddFooter(false)
|
||||
.Page((items, _) =>
|
||||
{
|
||||
@@ -221,10 +241,28 @@ public sealed partial class Help : NadekoModule<HelpService>
|
||||
// order by name
|
||||
var allowed = new List<CommandInfo>();
|
||||
|
||||
foreach (var cmd in _cmds.Commands
|
||||
.Where(c => c.Module.GetTopLevelModule()
|
||||
.Name
|
||||
.StartsWith(module, StringComparison.InvariantCultureIgnoreCase)))
|
||||
var mdls = _cmds.Commands
|
||||
.Where(c => c.Module.GetTopLevelModule()
|
||||
.Name
|
||||
.StartsWith(module, StringComparison.InvariantCultureIgnoreCase))
|
||||
.ToArray();
|
||||
|
||||
if (mdls.Length == 0)
|
||||
{
|
||||
var group = _cmds.Modules
|
||||
.Where(x => x.Parent is not null)
|
||||
.FirstOrDefault(x => string.Equals(x.Name.Replace("Commands", ""),
|
||||
module,
|
||||
StringComparison.InvariantCultureIgnoreCase));
|
||||
|
||||
if (group is not null)
|
||||
{
|
||||
await Group(group);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
foreach (var cmd in mdls)
|
||||
{
|
||||
var result = await _perms.CheckPermsAsync(ctx.Guild,
|
||||
ctx.Channel,
|
||||
@@ -236,6 +274,7 @@ public sealed partial class Help : NadekoModule<HelpService>
|
||||
allowed.Add(cmd);
|
||||
}
|
||||
|
||||
|
||||
var cmds = allowed.OrderBy(c => c.Aliases[0])
|
||||
.DistinctBy(x => x.Aliases[0])
|
||||
.ToList();
|
||||
@@ -275,55 +314,97 @@ public sealed partial class Help : NadekoModule<HelpService>
|
||||
return;
|
||||
}
|
||||
|
||||
var cnt = 0;
|
||||
var groups = cmdsWithGroup.GroupBy(_ => cnt++ / 48).ToArray();
|
||||
var sb = new SelectMenuBuilder()
|
||||
.WithCustomId("cmds:submodule_select")
|
||||
.WithPlaceholder("Select a submodule to see detailed commands");
|
||||
|
||||
var groups = cmdsWithGroup.ToArray();
|
||||
var embed = _sender.CreateEmbed().WithOkColor();
|
||||
foreach (var g in groups)
|
||||
{
|
||||
var last = g.Count();
|
||||
for (var i = 0; i < last; i++)
|
||||
{
|
||||
var transformed = g.ElementAt(i)
|
||||
.Select(x =>
|
||||
{
|
||||
//if cross is specified, and the command doesn't satisfy the requirements, cross it out
|
||||
if (opts.View == CommandsOptions.ViewType.Cross)
|
||||
{
|
||||
return $"{(succ.Contains(x) ? "✅" : "❌")} {prefix + x.Aliases[0]}";
|
||||
}
|
||||
sb.AddOption(g.Key, g.Key);
|
||||
var transformed = g
|
||||
.Select(x =>
|
||||
{
|
||||
//if cross is specified, and the command doesn't satisfy the requirements, cross it out
|
||||
if (opts.View == CommandsOptions.ViewType.Cross)
|
||||
{
|
||||
return $"{(succ.Contains(x) ? "✅" : "❌")} {prefix + x.Aliases[0]}";
|
||||
}
|
||||
|
||||
if (x.Aliases.Count == 1)
|
||||
return prefix + x.Aliases[0];
|
||||
|
||||
return prefix + x.Aliases[0] + " | " + prefix + x.Aliases[1];
|
||||
});
|
||||
if (x.Aliases.Count == 1)
|
||||
return prefix + x.Aliases[0];
|
||||
|
||||
embed.AddField(g.ElementAt(i).Key, "" + string.Join("\n", transformed) + "", true);
|
||||
}
|
||||
return prefix + x.Aliases[0] + " | " + prefix + x.Aliases[1];
|
||||
});
|
||||
|
||||
embed.AddField(g.Key, "" + string.Join("\n", transformed) + "", true);
|
||||
}
|
||||
|
||||
embed.WithFooter(GetText(strs.commands_instr(prefix)));
|
||||
await Response().Embed(embed).SendAsync();
|
||||
|
||||
|
||||
var inter = _inter.Create(ctx.User.Id,
|
||||
sb,
|
||||
async (smc) =>
|
||||
{
|
||||
var groupName = smc.Data.Values.FirstOrDefault();
|
||||
var mdl = _cmds.Modules.FirstOrDefault(x
|
||||
=> string.Equals(x.Name.Replace("Commands", ""), groupName, StringComparison.InvariantCultureIgnoreCase));
|
||||
await smc.DeferAsync();
|
||||
await Group(mdl);
|
||||
}
|
||||
);
|
||||
|
||||
await Response().Embed(embed).Interaction(inter).SendAsync();
|
||||
}
|
||||
|
||||
private async Task Group(ModuleInfo group)
|
||||
{
|
||||
var eb = _sender.CreateEmbed()
|
||||
.WithTitle(GetText(strs.cmd_group_commands(group.Name)))
|
||||
.WithOkColor();
|
||||
var menu = new SelectMenuBuilder()
|
||||
.WithCustomId("cmds:group_select")
|
||||
.WithPlaceholder("Select a command to see its details");
|
||||
|
||||
foreach (var cmd in group.Commands.DistinctBy(x => x.Aliases[0]))
|
||||
{
|
||||
string cmdName;
|
||||
if (cmd.Aliases.Count > 1)
|
||||
cmdName = Format.Code(prefix + cmd.Aliases[0]) + " | " + Format.Code(prefix + cmd.Aliases[1]);
|
||||
else
|
||||
cmdName = Format.Code(prefix + cmd.Aliases.First());
|
||||
|
||||
eb.AddField(cmdName, cmd.RealSummary(_strings, _medusae, Culture, prefix));
|
||||
menu.AddOption(prefix + cmd.Aliases[0], cmd.Aliases[0]);
|
||||
}
|
||||
|
||||
await Response().Embed(eb).SendAsync();
|
||||
var inter = _inter.Create(ctx.User.Id,
|
||||
menu,
|
||||
async (smc) =>
|
||||
{
|
||||
await smc.DeferAsync();
|
||||
|
||||
await H(smc.Data.Values.FirstOrDefault());
|
||||
});
|
||||
|
||||
await Response()
|
||||
.Paginated()
|
||||
.Items(group.Commands.DistinctBy(x => x.Aliases[0]).ToArray())
|
||||
.PageSize(25)
|
||||
.Interaction(inter)
|
||||
.Page((items, _) =>
|
||||
{
|
||||
var eb = _sender.CreateEmbed()
|
||||
.WithTitle(GetText(strs.cmd_group_commands(group.Name)))
|
||||
.WithOkColor();
|
||||
|
||||
foreach (var cmd in items)
|
||||
{
|
||||
string cmdName;
|
||||
if (cmd.Aliases.Count > 1)
|
||||
cmdName = Format.Code(prefix + cmd.Aliases[0]) + " | " + Format.Code(prefix + cmd.Aliases[1]);
|
||||
else
|
||||
cmdName = Format.Code(prefix + cmd.Aliases.First());
|
||||
|
||||
eb.AddField(cmdName, cmd.RealSummary(_strings, _medusae, Culture, prefix));
|
||||
}
|
||||
|
||||
return eb;
|
||||
})
|
||||
.SendAsync();
|
||||
}
|
||||
|
||||
[Cmd]
|
||||
@@ -343,8 +424,9 @@ public sealed partial class Help : NadekoModule<HelpService>
|
||||
|
||||
var group = _cmds.Modules
|
||||
.SelectMany(x => x.Submodules)
|
||||
.Where(x => !string.IsNullOrWhiteSpace(x.Group))
|
||||
.FirstOrDefault(x => x.Group.Equals(fail, StringComparison.InvariantCultureIgnoreCase));
|
||||
.FirstOrDefault(x => string.Equals(x.Group,
|
||||
fail,
|
||||
StringComparison.InvariantCultureIgnoreCase));
|
||||
|
||||
if (group is not null)
|
||||
{
|
||||
@@ -424,7 +506,7 @@ public sealed partial class Help : NadekoModule<HelpService>
|
||||
.ToList());
|
||||
|
||||
var readableData = JsonConvert.SerializeObject(cmdData, Formatting.Indented);
|
||||
|
||||
|
||||
// send the indented file to chat
|
||||
await using var rDataStream = new MemoryStream(Encoding.ASCII.GetBytes(readableData));
|
||||
await ctx.Channel.SendFileAsync(rDataStream, "cmds.json", GetText(strs.commandlist_regen));
|
||||
@@ -438,7 +520,7 @@ public sealed partial class Help : NadekoModule<HelpService>
|
||||
.SendAsync();
|
||||
|
||||
|
||||
private Task SelfhostAction(SocketMessageComponent smc, object _)
|
||||
private Task SelfhostAction(SocketMessageComponent smc)
|
||||
=> smc.RespondConfirmAsync(_sender,
|
||||
"""
|
||||
- In case you don't want or cannot Donate to NadekoBot project, but you
|
||||
@@ -456,11 +538,11 @@ public sealed partial class Help : NadekoModule<HelpService>
|
||||
public async Task Donate()
|
||||
{
|
||||
var selfhostInter = _inter.Create(ctx.User.Id,
|
||||
new SimpleInteraction<object>(new ButtonBuilder(
|
||||
emote: new Emoji("🖥️"),
|
||||
customId: "donate:selfhosting",
|
||||
label: "Selfhosting"),
|
||||
SelfhostAction));
|
||||
new ButtonBuilder(
|
||||
emote: new Emoji("🖥️"),
|
||||
customId: "donate:selfhosting",
|
||||
label: "Selfhosting"),
|
||||
SelfhostAction);
|
||||
|
||||
var eb = _sender.CreateEmbed()
|
||||
.WithOkColor()
|
||||
@@ -489,17 +571,9 @@ public sealed partial class Help : NadekoModule<HelpService>
|
||||
|
||||
**Step 3** ⏰ Wait a short while (usually 1-3 minutes) ⏰
|
||||
|
||||
Nadeko will DM you the welcome instructions, and you may will receive your rewards!
|
||||
Nadeko will DM you the welcome instructions, and you will receive your rewards!
|
||||
🎉 **Enjoy!** 🎉
|
||||
""")
|
||||
.AddField("Troubleshooting",
|
||||
"""
|
||||
*In case you didn't receive the rewards within 5 minutes:*
|
||||
`1.` Make sure your DMs are open to everyone. Maybe your pledge was processed successfully but the bot was unable to DM you. Use the `.patron` command to check your status.
|
||||
`2.` Make sure you've connected the CORRECT Discord account. Quite often users log in to different Discord accounts in their browser. You may also try disconnecting and reconnecting your account.
|
||||
`3.` Make sure your payment has been processed and not declined by Patreon.
|
||||
`4.` If any of the previous steps don't help, you can join the nadeko support server <https://discord.nadeko.bot> and ask for help in the #help channel
|
||||
""");
|
||||
""");
|
||||
|
||||
try
|
||||
{
|
||||
|
@@ -1,6 +1,7 @@
|
||||
#nullable disable
|
||||
using NadekoBot.Modules.Music.Services;
|
||||
using NadekoBot.Db.Models;
|
||||
using NadekoBot.Modules.Utility;
|
||||
|
||||
namespace NadekoBot.Modules.Music;
|
||||
|
||||
|
@@ -212,7 +212,7 @@ public sealed class MusicService : IMusicService, IPlaceholderProvider
|
||||
if (settings.AutoDisconnect)
|
||||
return LeaveVoiceChannelAsync(guildId);
|
||||
}
|
||||
|
||||
|
||||
return Task.CompletedTask;
|
||||
};
|
||||
|
||||
|
@@ -32,5 +32,14 @@ public class PatronageConfig : ConfigServiceBase<PatronConfigData>
|
||||
c.IsEnabled = false;
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
ModifyConfig(c =>
|
||||
{
|
||||
if (c.Version == 2)
|
||||
{
|
||||
c.Version = 3;
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
@@ -1,6 +1,7 @@
|
||||
#nullable disable
|
||||
using LinqToDB;
|
||||
using LinqToDB.EntityFrameworkCore;
|
||||
using NadekoBot.Common.ModuleBehaviors;
|
||||
using NadekoBot.Modules.Gambling.Services;
|
||||
using NadekoBot.Modules.Patronage;
|
||||
using NadekoBot.Services.Currency;
|
||||
@@ -8,7 +9,7 @@ using NadekoBot.Db.Models;
|
||||
|
||||
namespace NadekoBot.Modules.Utility;
|
||||
|
||||
public sealed class CurrencyRewardService : INService, IDisposable
|
||||
public sealed class CurrencyRewardService : INService, IReadyExecutor
|
||||
{
|
||||
private readonly ICurrencyService _cs;
|
||||
private readonly IPatronageService _ps;
|
||||
@@ -32,16 +33,14 @@ public sealed class CurrencyRewardService : INService, IDisposable
|
||||
_config = config;
|
||||
_client = client;
|
||||
|
||||
}
|
||||
|
||||
public Task OnReadyAsync()
|
||||
{
|
||||
_ps.OnNewPatronPayment += OnNewPayment;
|
||||
_ps.OnPatronRefunded += OnPatronRefund;
|
||||
_ps.OnPatronUpdated += OnPatronUpdate;
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
_ps.OnNewPatronPayment -= OnNewPayment;
|
||||
_ps.OnPatronRefunded -= OnPatronRefund;
|
||||
_ps.OnPatronUpdated -= OnPatronUpdate;
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
private async Task OnPatronUpdate(Patron oldPatron, Patron newPatron)
|
||||
|
@@ -1,11 +0,0 @@
|
||||
using NadekoBot.Db.Models;
|
||||
|
||||
namespace NadekoBot.Modules.Patronage;
|
||||
|
||||
public readonly struct InsufficientTier
|
||||
{
|
||||
public FeatureType FeatureType { get; init; }
|
||||
public string Feature { get; init; }
|
||||
public PatronTier RequiredTier { get; init; }
|
||||
public PatronTier UserTier { get; init; }
|
||||
}
|
@@ -140,7 +140,6 @@ public class PatreonClient : IDisposable
|
||||
LastChargeDate = m.Attributes.LastChargeDate,
|
||||
LastChargeStatus = m.Attributes.LastChargeStatus
|
||||
})
|
||||
.Where(x => x.UserId == 140788173885276160)
|
||||
.ToArray();
|
||||
|
||||
yield return userData;
|
||||
|
@@ -25,9 +25,4 @@ public sealed class PatreonMemberData : ISubscriberData
|
||||
"Declined" or "Pending" => SubscriptionChargeStatus.Unpaid,
|
||||
_ => SubscriptionChargeStatus.Other,
|
||||
};
|
||||
}
|
||||
|
||||
public sealed class PatreonPledgeData
|
||||
{
|
||||
|
||||
}
|
@@ -71,17 +71,16 @@ public partial class Help
|
||||
return;
|
||||
}
|
||||
|
||||
var patron = await _service.GetPatronAsync(user.Id);
|
||||
var quotaStats = await _service.GetUserQuotaStatistic(user.Id);
|
||||
var maybePatron = await _service.GetPatronAsync(user.Id);
|
||||
|
||||
var quotaStats = await _service.LimitStats(user.Id);
|
||||
|
||||
var eb = _sender.CreateEmbed()
|
||||
.WithAuthor(user)
|
||||
.WithTitle(GetText(strs.patron_info))
|
||||
.WithOkColor();
|
||||
|
||||
if (quotaStats.Commands.Count == 0
|
||||
&& quotaStats.Groups.Count == 0
|
||||
&& quotaStats.Modules.Count == 0)
|
||||
if (quotaStats.Count == 0 || maybePatron is not { } patron)
|
||||
{
|
||||
eb.WithDescription(GetText(strs.no_quota_found));
|
||||
}
|
||||
@@ -97,26 +96,9 @@ public partial class Help
|
||||
|
||||
eb.AddField(GetText(strs.quotas), "", false);
|
||||
|
||||
if (quotaStats.Commands.Count > 0)
|
||||
{
|
||||
var text = GetQuotaList(quotaStats.Commands);
|
||||
if (!string.IsNullOrWhiteSpace(text))
|
||||
eb.AddField(GetText(strs.commands), text, true);
|
||||
}
|
||||
|
||||
if (quotaStats.Groups.Count > 0)
|
||||
{
|
||||
var text = GetQuotaList(quotaStats.Groups);
|
||||
if (!string.IsNullOrWhiteSpace(text))
|
||||
eb.AddField(GetText(strs.groups), text, true);
|
||||
}
|
||||
|
||||
if (quotaStats.Modules.Count > 0)
|
||||
{
|
||||
var text = GetQuotaList(quotaStats.Modules);
|
||||
if (!string.IsNullOrWhiteSpace(text))
|
||||
eb.AddField(GetText(strs.modules), text, true);
|
||||
}
|
||||
var text = GetQuotaList(quotaStats);
|
||||
if (!string.IsNullOrWhiteSpace(text))
|
||||
eb.AddField(GetText(strs.modules), text, true);
|
||||
}
|
||||
|
||||
|
||||
@@ -131,26 +113,28 @@ public partial class Help
|
||||
}
|
||||
}
|
||||
|
||||
private string GetQuotaList(IReadOnlyDictionary<string, FeatureQuotaStats> featureQuotaStats)
|
||||
private string GetQuotaList(
|
||||
IReadOnlyDictionary<LimitedFeatureName, (int Cur, QuotaLimit Quota)> featureQuotaStats)
|
||||
{
|
||||
var text = string.Empty;
|
||||
foreach (var (key, q) in featureQuotaStats)
|
||||
foreach (var (key, (cur, quota)) in featureQuotaStats)
|
||||
{
|
||||
text += $"\n\t`{key}`\n";
|
||||
if (q.Hourly != default)
|
||||
text += $" {GetEmoji(q.Hourly)} {q.Hourly.Cur}/{q.Hourly.Max} per hour\n";
|
||||
if (q.Daily != default)
|
||||
text += $" {GetEmoji(q.Daily)} {q.Daily.Cur}/{q.Daily.Max} per day\n";
|
||||
if (q.Monthly != default)
|
||||
text += $" {GetEmoji(q.Monthly)} {q.Monthly.Cur}/{q.Monthly.Max} per month\n";
|
||||
if (quota.QuotaPeriod == QuotaPer.PerHour)
|
||||
text += $" {cur}/{(quota.Quota == -1 ? "∞" : quota.Quota)} {QuotaPeriodToString(quota.QuotaPeriod)}\n";
|
||||
}
|
||||
|
||||
return text;
|
||||
}
|
||||
|
||||
private string GetEmoji((uint Cur, uint Max) limit)
|
||||
=> limit.Cur < limit.Max
|
||||
? "✅"
|
||||
: "⚠️";
|
||||
public string QuotaPeriodToString(QuotaPer per)
|
||||
=> per switch
|
||||
{
|
||||
QuotaPer.PerHour => "per hour",
|
||||
QuotaPer.PerDay => "per day",
|
||||
QuotaPer.PerMonth => "per month",
|
||||
QuotaPer.Total => "total",
|
||||
_ => throw new ArgumentOutOfRangeException(nameof(per), per, null)
|
||||
};
|
||||
}
|
||||
}
|
@@ -2,9 +2,8 @@
|
||||
using LinqToDB.EntityFrameworkCore;
|
||||
using NadekoBot.Common.ModuleBehaviors;
|
||||
using NadekoBot.Db.Models;
|
||||
using OneOf;
|
||||
using OneOf.Types;
|
||||
using CommandInfo = Discord.Commands.CommandInfo;
|
||||
using StackExchange.Redis;
|
||||
using System.Diagnostics;
|
||||
|
||||
namespace NadekoBot.Modules.Patronage;
|
||||
|
||||
@@ -12,7 +11,6 @@ namespace NadekoBot.Modules.Patronage;
|
||||
public sealed class PatronageService
|
||||
: IPatronageService,
|
||||
IReadyExecutor,
|
||||
IExecPreCommand,
|
||||
INService
|
||||
{
|
||||
public event Func<Patron, Task> OnNewPatronPayment = static delegate { return Task.CompletedTask; };
|
||||
@@ -60,7 +58,7 @@ public sealed class PatronageService
|
||||
if (_client.ShardId != 0)
|
||||
return Task.CompletedTask;
|
||||
|
||||
return Task.WhenAll(ResetLoopAsync(), LoadSubscribersLoopAsync());
|
||||
return Task.WhenAll(LoadSubscribersLoopAsync());
|
||||
}
|
||||
|
||||
private async Task LoadSubscribersLoopAsync()
|
||||
@@ -85,71 +83,6 @@ public sealed class PatronageService
|
||||
}
|
||||
}
|
||||
|
||||
public async Task ResetLoopAsync()
|
||||
{
|
||||
await Task.Delay(1.Minutes());
|
||||
while (true)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (!_pConf.Data.IsEnabled)
|
||||
{
|
||||
await Task.Delay(1.Minutes());
|
||||
continue;
|
||||
}
|
||||
|
||||
var now = DateTime.UtcNow;
|
||||
var lastRun = DateTime.MinValue;
|
||||
|
||||
var result = await _cache.GetAsync(_quotaKey);
|
||||
if (result.TryGetValue(out var lastVal) && lastVal != default)
|
||||
{
|
||||
lastRun = DateTime.FromBinary(lastVal);
|
||||
}
|
||||
|
||||
var nowDate = now.ToDateOnly();
|
||||
var lastDate = lastRun.ToDateOnly();
|
||||
|
||||
await using var ctx = _db.GetDbContext();
|
||||
|
||||
if ((lastDate.Day == 1 || (lastDate.Month != nowDate.Month)) && nowDate.Day > 1)
|
||||
{
|
||||
// assumes bot won't be offline for a year
|
||||
await ctx.GetTable<PatronQuota>()
|
||||
.TruncateAsync();
|
||||
}
|
||||
else if (nowDate.DayNumber != lastDate.DayNumber)
|
||||
{
|
||||
// day is different, means hour is different.
|
||||
// reset both hourly and daily quota counts.
|
||||
await ctx.GetTable<PatronQuota>()
|
||||
.UpdateAsync((old) => new()
|
||||
{
|
||||
HourlyCount = 0,
|
||||
DailyCount = 0,
|
||||
});
|
||||
}
|
||||
else if (now.Hour != lastRun.Hour) // if it's not, just reset hourly quotas
|
||||
{
|
||||
await ctx.GetTable<PatronQuota>()
|
||||
.UpdateAsync((old) => new()
|
||||
{
|
||||
HourlyCount = 0
|
||||
});
|
||||
}
|
||||
|
||||
// assumes that the code above runs in less than an hour
|
||||
await _cache.AddAsync(_quotaKey, now.ToBinary());
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Log.Error(ex, "Error in quota reset loop. Message: {ErrorMessage}", ex.Message);
|
||||
}
|
||||
|
||||
await Task.Delay(TimeSpan.FromHours(1).Add(TimeSpan.FromMinutes(1)));
|
||||
}
|
||||
}
|
||||
|
||||
private async Task ProcesssPatronsAsync(IReadOnlyCollection<ISubscriberData> subscribersEnum)
|
||||
{
|
||||
// process only users who have discord accounts connected
|
||||
@@ -203,7 +136,8 @@ public sealed class PatronageService
|
||||
// if his sub would end in teh future, extend it by one month.
|
||||
// if it's not, just add 1 month to the last charge date
|
||||
var count = await ctx.GetTable<PatronUser>()
|
||||
.Where(x => x.UniquePlatformUserId == subscriber.UniquePlatformUserId)
|
||||
.Where(x => x.UniquePlatformUserId
|
||||
== subscriber.UniquePlatformUserId)
|
||||
.UpdateAsync(old => new()
|
||||
{
|
||||
UserId = subscriber.UserId,
|
||||
@@ -215,14 +149,13 @@ public sealed class PatronageService
|
||||
: dateInOneMonth,
|
||||
});
|
||||
|
||||
// this should never happen
|
||||
if (count == 0)
|
||||
{
|
||||
// await tran.RollbackAsync();
|
||||
continue;
|
||||
}
|
||||
|
||||
// await tran.CommitAsync();
|
||||
dbPatron.UserId = subscriber.UserId;
|
||||
dbPatron.AmountCents = subscriber.Cents;
|
||||
dbPatron.LastCharge = lastChargeUtc;
|
||||
dbPatron.ValidThru = dbPatron.ValidThru >= todayDate
|
||||
? dbPatron.ValidThru.AddMonths(1)
|
||||
: dateInOneMonth;
|
||||
|
||||
await OnNewPatronPayment(PatronUserToPatron(dbPatron));
|
||||
}
|
||||
@@ -284,313 +217,7 @@ public sealed class PatronageService
|
||||
}
|
||||
}
|
||||
|
||||
public async Task<bool> ExecPreCommandAsync(
|
||||
ICommandContext ctx,
|
||||
string moduleName,
|
||||
CommandInfo command)
|
||||
{
|
||||
var ownerId = ctx.Guild?.OwnerId ?? 0;
|
||||
|
||||
var result = await AttemptRunCommand(
|
||||
ctx.User.Id,
|
||||
ownerId: ownerId,
|
||||
command.Aliases.First().ToLowerInvariant(),
|
||||
command.Module.Parent == null ? string.Empty : command.Module.GetGroupName().ToLowerInvariant(),
|
||||
moduleName.ToLowerInvariant()
|
||||
);
|
||||
|
||||
return result.Match(
|
||||
_ => false,
|
||||
ins =>
|
||||
{
|
||||
var eb = _sender.CreateEmbed()
|
||||
.WithPendingColor()
|
||||
.WithTitle("Insufficient Patron Tier")
|
||||
.AddField("For", $"{ins.FeatureType}: `{ins.Feature}`", true)
|
||||
.AddField("Required Tier",
|
||||
$"[{ins.RequiredTier.ToFullName()}](https://patreon.com/join/nadekobot)",
|
||||
true);
|
||||
|
||||
if (ctx.Guild is null || ctx.Guild?.OwnerId == ctx.User.Id)
|
||||
eb.WithDescription("You don't have the sufficent Patron Tier to run this command.")
|
||||
.WithFooter("You can use '.patron' and '.donate' commands for more info");
|
||||
else
|
||||
eb.WithDescription(
|
||||
"Neither you nor the server owner have the sufficent Patron Tier to run this command.")
|
||||
.WithFooter("You can use '.patron' and '.donate' commands for more info");
|
||||
|
||||
_ = ctx.WarningAsync();
|
||||
|
||||
if (ctx.Guild?.OwnerId == ctx.User.Id)
|
||||
_ = _sender.Response(ctx)
|
||||
.Context(ctx)
|
||||
.Embed(eb)
|
||||
.SendAsync();
|
||||
else
|
||||
_ = _sender.Response(ctx).User(ctx.User).Embed(eb).SendAsync();
|
||||
|
||||
return true;
|
||||
},
|
||||
quota =>
|
||||
{
|
||||
var eb = _sender.CreateEmbed()
|
||||
.WithPendingColor()
|
||||
.WithTitle("Quota Limit Reached");
|
||||
|
||||
if (quota.IsOwnQuota || ctx.User.Id == ownerId)
|
||||
{
|
||||
eb.WithDescription($"You've reached your quota of `{quota.Quota} {quota.QuotaPeriod.ToFullName()}`")
|
||||
.WithFooter("You may want to check your quota by using the '.patron' command.");
|
||||
}
|
||||
else
|
||||
{
|
||||
eb.WithDescription(
|
||||
$"This server reached the quota of {quota.Quota} `{quota.QuotaPeriod.ToFullName()}`")
|
||||
.WithFooter("You may contact the server owner about this issue.\n"
|
||||
+ "Alternatively, you can become patron yourself by using the '.donate' command.\n"
|
||||
+ "If you're already a patron, it means you've reached your quota.\n"
|
||||
+ "You can use '.patron' command to check your quota status.");
|
||||
}
|
||||
|
||||
eb.AddField("For", $"{quota.FeatureType}: `{quota.Feature}`", true)
|
||||
.AddField("Resets At", quota.ResetsAt.ToShortAndRelativeTimestampTag(), true);
|
||||
|
||||
_ = ctx.WarningAsync();
|
||||
|
||||
// send the message in the server in case it's the owner
|
||||
if (ctx.Guild?.OwnerId == ctx.User.Id)
|
||||
_ = _sender.Response(ctx)
|
||||
.Embed(eb)
|
||||
.SendAsync();
|
||||
else
|
||||
_ = _sender.Response(ctx).User(ctx.User).Embed(eb).SendAsync();
|
||||
|
||||
return true;
|
||||
});
|
||||
}
|
||||
|
||||
private async ValueTask<OneOf<OneOf.Types.Success, InsufficientTier, QuotaLimit>> AttemptRunCommand(
|
||||
ulong userId,
|
||||
ulong ownerId,
|
||||
string commandName,
|
||||
string groupName,
|
||||
string moduleName)
|
||||
{
|
||||
// try to run as a user
|
||||
var res = await AttemptRunCommand(userId, commandName, groupName, moduleName, true);
|
||||
|
||||
// if it fails, try to run as an owner
|
||||
// but only if the command is ran in a server
|
||||
// and if the owner is not the user
|
||||
if (!res.IsT0 && ownerId != 0 && ownerId != userId)
|
||||
res = await AttemptRunCommand(ownerId, commandName, groupName, moduleName, false);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns either the current usage counter if limit wasn't reached, or QuotaLimit if it is.
|
||||
/// </summary>
|
||||
public async ValueTask<OneOf<(uint Hourly, uint Daily, uint Monthly), QuotaLimit>> TryIncrementQuotaCounterAsync(
|
||||
ulong userId,
|
||||
bool isSelf,
|
||||
FeatureType featureType,
|
||||
string featureName,
|
||||
uint? maybeHourly,
|
||||
uint? maybeDaily,
|
||||
uint? maybeMonthly)
|
||||
{
|
||||
await using var ctx = _db.GetDbContext();
|
||||
|
||||
var now = DateTime.UtcNow;
|
||||
await using var tran = await ctx.Database.BeginTransactionAsync();
|
||||
|
||||
var userQuotaData = await ctx.GetTable<PatronQuota>()
|
||||
.FirstOrDefaultAsyncLinqToDB(x => x.UserId == userId
|
||||
&& x.Feature == featureName)
|
||||
?? new PatronQuota();
|
||||
|
||||
// if hourly exists, if daily exists, etc...
|
||||
if (maybeHourly is uint hourly && userQuotaData.HourlyCount >= hourly)
|
||||
{
|
||||
return new QuotaLimit()
|
||||
{
|
||||
QuotaPeriod = QuotaPer.PerHour,
|
||||
Quota = hourly,
|
||||
// quite a neat trick. https://stackoverflow.com/a/5733560
|
||||
ResetsAt = now.Date.AddHours(now.Hour + 1),
|
||||
Feature = featureName,
|
||||
FeatureType = featureType,
|
||||
IsOwnQuota = isSelf
|
||||
};
|
||||
}
|
||||
|
||||
if (maybeDaily is uint daily
|
||||
&& userQuotaData.DailyCount >= daily)
|
||||
{
|
||||
return new QuotaLimit()
|
||||
{
|
||||
QuotaPeriod = QuotaPer.PerDay,
|
||||
Quota = daily,
|
||||
ResetsAt = now.Date.AddDays(1),
|
||||
Feature = featureName,
|
||||
FeatureType = featureType,
|
||||
IsOwnQuota = isSelf
|
||||
};
|
||||
}
|
||||
|
||||
if (maybeMonthly is uint monthly && userQuotaData.MonthlyCount >= monthly)
|
||||
{
|
||||
return new QuotaLimit()
|
||||
{
|
||||
QuotaPeriod = QuotaPer.PerMonth,
|
||||
Quota = monthly,
|
||||
ResetsAt = now.Date.SecondOfNextMonth(),
|
||||
Feature = featureName,
|
||||
FeatureType = featureType,
|
||||
IsOwnQuota = isSelf
|
||||
};
|
||||
}
|
||||
|
||||
await ctx.GetTable<PatronQuota>()
|
||||
.InsertOrUpdateAsync(() => new()
|
||||
{
|
||||
UserId = userId,
|
||||
FeatureType = featureType,
|
||||
Feature = featureName,
|
||||
DailyCount = 1,
|
||||
MonthlyCount = 1,
|
||||
HourlyCount = 1,
|
||||
},
|
||||
(old) => new()
|
||||
{
|
||||
HourlyCount = old.HourlyCount + 1,
|
||||
DailyCount = old.DailyCount + 1,
|
||||
MonthlyCount = old.MonthlyCount + 1,
|
||||
},
|
||||
() => new()
|
||||
{
|
||||
UserId = userId,
|
||||
FeatureType = featureType,
|
||||
Feature = featureName,
|
||||
});
|
||||
|
||||
await tran.CommitAsync();
|
||||
|
||||
return (userQuotaData.HourlyCount + 1, userQuotaData.DailyCount + 1, userQuotaData.MonthlyCount + 1);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Attempts to add 1 to user's quota for the command, group and module.
|
||||
/// Input MUST BE lowercase
|
||||
/// </summary>
|
||||
/// <param name="userId">Id of the user who is attempting to run the command</param>
|
||||
/// <param name="commandName">Name of the command the user is trying to run</param>
|
||||
/// <param name="groupName">Name of the command's group</param>
|
||||
/// <param name="moduleName">Name of the command's top level module</param>
|
||||
/// <param name="isSelf">Whether this is check is for the user himself. False if it's someone else's id (owner)</param>
|
||||
/// <returns>Either a succcess (user can run the command) or one of the error values.</returns>
|
||||
private async ValueTask<OneOf<OneOf.Types.Success, InsufficientTier, QuotaLimit>> AttemptRunCommand(
|
||||
ulong userId,
|
||||
string commandName,
|
||||
string groupName,
|
||||
string moduleName,
|
||||
bool isSelf)
|
||||
{
|
||||
var confData = _pConf.Data;
|
||||
|
||||
if (!confData.IsEnabled)
|
||||
return default;
|
||||
|
||||
if (_creds.GetCreds().IsOwner(userId))
|
||||
return default;
|
||||
|
||||
// get user tier
|
||||
var patron = await GetPatronAsync(userId);
|
||||
FeatureType quotaForFeatureType;
|
||||
|
||||
if (confData.Quotas.Commands.TryGetValue(commandName, out var quotaData))
|
||||
{
|
||||
quotaForFeatureType = FeatureType.Command;
|
||||
}
|
||||
else if (confData.Quotas.Groups.TryGetValue(groupName, out quotaData))
|
||||
{
|
||||
quotaForFeatureType = FeatureType.Group;
|
||||
}
|
||||
else if (confData.Quotas.Modules.TryGetValue(moduleName, out quotaData))
|
||||
{
|
||||
quotaForFeatureType = FeatureType.Module;
|
||||
}
|
||||
else
|
||||
{
|
||||
return default;
|
||||
}
|
||||
|
||||
var featureName = quotaForFeatureType switch
|
||||
{
|
||||
FeatureType.Command => commandName,
|
||||
FeatureType.Group => groupName,
|
||||
FeatureType.Module => moduleName,
|
||||
_ => throw new ArgumentOutOfRangeException(nameof(quotaForFeatureType))
|
||||
};
|
||||
|
||||
if (!TryGetTierDataOrLower(quotaData, patron.Tier, out var data))
|
||||
{
|
||||
return new InsufficientTier()
|
||||
{
|
||||
Feature = featureName,
|
||||
FeatureType = quotaForFeatureType,
|
||||
RequiredTier = quotaData.Count == 0
|
||||
? PatronTier.ComingSoon
|
||||
: quotaData.Keys.First(),
|
||||
UserTier = patron.Tier,
|
||||
};
|
||||
}
|
||||
|
||||
// no quota limits for this tier
|
||||
if (data is null)
|
||||
return default;
|
||||
|
||||
var quotaCheckResult = await TryIncrementQuotaCounterAsync(userId,
|
||||
isSelf,
|
||||
quotaForFeatureType,
|
||||
featureName,
|
||||
data.TryGetValue(QuotaPer.PerHour, out var hourly) ? hourly : null,
|
||||
data.TryGetValue(QuotaPer.PerDay, out var daily) ? daily : null,
|
||||
data.TryGetValue(QuotaPer.PerMonth, out var monthly) ? monthly : null
|
||||
);
|
||||
|
||||
return quotaCheckResult.Match<OneOf<Success, InsufficientTier, QuotaLimit>>(
|
||||
_ => new Success(),
|
||||
x => x);
|
||||
}
|
||||
|
||||
private bool TryGetTierDataOrLower<T>(
|
||||
IReadOnlyDictionary<PatronTier, T?> data,
|
||||
PatronTier tier,
|
||||
out T? o)
|
||||
{
|
||||
// check for quotas on this tier
|
||||
if (data.TryGetValue(tier, out o))
|
||||
return true;
|
||||
|
||||
// if there are none, get the quota first tier below this one
|
||||
// which has quotas specified
|
||||
for (var i = _tiers.Length - 1; i >= 0; i--)
|
||||
{
|
||||
var lowerTier = _tiers[i];
|
||||
if (lowerTier < tier && data.TryGetValue(lowerTier, out o))
|
||||
return true;
|
||||
}
|
||||
|
||||
// if there are none, that means the feature is intended
|
||||
// to be patron-only but the quotas haven't been specified yet
|
||||
// so it will be marked as "Coming Soon"
|
||||
o = default;
|
||||
return false;
|
||||
}
|
||||
|
||||
public async Task<Patron> GetPatronAsync(ulong userId)
|
||||
public async Task<Patron?> GetPatronAsync(ulong userId)
|
||||
{
|
||||
await using var ctx = _db.GetDbContext();
|
||||
|
||||
@@ -616,128 +243,135 @@ public sealed class PatronageService
|
||||
return PatronUserToPatron(max);
|
||||
}
|
||||
|
||||
public async Task<UserQuotaStats> GetUserQuotaStatistic(ulong userId)
|
||||
public async Task<bool> LimitHitAsync(LimitedFeatureName key, ulong userId, int amount = 1)
|
||||
{
|
||||
var pConfData = _pConf.Data;
|
||||
if (_creds.GetCreds().IsOwner(userId))
|
||||
return true;
|
||||
|
||||
if (!pConfData.IsEnabled)
|
||||
return new();
|
||||
if (!_pConf.Data.IsEnabled)
|
||||
return true;
|
||||
|
||||
var patron = await GetPatronAsync(userId);
|
||||
var userLimit = await GetUserLimit(key, userId);
|
||||
|
||||
await using var ctx = _db.GetDbContext();
|
||||
var allPatronQuotas = await ctx.GetTable<PatronQuota>()
|
||||
.Where(x => x.UserId == userId)
|
||||
.ToListAsync();
|
||||
if (userLimit.Quota == 0)
|
||||
return false;
|
||||
|
||||
var allQuotasDict = allPatronQuotas
|
||||
.GroupBy(static x => x.FeatureType)
|
||||
.ToDictionary(static x => x.Key, static x => x.ToDictionary(static y => y.Feature));
|
||||
if (userLimit.Quota == -1)
|
||||
return true;
|
||||
|
||||
allQuotasDict.TryGetValue(FeatureType.Command, out var data);
|
||||
var userCommandQuotaStats = GetFeatureQuotaStats(patron.Tier, data, pConfData.Quotas.Commands);
|
||||
|
||||
allQuotasDict.TryGetValue(FeatureType.Group, out data);
|
||||
var userGroupQuotaStats = GetFeatureQuotaStats(patron.Tier, data, pConfData.Quotas.Groups);
|
||||
|
||||
allQuotasDict.TryGetValue(FeatureType.Module, out data);
|
||||
var userModuleQuotaStats = GetFeatureQuotaStats(patron.Tier, data, pConfData.Quotas.Modules);
|
||||
|
||||
return new UserQuotaStats()
|
||||
{
|
||||
Tier = patron.Tier,
|
||||
Commands = userCommandQuotaStats,
|
||||
Groups = userGroupQuotaStats,
|
||||
Modules = userModuleQuotaStats,
|
||||
};
|
||||
return await TryAddLimit(key, userLimit, userId, amount);
|
||||
}
|
||||
|
||||
private IReadOnlyDictionary<string, FeatureQuotaStats> GetFeatureQuotaStats(
|
||||
PatronTier patronTier,
|
||||
IReadOnlyDictionary<string, PatronQuota>? allQuotasDict,
|
||||
Dictionary<string, Dictionary<PatronTier, Dictionary<QuotaPer, uint>?>> commands)
|
||||
public async Task<bool> LimitForceHit(LimitedFeatureName key, ulong userId, int amount)
|
||||
{
|
||||
var userCommandQuotaStats = new Dictionary<string, FeatureQuotaStats>();
|
||||
foreach (var (key, quotaData) in commands)
|
||||
if (_creds.GetCreds().IsOwner(userId))
|
||||
return true;
|
||||
|
||||
if (!_pConf.Data.IsEnabled)
|
||||
return true;
|
||||
|
||||
var userLimit = await GetUserLimit(key, userId);
|
||||
|
||||
var cacheKey = CreateKey(key, userId);
|
||||
await _cache.GetOrAddAsync(cacheKey, () => Task.FromResult(0), GetExpiry(userLimit));
|
||||
|
||||
return await TryAddLimit(key, userLimit, userId, amount);
|
||||
}
|
||||
|
||||
private async Task<bool> TryAddLimit(
|
||||
LimitedFeatureName key,
|
||||
QuotaLimit userLimit,
|
||||
ulong userId,
|
||||
int amount)
|
||||
{
|
||||
var cacheKey = CreateKey(key, userId);
|
||||
var cur = await _cache.GetOrAddAsync(cacheKey, () => Task.FromResult(0), GetExpiry(userLimit));
|
||||
|
||||
if (cur + amount < userLimit.Quota)
|
||||
{
|
||||
if (TryGetTierDataOrLower(quotaData, patronTier, out var data))
|
||||
await _cache.AddAsync(cacheKey, cur + amount);
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private TimeSpan? GetExpiry(QuotaLimit userLimit)
|
||||
{
|
||||
var now = DateTime.UtcNow;
|
||||
switch (userLimit.QuotaPeriod)
|
||||
{
|
||||
case QuotaPer.PerHour:
|
||||
return TimeSpan.FromMinutes(60 - now.Minute);
|
||||
case QuotaPer.PerDay:
|
||||
return TimeSpan.FromMinutes((24 * 60) - ((now.Hour * 60) + now.Minute));
|
||||
case QuotaPer.PerMonth:
|
||||
var firstOfNextMonth = now.FirstOfNextMonth();
|
||||
return firstOfNextMonth - now;
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private TypedKey<int> CreateKey(LimitedFeatureName key, ulong userId)
|
||||
=> new($"limited_feature:{key}:{userId}");
|
||||
|
||||
private readonly QuotaLimit _emptyQuota = new QuotaLimit()
|
||||
{
|
||||
Quota = 0,
|
||||
QuotaPeriod = QuotaPer.PerDay,
|
||||
};
|
||||
|
||||
private readonly QuotaLimit _infiniteQuota = new QuotaLimit()
|
||||
{
|
||||
Quota = -1,
|
||||
QuotaPeriod = QuotaPer.PerDay,
|
||||
};
|
||||
|
||||
public async Task<QuotaLimit> GetUserLimit(LimitedFeatureName name, ulong userId)
|
||||
{
|
||||
if (!_pConf.Data.IsEnabled)
|
||||
return _infiniteQuota;
|
||||
|
||||
var maybePatron = await GetPatronAsync(userId);
|
||||
|
||||
if (maybePatron is not { } patron)
|
||||
return _emptyQuota;
|
||||
|
||||
if (patron.ValidThru < DateTime.UtcNow)
|
||||
return _emptyQuota;
|
||||
|
||||
foreach (var (key, value) in _pConf.Data.Limits)
|
||||
{
|
||||
if (patron.Amount >= key)
|
||||
{
|
||||
// if data is null that means the quota for the user's tier is unlimited
|
||||
// no point in returning it?
|
||||
|
||||
if (data is null)
|
||||
continue;
|
||||
|
||||
var (daily, hourly, monthly) = default((uint, uint, uint));
|
||||
// try to get users stats for this feature
|
||||
// if it fails just leave them at 0
|
||||
if (allQuotasDict?.TryGetValue(key, out var quota) ?? false)
|
||||
(daily, hourly, monthly) = (quota.DailyCount, quota.HourlyCount, quota.MonthlyCount);
|
||||
|
||||
userCommandQuotaStats[key] = new FeatureQuotaStats()
|
||||
if (value.TryGetValue(name, out var quotaLimit))
|
||||
{
|
||||
Hourly = data.TryGetValue(QuotaPer.PerHour, out var hourD)
|
||||
? (hourly, hourD)
|
||||
: default,
|
||||
Daily = data.TryGetValue(QuotaPer.PerDay, out var maxD)
|
||||
? (daily, maxD)
|
||||
: default,
|
||||
Monthly = data.TryGetValue(QuotaPer.PerMonth, out var maxM)
|
||||
? (monthly, maxM)
|
||||
: default,
|
||||
};
|
||||
return quotaLimit;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return userCommandQuotaStats;
|
||||
return _emptyQuota;
|
||||
}
|
||||
|
||||
public async Task<FeatureLimit> TryGetFeatureLimitAsync(FeatureLimitKey key, ulong userId, int? defaultValue)
|
||||
public async Task<Dictionary<LimitedFeatureName, (int, QuotaLimit)>> LimitStats(ulong userId)
|
||||
{
|
||||
var conf = _pConf.Data;
|
||||
|
||||
// if patron system is disabled, the quota is just default
|
||||
if (!conf.IsEnabled)
|
||||
return new()
|
||||
{
|
||||
Name = key.PrettyName,
|
||||
Quota = defaultValue,
|
||||
IsPatronLimit = false
|
||||
};
|
||||
|
||||
|
||||
if (!conf.Quotas.Features.TryGetValue(key.Key, out var data))
|
||||
return new()
|
||||
{
|
||||
Name = key.PrettyName,
|
||||
Quota = defaultValue,
|
||||
IsPatronLimit = false,
|
||||
};
|
||||
|
||||
var patron = await GetPatronAsync(userId);
|
||||
if (!TryGetTierDataOrLower(data, patron.Tier, out var limit))
|
||||
return new()
|
||||
{
|
||||
Name = key.PrettyName,
|
||||
Quota = 0,
|
||||
IsPatronLimit = true,
|
||||
};
|
||||
|
||||
return new()
|
||||
var dict = new Dictionary<LimitedFeatureName, (int, QuotaLimit)>();
|
||||
foreach (var featureName in Enum.GetValues<LimitedFeatureName>())
|
||||
{
|
||||
Name = key.PrettyName,
|
||||
Quota = limit,
|
||||
IsPatronLimit = true
|
||||
};
|
||||
var cacheKey = CreateKey(featureName, userId);
|
||||
var userLimit = await GetUserLimit(featureName, userId);
|
||||
var cur = await _cache.GetOrAddAsync(cacheKey, () => Task.FromResult(0), GetExpiry(userLimit));
|
||||
|
||||
dict[featureName] = (cur, userLimit);
|
||||
}
|
||||
|
||||
return dict;
|
||||
}
|
||||
|
||||
// public async Task<Patron> GiftPatronAsync(IUser user, int amount)
|
||||
// {
|
||||
// if (amount < 1)
|
||||
// throw new ArgumentOutOfRangeException(nameof(amount));
|
||||
//
|
||||
//
|
||||
// }
|
||||
|
||||
private Patron PatronUserToPatron(PatronUser user)
|
||||
=> new Patron()
|
||||
@@ -767,6 +401,22 @@ public sealed class PatronageService
|
||||
};
|
||||
}
|
||||
|
||||
public int PercentBonus(Patron? maybePatron)
|
||||
=> maybePatron is { } user && user.ValidThru > DateTime.UtcNow
|
||||
? PercentBonus(user.Amount)
|
||||
: 0;
|
||||
|
||||
public int PercentBonus(long amount)
|
||||
=> amount switch
|
||||
{
|
||||
>= 10_000 => 100,
|
||||
>= 5000 => 50,
|
||||
>= 2000 => 20,
|
||||
>= 1000 => 10,
|
||||
>= 500 => 5,
|
||||
_ => 0
|
||||
};
|
||||
|
||||
private async Task SendWelcomeMessage(Patron patron)
|
||||
{
|
||||
try
|
||||
@@ -776,28 +426,28 @@ public sealed class PatronageService
|
||||
return;
|
||||
|
||||
var eb = _sender.CreateEmbed()
|
||||
.WithOkColor()
|
||||
.WithTitle("❤️ Thank you for supporting NadekoBot! ❤️")
|
||||
.WithDescription(
|
||||
"Your donation has been processed and you will receive the rewards shortly.\n"
|
||||
+ "You can visit <https://www.patreon.com/join/nadekobot> to see rewards for your tier. 🎉")
|
||||
.AddField("Tier", Format.Bold(patron.Tier.ToString()), true)
|
||||
.AddField("Pledge", $"**{patron.Amount / 100.0f:N1}$**", true)
|
||||
.AddField("Expires",
|
||||
patron.ValidThru.AddDays(1).ToShortAndRelativeTimestampTag(),
|
||||
true)
|
||||
.AddField("Instructions",
|
||||
"""
|
||||
*- Within the next **1-2 minutes** you will have all of the benefits of the Tier you've subscribed to.*
|
||||
*- You can check your benefits on <https://www.patreon.com/join/nadekobot>*
|
||||
*- You can use the `.patron` command in this chat to check your current quota usage for the Patron-only commands*
|
||||
*- **ALL** of the servers that you **own** will enjoy your Patron benefits.*
|
||||
*- You can use any of the commands available in your tier on any server (assuming you have sufficient permissions to run those commands)*
|
||||
*- Any user in any of your servers can use Patron-only commands, but they will spend **your quota**, which is why it's recommended to use Nadeko's command cooldown system (.h .cmdcd) or permission system to limit the command usage for your server members.*
|
||||
*- Permission guide can be found here if you're not familiar with it: <https://nadekobot.readthedocs.io/en/latest/permissions-system/>*
|
||||
""",
|
||||
inline: false)
|
||||
.WithFooter($"platform id: {patron.UniquePlatformUserId}");
|
||||
.WithOkColor()
|
||||
.WithTitle("❤️ Thank you for supporting NadekoBot! ❤️")
|
||||
.WithDescription(
|
||||
"Your donation has been processed and you will receive the rewards shortly.\n"
|
||||
+ "You can visit <https://www.patreon.com/join/nadekobot> to see rewards for your tier. 🎉")
|
||||
.AddField("Tier", Format.Bold(patron.Tier.ToString()), true)
|
||||
.AddField("Pledge", $"**{patron.Amount / 100.0f:N1}$**", true)
|
||||
.AddField("Expires",
|
||||
patron.ValidThru.AddDays(1).ToShortAndRelativeTimestampTag(),
|
||||
true)
|
||||
.AddField("Instructions",
|
||||
"""
|
||||
*- Within the next **1-2 minutes** you will have all of the benefits of the Tier you've subscribed to.*
|
||||
*- You can check your benefits on <https://www.patreon.com/join/nadekobot>*
|
||||
*- You can use the `.patron` command in this chat to check your current quota usage for the Patron-only commands*
|
||||
*- **ALL** of the servers that you **own** will enjoy your Patron benefits.*
|
||||
*- You can use any of the commands available in your tier on any server (assuming you have sufficient permissions to run those commands)*
|
||||
*- Any user in any of your servers can use Patron-only commands, but they will spend **your quota**, which is why it's recommended to use Nadeko's command cooldown system (.h .cmdcd) or permission system to limit the command usage for your server members.*
|
||||
*- Permission guide can be found here if you're not familiar with it: <https://nadekobot.readthedocs.io/en/latest/permissions-system/>*
|
||||
""",
|
||||
inline: false)
|
||||
.WithFooter($"platform id: {patron.UniquePlatformUserId}");
|
||||
|
||||
await _sender.Response(user).Embed(eb).SendAsync();
|
||||
}
|
||||
|
@@ -1,6 +1,7 @@
|
||||
using AngleSharp;
|
||||
using CsvHelper;
|
||||
using CsvHelper.Configuration;
|
||||
using System.Diagnostics;
|
||||
using System.Globalization;
|
||||
using System.Text.Json;
|
||||
|
||||
@@ -22,46 +23,32 @@ public sealed class DefaultStockDataService : IStockDataService, INService
|
||||
|
||||
using var http = _httpClientFactory.CreateClient();
|
||||
|
||||
|
||||
|
||||
var quoteHtmlPage = $"https://finance.yahoo.com/quote/{query.ToUpperInvariant()}";
|
||||
|
||||
var config = Configuration.Default.WithDefaultLoader();
|
||||
using var document = await BrowsingContext.New(config).OpenAsync(quoteHtmlPage);
|
||||
var divElem =
|
||||
document.QuerySelector(
|
||||
"#quote-header-info > div:nth-child(2) > div > div > h1");
|
||||
var tickerName = (divElem)?.TextContent;
|
||||
|
||||
var tickerName = document.QuerySelector("div.top > .left > .container > h1")
|
||||
?.TextContent;
|
||||
|
||||
if (tickerName is null)
|
||||
return default;
|
||||
|
||||
var marketcap = document
|
||||
.QuerySelectorAll("table")
|
||||
.Skip(1)
|
||||
.First()
|
||||
.QuerySelector("tbody > tr > td:nth-child(2)")
|
||||
.QuerySelector("li > span > fin-streamer[data-field='marketCap']")
|
||||
?.TextContent;
|
||||
|
||||
|
||||
var volume = document.QuerySelector("td[data-test='AVERAGE_VOLUME_3MONTH-value']")
|
||||
var volume = document.QuerySelector("li > span > fin-streamer[data-field='regularMarketVolume']")
|
||||
?.TextContent;
|
||||
|
||||
var close= document.QuerySelector("td[data-test='PREV_CLOSE-value']")
|
||||
?.TextContent ?? "0";
|
||||
|
||||
var price = document
|
||||
.QuerySelector("#quote-header-info")
|
||||
?.QuerySelector("fin-streamer[data-field='regularMarketPrice']")
|
||||
?.TextContent ?? close;
|
||||
|
||||
// var data = await http.GetFromJsonAsync<YahooQueryModel>(
|
||||
// $"https://query1.finance.yahoo.com/v7/finance/quote?symbols={query}");
|
||||
//
|
||||
// if (data is null)
|
||||
// return default;
|
||||
|
||||
// var symbol = data.QuoteResponse.Result.FirstOrDefault();
|
||||
var close = document.QuerySelector("li > span > fin-streamer[data-field='regularMarketPreviousClose']")
|
||||
?.TextContent
|
||||
?? "0";
|
||||
|
||||
// if (symbol is null)
|
||||
// return default;
|
||||
var price = document.QuerySelector("fin-streamer.livePrice > span")
|
||||
?.TextContent
|
||||
?? "0";
|
||||
|
||||
return new()
|
||||
{
|
||||
|
@@ -1,5 +1,4 @@
|
||||
#nullable disable
|
||||
using CodeHollow.FeedReader;
|
||||
using CodeHollow.FeedReader;
|
||||
using NadekoBot.Modules.Searches.Services;
|
||||
using System.Text.RegularExpressions;
|
||||
|
||||
@@ -17,19 +16,21 @@ public partial class Searches
|
||||
[RequireContext(ContextType.Guild)]
|
||||
[UserPerm(GuildPerm.ManageMessages)]
|
||||
[Priority(1)]
|
||||
public Task YtUploadNotif(string url, [Leftover] string message = null)
|
||||
public Task YtUploadNotif(string url, [Leftover] string? message = null)
|
||||
=> YtUploadNotif(url, null, message);
|
||||
|
||||
[Cmd]
|
||||
[RequireContext(ContextType.Guild)]
|
||||
[UserPerm(GuildPerm.ManageMessages)]
|
||||
[Priority(2)]
|
||||
public Task YtUploadNotif(string url, ITextChannel channel = null, [Leftover] string message = null)
|
||||
public Task YtUploadNotif(string url, ITextChannel? channel = null, [Leftover] string? message = null)
|
||||
{
|
||||
var m = _ytChannelRegex.Match(url);
|
||||
if (!m.Success)
|
||||
return Response().Error(strs.invalid_input).SendAsync();
|
||||
|
||||
channel ??= ctx.Channel as ITextChannel;
|
||||
|
||||
if (!((IGuildUser)ctx.User).GetPermissions(channel).MentionEveryone)
|
||||
message = message?.SanitizeAllMentions();
|
||||
|
||||
@@ -42,7 +43,7 @@ public partial class Searches
|
||||
[RequireContext(ContextType.Guild)]
|
||||
[UserPerm(GuildPerm.ManageMessages)]
|
||||
[Priority(0)]
|
||||
public Task Feed(string url, [Leftover] string message = null)
|
||||
public Task Feed(string url, [Leftover] string? message = null)
|
||||
=> Feed(url, null, message);
|
||||
|
||||
|
||||
@@ -50,7 +51,7 @@ public partial class Searches
|
||||
[RequireContext(ContextType.Guild)]
|
||||
[UserPerm(GuildPerm.ManageMessages)]
|
||||
[Priority(1)]
|
||||
public async Task Feed(string url, ITextChannel channel = null, [Leftover] string message = null)
|
||||
public async Task Feed(string url, ITextChannel? channel = null, [Leftover] string? message = null)
|
||||
{
|
||||
if (!Uri.TryCreate(url, UriKind.Absolute, out var uri)
|
||||
|| (uri.Scheme != Uri.UriSchemeHttp && uri.Scheme != Uri.UriSchemeHttps))
|
||||
@@ -59,10 +60,11 @@ public partial class Searches
|
||||
return;
|
||||
}
|
||||
|
||||
channel ??= (ITextChannel)ctx.Channel;
|
||||
|
||||
if (!((IGuildUser)ctx.User).GetPermissions(channel).MentionEveryone)
|
||||
message = message?.SanitizeAllMentions();
|
||||
|
||||
channel ??= (ITextChannel)ctx.Channel;
|
||||
try
|
||||
{
|
||||
await FeedReader.ReadAsync(url);
|
||||
|
@@ -79,6 +79,15 @@ public class FeedsService : INService
|
||||
}
|
||||
}
|
||||
|
||||
private DateTime? GetPubDate(FeedItem item)
|
||||
{
|
||||
if (item.PublishingDate is not null)
|
||||
return item.PublishingDate;
|
||||
if (item.SpecificItem is AtomFeedItem atomItem)
|
||||
return atomItem.UpdatedDate;
|
||||
return null;
|
||||
}
|
||||
|
||||
public async Task<EmbedBuilder> TrackFeeds()
|
||||
{
|
||||
while (true)
|
||||
@@ -94,24 +103,32 @@ public class FeedsService : INService
|
||||
{
|
||||
var feed = await FeedReader.ReadAsync(rssUrl);
|
||||
|
||||
var items = feed
|
||||
.Items.Select(item => (Item: item,
|
||||
LastUpdate: item.PublishingDate?.ToUniversalTime()
|
||||
?? (item.SpecificItem as AtomFeedItem)?.UpdatedDate?.ToUniversalTime()))
|
||||
.Where(data => data.LastUpdate is not null)
|
||||
.Select(data => (data.Item, LastUpdate: (DateTime)data.LastUpdate))
|
||||
.OrderByDescending(data => data.LastUpdate)
|
||||
.Reverse() // start from the oldest
|
||||
.ToList();
|
||||
var items = new List<(FeedItem Item, DateTime LastUpdate)>();
|
||||
foreach (var item in feed.Items)
|
||||
{
|
||||
var pubDate = GetPubDate(item);
|
||||
|
||||
if (pubDate is null)
|
||||
continue;
|
||||
|
||||
items.Add((item, pubDate.Value.ToUniversalTime()));
|
||||
|
||||
// show at most 3 items if you're behind
|
||||
if (items.Count > 2)
|
||||
break;
|
||||
}
|
||||
|
||||
if (items.Count == 0)
|
||||
continue;
|
||||
|
||||
if (!_lastPosts.TryGetValue(kvp.Key, out var lastFeedUpdate))
|
||||
{
|
||||
lastFeedUpdate = _lastPosts[kvp.Key] =
|
||||
items.Any() ? items[items.Count - 1].LastUpdate : DateTime.UtcNow;
|
||||
lastFeedUpdate = _lastPosts[kvp.Key] = items[0].LastUpdate;
|
||||
}
|
||||
|
||||
foreach (var (feedItem, itemUpdateDate) in items)
|
||||
for (var index = 1; index <= items.Count; index++)
|
||||
{
|
||||
var (feedItem, itemUpdateDate) = items[^index];
|
||||
if (itemUpdateDate <= lastFeedUpdate)
|
||||
continue;
|
||||
|
||||
@@ -168,27 +185,26 @@ public class FeedsService : INService
|
||||
if (!string.IsNullOrWhiteSpace(feedItem.Description))
|
||||
embed.WithDescription(desc.TrimTo(2048));
|
||||
|
||||
//send the created embed to all subscribed channels
|
||||
var feedSendTasks = kvp.Value
|
||||
.Where(x => x.GuildConfig is not null)
|
||||
.Select(x =>
|
||||
{
|
||||
var ch = _client.GetGuild(x.GuildConfig.GuildId)
|
||||
?.GetTextChannel(x.ChannelId);
|
||||
|
||||
if (ch is null)
|
||||
return null;
|
||||
var tasks = new List<Task>();
|
||||
|
||||
return _sender.Response(ch)
|
||||
.Embed(embed)
|
||||
.Text(string.IsNullOrWhiteSpace(x.Message)
|
||||
? string.Empty
|
||||
: x.Message)
|
||||
.SendAsync();
|
||||
})
|
||||
.Where(x => x is not null);
|
||||
foreach (var val in kvp.Value)
|
||||
{
|
||||
var ch = _client.GetGuild(val.GuildConfig.GuildId).GetTextChannel(val.ChannelId);
|
||||
|
||||
allSendTasks.Add(feedSendTasks.WhenAll());
|
||||
if (ch is null)
|
||||
continue;
|
||||
|
||||
var sendTask = _sender.Response(ch)
|
||||
.Embed(embed)
|
||||
.Text(string.IsNullOrWhiteSpace(val.Message)
|
||||
? string.Empty
|
||||
: val.Message)
|
||||
.SendAsync();
|
||||
tasks.Add(sendTask);
|
||||
}
|
||||
|
||||
allSendTasks.Add(tasks.WhenAll());
|
||||
|
||||
// as data retrieval was successful, reset error counter
|
||||
ClearErrors(rssUrl);
|
||||
|
@@ -1,312 +0,0 @@
|
||||
#nullable disable
|
||||
using NadekoBot.Modules.Searches.Common;
|
||||
using NadekoBot.Modules.Searches.Services;
|
||||
using Newtonsoft.Json;
|
||||
using Newtonsoft.Json.Linq;
|
||||
using System.Globalization;
|
||||
using System.Text;
|
||||
|
||||
namespace NadekoBot.Modules.Searches;
|
||||
|
||||
public partial class Searches
|
||||
{
|
||||
[Group]
|
||||
public partial class PathOfExileCommands : NadekoModule<SearchesService>
|
||||
{
|
||||
private const string POE_URL = "https://www.pathofexile.com/character-window/get-characters?accountName=";
|
||||
private const string PON_URL = "http://poe.ninja/api/Data/GetCurrencyOverview?league=";
|
||||
private const string POGS_URL = "http://pathofexile.gamepedia.com/api.php?action=opensearch&search=";
|
||||
|
||||
private const string POG_URL =
|
||||
"https://pathofexile.gamepedia.com/api.php?action=browsebysubject&format=json&subject=";
|
||||
|
||||
private const string POGI_URL =
|
||||
"https://pathofexile.gamepedia.com/api.php?action=query&prop=imageinfo&iiprop=url&format=json&titles=File:";
|
||||
|
||||
private const string PROFILE_URL = "https://www.pathofexile.com/account/view-profile/";
|
||||
|
||||
private readonly IHttpClientFactory _httpFactory;
|
||||
|
||||
private Dictionary<string, string> currencyDictionary = new(StringComparer.OrdinalIgnoreCase)
|
||||
{
|
||||
{ "Chaos Orb", "Chaos Orb" },
|
||||
{ "Orb of Alchemy", "Orb of Alchemy" },
|
||||
{ "Jeweller's Orb", "Jeweller's Orb" },
|
||||
{ "Exalted Orb", "Exalted Orb" },
|
||||
{ "Mirror of Kalandra", "Mirror of Kalandra" },
|
||||
{ "Vaal Orb", "Vaal Orb" },
|
||||
{ "Orb of Alteration", "Orb of Alteration" },
|
||||
{ "Orb of Scouring", "Orb of Scouring" },
|
||||
{ "Divine Orb", "Divine Orb" },
|
||||
{ "Orb of Annulment", "Orb of Annulment" },
|
||||
{ "Master Cartographer's Sextant", "Master Cartographer's Sextant" },
|
||||
{ "Journeyman Cartographer's Sextant", "Journeyman Cartographer's Sextant" },
|
||||
{ "Apprentice Cartographer's Sextant", "Apprentice Cartographer's Sextant" },
|
||||
{ "Blessed Orb", "Blessed Orb" },
|
||||
{ "Orb of Regret", "Orb of Regret" },
|
||||
{ "Gemcutter's Prism", "Gemcutter's Prism" },
|
||||
{ "Glassblower's Bauble", "Glassblower's Bauble" },
|
||||
{ "Orb of Fusing", "Orb of Fusing" },
|
||||
{ "Cartographer's Chisel", "Cartographer's Chisel" },
|
||||
{ "Chromatic Orb", "Chromatic Orb" },
|
||||
{ "Orb of Augmentation", "Orb of Augmentation" },
|
||||
{ "Blacksmith's Whetstone", "Blacksmith's Whetstone" },
|
||||
{ "Orb of Transmutation", "Orb of Transmutation" },
|
||||
{ "Armourer's Scrap", "Armourer's Scrap" },
|
||||
{ "Scroll of Wisdom", "Scroll of Wisdom" },
|
||||
{ "Regal Orb", "Regal Orb" },
|
||||
{ "Chaos", "Chaos Orb" },
|
||||
{ "Alch", "Orb of Alchemy" },
|
||||
{ "Alchs", "Orb of Alchemy" },
|
||||
{ "Jews", "Jeweller's Orb" },
|
||||
{ "Jeweller", "Jeweller's Orb" },
|
||||
{ "Jewellers", "Jeweller's Orb" },
|
||||
{ "Jeweller's", "Jeweller's Orb" },
|
||||
{ "X", "Exalted Orb" },
|
||||
{ "Ex", "Exalted Orb" },
|
||||
{ "Exalt", "Exalted Orb" },
|
||||
{ "Exalts", "Exalted Orb" },
|
||||
{ "Mirror", "Mirror of Kalandra" },
|
||||
{ "Mirrors", "Mirror of Kalandra" },
|
||||
{ "Vaal", "Vaal Orb" },
|
||||
{ "Alt", "Orb of Alteration" },
|
||||
{ "Alts", "Orb of Alteration" },
|
||||
{ "Scour", "Orb of Scouring" },
|
||||
{ "Scours", "Orb of Scouring" },
|
||||
{ "Divine", "Divine Orb" },
|
||||
{ "Annul", "Orb of Annulment" },
|
||||
{ "Annulment", "Orb of Annulment" },
|
||||
{ "Master Sextant", "Master Cartographer's Sextant" },
|
||||
{ "Journeyman Sextant", "Journeyman Cartographer's Sextant" },
|
||||
{ "Apprentice Sextant", "Apprentice Cartographer's Sextant" },
|
||||
{ "Blessed", "Blessed Orb" },
|
||||
{ "Regret", "Orb of Regret" },
|
||||
{ "Regrets", "Orb of Regret" },
|
||||
{ "Gcp", "Gemcutter's Prism" },
|
||||
{ "Glassblowers", "Glassblower's Bauble" },
|
||||
{ "Glassblower's", "Glassblower's Bauble" },
|
||||
{ "Fusing", "Orb of Fusing" },
|
||||
{ "Fuses", "Orb of Fusing" },
|
||||
{ "Fuse", "Orb of Fusing" },
|
||||
{ "Chisel", "Cartographer's Chisel" },
|
||||
{ "Chisels", "Cartographer's Chisel" },
|
||||
{ "Chance", "Orb of Chance" },
|
||||
{ "Chances", "Orb of Chance" },
|
||||
{ "Chrome", "Chromatic Orb" },
|
||||
{ "Chromes", "Chromatic Orb" },
|
||||
{ "Aug", "Orb of Augmentation" },
|
||||
{ "Augmentation", "Orb of Augmentation" },
|
||||
{ "Augment", "Orb of Augmentation" },
|
||||
{ "Augments", "Orb of Augmentation" },
|
||||
{ "Whetstone", "Blacksmith's Whetstone" },
|
||||
{ "Whetstones", "Blacksmith's Whetstone" },
|
||||
{ "Transmute", "Orb of Transmutation" },
|
||||
{ "Transmutes", "Orb of Transmutation" },
|
||||
{ "Armourers", "Armourer's Scrap" },
|
||||
{ "Armourer's", "Armourer's Scrap" },
|
||||
{ "Wisdom Scroll", "Scroll of Wisdom" },
|
||||
{ "Wisdom Scrolls", "Scroll of Wisdom" },
|
||||
{ "Regal", "Regal Orb" },
|
||||
{ "Regals", "Regal Orb" }
|
||||
};
|
||||
|
||||
public PathOfExileCommands(IHttpClientFactory httpFactory)
|
||||
=> _httpFactory = httpFactory;
|
||||
|
||||
[Cmd]
|
||||
public async Task PathOfExile(string usr, string league = "", int page = 1)
|
||||
{
|
||||
if (--page < 0)
|
||||
return;
|
||||
|
||||
if (string.IsNullOrWhiteSpace(usr))
|
||||
{
|
||||
await Response().Error("Please provide an account name.").SendAsync();
|
||||
return;
|
||||
}
|
||||
|
||||
var characters = new List<Account>();
|
||||
|
||||
try
|
||||
{
|
||||
using var http = _httpFactory.CreateClient();
|
||||
var res = await http.GetStringAsync($"{POE_URL}{usr}");
|
||||
characters = JsonConvert.DeserializeObject<List<Account>>(res);
|
||||
}
|
||||
catch
|
||||
{
|
||||
var embed = _sender.CreateEmbed().WithDescription(GetText(strs.account_not_found)).WithErrorColor();
|
||||
|
||||
await Response().Embed(embed).SendAsync();
|
||||
return;
|
||||
}
|
||||
|
||||
if (!string.IsNullOrWhiteSpace(league))
|
||||
characters.RemoveAll(c => c.League != league);
|
||||
|
||||
await Response()
|
||||
.Paginated()
|
||||
.Items(characters)
|
||||
.PageSize(9)
|
||||
.CurrentPage(page)
|
||||
.Page((items, curPage) =>
|
||||
{
|
||||
var embed = _sender.CreateEmbed()
|
||||
.WithAuthor($"Characters on {usr}'s account",
|
||||
"https://web.poecdn.com/image/favicon/ogimage.png",
|
||||
$"{PROFILE_URL}{usr}")
|
||||
.WithOkColor();
|
||||
|
||||
if (characters.Count == 0)
|
||||
return embed.WithDescription("This account has no characters.");
|
||||
|
||||
var sb = new StringBuilder();
|
||||
sb.AppendLine($"```{"#",-5}{"Character Name",-23}{"League",-10}{"Class",-13}{"Level",-3}");
|
||||
for (var i = 0; i < items.Count; i++)
|
||||
{
|
||||
var character = items[i];
|
||||
|
||||
sb.AppendLine(
|
||||
$"#{i + 1 + (curPage * 9),-4}{character.Name,-23}{ShortLeagueName(character.League),-10}{character.Class,-13}{character.Level,-3}");
|
||||
}
|
||||
|
||||
sb.AppendLine("```");
|
||||
embed.WithDescription(sb.ToString());
|
||||
|
||||
return embed;
|
||||
})
|
||||
.SendAsync();
|
||||
}
|
||||
|
||||
[Cmd]
|
||||
public async Task PathOfExileLeagues()
|
||||
{
|
||||
var leagues = new List<Leagues>();
|
||||
|
||||
try
|
||||
{
|
||||
using var http = _httpFactory.CreateClient();
|
||||
var res = await http.GetStringAsync("http://api.pathofexile.com/leagues?type=main&compact=1");
|
||||
leagues = JsonConvert.DeserializeObject<List<Leagues>>(res);
|
||||
}
|
||||
catch
|
||||
{
|
||||
var eembed = _sender.CreateEmbed().WithDescription(GetText(strs.leagues_not_found)).WithErrorColor();
|
||||
|
||||
await Response().Embed(eembed).SendAsync();
|
||||
return;
|
||||
}
|
||||
|
||||
var embed = _sender.CreateEmbed()
|
||||
.WithAuthor("Path of Exile Leagues",
|
||||
"https://web.poecdn.com/image/favicon/ogimage.png",
|
||||
"https://www.pathofexile.com")
|
||||
.WithOkColor();
|
||||
|
||||
var sb = new StringBuilder();
|
||||
sb.AppendLine($"```{"#",-5}{"League Name",-23}");
|
||||
for (var i = 0; i < leagues.Count; i++)
|
||||
{
|
||||
var league = leagues[i];
|
||||
|
||||
sb.AppendLine($"#{i + 1,-4}{league.Id,-23}");
|
||||
}
|
||||
|
||||
sb.AppendLine("```");
|
||||
|
||||
embed.WithDescription(sb.ToString());
|
||||
|
||||
await Response().Embed(embed).SendAsync();
|
||||
}
|
||||
|
||||
[Cmd]
|
||||
public async Task PathOfExileCurrency(
|
||||
string leagueName,
|
||||
string currencyName,
|
||||
string convertName = "Chaos Orb")
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(leagueName))
|
||||
{
|
||||
await Response().Error("Please provide league name.").SendAsync();
|
||||
return;
|
||||
}
|
||||
|
||||
if (string.IsNullOrWhiteSpace(currencyName))
|
||||
{
|
||||
await Response().Error("Please provide currency name.").SendAsync();
|
||||
return;
|
||||
}
|
||||
|
||||
var cleanCurrency = ShortCurrencyName(currencyName);
|
||||
var cleanConvert = ShortCurrencyName(convertName);
|
||||
|
||||
try
|
||||
{
|
||||
var res = $"{PON_URL}{leagueName}";
|
||||
using var http = _httpFactory.CreateClient();
|
||||
var obj = JObject.Parse(await http.GetStringAsync(res));
|
||||
|
||||
var chaosEquivalent = 0.0F;
|
||||
var conversionEquivalent = 0.0F;
|
||||
|
||||
// poe.ninja API does not include a "chaosEquivalent" property for Chaos Orbs.
|
||||
if (cleanCurrency == "Chaos Orb")
|
||||
chaosEquivalent = 1.0F;
|
||||
else
|
||||
{
|
||||
var currencyInput = obj["lines"]
|
||||
.Values<JObject>()
|
||||
.Where(i => i["currencyTypeName"].Value<string>() == cleanCurrency)
|
||||
.FirstOrDefault();
|
||||
chaosEquivalent = float.Parse(currencyInput["chaosEquivalent"].ToString(),
|
||||
CultureInfo.InvariantCulture);
|
||||
}
|
||||
|
||||
if (cleanConvert == "Chaos Orb")
|
||||
conversionEquivalent = 1.0F;
|
||||
else
|
||||
{
|
||||
var currencyOutput = obj["lines"]
|
||||
.Values<JObject>()
|
||||
.Where(i => i["currencyTypeName"].Value<string>() == cleanConvert)
|
||||
.FirstOrDefault();
|
||||
conversionEquivalent = float.Parse(currencyOutput["chaosEquivalent"].ToString(),
|
||||
CultureInfo.InvariantCulture);
|
||||
}
|
||||
|
||||
var embed = _sender.CreateEmbed()
|
||||
.WithAuthor($"{leagueName} Currency Exchange",
|
||||
"https://web.poecdn.com/image/favicon/ogimage.png",
|
||||
"http://poe.ninja")
|
||||
.AddField("Currency Type", cleanCurrency, true)
|
||||
.AddField($"{cleanConvert} Equivalent", chaosEquivalent / conversionEquivalent, true)
|
||||
.WithOkColor();
|
||||
|
||||
await Response().Embed(embed).SendAsync();
|
||||
}
|
||||
catch
|
||||
{
|
||||
var embed = _sender.CreateEmbed().WithDescription(GetText(strs.ninja_not_found)).WithErrorColor();
|
||||
|
||||
await Response().Embed(embed).SendAsync();
|
||||
}
|
||||
}
|
||||
|
||||
private string ShortCurrencyName(string str)
|
||||
{
|
||||
if (currencyDictionary.ContainsValue(str))
|
||||
return str;
|
||||
|
||||
var currency = currencyDictionary[str];
|
||||
|
||||
return currency;
|
||||
}
|
||||
|
||||
private static string ShortLeagueName(string str)
|
||||
{
|
||||
var league = str.Replace("Hardcore", "HC", StringComparison.InvariantCultureIgnoreCase);
|
||||
|
||||
return league;
|
||||
}
|
||||
}
|
||||
}
|
@@ -2,6 +2,7 @@
|
||||
using Microsoft.Extensions.Caching.Memory;
|
||||
using NadekoBot.Modules.Searches.Common;
|
||||
using NadekoBot.Modules.Searches.Services;
|
||||
using NadekoBot.Modules.Utility;
|
||||
using Newtonsoft.Json;
|
||||
using Newtonsoft.Json.Linq;
|
||||
using SixLabors.ImageSharp;
|
||||
@@ -168,7 +169,7 @@ public partial class Searches : NadekoModule<SearchesService>
|
||||
.AddField("Rating", movie.ImdbRating, true)
|
||||
.AddField("Genre", movie.Genre, true)
|
||||
.AddField("Year", movie.Year, true)
|
||||
.WithImageUrl(movie.Poster))
|
||||
.WithImageUrl(Uri.IsWellFormedUriString(movie.Poster, UriKind.Absolute) ? movie.Poster : null))
|
||||
.SendAsync();
|
||||
}
|
||||
|
||||
|
314
src/NadekoBot/Modules/Utility/Ai/AiAssistantService.cs
Normal file
314
src/NadekoBot/Modules/Utility/Ai/AiAssistantService.cs
Normal file
@@ -0,0 +1,314 @@
|
||||
using NadekoBot.Common.ModuleBehaviors;
|
||||
using NadekoBot.Modules.Administration;
|
||||
using NadekoBot.Modules.Games.Services;
|
||||
using System.Net;
|
||||
using System.Net.Http.Json;
|
||||
using System.Text;
|
||||
using System.Text.Json;
|
||||
using JsonSerializer = System.Text.Json.JsonSerializer;
|
||||
|
||||
namespace NadekoBot.Modules.Utility;
|
||||
|
||||
public enum GetCommandErrorResult
|
||||
{
|
||||
RateLimitHit,
|
||||
NotAuthorized,
|
||||
Disregard,
|
||||
Unknown
|
||||
}
|
||||
|
||||
public sealed class AiAssistantService
|
||||
: IAiAssistantService, IReadyExecutor,
|
||||
IExecOnMessage,
|
||||
INService
|
||||
{
|
||||
private IReadOnlyCollection<AiCommandModel> _commands = [];
|
||||
|
||||
private readonly IBotStrings _strings;
|
||||
private readonly IHttpClientFactory _httpFactory;
|
||||
private readonly CommandService _cmds;
|
||||
private readonly IBotCredsProvider _credsProvider;
|
||||
private readonly DiscordSocketClient _client;
|
||||
private readonly ICommandHandler _cmdHandler;
|
||||
private readonly BotConfigService _bcs;
|
||||
private readonly IMessageSenderService _sender;
|
||||
|
||||
private readonly JsonSerializerOptions _serializerOptions = new();
|
||||
private readonly IPermissionChecker _permChecker;
|
||||
private readonly IBotCache _botCache;
|
||||
private readonly ChatterBotService _cbs;
|
||||
|
||||
public AiAssistantService(
|
||||
DiscordSocketClient client,
|
||||
IBotStrings strings,
|
||||
IHttpClientFactory httpFactory,
|
||||
CommandService cmds,
|
||||
IBotCredsProvider credsProvider,
|
||||
ICommandHandler cmdHandler,
|
||||
BotConfigService bcs,
|
||||
IPermissionChecker permChecker,
|
||||
IBotCache botCache,
|
||||
ChatterBotService cbs,
|
||||
IMessageSenderService sender)
|
||||
{
|
||||
_client = client;
|
||||
_strings = strings;
|
||||
_httpFactory = httpFactory;
|
||||
_cmds = cmds;
|
||||
_credsProvider = credsProvider;
|
||||
_cmdHandler = cmdHandler;
|
||||
_bcs = bcs;
|
||||
_sender = sender;
|
||||
_permChecker = permChecker;
|
||||
_botCache = botCache;
|
||||
_cbs = cbs;
|
||||
}
|
||||
|
||||
public async Task<OneOf.OneOf<NadekoCommandCallModel, GetCommandErrorResult>> TryGetCommandAsync(
|
||||
ulong userId,
|
||||
string prompt,
|
||||
IReadOnlyCollection<AiCommandModel> commands,
|
||||
string prefix)
|
||||
{
|
||||
using var content = new StringContent(
|
||||
JsonSerializer.Serialize(new
|
||||
{
|
||||
query = prompt,
|
||||
commands = commands.ToDictionary(x => x.Name,
|
||||
x => new AiCommandModel()
|
||||
{
|
||||
Desc = string.Format(x.Desc ?? "", prefix),
|
||||
Params = x.Params,
|
||||
Name = x.Name
|
||||
}),
|
||||
}),
|
||||
Encoding.UTF8,
|
||||
"application/json"
|
||||
);
|
||||
|
||||
using var request = new HttpRequestMessage();
|
||||
request.Method = HttpMethod.Post;
|
||||
// request.RequestUri = new("https://nai.nadeko.bot/get-command");
|
||||
request.RequestUri = new("https://nai.nadeko.bot/get-command");
|
||||
request.Content = content;
|
||||
|
||||
var creds = _credsProvider.GetCreds();
|
||||
|
||||
request.Headers.TryAddWithoutValidation("x-auth-token", creds.NadekoAiToken);
|
||||
request.Headers.TryAddWithoutValidation("x-auth-userid", userId.ToString());
|
||||
|
||||
|
||||
using var client = _httpFactory.CreateClient();
|
||||
|
||||
// todo customize according to the bot's config
|
||||
// - CurrencyName
|
||||
// -
|
||||
|
||||
using var response = await client.SendAsync(request);
|
||||
|
||||
if (response.StatusCode == HttpStatusCode.TooManyRequests)
|
||||
{
|
||||
return GetCommandErrorResult.RateLimitHit;
|
||||
}
|
||||
else if (response.StatusCode == HttpStatusCode.Unauthorized)
|
||||
{
|
||||
return GetCommandErrorResult.NotAuthorized;
|
||||
}
|
||||
|
||||
var funcModel = await response.Content.ReadFromJsonAsync<CommandPromptResultModel>();
|
||||
|
||||
|
||||
if (funcModel?.Name == "disregard")
|
||||
{
|
||||
Log.Warning("Disregarding the prompt: {Prompt}", prompt);
|
||||
return GetCommandErrorResult.Disregard;
|
||||
}
|
||||
|
||||
if (funcModel is null)
|
||||
return GetCommandErrorResult.Unknown;
|
||||
|
||||
var comModel = new NadekoCommandCallModel()
|
||||
{
|
||||
Name = funcModel.Name,
|
||||
Arguments = funcModel.Arguments
|
||||
.OrderBy(param => _commands.FirstOrDefault(x => x.Name == funcModel.Name)
|
||||
?.Params
|
||||
.Select((x, i) => (x, i))
|
||||
.Where(x => x.x.Name == param.Key)
|
||||
.Select(x => x.i)
|
||||
.FirstOrDefault())
|
||||
.Select(x => x.Value)
|
||||
.Where(x => !string.IsNullOrWhiteSpace(x))
|
||||
.ToArray(),
|
||||
Remaining = funcModel.Remaining
|
||||
};
|
||||
|
||||
return comModel;
|
||||
}
|
||||
|
||||
public IReadOnlyCollection<AiCommandModel> GetCommands()
|
||||
=> _commands;
|
||||
|
||||
public Task OnReadyAsync()
|
||||
{
|
||||
var cmds = _cmds.Commands
|
||||
.Select(x => (MethodName: x.Summary, CommandName: x.Aliases[0]))
|
||||
.Where(x => !x.MethodName.Contains("///"))
|
||||
.Distinct()
|
||||
.ToList();
|
||||
|
||||
var funcs = new List<AiCommandModel>();
|
||||
foreach (var (method, cmd) in cmds)
|
||||
{
|
||||
var commandStrings = _strings.GetCommandStrings(method);
|
||||
|
||||
if (commandStrings is null)
|
||||
continue;
|
||||
|
||||
funcs.Add(new()
|
||||
{
|
||||
Name = cmd,
|
||||
Desc = commandStrings?.Desc?.Replace("currency", "flowers") ?? string.Empty,
|
||||
Params = commandStrings?.Params.FirstOrDefault()
|
||||
?.Select(x => new AiCommandParamModel()
|
||||
{
|
||||
Desc = x.Value.Desc,
|
||||
Name = x.Key,
|
||||
})
|
||||
.ToArray()
|
||||
?? []
|
||||
});
|
||||
}
|
||||
|
||||
_commands = funcs;
|
||||
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
public int Priority
|
||||
=> 2;
|
||||
|
||||
public async Task<bool> ExecOnMessageAsync(IGuild guild, IUserMessage msg)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(_credsProvider.GetCreds().NadekoAiToken))
|
||||
return false;
|
||||
|
||||
if (guild is not SocketGuild sg)
|
||||
return false;
|
||||
|
||||
var nadekoId = _client.CurrentUser.Id;
|
||||
|
||||
var channel = msg.Channel as ITextChannel;
|
||||
if (channel is null)
|
||||
return false;
|
||||
|
||||
var normalMention = $"<@{nadekoId}> ";
|
||||
var nickMention = $"<@!{nadekoId}> ";
|
||||
string query;
|
||||
if (msg.Content.StartsWith(normalMention, StringComparison.InvariantCulture))
|
||||
query = msg.Content[normalMention.Length..].Trim();
|
||||
else if (msg.Content.StartsWith(nickMention, StringComparison.InvariantCulture))
|
||||
query = msg.Content[nickMention.Length..].Trim();
|
||||
else
|
||||
return false;
|
||||
|
||||
var success = await TryExecuteAiCommand(guild, msg, channel, query);
|
||||
|
||||
return success;
|
||||
}
|
||||
|
||||
public async Task<bool> TryExecuteAiCommand(
|
||||
IGuild guild,
|
||||
IUserMessage msg,
|
||||
ITextChannel channel,
|
||||
string query)
|
||||
{
|
||||
// check permissions
|
||||
var pcResult = await _permChecker.CheckPermsAsync(
|
||||
guild,
|
||||
msg.Channel,
|
||||
msg.Author,
|
||||
"Utility",
|
||||
"prompt"
|
||||
);
|
||||
|
||||
if (!pcResult.IsAllowed)
|
||||
return false;
|
||||
|
||||
using var _ = channel.EnterTypingState();
|
||||
|
||||
var result = await TryGetCommandAsync(msg.Author.Id, query, _commands, _cmdHandler.GetPrefix(guild.Id));
|
||||
|
||||
if (result.TryPickT0(out var model, out var error))
|
||||
{
|
||||
if (model.Name == ".ai_chat")
|
||||
{
|
||||
if (guild is not SocketGuild sg)
|
||||
return false;
|
||||
|
||||
var sess = _cbs.GetOrCreateSession(guild.Id);
|
||||
if (sess is null)
|
||||
return false;
|
||||
|
||||
await _cbs.RunChatterBot(sg, msg, channel, sess, query);
|
||||
return false;
|
||||
}
|
||||
|
||||
var commandString = GetCommandString(model);
|
||||
|
||||
var msgTask = _sender.Response(channel)
|
||||
.Embed(_sender.CreateEmbed()
|
||||
.WithOkColor()
|
||||
.WithAuthor(msg.Author.GlobalName,
|
||||
msg.Author.RealAvatarUrl().ToString())
|
||||
.WithDescription(commandString))
|
||||
.SendAsync();
|
||||
|
||||
|
||||
await _cmdHandler.TryRunCommand(
|
||||
(SocketGuild)guild,
|
||||
(ISocketMessageChannel)channel,
|
||||
new DoAsUserMessage((SocketUserMessage)msg, msg.Author, commandString));
|
||||
|
||||
var cmdMsg = await msgTask;
|
||||
|
||||
cmdMsg.DeleteAfter(5);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
if (error == GetCommandErrorResult.Disregard)
|
||||
{
|
||||
// await msg.ErrorAsync();
|
||||
return false;
|
||||
}
|
||||
|
||||
var key = new TypedKey<bool>($"sub_error:{msg.Author.Id}:{error}");
|
||||
|
||||
if (!await _botCache.AddAsync(key, true, TimeSpan.FromDays(1), overwrite: false))
|
||||
return false;
|
||||
|
||||
var errorMsg = error switch
|
||||
{
|
||||
GetCommandErrorResult.RateLimitHit
|
||||
=> "You've spent your daily requests quota.",
|
||||
GetCommandErrorResult.NotAuthorized
|
||||
=> "In order to use this command you have to have a 5$ or higher subscription at <https://patreon.com/nadekobot>",
|
||||
GetCommandErrorResult.Unknown
|
||||
=> "The service is temporarily unavailable.",
|
||||
_ => throw new ArgumentOutOfRangeException()
|
||||
};
|
||||
|
||||
await _sender.Response(channel)
|
||||
.Error(errorMsg)
|
||||
.SendAsync();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private string GetCommandString(NadekoCommandCallModel res)
|
||||
=> $"{_bcs.Data.Prefix}{res.Name} {res.Arguments.Select((x, i) => GetParamString(x, i + 1 == res.Arguments.Count)).Join(" ")}";
|
||||
|
||||
private static string GetParamString(string val, bool isLast)
|
||||
=> isLast ? val : "\"" + val + "\"";
|
||||
}
|
15
src/NadekoBot/Modules/Utility/Ai/AiCommandModel.cs
Normal file
15
src/NadekoBot/Modules/Utility/Ai/AiCommandModel.cs
Normal file
@@ -0,0 +1,15 @@
|
||||
using System.Text.Json.Serialization;
|
||||
|
||||
namespace NadekoBot.Modules.Utility;
|
||||
|
||||
public sealed class AiCommandModel
|
||||
{
|
||||
[JsonPropertyName("name")]
|
||||
public required string Name { get; set; }
|
||||
|
||||
[JsonPropertyName("desc")]
|
||||
public required string Desc { get; set; }
|
||||
|
||||
[JsonPropertyName("params")]
|
||||
public required IReadOnlyList<AiCommandParamModel> Params { get; set; }
|
||||
}
|
12
src/NadekoBot/Modules/Utility/Ai/AiCommandParamModel.cs
Normal file
12
src/NadekoBot/Modules/Utility/Ai/AiCommandParamModel.cs
Normal file
@@ -0,0 +1,12 @@
|
||||
using System.Text.Json.Serialization;
|
||||
|
||||
namespace NadekoBot.Modules.Utility;
|
||||
|
||||
public sealed class AiCommandParamModel
|
||||
{
|
||||
[JsonPropertyName("name")]
|
||||
public required string Name { get; set; }
|
||||
|
||||
[JsonPropertyName("desc")]
|
||||
public required string Desc { get; set; }
|
||||
}
|
16
src/NadekoBot/Modules/Utility/Ai/CommandPromptResultModel.cs
Normal file
16
src/NadekoBot/Modules/Utility/Ai/CommandPromptResultModel.cs
Normal file
@@ -0,0 +1,16 @@
|
||||
using System.Text.Json.Serialization;
|
||||
|
||||
namespace NadekoBot.Modules.Utility;
|
||||
|
||||
public sealed class CommandPromptResultModel
|
||||
{
|
||||
[JsonPropertyName("name")]
|
||||
public required string Name { get; set; }
|
||||
|
||||
[JsonPropertyName("arguments")]
|
||||
public required Dictionary<string, string> Arguments { get; set; }
|
||||
|
||||
[JsonPropertyName("remaining")]
|
||||
[JsonConverter(typeof(NumberToStringConverter))]
|
||||
public required string Remaining { get; set; }
|
||||
}
|
20
src/NadekoBot/Modules/Utility/Ai/IAiAssistantService.cs
Normal file
20
src/NadekoBot/Modules/Utility/Ai/IAiAssistantService.cs
Normal file
@@ -0,0 +1,20 @@
|
||||
using OneOf;
|
||||
|
||||
namespace NadekoBot.Modules.Utility;
|
||||
|
||||
public interface IAiAssistantService
|
||||
{
|
||||
Task<OneOf<NadekoCommandCallModel, GetCommandErrorResult>> TryGetCommandAsync(
|
||||
ulong userId,
|
||||
string prompt,
|
||||
IReadOnlyCollection<AiCommandModel> commands,
|
||||
string prefix);
|
||||
|
||||
IReadOnlyCollection<AiCommandModel> GetCommands();
|
||||
|
||||
Task<bool> TryExecuteAiCommand(
|
||||
IGuild guild,
|
||||
IUserMessage msg,
|
||||
ITextChannel channel,
|
||||
string query);
|
||||
}
|
@@ -0,0 +1,8 @@
|
||||
namespace NadekoBot.Modules.Utility;
|
||||
|
||||
public sealed class NadekoCommandCallModel
|
||||
{
|
||||
public required string Name { get; set; }
|
||||
public required IReadOnlyList<string> Arguments { get; set; }
|
||||
public required string Remaining { get; set; }
|
||||
}
|
23
src/NadekoBot/Modules/Utility/Ai/UtilityCommands.cs
Normal file
23
src/NadekoBot/Modules/Utility/Ai/UtilityCommands.cs
Normal file
@@ -0,0 +1,23 @@
|
||||
using NadekoBot.Modules.Administration;
|
||||
|
||||
namespace NadekoBot.Modules.Utility;
|
||||
|
||||
public partial class UtilityCommands
|
||||
{
|
||||
public class PromptCommands : NadekoModule<IAiAssistantService>
|
||||
{
|
||||
[Cmd]
|
||||
[RequireContext(ContextType.Guild)]
|
||||
public async Task Prompt([Leftover] string query)
|
||||
{
|
||||
await ctx.Channel.TriggerTypingAsync();
|
||||
var res = await _service.TryExecuteAiCommand(ctx.Guild, ctx.Message, (ITextChannel)ctx.Channel, query);
|
||||
}
|
||||
|
||||
private string GetCommandString(NadekoCommandCallModel res)
|
||||
=> $"{_bcs.Data.Prefix}{res.Name} {res.Arguments.Select((x, i) => GetParamString(x, i + 1 == res.Arguments.Count)).Join(" ")}";
|
||||
|
||||
private static string GetParamString(string val, bool isLast)
|
||||
=> isLast ? val : "\"" + val + "\"";
|
||||
}
|
||||
}
|
@@ -144,9 +144,9 @@ public partial class Utility
|
||||
true)
|
||||
.WithOkColor();
|
||||
|
||||
var patron = await _ps.GetPatronAsync(user.Id);
|
||||
var mPatron = await _ps.GetPatronAsync(user.Id);
|
||||
|
||||
if (patron.Tier != PatronTier.None)
|
||||
if (mPatron is {} patron && patron.Tier != PatronTier.None)
|
||||
{
|
||||
embed.WithFooter(patron.Tier switch
|
||||
{
|
||||
|
@@ -1,4 +1,6 @@
|
||||
#nullable disable warnings
|
||||
#nullable disable warnings
|
||||
using LinqToDB;
|
||||
using LinqToDB.EntityFrameworkCore;
|
||||
using NadekoBot.Common.Yml;
|
||||
using NadekoBot.Db;
|
||||
using NadekoBot.Db.Models;
|
||||
@@ -71,7 +73,7 @@ public partial class Utility
|
||||
.Confirm(GetText(strs.quotes_page(page + 1)),
|
||||
string.Join("\n",
|
||||
quotes.Select(q
|
||||
=> $"`#{q.Id}` {Format.Bold(q.Keyword.SanitizeAllMentions()),-20} by {q.AuthorName.SanitizeAllMentions()}")))
|
||||
=> $"`{new kwum(q.Id)}` {Format.Bold(q.Keyword.SanitizeAllMentions()),-20} by {q.AuthorName.SanitizeAllMentions()}")))
|
||||
.SendAsync();
|
||||
}
|
||||
else
|
||||
@@ -107,19 +109,19 @@ public partial class Utility
|
||||
text = await repSvc.ReplaceAsync(text, repCtx);
|
||||
|
||||
await Response()
|
||||
.Text($"`#{quote.Id}` 📣 " + text)
|
||||
.Text($"`{new kwum(quote.Id)}` 📣 " + text)
|
||||
.Sanitize()
|
||||
.SendAsync();
|
||||
}
|
||||
|
||||
[Cmd]
|
||||
[RequireContext(ContextType.Guild)]
|
||||
public async Task QuoteShow(int id)
|
||||
public async Task QuoteShow(kwum quoteId)
|
||||
{
|
||||
Quote? quote;
|
||||
await using (var uow = _db.GetDbContext())
|
||||
{
|
||||
quote = uow.Set<Quote>().GetById(id);
|
||||
quote = uow.Set<Quote>().GetById(quoteId);
|
||||
if (quote?.GuildId != ctx.Guild.Id)
|
||||
quote = null;
|
||||
}
|
||||
@@ -133,23 +135,54 @@ public partial class Utility
|
||||
await ShowQuoteData(quote);
|
||||
}
|
||||
|
||||
private async Task ShowQuoteData(Quote data)
|
||||
private NadekoInteractionBase CreateEditInteraction(kwum id, Quote found)
|
||||
{
|
||||
var modal = new ModalBuilder()
|
||||
.WithCustomId("quote:edit_modal")
|
||||
.WithTitle($"Edit expression {id}")
|
||||
.AddTextInput(new TextInputBuilder()
|
||||
.WithLabel(GetText(strs.response))
|
||||
.WithValue(found.Text)
|
||||
.WithMinLength(1)
|
||||
.WithCustomId("quote:edit_modal:response")
|
||||
.WithStyle(TextInputStyle.Paragraph));
|
||||
|
||||
var inter = _inter.Create(ctx.User.Id,
|
||||
new ButtonBuilder()
|
||||
.WithEmote(Emoji.Parse("📝"))
|
||||
.WithLabel("Edit")
|
||||
.WithStyle(ButtonStyle.Primary)
|
||||
.WithCustomId("test"),
|
||||
modal,
|
||||
async (sm) =>
|
||||
{
|
||||
var msg = sm.Data.Components.FirstOrDefault()?.Value;
|
||||
|
||||
if(!string.IsNullOrWhiteSpace(msg))
|
||||
await QuoteEdit(id, msg);
|
||||
}
|
||||
);
|
||||
return inter;
|
||||
}
|
||||
|
||||
private async Task ShowQuoteData(Quote quote)
|
||||
{
|
||||
var inter = CreateEditInteraction(quote.Id, quote);
|
||||
var eb = _sender.CreateEmbed()
|
||||
.WithOkColor()
|
||||
.WithTitle($"{GetText(strs.quote_id($"#{data.Id}"))} | {GetText(strs.response)}:")
|
||||
.WithDescription(Format.Sanitize(data.Text).Replace("](", "]\\(").TrimTo(4096))
|
||||
.AddField(GetText(strs.trigger), data.Keyword)
|
||||
.WithTitle($"{GetText(strs.quote_id($"`{new kwum(quote.Id)}"))}`")
|
||||
.WithDescription(Format.Sanitize(quote.Text).Replace("](", "]\\(").TrimTo(4096))
|
||||
.AddField(GetText(strs.trigger), quote.Keyword)
|
||||
.WithFooter(
|
||||
GetText(strs.created_by($"{data.AuthorName} ({data.AuthorId})")));
|
||||
GetText(strs.created_by($"{quote.AuthorName} ({quote.AuthorId})")));
|
||||
|
||||
if (!(data.Text.Length > 4096))
|
||||
if (!(quote.Text.Length > 4096))
|
||||
{
|
||||
await Response().Embed(eb).SendAsync();
|
||||
await Response().Embed(eb).Interaction(quote.AuthorId == ctx.User.Id ? inter : null).SendAsync();
|
||||
return;
|
||||
}
|
||||
|
||||
await using var textStream = await data.Text.ToStream();
|
||||
await using var textStream = await quote.Text.ToStream();
|
||||
|
||||
await Response()
|
||||
.Embed(eb)
|
||||
@@ -174,7 +207,7 @@ public partial class Utility
|
||||
return;
|
||||
|
||||
await Response()
|
||||
.Confirm($"`#{quote.Id}` 💬 ",
|
||||
.Confirm($"`{new kwum(quote.Id)}` 💬 ",
|
||||
quote.Keyword.ToLowerInvariant()
|
||||
+ ": "
|
||||
+ quote.Text.SanitizeAllMentions())
|
||||
@@ -195,9 +228,9 @@ public partial class Utility
|
||||
|
||||
[Cmd]
|
||||
[RequireContext(ContextType.Guild)]
|
||||
public async Task QuoteId(int id)
|
||||
public async Task QuoteId(kwum quoteId)
|
||||
{
|
||||
if (id < 0)
|
||||
if (quoteId < 0)
|
||||
return;
|
||||
|
||||
Quote quote;
|
||||
@@ -206,7 +239,7 @@ public partial class Utility
|
||||
|
||||
await using (var uow = _db.GetDbContext())
|
||||
{
|
||||
quote = uow.Set<Quote>().GetById(id);
|
||||
quote = uow.Set<Quote>().GetById(quoteId);
|
||||
}
|
||||
|
||||
if (quote is null || quote.GuildId != ctx.Guild.Id)
|
||||
@@ -215,7 +248,7 @@ public partial class Utility
|
||||
return;
|
||||
}
|
||||
|
||||
var infoText = $"`#{quote.Id} added by {quote.AuthorName.SanitizeAllMentions()}` 🗯️ "
|
||||
var infoText = $"*`{new kwum(quote.Id)}` added by {quote.AuthorName.SanitizeAllMentions()}* 🗯️ "
|
||||
+ quote.Keyword.ToLowerInvariant().SanitizeAllMentions()
|
||||
+ ":\n";
|
||||
|
||||
@@ -252,12 +285,53 @@ public partial class Utility
|
||||
await uow.SaveChangesAsync();
|
||||
}
|
||||
|
||||
await Response().Confirm(strs.quote_added_new(Format.Code(q.Id.ToString()))).SendAsync();
|
||||
await Response().Confirm(strs.quote_added_new(Format.Code(new kwum(q.Id).ToString()))).SendAsync();
|
||||
}
|
||||
|
||||
[Cmd]
|
||||
[RequireContext(ContextType.Guild)]
|
||||
public async Task QuoteDelete(int id)
|
||||
public async Task QuoteEdit(kwum quoteId, [Leftover] string text)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(text))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
Quote q;
|
||||
await using (var uow = _db.GetDbContext())
|
||||
{
|
||||
var intId = (int)quoteId;
|
||||
var result = await uow.GetTable<Quote>()
|
||||
.Where(x => x.Id == intId && x.AuthorId == ctx.User.Id)
|
||||
.Set(x => x.Text, text)
|
||||
.UpdateWithOutputAsync((del, ins) => ins);
|
||||
|
||||
q = result.FirstOrDefault();
|
||||
|
||||
await uow.SaveChangesAsync();
|
||||
}
|
||||
|
||||
if (q is not null)
|
||||
{
|
||||
await Response()
|
||||
.Embed(_sender.CreateEmbed()
|
||||
.WithOkColor()
|
||||
.WithTitle(GetText(strs.quote_edited))
|
||||
.WithDescription($"#{quoteId}")
|
||||
.AddField(GetText(strs.trigger), q.Keyword)
|
||||
.AddField(GetText(strs.response),
|
||||
text.Length > 1024 ? GetText(strs.redacted_too_long) : text))
|
||||
.SendAsync();
|
||||
}
|
||||
else
|
||||
{
|
||||
await Response().Error(strs.expr_no_found_id).SendAsync();
|
||||
}
|
||||
}
|
||||
|
||||
[Cmd]
|
||||
[RequireContext(ContextType.Guild)]
|
||||
public async Task QuoteDelete(kwum quoteId)
|
||||
{
|
||||
var hasManageMessages = ((IGuildUser)ctx.Message.Author).GuildPermissions.ManageMessages;
|
||||
|
||||
@@ -265,7 +339,7 @@ public partial class Utility
|
||||
string response;
|
||||
await using (var uow = _db.GetDbContext())
|
||||
{
|
||||
var q = uow.Set<Quote>().GetById(id);
|
||||
var q = uow.Set<Quote>().GetById(quoteId);
|
||||
|
||||
if (q?.GuildId != ctx.Guild.Id || (!hasManageMessages && q.AuthorId != ctx.Message.Author.Id))
|
||||
response = GetText(strs.quotes_remove_none);
|
||||
@@ -274,7 +348,7 @@ public partial class Utility
|
||||
uow.Set<Quote>().Remove(q);
|
||||
await uow.SaveChangesAsync();
|
||||
success = true;
|
||||
response = GetText(strs.quote_deleted(id));
|
||||
response = GetText(strs.quote_deleted(new kwum(quoteId)));
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -113,10 +113,9 @@ public partial class Utility
|
||||
foreach (var rem in rems)
|
||||
{
|
||||
var when = rem.When;
|
||||
var diff = when - DateTime.UtcNow;
|
||||
embed.AddField(
|
||||
$"#{++i + (page * 10)} {rem.When:HH:mm yyyy-MM-dd} UTC "
|
||||
+ $"(in {diff.ToPrettyStringHm()})",
|
||||
+ $"{TimestampTag.FromDateTime(when)}",
|
||||
$@"`Target:` {(rem.IsPrivate ? "DM" : "Channel")}
|
||||
`TargetId:` {rem.ChannelId}
|
||||
`Message:` {rem.Message?.TrimTo(50)}");
|
||||
@@ -203,16 +202,15 @@ public partial class Utility
|
||||
await uow.SaveChangesAsync();
|
||||
}
|
||||
|
||||
var gTime = ctx.Guild is null ? time : TimeZoneInfo.ConvertTime(time, _tz.GetTimeZoneOrUtc(ctx.Guild.Id));
|
||||
// var gTime = ctx.Guild is null ? time : TimeZoneInfo.ConvertTime(time, _tz.GetTimeZoneOrUtc(ctx.Guild.Id));
|
||||
try
|
||||
{
|
||||
await Response()
|
||||
.Confirm($"\u23f0 {GetText(strs.remind(
|
||||
.Confirm($"\u23f0 {GetText(strs.remind2(
|
||||
Format.Bold(!isPrivate ? $"<#{targetId}>" : ctx.User.Username),
|
||||
Format.Bold(message),
|
||||
ts.ToPrettyStringHm(),
|
||||
gTime,
|
||||
gTime))}")
|
||||
TimestampTag.FromDateTime(DateTime.UtcNow.Add(ts), TimestampTagStyles.Relative),
|
||||
TimestampTag.FormatFromDateTime(time, TimestampTagStyles.ShortDateTime)))}")
|
||||
.SendAsync();
|
||||
}
|
||||
catch
|
||||
|
@@ -117,35 +117,35 @@ public partial class Utility
|
||||
[RequireContext(ContextType.Guild)]
|
||||
[UserPerm(GuildPerm.ManageMessages)]
|
||||
[Priority(0)]
|
||||
public Task Repeat(ITextChannel ch, StoopidTime interval, [Leftover] string message)
|
||||
=> Repeat(ch, null, interval, message);
|
||||
public Task Repeat(ITextChannel channel, StoopidTime interval, [Leftover] string message)
|
||||
=> Repeat(channel, null, interval, message);
|
||||
|
||||
[Cmd]
|
||||
[RequireContext(ContextType.Guild)]
|
||||
[UserPerm(GuildPerm.ManageMessages)]
|
||||
[Priority(1)]
|
||||
public Task Repeat(GuildDateTime dt, [Leftover] string message)
|
||||
=> Repeat(dt, null, message);
|
||||
public Task Repeat(GuildDateTime timeOfDay, [Leftover] string message)
|
||||
=> Repeat(timeOfDay, null, message);
|
||||
|
||||
[Cmd]
|
||||
[RequireContext(ContextType.Guild)]
|
||||
[UserPerm(GuildPerm.ManageMessages)]
|
||||
[Priority(1)]
|
||||
public Task Repeat(ITextChannel channel, GuildDateTime dt, [Leftover] string message)
|
||||
=> Repeat(channel, dt, null, message);
|
||||
public Task Repeat(ITextChannel channel, GuildDateTime timeOfDay, [Leftover] string message)
|
||||
=> Repeat(channel, timeOfDay, null, message);
|
||||
|
||||
[Cmd]
|
||||
[RequireContext(ContextType.Guild)]
|
||||
[UserPerm(GuildPerm.ManageMessages)]
|
||||
[Priority(2)]
|
||||
public Task Repeat(GuildDateTime? dt, StoopidTime? interval, [Leftover] string message)
|
||||
=> Repeat(ctx.Channel, dt, interval, message);
|
||||
public Task Repeat(GuildDateTime? timeOfDay, StoopidTime? interval, [Leftover] string message)
|
||||
=> Repeat(ctx.Channel, timeOfDay, interval, message);
|
||||
|
||||
[Cmd]
|
||||
[RequireContext(ContextType.Guild)]
|
||||
[UserPerm(GuildPerm.ManageMessages)]
|
||||
[Priority(3)]
|
||||
public async Task Repeat(IMessageChannel channel, GuildDateTime? dt, StoopidTime? interval,
|
||||
public async Task Repeat(IMessageChannel channel, GuildDateTime? timeOfDay, StoopidTime? interval,
|
||||
[Leftover] string message)
|
||||
{
|
||||
if (channel is not ITextChannel txtCh || txtCh.GuildId != ctx.Guild.Id)
|
||||
@@ -155,7 +155,7 @@ public partial class Utility
|
||||
if (!perms.SendMessages)
|
||||
return;
|
||||
|
||||
var startTimeOfDay = dt?.InputTimeUtc.TimeOfDay;
|
||||
var startTimeOfDay = timeOfDay?.InputTimeUtc.TimeOfDay;
|
||||
// if interval not null, that means user specified it (don't change it)
|
||||
|
||||
// if interval is null set the default to:
|
||||
|
@@ -2,6 +2,7 @@
|
||||
using NadekoBot.Modules.Xp.Services;
|
||||
using NadekoBot.Db.Models;
|
||||
using NadekoBot.Modules.Patronage;
|
||||
using NadekoBot.Modules.Utility;
|
||||
|
||||
namespace NadekoBot.Modules.Xp;
|
||||
|
||||
@@ -475,7 +476,8 @@ public partial class Xp : NadekoModule<XpService>
|
||||
emote: Emoji.Parse("👐"),
|
||||
isDisabled: ownedItem.IsUsing);
|
||||
|
||||
var inter = new SimpleInteraction<(string key, XpShopItemType type)?>(
|
||||
var inter = _inter.Create(
|
||||
ctx.User.Id,
|
||||
button,
|
||||
OnShopUse,
|
||||
(key, itemType));
|
||||
@@ -488,7 +490,8 @@ public partial class Xp : NadekoModule<XpService>
|
||||
"xpshop:buy",
|
||||
emote: Emoji.Parse("💰"));
|
||||
|
||||
var inter = new SimpleInteraction<(string key, XpShopItemType type)?>(
|
||||
var inter = _inter.Create(
|
||||
ctx.User.Id,
|
||||
button,
|
||||
OnShopBuy,
|
||||
(key, itemType));
|
||||
@@ -504,13 +507,13 @@ public partial class Xp : NadekoModule<XpService>
|
||||
{
|
||||
var result = await _service.BuyShopItemAsync(ctx.User.Id, (XpShopItemType)type, key);
|
||||
|
||||
NadekoInteraction GetUseInteraction()
|
||||
NadekoInteractionBase GetUseInteraction()
|
||||
{
|
||||
return _inter.Create(ctx.User.Id,
|
||||
new SimpleInteraction<object>(
|
||||
new ButtonBuilder(label: "Use", customId: "xpshop:use_item", emote: Emoji.Parse("👐")),
|
||||
async (smc, _) => await XpShopUse(type, key)
|
||||
));
|
||||
new(label: "Use", customId: "xpshop:use_item", emote: Emoji.Parse("👐")),
|
||||
async (_, state) => await XpShopUse(state.type, state.key),
|
||||
(type, key)
|
||||
);
|
||||
}
|
||||
|
||||
if (result != BuyResult.Success)
|
||||
@@ -551,11 +554,8 @@ public partial class Xp : NadekoModule<XpService>
|
||||
await ctx.OkAsync();
|
||||
}
|
||||
|
||||
private async Task OnShopUse(SocketMessageComponent smc, (string? key, XpShopItemType type)? maybeState)
|
||||
private async Task OnShopUse(SocketMessageComponent smc, (string key, XpShopItemType type) state)
|
||||
{
|
||||
if (maybeState is not { } state)
|
||||
return;
|
||||
|
||||
var (key, type) = state;
|
||||
|
||||
var result = await _service.UseShopItemAsync(ctx.User.Id, type, key);
|
||||
@@ -567,11 +567,8 @@ public partial class Xp : NadekoModule<XpService>
|
||||
}
|
||||
}
|
||||
|
||||
private async Task OnShopBuy(SocketMessageComponent smc, (string? key, XpShopItemType type)? maybeState)
|
||||
private async Task OnShopBuy(SocketMessageComponent smc, (string key, XpShopItemType type) state)
|
||||
{
|
||||
if (maybeState is not { } state)
|
||||
return;
|
||||
|
||||
var (key, type) = state;
|
||||
|
||||
var result = await _service.BuyShopItemAsync(ctx.User.Id, type, key);
|
||||
|
@@ -668,7 +668,7 @@ public class XpService : INService, IReadyExecutor, IExecNoCommand
|
||||
/// <param name="channel"></param>
|
||||
private async Task ScanUserForVoiceXp(SocketGuildUser user, SocketVoiceChannel channel)
|
||||
{
|
||||
if (UserParticipatingInVoiceChannel(user) && ShouldTrackXp(user, channel.Id))
|
||||
if (UserParticipatingInVoiceChannel(user) && ShouldTrackXp(user, channel))
|
||||
await UserJoinedVoiceChannel(user);
|
||||
else
|
||||
await UserLeftVoiceChannel(user, channel);
|
||||
@@ -767,9 +767,12 @@ public class XpService : INService, IReadyExecutor, IExecNoCommand
|
||||
}
|
||||
*/
|
||||
|
||||
private bool ShouldTrackXp(SocketGuildUser user, ulong channelId)
|
||||
private bool ShouldTrackXp(SocketGuildUser user, IMessageChannel channel)
|
||||
{
|
||||
if (_excludedChannels.TryGetValue(user.Guild.Id, out var chans) && chans.Contains(channelId))
|
||||
var channelId = channel.Id;
|
||||
|
||||
if (_excludedChannels.TryGetValue(user.Guild.Id, out var chans) && (chans.Contains(channelId)
|
||||
|| (channel is SocketThreadChannel tc && chans.Contains(tc.ParentChannel.Id))))
|
||||
return false;
|
||||
|
||||
if (_excludedServers.Contains(user.Guild.Id))
|
||||
@@ -788,7 +791,7 @@ public class XpService : INService, IReadyExecutor, IExecNoCommand
|
||||
|
||||
_ = Task.Run(async () =>
|
||||
{
|
||||
if (!ShouldTrackXp(user, arg.Channel.Id))
|
||||
if (!ShouldTrackXp(user, arg.Channel))
|
||||
return;
|
||||
|
||||
var xpConf = _xpConfig.Data;
|
||||
@@ -1286,9 +1289,9 @@ public class XpService : INService, IReadyExecutor, IExecNoCommand
|
||||
Image? frame = null;
|
||||
if (item is null)
|
||||
{
|
||||
if (patron.Tier == PatronTier.V)
|
||||
if (patron?.Tier == PatronTier.V)
|
||||
frame = Image.Load<Rgba32>(File.OpenRead("data/images/frame_silver.png"));
|
||||
else if (patron.Tier >= PatronTier.X || _creds.IsOwner(userId))
|
||||
else if (patron?.Tier >= PatronTier.X || _creds.IsOwner(userId))
|
||||
frame = Image.Load<Rgba32>(File.OpenRead("data/images/frame_gold.png"));
|
||||
}
|
||||
else
|
||||
@@ -1465,7 +1468,7 @@ public class XpService : INService, IReadyExecutor, IExecNoCommand
|
||||
{
|
||||
var patron = await _ps.GetPatronAsync(userId);
|
||||
|
||||
if ((int)patron.Tier < (int)req)
|
||||
if (patron is null || (int)patron.Value.Tier < (int)req)
|
||||
return BuyResult.InsufficientPatronTier;
|
||||
}
|
||||
|
||||
|
@@ -1,11 +1,10 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net8.0</TargetFramework>
|
||||
<Nullable>enable</Nullable>
|
||||
<ImplicitUsings>true</ImplicitUsings>
|
||||
<SatelliteResourceLanguages>en</SatelliteResourceLanguages>
|
||||
<Version>5.0.7</Version>
|
||||
<Version>5.1.0</Version>
|
||||
|
||||
<!-- Output/build -->
|
||||
<RunWorkingDirectory>$(MSBuildProjectDirectory)</RunWorkingDirectory>
|
||||
@@ -31,9 +30,9 @@
|
||||
<PackageReference Include="CodeHollow.FeedReader" Version="1.2.6"/>
|
||||
<PackageReference Include="CommandLineParser" Version="2.9.1"/>
|
||||
<PackageReference Include="Discord.Net" Version="3.204.0"/>
|
||||
<PackageReference Include="CoreCLR-NCalc" Version="3.1.246" />
|
||||
<PackageReference Include="CoreCLR-NCalc" Version="3.1.246"/>
|
||||
<PackageReference Include="Google.Apis.Urlshortener.v1" Version="1.41.1.138"/>
|
||||
<PackageReference Include="Google.Apis.YouTube.v3" Version="1.68.0.3414" />
|
||||
<PackageReference Include="Google.Apis.YouTube.v3" Version="1.68.0.3414"/>
|
||||
<PackageReference Include="Google.Apis.Customsearch.v1" Version="1.49.0.2084"/>
|
||||
<!-- <PackageReference Include="Grpc.AspNetCore" Version="2.62.0" />-->
|
||||
<PackageReference Include="Google.Protobuf" Version="3.26.1"/>
|
||||
@@ -52,11 +51,11 @@
|
||||
<PackageReference Include="NetEscapades.Configuration.Yaml" Version="3.1.0"/>
|
||||
|
||||
<!-- DI -->
|
||||
<!-- <PackageReference Include="Ninject" Version="3.3.6"/>-->
|
||||
<!-- <PackageReference Include="Ninject.Extensions.Conventions" Version="3.3.0"/>-->
|
||||
<!-- <PackageReference Include="Ninject" Version="3.3.6"/>-->
|
||||
<!-- <PackageReference Include="Ninject.Extensions.Conventions" Version="3.3.0"/>-->
|
||||
<!-- <PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="8.0.0" />-->
|
||||
<PackageReference Include="Microsoft.Extensions.DependencyInjection.Abstractions" Version="8.0.1"/>
|
||||
<PackageReference Include="DryIoc.dll" Version="5.4.3" />
|
||||
<PackageReference Include="DryIoc.dll" Version="5.4.3"/>
|
||||
<!-- <PackageReference Include="Scrutor" Version="4.2.0" />-->
|
||||
|
||||
<PackageReference Include="Microsoft.Extensions.Http" Version="8.0.0"/>
|
||||
@@ -68,15 +67,15 @@
|
||||
<PackageReference Include="OneOf" Version="3.0.263"/>
|
||||
<PackageReference Include="OneOf.SourceGenerator" Version="3.0.263"/>
|
||||
<PackageReference Include="Serilog.Sinks.Console" Version="5.0.1"/>
|
||||
<PackageReference Include="Serilog.Sinks.Seq" Version="7.0.1" />
|
||||
<PackageReference Include="Serilog.Sinks.Seq" Version="7.0.1"/>
|
||||
|
||||
<PackageReference Include="SixLabors.Fonts" Version="1.0.0-beta17"/>
|
||||
<PackageReference Include="SixLabors.ImageSharp" Version="2.1.8"/>
|
||||
<PackageReference Include="SixLabors.ImageSharp.Drawing" Version="1.0.0-beta14"/>
|
||||
<PackageReference Include="SixLabors.Shapes" Version="1.0.0-beta0009"/>
|
||||
<PackageReference Include="StackExchange.Redis" Version="2.7.33"/>
|
||||
<PackageReference Include="YamlDotNet" Version="15.1.4" />
|
||||
<PackageReference Include="SharpToken" Version="2.0.2"/>
|
||||
<PackageReference Include="YamlDotNet" Version="15.1.4"/>
|
||||
<PackageReference Include="SharpToken" Version="2.0.3" />
|
||||
|
||||
<PackageReference Include="JetBrains.Annotations" Version="2023.3.0"/>
|
||||
|
||||
@@ -100,7 +99,7 @@
|
||||
<PackageReference Include="TwitchLib.Api" Version="3.4.1"/>
|
||||
|
||||
<!-- sqlselectcsv and stock -->
|
||||
<PackageReference Include="CsvHelper" Version="32.0.3" />
|
||||
<PackageReference Include="CsvHelper" Version="32.0.3"/>
|
||||
|
||||
</ItemGroup>
|
||||
|
||||
@@ -109,6 +108,8 @@
|
||||
<ProjectReference Include="..\NadekoBot.Voice\NadekoBot.Voice.csproj"/>
|
||||
<ProjectReference Include="..\NadekoBot.Generators\NadekoBot.Generators.csproj" OutputItemType="Analyzer"/>
|
||||
</ItemGroup>
|
||||
|
||||
|
||||
<ItemGroup>
|
||||
<AdditionalFiles Include="data\strings\responses\responses.en-US.json"/>
|
||||
</ItemGroup>
|
||||
@@ -131,10 +132,6 @@
|
||||
</None>
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Folder Include="Modules\Utility\GuildColors\" />
|
||||
</ItemGroup>
|
||||
|
||||
<PropertyGroup Condition=" '$(Configuration)' == 'GlobalNadeko' ">
|
||||
<!-- Define trace doesn't seem to affect the build at all so I had to remove $(DefineConstants)-->
|
||||
<DefineTrace>false</DefineTrace>
|
||||
|
@@ -191,6 +191,12 @@ public sealed class BotCredsProvider : IBotCredsProvider
|
||||
creds.Version = 7;
|
||||
File.WriteAllText(CREDS_FILE_NAME, Yaml.Serializer.Serialize(creds));
|
||||
}
|
||||
|
||||
if (creds.Version <= 7)
|
||||
{
|
||||
creds.Version = 8;
|
||||
File.WriteAllText(CREDS_FILE_NAME, Yaml.Serializer.Serialize(creds));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -3,6 +3,7 @@ using OneOf.Types;
|
||||
using StackExchange.Redis;
|
||||
using System.Text.Json;
|
||||
using System.Text.Json.Serialization;
|
||||
using YamlDotNet.Core.Tokens;
|
||||
|
||||
namespace NadekoBot.Common;
|
||||
|
||||
@@ -47,6 +48,7 @@ public sealed class RedisBotCache : IBotCache
|
||||
var success = await db.StringSetAsync(key.Key,
|
||||
val,
|
||||
expiry: expiry,
|
||||
keepTtl: true,
|
||||
when: overwrite ? When.Always : When.NotExists);
|
||||
|
||||
return success;
|
||||
|
@@ -4,8 +4,9 @@ namespace NadekoBot;
|
||||
public interface IBotCredentials
|
||||
{
|
||||
string Token { get; }
|
||||
string GoogleApiKey { get; }
|
||||
string NadekoAiToken { get; }
|
||||
ICollection<ulong> OwnerIds { get; set; }
|
||||
string GoogleApiKey { get; }
|
||||
bool UsePrivilegedIntents { get; }
|
||||
string RapidApiKey { get; }
|
||||
|
||||
|
@@ -29,6 +29,15 @@ public sealed class Creds : IBotCredentials
|
||||
""")]
|
||||
public int TotalShards { get; set; }
|
||||
|
||||
[Comment("""
|
||||
Pledge 5$ or more on https://patreon.com/nadekobot and connect your discord account to Patreon.
|
||||
Go to https://dashy.nadeko.bot and login with your discord account
|
||||
Go to the Keys page and click "Generate New Key" and copy it here
|
||||
You and anyone else with the permission to run `.prompt` command will be able to use natural language to run bot's commands.
|
||||
For example '@Bot how's the weather in Paris' will return the current weather in Paris as if you were to run `.weather Paris` command
|
||||
""")]
|
||||
public string NadekoAiToken { get; set; }
|
||||
|
||||
[Comment(
|
||||
"""
|
||||
Login to https://console.cloud.google.com, create a new project, go to APIs & Services -> Library -> YouTube Data API and enable it.
|
||||
@@ -64,7 +73,7 @@ public sealed class Creds : IBotCredentials
|
||||
[Comment("""Official cleverbot api key.""")]
|
||||
public string CleverbotApiKey { get; set; }
|
||||
|
||||
[Comment(@"Official GPT-3 api key.")]
|
||||
[Comment(@"OpenAi api key.")]
|
||||
public string Gpt3ApiKey { get; set; }
|
||||
|
||||
[Comment("""
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user