mirror of
https://gitlab.com/Kwoth/nadekobot.git
synced 2025-09-11 01:38:27 -04:00
Compare commits
60 Commits
Author | SHA1 | Date | |
---|---|---|---|
|
c473669cbc | ||
|
b97c486b80 | ||
|
716e092fd0 | ||
|
a362ee90fc | ||
|
1de6cdb8dc | ||
|
f473014fe9 | ||
|
2c3e5fe507 | ||
|
ecc192c6a9 | ||
|
f7bd181034 | ||
|
664a4b3604 | ||
|
0326e88910 | ||
|
e4202b33f5 | ||
|
021e7978da | ||
|
28ad6db2de | ||
|
fb62df7aa2 | ||
|
33663d7efc | ||
|
6d1edc07cb | ||
|
c36ab34c4f | ||
|
e85e7c49cb | ||
|
e56190e9da | ||
|
2d16ecf6de | ||
|
2b12269917 | ||
|
79c2dfec2d | ||
|
73356b6beb | ||
|
bc22987330 | ||
|
c033c0e3c8 | ||
|
c9ed2cf4b5 | ||
|
52b87c7776 | ||
|
8b2ed0dbdc | ||
|
9424d4d5f9 | ||
|
67b186a1a5 | ||
|
436f9ed074 | ||
|
c1e51329be | ||
|
ae1193c1c5 | ||
|
9601a4d1a9 | ||
|
bdfde1205a | ||
|
5992628f80 | ||
|
d24e6fd8e7 | ||
|
c31c2e8d8e | ||
|
9aaf062d78 | ||
|
0b9e812d59 | ||
|
dc63e46852 | ||
|
e314686a03 | ||
|
f764a650da | ||
|
67616deb79 | ||
|
d0aa80a004 | ||
|
f66c105cc0 | ||
|
2a528cb3d6 | ||
|
8b40f97a3d | ||
|
fa9263ed32 | ||
|
88c42b74c7 | ||
|
f7406ec90b | ||
|
e446c8ee8b | ||
|
5839e944e1 | ||
|
15e41c10db | ||
|
99a8ea18bb | ||
|
5453f8acfa | ||
|
c95d1421c6 | ||
|
f631f16690 | ||
|
d397c2dce8 |
66
CHANGELOG.md
66
CHANGELOG.md
@@ -2,6 +2,70 @@
|
|||||||
|
|
||||||
Mostly based on [keepachangelog](https://keepachangelog.com/en/1.0.0/) except date format. a-c-f-r-o
|
Mostly based on [keepachangelog](https://keepachangelog.com/en/1.0.0/) except date format. a-c-f-r-o
|
||||||
|
|
||||||
|
## [5.1.10] - 24.09.2024
|
||||||
|
|
||||||
|
### Fixed
|
||||||
|
|
||||||
|
- Fixed claimed waifu decay in `games.yml`
|
||||||
|
|
||||||
|
### Changed
|
||||||
|
|
||||||
|
- Added some logs for greet service in case there are unforeseen issues, for easier debugging
|
||||||
|
|
||||||
|
## [5.1.9] - 21.09.2024
|
||||||
|
|
||||||
|
### Fixed
|
||||||
|
|
||||||
|
- Fixed `.greettest`, and other `.*test` commands if you didn't have them enabled.
|
||||||
|
- Fixed `.greetdmtest` sending messages twice.
|
||||||
|
- Fixed a serious bug which caused greet messages to be jumbled up, and wrong ones to be sent for the wrong events.
|
||||||
|
- There is no database issue, all greet messages are safe, the cache was caching any setting every 3 seconds with no regard for the type of the event
|
||||||
|
- This also caused `.greetdm` messages to not be sent if `.greet` is enabled
|
||||||
|
- This bug was introduced in 5.1.8. PLEASE UPDATE if you are on 5.1.8
|
||||||
|
- Selfhosters only: Fixed medusa dependency loading
|
||||||
|
- Note: Make sure to not publish any other DLLs besides the ones you are sure you will need, as there can be version conflicts which didn't happen before.
|
||||||
|
|
||||||
|
## [5.1.8] - 19.09.2024
|
||||||
|
|
||||||
|
### Added
|
||||||
|
|
||||||
|
- Added `.leaveunkeptservers` which will make the bot leave all servers on all shards whose owners didn't run `.keep` command.
|
||||||
|
- This is a dangerous and irreversible command, don't use it. Meant for use on the public bot.
|
||||||
|
- `.adpl` now supports custom statuses (you no longer need to specify Playing, Watching, etc...)
|
||||||
|
|
||||||
|
### Changed
|
||||||
|
|
||||||
|
- `.quote` commands cleaned up and improved
|
||||||
|
- All quote commands now start with `.q<whatever>` and follow the same naming pattern as Expression commands
|
||||||
|
- `.liqu` renamed to `.qli`
|
||||||
|
- `.quotesearch` / `.qse` is now paginated for easier searching
|
||||||
|
- `.whosplaying` is now paginated
|
||||||
|
- `.img` is now paginated
|
||||||
|
- `.setgame` renamed to`.setactivity` and now supports custom text activity. You don't have to specify playing, listening etc before the activity
|
||||||
|
- Clarified and added some embed / placeholder links to command help where needed
|
||||||
|
- dev: A lot of code cleanup and internal improvements
|
||||||
|
|
||||||
|
### Fixed
|
||||||
|
|
||||||
|
- Fixed `.xpcurrew` breaking xp gain if user gains 0 xp from being in a voice channel
|
||||||
|
- Fixed a bug in `.gatari` command
|
||||||
|
- Fixed some waifu related strings
|
||||||
|
- Fixed `.quoteshow` and `.quoteid` commands
|
||||||
|
- Fixed some placeholders not working in `.greetdm`
|
||||||
|
- Fixed postgres support
|
||||||
|
- Fixed and clarified some command strings/parameter descriptions
|
||||||
|
|
||||||
|
### Removed
|
||||||
|
|
||||||
|
- Removed mysql support as it didn't work for a while, and requires some special handling/maintenance
|
||||||
|
- Sqlite and Postgres support stays
|
||||||
|
|
||||||
|
## [5.1.7] - 08.08.2024
|
||||||
|
|
||||||
|
### Fixed
|
||||||
|
|
||||||
|
- Fixed some command groups incorrectly showing up as modules
|
||||||
|
|
||||||
## [5.1.6] - 07.08.2024
|
## [5.1.6] - 07.08.2024
|
||||||
|
|
||||||
### Added
|
### Added
|
||||||
@@ -14,7 +78,7 @@ Mostly based on [keepachangelog](https://keepachangelog.com/en/1.0.0/) except da
|
|||||||
|
|
||||||
### Fixed
|
### Fixed
|
||||||
|
|
||||||
- `.afk` messages can no longer ping, and the response is moved to DMs to avoid
|
- `.afk` messages can no longer ping, and the response is moved to DMs to avoid abuse
|
||||||
- Possible fix for `.remind` timestamp
|
- Possible fix for `.remind` timestamp
|
||||||
|
|
||||||
### Removed
|
### Removed
|
||||||
|
@@ -5,6 +5,5 @@ else {
|
|||||||
$migrationName = $args[0]
|
$migrationName = $args[0]
|
||||||
dotnet ef migrations add $migrationName -c SqliteContext -p src/NadekoBot/NadekoBot.csproj
|
dotnet ef migrations add $migrationName -c SqliteContext -p src/NadekoBot/NadekoBot.csproj
|
||||||
dotnet ef migrations add $migrationName -c PostgreSqlContext -p src/NadekoBot/NadekoBot.csproj
|
dotnet ef migrations add $migrationName -c PostgreSqlContext -p src/NadekoBot/NadekoBot.csproj
|
||||||
dotnet ef migrations add $migrationName -c MysqlContext -p src/NadekoBot/NadekoBot.csproj
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -1,4 +1,3 @@
|
|||||||
dotnet ef migrations remove -c SqliteContext -f -p src/NadekoBot/NadekoBot.csproj
|
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 PostgreSqlContext -f -p src/NadekoBot/NadekoBot.csproj
|
||||||
dotnet ef migrations remove -c MysqlContext -f -p src/NadekoBot/NadekoBot.csproj
|
|
||||||
|
|
||||||
|
@@ -1,76 +0,0 @@
|
|||||||
using System.Linq;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
using Nadeko.Common;
|
|
||||||
using NadekoBot.Services;
|
|
||||||
using NUnit.Framework;
|
|
||||||
|
|
||||||
namespace NadekoBot.Tests
|
|
||||||
{
|
|
||||||
public class GroupGreetTests
|
|
||||||
{
|
|
||||||
private GreetGrouper<int> _grouper;
|
|
||||||
|
|
||||||
[SetUp]
|
|
||||||
public void Setup()
|
|
||||||
=> _grouper = new GreetGrouper<int>();
|
|
||||||
|
|
||||||
[Test]
|
|
||||||
public void CreateTest()
|
|
||||||
{
|
|
||||||
var created = _grouper.CreateOrAdd(0, 5);
|
|
||||||
|
|
||||||
Assert.True(created);
|
|
||||||
}
|
|
||||||
|
|
||||||
[Test]
|
|
||||||
public void CreateClearTest()
|
|
||||||
{
|
|
||||||
_grouper.CreateOrAdd(0, 5);
|
|
||||||
_grouper.ClearGroup(0, 5, out var items);
|
|
||||||
|
|
||||||
Assert.AreEqual(0, items.Count());
|
|
||||||
}
|
|
||||||
|
|
||||||
[Test]
|
|
||||||
public void NotCreatedTest()
|
|
||||||
{
|
|
||||||
_grouper.CreateOrAdd(0, 5);
|
|
||||||
var created = _grouper.CreateOrAdd(0, 4);
|
|
||||||
|
|
||||||
Assert.False(created);
|
|
||||||
}
|
|
||||||
|
|
||||||
[Test]
|
|
||||||
public void ClearAddedTest()
|
|
||||||
{
|
|
||||||
_grouper.CreateOrAdd(0, 5);
|
|
||||||
_grouper.CreateOrAdd(0, 4);
|
|
||||||
_grouper.ClearGroup(0, 5, out var items);
|
|
||||||
|
|
||||||
var list = items.ToList();
|
|
||||||
|
|
||||||
Assert.AreEqual(1, list.Count, $"Count was {list.Count}");
|
|
||||||
Assert.AreEqual(4, list[0]);
|
|
||||||
}
|
|
||||||
|
|
||||||
[Test]
|
|
||||||
public async Task ClearManyTest()
|
|
||||||
{
|
|
||||||
_grouper.CreateOrAdd(0, 5);
|
|
||||||
|
|
||||||
// add 15 items
|
|
||||||
await Enumerable.Range(10, 15)
|
|
||||||
.Select(x => Task.Run(() => _grouper.CreateOrAdd(0, x))).WhenAll();
|
|
||||||
|
|
||||||
// get 5 at most
|
|
||||||
_grouper.ClearGroup(0, 5, out var items);
|
|
||||||
var list = items.ToList();
|
|
||||||
Assert.AreEqual(5, list.Count, $"Count was {list.Count}");
|
|
||||||
|
|
||||||
// try to get 15, but there should be 10 left
|
|
||||||
_grouper.ClearGroup(0, 15, out items);
|
|
||||||
list = items.ToList();
|
|
||||||
Assert.AreEqual(10, list.Count, $"Count was {list.Count}");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@@ -1,5 +1,6 @@
|
|||||||
#nullable disable
|
#nullable disable
|
||||||
using DryIoc;
|
using DryIoc;
|
||||||
|
using Microsoft.EntityFrameworkCore;
|
||||||
using Microsoft.Extensions.Caching.Memory;
|
using Microsoft.Extensions.Caching.Memory;
|
||||||
using Microsoft.Extensions.DependencyInjection;
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
using NadekoBot.Common.Configs;
|
using NadekoBot.Common.Configs;
|
||||||
@@ -88,18 +89,18 @@ public sealed class Bot : IBot
|
|||||||
|
|
||||||
|
|
||||||
public IReadOnlyList<ulong> GetCurrentGuildIds()
|
public IReadOnlyList<ulong> GetCurrentGuildIds()
|
||||||
=> Client.Guilds.Select(x => x.Id).ToList().ToList();
|
=> Client.Guilds.Select(x => x.Id).ToList().AsReadOnly();
|
||||||
|
|
||||||
private void AddServices()
|
private async Task AddServices()
|
||||||
{
|
{
|
||||||
var startingGuildIdList = GetCurrentGuildIds();
|
var startingGuildIdList = GetCurrentGuildIds().ToList();
|
||||||
var startTime = Stopwatch.GetTimestamp();
|
var startTime = Stopwatch.GetTimestamp();
|
||||||
var bot = Client.CurrentUser;
|
var bot = Client.CurrentUser;
|
||||||
|
|
||||||
using (var uow = _db.GetDbContext())
|
await using (var uow = _db.GetDbContext())
|
||||||
{
|
{
|
||||||
|
AllGuildConfigs = await uow.GuildConfigs.GetAllGuildConfigs(startingGuildIdList);
|
||||||
uow.EnsureUserCreated(bot.Id, bot.Username, bot.Discriminator, bot.AvatarId);
|
uow.EnsureUserCreated(bot.Id, bot.Username, bot.Discriminator, bot.AvatarId);
|
||||||
AllGuildConfigs = uow.Set<GuildConfig>().GetAllGuildConfigs(startingGuildIdList).ToImmutableArray();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// var svcs = new StandardKernel(new NinjectSettings()
|
// var svcs = new StandardKernel(new NinjectSettings()
|
||||||
@@ -109,7 +110,7 @@ public sealed class Bot : IBot
|
|||||||
// });
|
// });
|
||||||
|
|
||||||
var svcs = new Container();
|
var svcs = new Container();
|
||||||
|
|
||||||
// this is required in order for medusa unloading to work
|
// this is required in order for medusa unloading to work
|
||||||
// svcs.Components.Remove<IPlanner, Planner>();
|
// svcs.Components.Remove<IPlanner, Planner>();
|
||||||
// svcs.Components.Add<IPlanner, RemovablePlanner>();
|
// svcs.Components.Add<IPlanner, RemovablePlanner>();
|
||||||
@@ -160,8 +161,9 @@ public sealed class Bot : IBot
|
|||||||
{
|
{
|
||||||
LoadTypeReaders(a);
|
LoadTypeReaders(a);
|
||||||
}
|
}
|
||||||
|
|
||||||
Log.Information("All services loaded in {ServiceLoadTime:F2}s", Stopwatch.GetElapsedTime(startTime) .TotalSeconds);
|
Log.Information("All services loaded in {ServiceLoadTime:F2}s",
|
||||||
|
Stopwatch.GetElapsedTime(startTime).TotalSeconds);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void LoadTypeReaders(Assembly assembly)
|
private void LoadTypeReaders(Assembly assembly)
|
||||||
@@ -261,11 +263,11 @@ public sealed class Bot : IBot
|
|||||||
var startTime = Stopwatch.GetTimestamp();
|
var startTime = Stopwatch.GetTimestamp();
|
||||||
|
|
||||||
await LoginAsync(_creds.Token);
|
await LoginAsync(_creds.Token);
|
||||||
|
|
||||||
Log.Information("Shard {ShardId} loading services...", Client.ShardId);
|
Log.Information("Shard {ShardId} loading services...", Client.ShardId);
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
AddServices();
|
await AddServices();
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
@@ -273,7 +275,9 @@ public sealed class Bot : IBot
|
|||||||
Helpers.ReadErrorAndExit(9);
|
Helpers.ReadErrorAndExit(9);
|
||||||
}
|
}
|
||||||
|
|
||||||
Log.Information("Shard {ShardId} connected in {Elapsed:F2}s", Client.ShardId, Stopwatch.GetElapsedTime(startTime).TotalSeconds);
|
Log.Information("Shard {ShardId} connected in {Elapsed:F2}s",
|
||||||
|
Client.ShardId,
|
||||||
|
Stopwatch.GetElapsedTime(startTime).TotalSeconds);
|
||||||
var commandHandler = Services.GetRequiredService<CommandHandler>();
|
var commandHandler = Services.GetRequiredService<CommandHandler>();
|
||||||
|
|
||||||
// start handling messages received in commandhandler
|
// start handling messages received in commandhandler
|
||||||
@@ -338,26 +342,26 @@ public sealed class Bot : IBot
|
|||||||
if (arg.Exception is { InnerException: WebSocketClosedException { CloseCode: 4014 } })
|
if (arg.Exception is { InnerException: WebSocketClosedException { CloseCode: 4014 } })
|
||||||
{
|
{
|
||||||
Log.Error("""
|
Log.Error("""
|
||||||
Login failed.
|
Login failed.
|
||||||
|
|
||||||
*** Please enable privileged intents ***
|
*** Please enable privileged intents ***
|
||||||
|
|
||||||
Certain Nadeko features require Discord's privileged gateway intents.
|
Certain Nadeko features require Discord's privileged gateway intents.
|
||||||
These include greeting and goodbye messages, as well as creating the Owner message channels for DM forwarding.
|
These include greeting and goodbye messages, as well as creating the Owner message channels for DM forwarding.
|
||||||
|
|
||||||
How to enable privileged intents:
|
How to enable privileged intents:
|
||||||
1. Head over to the Discord Developer Portal https://discord.com/developers/applications/
|
1. Head over to the Discord Developer Portal https://discord.com/developers/applications/
|
||||||
2. Select your Application.
|
2. Select your Application.
|
||||||
3. Click on `Bot` in the left side navigation panel, and scroll down to the intents section.
|
3. Click on `Bot` in the left side navigation panel, and scroll down to the intents section.
|
||||||
4. Enable all intents.
|
4. Enable all intents.
|
||||||
5. Restart your bot.
|
5. Restart your bot.
|
||||||
|
|
||||||
Read this only if your bot is in 100 or more servers:
|
Read this only if your bot is in 100 or more servers:
|
||||||
|
|
||||||
You'll need to apply to use the intents with Discord, but for small selfhosts, all that is required is enabling the intents in the developer portal.
|
You'll need to apply to use the intents with Discord, but for small selfhosts, all that is required is enabling the intents in the developer portal.
|
||||||
Yes, this is a new thing from Discord, as of October 2020. No, there's nothing we can do about it. Yes, we're aware it worked before.
|
Yes, this is a new thing from Discord, as of October 2020. No, there's nothing we can do about it. Yes, we're aware it worked before.
|
||||||
While waiting for your bot to be accepted, you can change the 'usePrivilegedIntents' inside your creds.yml to 'false', although this will break many of the nadeko's features
|
While waiting for your bot to be accepted, you can change the 'usePrivilegedIntents' inside your creds.yml to 'false', although this will break many of the nadeko's features
|
||||||
""");
|
""");
|
||||||
return Task.CompletedTask;
|
return Task.CompletedTask;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -1,4 +1,5 @@
|
|||||||
#nullable disable
|
#nullable disable
|
||||||
|
using LinqToDB.EntityFrameworkCore;
|
||||||
using Microsoft.EntityFrameworkCore;
|
using Microsoft.EntityFrameworkCore;
|
||||||
using NadekoBot.Db.Models;
|
using NadekoBot.Db.Models;
|
||||||
|
|
||||||
@@ -32,8 +33,8 @@ public static class GuildConfigExtensions
|
|||||||
{
|
{
|
||||||
var conf = ctx.GuildConfigsForId(guildId,
|
var conf = ctx.GuildConfigsForId(guildId,
|
||||||
set => set.Include(y => y.StreamRole)
|
set => set.Include(y => y.StreamRole)
|
||||||
.Include(y => y.StreamRole.Whitelist)
|
.Include(y => y.StreamRole.Whitelist)
|
||||||
.Include(y => y.StreamRole.Blacklist));
|
.Include(y => y.StreamRole.Blacklist));
|
||||||
|
|
||||||
if (conf.StreamRole is null)
|
if (conf.StreamRole is null)
|
||||||
conf.StreamRole = new();
|
conf.StreamRole = new();
|
||||||
@@ -42,19 +43,28 @@ public static class GuildConfigExtensions
|
|||||||
}
|
}
|
||||||
|
|
||||||
private static IQueryable<GuildConfig> IncludeEverything(this DbSet<GuildConfig> configs)
|
private static IQueryable<GuildConfig> IncludeEverything(this DbSet<GuildConfig> configs)
|
||||||
=> configs.AsQueryable()
|
=> configs
|
||||||
.AsSplitQuery()
|
.AsSplitQuery()
|
||||||
.Include(gc => gc.CommandCooldowns)
|
.Include(gc => gc.CommandCooldowns)
|
||||||
.Include(gc => gc.FollowedStreams)
|
.Include(gc => gc.FollowedStreams)
|
||||||
.Include(gc => gc.StreamRole)
|
.Include(gc => gc.StreamRole)
|
||||||
.Include(gc => gc.XpSettings)
|
.Include(gc => gc.DelMsgOnCmdChannels)
|
||||||
.ThenInclude(x => x.ExclusionList)
|
.Include(gc => gc.XpSettings)
|
||||||
.Include(gc => gc.DelMsgOnCmdChannels);
|
.ThenInclude(x => x.ExclusionList);
|
||||||
|
|
||||||
public static IEnumerable<GuildConfig> GetAllGuildConfigs(
|
public static async Task<GuildConfig[]> GetAllGuildConfigs(
|
||||||
this DbSet<GuildConfig> configs,
|
this DbSet<GuildConfig> configs,
|
||||||
IReadOnlyList<ulong> availableGuilds)
|
List<ulong> availableGuilds)
|
||||||
=> configs.IncludeEverything().AsNoTracking().Where(x => availableGuilds.Contains(x.GuildId)).ToList();
|
{
|
||||||
|
var result = await configs
|
||||||
|
.AsQueryable()
|
||||||
|
.Include(x => x.CommandCooldowns)
|
||||||
|
.Where(x => availableGuilds.Contains(x.GuildId))
|
||||||
|
.AsNoTracking()
|
||||||
|
.ToArrayAsync();
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets and creates if it doesn't exist a config for a guild.
|
/// Gets and creates if it doesn't exist a config for a guild.
|
||||||
@@ -80,13 +90,14 @@ public static class GuildConfigExtensions
|
|||||||
|
|
||||||
if (config is null)
|
if (config is null)
|
||||||
{
|
{
|
||||||
ctx.Set<GuildConfig>().Add(config = new()
|
ctx.Set<GuildConfig>()
|
||||||
{
|
.Add(config = new()
|
||||||
GuildId = guildId,
|
{
|
||||||
Permissions = Permissionv2.GetDefaultPermlist,
|
GuildId = guildId,
|
||||||
WarningsInitialized = true,
|
Permissions = Permissionv2.GetDefaultPermlist,
|
||||||
WarnPunishments = DefaultWarnPunishments
|
WarningsInitialized = true,
|
||||||
});
|
WarnPunishments = DefaultWarnPunishments
|
||||||
|
});
|
||||||
ctx.SaveChanges();
|
ctx.SaveChanges();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -122,18 +133,18 @@ public static class GuildConfigExtensions
|
|||||||
public static LogSetting LogSettingsFor(this DbContext ctx, ulong guildId)
|
public static LogSetting LogSettingsFor(this DbContext ctx, ulong guildId)
|
||||||
{
|
{
|
||||||
var logSetting = ctx.Set<LogSetting>()
|
var logSetting = ctx.Set<LogSetting>()
|
||||||
.AsQueryable()
|
.AsQueryable()
|
||||||
.Include(x => x.LogIgnores)
|
.Include(x => x.LogIgnores)
|
||||||
.Where(x => x.GuildId == guildId)
|
.Where(x => x.GuildId == guildId)
|
||||||
.FirstOrDefault();
|
.FirstOrDefault();
|
||||||
|
|
||||||
if (logSetting is null)
|
if (logSetting is null)
|
||||||
{
|
{
|
||||||
ctx.Set<LogSetting>()
|
ctx.Set<LogSetting>()
|
||||||
.Add(logSetting = new()
|
.Add(logSetting = new()
|
||||||
{
|
{
|
||||||
GuildId = guildId
|
GuildId = guildId
|
||||||
});
|
});
|
||||||
ctx.SaveChanges();
|
ctx.SaveChanges();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -149,18 +160,20 @@ public static class GuildConfigExtensions
|
|||||||
|
|
||||||
public static GuildConfig GcWithPermissionsFor(this DbContext ctx, ulong guildId)
|
public static GuildConfig GcWithPermissionsFor(this DbContext ctx, ulong guildId)
|
||||||
{
|
{
|
||||||
var config = ctx.Set<GuildConfig>().AsQueryable()
|
var config = ctx.Set<GuildConfig>()
|
||||||
.Where(gc => gc.GuildId == guildId)
|
.AsQueryable()
|
||||||
.Include(gc => gc.Permissions)
|
.Where(gc => gc.GuildId == guildId)
|
||||||
.FirstOrDefault();
|
.Include(gc => gc.Permissions)
|
||||||
|
.FirstOrDefault();
|
||||||
|
|
||||||
if (config is null) // if there is no guildconfig, create new one
|
if (config is null) // if there is no guildconfig, create new one
|
||||||
{
|
{
|
||||||
ctx.Set<GuildConfig>().Add(config = new()
|
ctx.Set<GuildConfig>()
|
||||||
{
|
.Add(config = new()
|
||||||
GuildId = guildId,
|
{
|
||||||
Permissions = Permissionv2.GetDefaultPermlist
|
GuildId = guildId,
|
||||||
});
|
Permissions = Permissionv2.GetDefaultPermlist
|
||||||
|
});
|
||||||
ctx.SaveChanges();
|
ctx.SaveChanges();
|
||||||
}
|
}
|
||||||
else if (config.Permissions is null || !config.Permissions.Any()) // if no perms, add default ones
|
else if (config.Permissions is null || !config.Permissions.Any()) // if no perms, add default ones
|
||||||
@@ -177,21 +190,21 @@ public static class GuildConfigExtensions
|
|||||||
|
|
||||||
public static IEnumerable<FollowedStream> GetFollowedStreams(this DbSet<GuildConfig> configs, List<ulong> included)
|
public static IEnumerable<FollowedStream> GetFollowedStreams(this DbSet<GuildConfig> configs, List<ulong> included)
|
||||||
=> configs.AsQueryable()
|
=> configs.AsQueryable()
|
||||||
.Where(gc => included.Contains(gc.GuildId))
|
.Where(gc => included.Contains(gc.GuildId))
|
||||||
.Include(gc => gc.FollowedStreams)
|
.Include(gc => gc.FollowedStreams)
|
||||||
.SelectMany(gc => gc.FollowedStreams)
|
.SelectMany(gc => gc.FollowedStreams)
|
||||||
.ToList();
|
.ToList();
|
||||||
|
|
||||||
|
|
||||||
public static XpSettings XpSettingsFor(this DbContext ctx, ulong guildId)
|
public static XpSettings XpSettingsFor(this DbContext ctx, ulong guildId)
|
||||||
{
|
{
|
||||||
var gc = ctx.GuildConfigsForId(guildId,
|
var gc = ctx.GuildConfigsForId(guildId,
|
||||||
set => set.Include(x => x.XpSettings)
|
set => set.Include(x => x.XpSettings)
|
||||||
.ThenInclude(x => x.RoleRewards)
|
.ThenInclude(x => x.RoleRewards)
|
||||||
.Include(x => x.XpSettings)
|
.Include(x => x.XpSettings)
|
||||||
.ThenInclude(x => x.CurrencyRewards)
|
.ThenInclude(x => x.CurrencyRewards)
|
||||||
.Include(x => x.XpSettings)
|
.Include(x => x.XpSettings)
|
||||||
.ThenInclude(x => x.ExclusionList));
|
.ThenInclude(x => x.ExclusionList));
|
||||||
|
|
||||||
if (gc.XpSettings is null)
|
if (gc.XpSettings is null)
|
||||||
gc.XpSettings = new();
|
gc.XpSettings = new();
|
||||||
@@ -201,15 +214,15 @@ public static class GuildConfigExtensions
|
|||||||
|
|
||||||
public static IEnumerable<GeneratingChannel> GetGeneratingChannels(this DbSet<GuildConfig> configs)
|
public static IEnumerable<GeneratingChannel> GetGeneratingChannels(this DbSet<GuildConfig> configs)
|
||||||
=> configs.AsQueryable()
|
=> configs.AsQueryable()
|
||||||
.Include(x => x.GenerateCurrencyChannelIds)
|
.Include(x => x.GenerateCurrencyChannelIds)
|
||||||
.Where(x => x.GenerateCurrencyChannelIds.Any())
|
.Where(x => x.GenerateCurrencyChannelIds.Any())
|
||||||
.SelectMany(x => x.GenerateCurrencyChannelIds)
|
.SelectMany(x => x.GenerateCurrencyChannelIds)
|
||||||
.Select(x => new GeneratingChannel
|
.Select(x => new GeneratingChannel
|
||||||
{
|
{
|
||||||
ChannelId = x.ChannelId,
|
ChannelId = x.ChannelId,
|
||||||
GuildId = x.GuildConfig.GuildId
|
GuildId = x.GuildConfig.GuildId
|
||||||
})
|
})
|
||||||
.ToArray();
|
.ToArray();
|
||||||
|
|
||||||
public class GeneratingChannel
|
public class GeneratingChannel
|
||||||
{
|
{
|
||||||
|
@@ -1,53 +0,0 @@
|
|||||||
#nullable disable
|
|
||||||
using Microsoft.EntityFrameworkCore;
|
|
||||||
using NadekoBot.Db.Models;
|
|
||||||
|
|
||||||
namespace NadekoBot.Db;
|
|
||||||
|
|
||||||
public static class QuoteExtensions
|
|
||||||
{
|
|
||||||
public static IEnumerable<Quote> GetForGuild(this DbSet<Quote> quotes, ulong guildId)
|
|
||||||
=> quotes.AsQueryable().Where(x => x.GuildId == guildId);
|
|
||||||
|
|
||||||
public static IReadOnlyCollection<Quote> GetGroup(
|
|
||||||
this DbSet<Quote> quotes,
|
|
||||||
ulong guildId,
|
|
||||||
int page,
|
|
||||||
OrderType order)
|
|
||||||
{
|
|
||||||
var q = quotes.AsQueryable().Where(x => x.GuildId == guildId);
|
|
||||||
if (order == OrderType.Keyword)
|
|
||||||
q = q.OrderBy(x => x.Keyword);
|
|
||||||
else
|
|
||||||
q = q.OrderBy(x => x.Id);
|
|
||||||
|
|
||||||
return q.Skip(15 * page).Take(15).ToArray();
|
|
||||||
}
|
|
||||||
|
|
||||||
public static async Task<Quote> GetRandomQuoteByKeywordAsync(
|
|
||||||
this DbSet<Quote> quotes,
|
|
||||||
ulong guildId,
|
|
||||||
string keyword)
|
|
||||||
{
|
|
||||||
return (await quotes.AsQueryable().Where(q => q.GuildId == guildId && q.Keyword == keyword).ToArrayAsync())
|
|
||||||
.RandomOrDefault();
|
|
||||||
}
|
|
||||||
|
|
||||||
public static async Task<Quote> SearchQuoteKeywordTextAsync(
|
|
||||||
this DbSet<Quote> quotes,
|
|
||||||
ulong guildId,
|
|
||||||
string keyword,
|
|
||||||
string text)
|
|
||||||
{
|
|
||||||
return (await quotes.AsQueryable()
|
|
||||||
.Where(q => q.GuildId == guildId
|
|
||||||
&& (keyword == null || q.Keyword == keyword)
|
|
||||||
&& (EF.Functions.Like(q.Text.ToUpper(), $"%{text.ToUpper()}%")
|
|
||||||
|| EF.Functions.Like(q.AuthorName, text)))
|
|
||||||
.ToArrayAsync())
|
|
||||||
.RandomOrDefault();
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void RemoveAllByKeyword(this DbSet<Quote> quotes, ulong guildId, string keyword)
|
|
||||||
=> quotes.RemoveRange(quotes.AsQueryable().Where(x => x.GuildId == guildId && x.Keyword.ToUpper() == keyword));
|
|
||||||
}
|
|
@@ -13,21 +13,23 @@ public class GuildConfig : DbEntity
|
|||||||
|
|
||||||
public string AutoAssignRoleIds { get; set; }
|
public string AutoAssignRoleIds { get; set; }
|
||||||
|
|
||||||
//greet stuff
|
// //greet stuff
|
||||||
public int AutoDeleteGreetMessagesTimer { get; set; } = 30;
|
// public int AutoDeleteGreetMessagesTimer { get; set; } = 30;
|
||||||
public int AutoDeleteByeMessagesTimer { get; set; } = 30;
|
// public int AutoDeleteByeMessagesTimer { get; set; } = 30;
|
||||||
|
//
|
||||||
public ulong GreetMessageChannelId { get; set; }
|
// public ulong GreetMessageChannelId { get; set; }
|
||||||
public ulong ByeMessageChannelId { get; set; }
|
// public ulong ByeMessageChannelId { get; set; }
|
||||||
|
//
|
||||||
public bool SendDmGreetMessage { get; set; }
|
// public bool SendDmGreetMessage { get; set; }
|
||||||
public string DmGreetMessageText { get; set; } = "Welcome to the %server% server, %user%!";
|
// public string DmGreetMessageText { get; set; } = "Welcome to the %server% server, %user%!";
|
||||||
|
//
|
||||||
public bool SendChannelGreetMessage { get; set; }
|
// public bool SendChannelGreetMessage { get; set; }
|
||||||
public string ChannelGreetMessageText { get; set; } = "Welcome to the %server% server, %user%!";
|
// public string ChannelGreetMessageText { get; set; } = "Welcome to the %server% server, %user%!";
|
||||||
|
//
|
||||||
public bool SendChannelByeMessage { get; set; }
|
// public bool SendChannelByeMessage { get; set; }
|
||||||
public string ChannelByeMessageText { get; set; } = "%user% has left!";
|
// public string ChannelByeMessageText { get; set; } = "%user% has left!";
|
||||||
|
// public bool SendBoostMessage { get; set; }
|
||||||
|
// pulic int BoostMessageDeleteAfter { get; set; }
|
||||||
|
|
||||||
//self assignable roles
|
//self assignable roles
|
||||||
public bool ExclusiveSelfAssignedRoles { get; set; }
|
public bool ExclusiveSelfAssignedRoles { get; set; }
|
||||||
@@ -98,10 +100,6 @@ public class GuildConfig : DbEntity
|
|||||||
|
|
||||||
#region Boost Message
|
#region Boost Message
|
||||||
|
|
||||||
public bool SendBoostMessage { get; set; }
|
|
||||||
public string BoostMessage { get; set; } = "%user% just boosted this server!";
|
|
||||||
public ulong BoostMessageChannelId { get; set; }
|
|
||||||
public int BoostMessageDeleteAfter { get; set; }
|
|
||||||
public bool StickyRoles { get; set; }
|
public bool StickyRoles { get; set; }
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
@@ -8,6 +8,4 @@ public class UserXpStats : DbEntity
|
|||||||
public long Xp { get; set; }
|
public long Xp { get; set; }
|
||||||
public long AwardedXp { get; set; }
|
public long AwardedXp { get; set; }
|
||||||
public XpNotificationLocation NotifyOnLevelUp { get; set; }
|
public XpNotificationLocation NotifyOnLevelUp { get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
public enum XpNotificationLocation { None, Dm, Channel }
|
|
8
src/NadekoBot/Db/Models/xp/XpNotificationLocation.cs
Normal file
8
src/NadekoBot/Db/Models/xp/XpNotificationLocation.cs
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
namespace NadekoBot.Db.Models;
|
||||||
|
|
||||||
|
public enum XpNotificationLocation
|
||||||
|
{
|
||||||
|
None,
|
||||||
|
Dm,
|
||||||
|
Channel
|
||||||
|
}
|
@@ -1,38 +0,0 @@
|
|||||||
using Microsoft.EntityFrameworkCore;
|
|
||||||
using NadekoBot.Db.Models;
|
|
||||||
|
|
||||||
namespace NadekoBot.Db;
|
|
||||||
|
|
||||||
public sealed class MysqlContext : NadekoContext
|
|
||||||
{
|
|
||||||
private readonly string _connStr;
|
|
||||||
private readonly string _version;
|
|
||||||
|
|
||||||
protected override string CurrencyTransactionOtherIdDefaultValue
|
|
||||||
=> "NULL";
|
|
||||||
|
|
||||||
public MysqlContext(string connStr = "Server=localhost", string version = "8.0")
|
|
||||||
{
|
|
||||||
_connStr = connStr;
|
|
||||||
_version = version;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
|
|
||||||
{
|
|
||||||
base.OnConfiguring(optionsBuilder);
|
|
||||||
optionsBuilder
|
|
||||||
.UseLowerCaseNamingConvention()
|
|
||||||
.UseMySql(_connStr, ServerVersion.Parse(_version));
|
|
||||||
}
|
|
||||||
|
|
||||||
protected override void OnModelCreating(ModelBuilder modelBuilder)
|
|
||||||
{
|
|
||||||
base.OnModelCreating(modelBuilder);
|
|
||||||
|
|
||||||
// mysql is case insensitive by default
|
|
||||||
// we can set binary collation to change that
|
|
||||||
modelBuilder.Entity<ClubInfo>()
|
|
||||||
.Property(x => x.Name)
|
|
||||||
.UseCollation("utf8mb4_bin");
|
|
||||||
}
|
|
||||||
}
|
|
@@ -10,6 +10,7 @@ namespace NadekoBot.Db;
|
|||||||
public abstract class NadekoContext : DbContext
|
public abstract class NadekoContext : DbContext
|
||||||
{
|
{
|
||||||
public DbSet<GuildConfig> GuildConfigs { get; set; }
|
public DbSet<GuildConfig> GuildConfigs { get; set; }
|
||||||
|
public DbSet<GreetSettings> GreetSettings { get; set; }
|
||||||
|
|
||||||
public DbSet<Quote> Quotes { get; set; }
|
public DbSet<Quote> Quotes { get; set; }
|
||||||
public DbSet<Reminder> Reminders { get; set; }
|
public DbSet<Reminder> Reminders { get; set; }
|
||||||
@@ -149,7 +150,7 @@ public abstract class NadekoContext : DbContext
|
|||||||
.OnDelete(DeleteBehavior.Cascade);
|
.OnDelete(DeleteBehavior.Cascade);
|
||||||
|
|
||||||
// start antispam
|
// start antispam
|
||||||
|
|
||||||
modelBuilder.Entity<GuildConfig>()
|
modelBuilder.Entity<GuildConfig>()
|
||||||
.HasOne(x => x.AntiSpamSetting)
|
.HasOne(x => x.AntiSpamSetting)
|
||||||
.WithOne()
|
.WithOne()
|
||||||
@@ -678,6 +679,29 @@ public abstract class NadekoContext : DbContext
|
|||||||
.OnDelete(DeleteBehavior.Cascade);
|
.OnDelete(DeleteBehavior.Cascade);
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
|
#region GreetSettings
|
||||||
|
|
||||||
|
modelBuilder
|
||||||
|
.Entity<GreetSettings>(gs => gs.HasIndex(x => new
|
||||||
|
{
|
||||||
|
x.GuildId,
|
||||||
|
x.GreetType
|
||||||
|
})
|
||||||
|
.IsUnique());
|
||||||
|
|
||||||
|
modelBuilder.Entity<GreetSettings>(gs =>
|
||||||
|
{
|
||||||
|
gs
|
||||||
|
.Property(x => x.IsEnabled)
|
||||||
|
.HasDefaultValue(false);
|
||||||
|
|
||||||
|
gs
|
||||||
|
.Property(x => x.AutoDeleteTimer)
|
||||||
|
.HasDefaultValue(0);
|
||||||
|
});
|
||||||
|
|
||||||
|
#endregion
|
||||||
}
|
}
|
||||||
|
|
||||||
#if DEBUG
|
#if DEBUG
|
||||||
|
@@ -44,8 +44,6 @@ public sealed class NadekoDbService : DbService
|
|||||||
case "postgres":
|
case "postgres":
|
||||||
case "pgsql":
|
case "pgsql":
|
||||||
return new PostgreSqlContext(connString);
|
return new PostgreSqlContext(connString);
|
||||||
case "mysql":
|
|
||||||
return new MysqlContext(connString);
|
|
||||||
case "sqlite":
|
case "sqlite":
|
||||||
return new SqliteContext(connString);
|
return new SqliteContext(connString);
|
||||||
default:
|
default:
|
||||||
|
@@ -7,16 +7,7 @@ public static class MigrationQueries
|
|||||||
{
|
{
|
||||||
public static void MigrateRero(MigrationBuilder migrationBuilder)
|
public static void MigrateRero(MigrationBuilder migrationBuilder)
|
||||||
{
|
{
|
||||||
if (migrationBuilder.IsMySql())
|
if (migrationBuilder.IsSqlite())
|
||||||
{
|
|
||||||
migrationBuilder.Sql(
|
|
||||||
@"INSERT IGNORE into reactionroles(guildid, channelid, messageid, emote, roleid, `group`, levelreq, dateadded)
|
|
||||||
select guildid, channelid, messageid, emotename, roleid, exclusive, 0, reactionrolemessage.dateadded
|
|
||||||
from reactionrole
|
|
||||||
left join reactionrolemessage on reactionrolemessage.id = reactionrole.reactionrolemessageid
|
|
||||||
left join guildconfigs on reactionrolemessage.guildconfigid = guildconfigs.id;");
|
|
||||||
}
|
|
||||||
else if (migrationBuilder.IsSqlite())
|
|
||||||
{
|
{
|
||||||
migrationBuilder.Sql(
|
migrationBuilder.Sql(
|
||||||
@"insert or ignore into reactionroles(guildid, channelid, messageid, emote, roleid, 'group', levelreq, dateadded)
|
@"insert or ignore into reactionroles(guildid, channelid, messageid, emote, roleid, 'group', levelreq, dateadded)
|
||||||
@@ -27,7 +18,8 @@ left join guildconfigs on reactionrolemessage.guildconfigid = guildconfigs.id;")
|
|||||||
}
|
}
|
||||||
else if (migrationBuilder.IsNpgsql())
|
else if (migrationBuilder.IsNpgsql())
|
||||||
{
|
{
|
||||||
migrationBuilder.Sql(@"insert into reactionroles(guildid, channelid, messageid, emote, roleid, ""group"", levelreq, dateadded)
|
migrationBuilder.Sql(
|
||||||
|
@"insert into reactionroles(guildid, channelid, messageid, emote, roleid, ""group"", levelreq, dateadded)
|
||||||
select guildid, channelid, messageid, emotename, roleid, exclusive::int, 0, reactionrolemessage.dateadded
|
select guildid, channelid, messageid, emotename, roleid, exclusive::int, 0, reactionrolemessage.dateadded
|
||||||
from reactionrole
|
from reactionrole
|
||||||
left join reactionrolemessage on reactionrolemessage.id = reactionrole.reactionrolemessageid
|
left join reactionrolemessage on reactionrolemessage.id = reactionrole.reactionrolemessageid
|
||||||
@@ -43,11 +35,34 @@ left join guildconfigs on reactionrolemessage.guildconfigid = guildconfigs.id;")
|
|||||||
public static void GuildConfigCleanup(MigrationBuilder builder)
|
public static void GuildConfigCleanup(MigrationBuilder builder)
|
||||||
{
|
{
|
||||||
builder.Sql($"""
|
builder.Sql($"""
|
||||||
|
DELETE FROM "DelMsgOnCmdChannel" WHERE "GuildConfigId" is NULL;
|
||||||
|
DELETE FROM "WarningPunishment" WHERE "GuildConfigId" NOT IN (SELECT "Id" from "GuildConfigs");
|
||||||
DELETE FROM "StreamRoleBlacklistedUser" WHERE "StreamRoleSettingsId" is NULL;
|
DELETE FROM "StreamRoleBlacklistedUser" WHERE "StreamRoleSettingsId" is NULL;
|
||||||
""");
|
""");
|
||||||
|
}
|
||||||
|
|
||||||
builder.Sql($"""
|
public static void GreetSettingsCopy(MigrationBuilder builder)
|
||||||
DELETE FROM "DelMsgOnCmdChannel" WHERE "GuildConfigId" is NULL;
|
{
|
||||||
""");
|
builder.Sql("""
|
||||||
|
INSERT INTO GreetSettings (GuildId, GreetType, MessageText, IsEnabled, ChannelId, AutoDeleteTimer)
|
||||||
|
SELECT GuildId, 0, ChannelGreetMessageText, SendChannelGreetMessage, GreetMessageChannelId, AutoDeleteGreetMessagesTimer
|
||||||
|
FROM GuildConfigs
|
||||||
|
WHERE SendChannelGreetMessage = TRUE;
|
||||||
|
|
||||||
|
INSERT INTO GreetSettings (GuildId, GreetType, MessageText, IsEnabled, ChannelId, AutoDeleteTimer)
|
||||||
|
SELECT GuildId, 1, DmGreetMessageText, SendDmGreetMessage, GreetMessageChannelId, 0
|
||||||
|
FROM GuildConfigs
|
||||||
|
WHERE SendDmGreetMessage = TRUE;
|
||||||
|
|
||||||
|
INSERT INTO GreetSettings (GuildId, GreetType, MessageText, IsEnabled, ChannelId, AutoDeleteTimer)
|
||||||
|
SELECT GuildId, 2, ChannelByeMessageText, SendChannelByeMessage, ByeMessageChannelId, AutoDeleteByeMessagesTimer
|
||||||
|
FROM GuildConfigs
|
||||||
|
WHERE SendChannelByeMessage = TRUE;
|
||||||
|
|
||||||
|
INSERT INTO GreetSettings (GuildId, GreetType, MessageText, IsEnabled, ChannelId, AutoDeleteTimer)
|
||||||
|
SELECT GuildId, 3, BoostMessage, SendBoostMessage, BoostMessageChannelId, BoostMessageDeleteAfter
|
||||||
|
FROM GuildConfigs
|
||||||
|
WHERE SendBoostMessage = TRUE;
|
||||||
|
""");
|
||||||
}
|
}
|
||||||
}
|
}
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -1,26 +0,0 @@
|
|||||||
using Microsoft.EntityFrameworkCore.Migrations;
|
|
||||||
|
|
||||||
#nullable disable
|
|
||||||
|
|
||||||
namespace NadekoBot.Migrations.Mysql
|
|
||||||
{
|
|
||||||
public partial class stondel : Migration
|
|
||||||
{
|
|
||||||
protected override void Up(MigrationBuilder migrationBuilder)
|
|
||||||
{
|
|
||||||
migrationBuilder.AddColumn<bool>(
|
|
||||||
name: "deletestreamonlinemessage",
|
|
||||||
table: "guildconfigs",
|
|
||||||
type: "tinyint(1)",
|
|
||||||
nullable: false,
|
|
||||||
defaultValue: false);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected override void Down(MigrationBuilder migrationBuilder)
|
|
||||||
{
|
|
||||||
migrationBuilder.DropColumn(
|
|
||||||
name: "deletestreamonlinemessage",
|
|
||||||
table: "guildconfigs");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
File diff suppressed because it is too large
Load Diff
@@ -1,41 +0,0 @@
|
|||||||
using Microsoft.EntityFrameworkCore.Metadata;
|
|
||||||
using Microsoft.EntityFrameworkCore.Migrations;
|
|
||||||
|
|
||||||
#nullable disable
|
|
||||||
|
|
||||||
namespace NadekoBot.Migrations.Mysql
|
|
||||||
{
|
|
||||||
public partial class bank : Migration
|
|
||||||
{
|
|
||||||
protected override void Up(MigrationBuilder migrationBuilder)
|
|
||||||
{
|
|
||||||
migrationBuilder.CreateTable(
|
|
||||||
name: "bankusers",
|
|
||||||
columns: table => new
|
|
||||||
{
|
|
||||||
id = table.Column<int>(type: "int", nullable: false)
|
|
||||||
.Annotation("MySql:ValueGenerationStrategy", MySqlValueGenerationStrategy.IdentityColumn),
|
|
||||||
userid = table.Column<ulong>(type: "bigint unsigned", nullable: false),
|
|
||||||
balance = table.Column<long>(type: "bigint", nullable: false),
|
|
||||||
dateadded = table.Column<DateTime>(type: "datetime(6)", nullable: true)
|
|
||||||
},
|
|
||||||
constraints: table =>
|
|
||||||
{
|
|
||||||
table.PrimaryKey("pk_bankusers", x => x.id);
|
|
||||||
})
|
|
||||||
.Annotation("MySql:CharSet", "utf8mb4");
|
|
||||||
|
|
||||||
migrationBuilder.CreateIndex(
|
|
||||||
name: "ix_bankusers_userid",
|
|
||||||
table: "bankusers",
|
|
||||||
column: "userid",
|
|
||||||
unique: true);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected override void Down(MigrationBuilder migrationBuilder)
|
|
||||||
{
|
|
||||||
migrationBuilder.DropTable(
|
|
||||||
name: "bankusers");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
File diff suppressed because it is too large
Load Diff
@@ -1,120 +0,0 @@
|
|||||||
using Microsoft.EntityFrameworkCore.Metadata;
|
|
||||||
using Microsoft.EntityFrameworkCore.Migrations;
|
|
||||||
|
|
||||||
#nullable disable
|
|
||||||
|
|
||||||
namespace NadekoBot.Migrations.Mysql
|
|
||||||
{
|
|
||||||
public partial class newrero : Migration
|
|
||||||
{
|
|
||||||
protected override void Up(MigrationBuilder migrationBuilder)
|
|
||||||
{
|
|
||||||
|
|
||||||
migrationBuilder.CreateTable(
|
|
||||||
name: "reactionroles",
|
|
||||||
columns: table => new
|
|
||||||
{
|
|
||||||
id = table.Column<int>(type: "int", nullable: false)
|
|
||||||
.Annotation("MySql:ValueGenerationStrategy", MySqlValueGenerationStrategy.IdentityColumn),
|
|
||||||
guildid = table.Column<ulong>(type: "bigint unsigned", nullable: false),
|
|
||||||
channelid = table.Column<ulong>(type: "bigint unsigned", nullable: false),
|
|
||||||
messageid = table.Column<ulong>(type: "bigint unsigned", nullable: false),
|
|
||||||
emote = table.Column<string>(type: "varchar(100)", maxLength: 100, nullable: true)
|
|
||||||
.Annotation("MySql:CharSet", "utf8mb4"),
|
|
||||||
roleid = table.Column<ulong>(type: "bigint unsigned", nullable: false),
|
|
||||||
group = table.Column<int>(type: "int", nullable: false),
|
|
||||||
levelreq = table.Column<int>(type: "int", nullable: false),
|
|
||||||
dateadded = table.Column<DateTime>(type: "datetime(6)", nullable: true)
|
|
||||||
},
|
|
||||||
constraints: table =>
|
|
||||||
{
|
|
||||||
table.PrimaryKey("pk_reactionroles", x => x.id);
|
|
||||||
})
|
|
||||||
.Annotation("MySql:CharSet", "utf8mb4");
|
|
||||||
|
|
||||||
migrationBuilder.CreateIndex(
|
|
||||||
name: "ix_reactionroles_guildid",
|
|
||||||
table: "reactionroles",
|
|
||||||
column: "guildid");
|
|
||||||
|
|
||||||
migrationBuilder.CreateIndex(
|
|
||||||
name: "ix_reactionroles_messageid_emote",
|
|
||||||
table: "reactionroles",
|
|
||||||
columns: new[] { "messageid", "emote" },
|
|
||||||
unique: true);
|
|
||||||
|
|
||||||
MigrationQueries.MigrateRero(migrationBuilder);
|
|
||||||
|
|
||||||
migrationBuilder.DropTable(
|
|
||||||
name: "reactionrole");
|
|
||||||
|
|
||||||
migrationBuilder.DropTable(
|
|
||||||
name: "reactionrolemessage");
|
|
||||||
}
|
|
||||||
|
|
||||||
protected override void Down(MigrationBuilder migrationBuilder)
|
|
||||||
{
|
|
||||||
migrationBuilder.DropTable(
|
|
||||||
name: "reactionroles");
|
|
||||||
|
|
||||||
migrationBuilder.CreateTable(
|
|
||||||
name: "reactionrolemessage",
|
|
||||||
columns: table => new
|
|
||||||
{
|
|
||||||
id = table.Column<int>(type: "int", nullable: false)
|
|
||||||
.Annotation("MySql:ValueGenerationStrategy", MySqlValueGenerationStrategy.IdentityColumn),
|
|
||||||
guildconfigid = table.Column<int>(type: "int", nullable: false),
|
|
||||||
channelid = table.Column<ulong>(type: "bigint unsigned", nullable: false),
|
|
||||||
dateadded = table.Column<DateTime>(type: "datetime(6)", nullable: true),
|
|
||||||
exclusive = table.Column<bool>(type: "tinyint(1)", nullable: false),
|
|
||||||
index = table.Column<int>(type: "int", nullable: false),
|
|
||||||
messageid = table.Column<ulong>(type: "bigint unsigned", nullable: false)
|
|
||||||
},
|
|
||||||
constraints: table =>
|
|
||||||
{
|
|
||||||
table.PrimaryKey("pk_reactionrolemessage", x => x.id);
|
|
||||||
table.ForeignKey(
|
|
||||||
name: "fk_reactionrolemessage_guildconfigs_guildconfigid",
|
|
||||||
column: x => x.guildconfigid,
|
|
||||||
principalTable: "guildconfigs",
|
|
||||||
principalColumn: "id",
|
|
||||||
onDelete: ReferentialAction.Cascade);
|
|
||||||
})
|
|
||||||
.Annotation("MySql:CharSet", "utf8mb4");
|
|
||||||
|
|
||||||
migrationBuilder.CreateTable(
|
|
||||||
name: "reactionrole",
|
|
||||||
columns: table => new
|
|
||||||
{
|
|
||||||
id = table.Column<int>(type: "int", nullable: false)
|
|
||||||
.Annotation("MySql:ValueGenerationStrategy", MySqlValueGenerationStrategy.IdentityColumn),
|
|
||||||
dateadded = table.Column<DateTime>(type: "datetime(6)", nullable: true),
|
|
||||||
emotename = table.Column<string>(type: "longtext", nullable: true)
|
|
||||||
.Annotation("MySql:CharSet", "utf8mb4"),
|
|
||||||
reactionrolemessageid = table.Column<int>(type: "int", nullable: true),
|
|
||||||
roleid = table.Column<ulong>(type: "bigint unsigned", nullable: false)
|
|
||||||
},
|
|
||||||
constraints: table =>
|
|
||||||
{
|
|
||||||
table.PrimaryKey("pk_reactionrole", x => x.id);
|
|
||||||
table.ForeignKey(
|
|
||||||
name: "fk_reactionrole_reactionrolemessage_reactionrolemessageid",
|
|
||||||
column: x => x.reactionrolemessageid,
|
|
||||||
principalTable: "reactionrolemessage",
|
|
||||||
principalColumn: "id",
|
|
||||||
onDelete: ReferentialAction.Cascade);
|
|
||||||
})
|
|
||||||
.Annotation("MySql:CharSet", "utf8mb4");
|
|
||||||
|
|
||||||
migrationBuilder.CreateIndex(
|
|
||||||
name: "ix_reactionrole_reactionrolemessageid",
|
|
||||||
table: "reactionrole",
|
|
||||||
column: "reactionrolemessageid");
|
|
||||||
|
|
||||||
migrationBuilder.CreateIndex(
|
|
||||||
name: "ix_reactionrolemessage_guildconfigid",
|
|
||||||
table: "reactionrolemessage",
|
|
||||||
column: "guildconfigid");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
File diff suppressed because it is too large
Load Diff
@@ -1,175 +0,0 @@
|
|||||||
using Microsoft.EntityFrameworkCore.Metadata;
|
|
||||||
using Microsoft.EntityFrameworkCore.Migrations;
|
|
||||||
|
|
||||||
#nullable disable
|
|
||||||
|
|
||||||
namespace NadekoBot.Migrations.Mysql
|
|
||||||
{
|
|
||||||
public partial class patronagesystem : Migration
|
|
||||||
{
|
|
||||||
protected override void Up(MigrationBuilder migrationBuilder)
|
|
||||||
{
|
|
||||||
migrationBuilder.RenameColumn(
|
|
||||||
name: "patreonuserid",
|
|
||||||
table: "rewardedusers",
|
|
||||||
newName: "platformuserid");
|
|
||||||
|
|
||||||
migrationBuilder.RenameIndex(
|
|
||||||
name: "ix_rewardedusers_patreonuserid",
|
|
||||||
table: "rewardedusers",
|
|
||||||
newName: "ix_rewardedusers_platformuserid");
|
|
||||||
|
|
||||||
migrationBuilder.AlterColumn<long>(
|
|
||||||
name: "xp",
|
|
||||||
table: "userxpstats",
|
|
||||||
type: "bigint",
|
|
||||||
nullable: false,
|
|
||||||
oldClrType: typeof(int),
|
|
||||||
oldType: "int");
|
|
||||||
|
|
||||||
migrationBuilder.AlterColumn<long>(
|
|
||||||
name: "awardedxp",
|
|
||||||
table: "userxpstats",
|
|
||||||
type: "bigint",
|
|
||||||
nullable: false,
|
|
||||||
oldClrType: typeof(int),
|
|
||||||
oldType: "int");
|
|
||||||
|
|
||||||
migrationBuilder.AlterColumn<long>(
|
|
||||||
name: "amountrewardedthismonth",
|
|
||||||
table: "rewardedusers",
|
|
||||||
type: "bigint",
|
|
||||||
nullable: false,
|
|
||||||
oldClrType: typeof(int),
|
|
||||||
oldType: "int");
|
|
||||||
|
|
||||||
migrationBuilder.AlterColumn<bool>(
|
|
||||||
name: "verboseerrors",
|
|
||||||
table: "guildconfigs",
|
|
||||||
type: "tinyint(1)",
|
|
||||||
nullable: false,
|
|
||||||
defaultValue: true,
|
|
||||||
oldClrType: typeof(bool),
|
|
||||||
oldType: "tinyint(1)");
|
|
||||||
|
|
||||||
migrationBuilder.AlterColumn<long>(
|
|
||||||
name: "totalxp",
|
|
||||||
table: "discorduser",
|
|
||||||
type: "bigint",
|
|
||||||
nullable: false,
|
|
||||||
defaultValue: 0L,
|
|
||||||
oldClrType: typeof(int),
|
|
||||||
oldType: "int",
|
|
||||||
oldDefaultValue: 0);
|
|
||||||
|
|
||||||
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"),
|
|
||||||
hourlycount = table.Column<uint>(type: "int unsigned", nullable: false),
|
|
||||||
dailycount = 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.CreateTable(
|
|
||||||
name: "patrons",
|
|
||||||
columns: table => new
|
|
||||||
{
|
|
||||||
userid = table.Column<ulong>(type: "bigint unsigned", nullable: false)
|
|
||||||
.Annotation("MySql:ValueGenerationStrategy", MySqlValueGenerationStrategy.IdentityColumn),
|
|
||||||
uniqueplatformuserid = table.Column<string>(type: "varchar(255)", nullable: true)
|
|
||||||
.Annotation("MySql:CharSet", "utf8mb4"),
|
|
||||||
amountcents = table.Column<int>(type: "int", nullable: false),
|
|
||||||
lastcharge = table.Column<DateTime>(type: "datetime(6)", nullable: false),
|
|
||||||
validthru = table.Column<DateTime>(type: "datetime(6)", nullable: false)
|
|
||||||
},
|
|
||||||
constraints: table =>
|
|
||||||
{
|
|
||||||
table.PrimaryKey("pk_patrons", x => x.userid);
|
|
||||||
})
|
|
||||||
.Annotation("MySql:CharSet", "utf8mb4");
|
|
||||||
|
|
||||||
migrationBuilder.CreateIndex(
|
|
||||||
name: "ix_patronquotas_userid",
|
|
||||||
table: "patronquotas",
|
|
||||||
column: "userid");
|
|
||||||
|
|
||||||
migrationBuilder.CreateIndex(
|
|
||||||
name: "ix_patrons_uniqueplatformuserid",
|
|
||||||
table: "patrons",
|
|
||||||
column: "uniqueplatformuserid",
|
|
||||||
unique: true);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected override void Down(MigrationBuilder migrationBuilder)
|
|
||||||
{
|
|
||||||
migrationBuilder.DropTable(
|
|
||||||
name: "patronquotas");
|
|
||||||
|
|
||||||
migrationBuilder.DropTable(
|
|
||||||
name: "patrons");
|
|
||||||
|
|
||||||
migrationBuilder.RenameColumn(
|
|
||||||
name: "platformuserid",
|
|
||||||
table: "rewardedusers",
|
|
||||||
newName: "patreonuserid");
|
|
||||||
|
|
||||||
migrationBuilder.RenameIndex(
|
|
||||||
name: "ix_rewardedusers_platformuserid",
|
|
||||||
table: "rewardedusers",
|
|
||||||
newName: "ix_rewardedusers_patreonuserid");
|
|
||||||
|
|
||||||
migrationBuilder.AlterColumn<int>(
|
|
||||||
name: "xp",
|
|
||||||
table: "userxpstats",
|
|
||||||
type: "int",
|
|
||||||
nullable: false,
|
|
||||||
oldClrType: typeof(long),
|
|
||||||
oldType: "bigint");
|
|
||||||
|
|
||||||
migrationBuilder.AlterColumn<int>(
|
|
||||||
name: "awardedxp",
|
|
||||||
table: "userxpstats",
|
|
||||||
type: "int",
|
|
||||||
nullable: false,
|
|
||||||
oldClrType: typeof(long),
|
|
||||||
oldType: "bigint");
|
|
||||||
|
|
||||||
migrationBuilder.AlterColumn<int>(
|
|
||||||
name: "amountrewardedthismonth",
|
|
||||||
table: "rewardedusers",
|
|
||||||
type: "int",
|
|
||||||
nullable: false,
|
|
||||||
oldClrType: typeof(long),
|
|
||||||
oldType: "bigint");
|
|
||||||
|
|
||||||
migrationBuilder.AlterColumn<bool>(
|
|
||||||
name: "verboseerrors",
|
|
||||||
table: "guildconfigs",
|
|
||||||
type: "tinyint(1)",
|
|
||||||
nullable: false,
|
|
||||||
oldClrType: typeof(bool),
|
|
||||||
oldType: "tinyint(1)",
|
|
||||||
oldDefaultValue: true);
|
|
||||||
|
|
||||||
migrationBuilder.AlterColumn<int>(
|
|
||||||
name: "totalxp",
|
|
||||||
table: "discorduser",
|
|
||||||
type: "int",
|
|
||||||
nullable: false,
|
|
||||||
defaultValue: 0,
|
|
||||||
oldClrType: typeof(long),
|
|
||||||
oldType: "bigint",
|
|
||||||
oldDefaultValue: 0L);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
File diff suppressed because it is too large
Load Diff
@@ -1,38 +0,0 @@
|
|||||||
using Microsoft.EntityFrameworkCore.Metadata;
|
|
||||||
using Microsoft.EntityFrameworkCore.Migrations;
|
|
||||||
|
|
||||||
#nullable disable
|
|
||||||
|
|
||||||
namespace NadekoBot.Migrations.Mysql
|
|
||||||
{
|
|
||||||
public partial class stondeldbcache : Migration
|
|
||||||
{
|
|
||||||
protected override void Up(MigrationBuilder migrationBuilder)
|
|
||||||
{
|
|
||||||
migrationBuilder.CreateTable(
|
|
||||||
name: "streamonlinemessages",
|
|
||||||
columns: table => new
|
|
||||||
{
|
|
||||||
id = table.Column<int>(type: "int", nullable: false)
|
|
||||||
.Annotation("MySql:ValueGenerationStrategy", MySqlValueGenerationStrategy.IdentityColumn),
|
|
||||||
channelid = table.Column<ulong>(type: "bigint unsigned", nullable: false),
|
|
||||||
messageid = table.Column<ulong>(type: "bigint unsigned", nullable: false),
|
|
||||||
type = table.Column<int>(type: "int", nullable: false),
|
|
||||||
name = table.Column<string>(type: "longtext", nullable: true)
|
|
||||||
.Annotation("MySql:CharSet", "utf8mb4"),
|
|
||||||
dateadded = table.Column<DateTime>(type: "datetime(6)", nullable: true)
|
|
||||||
},
|
|
||||||
constraints: table =>
|
|
||||||
{
|
|
||||||
table.PrimaryKey("pk_streamonlinemessages", x => x.id);
|
|
||||||
})
|
|
||||||
.Annotation("MySql:CharSet", "utf8mb4");
|
|
||||||
}
|
|
||||||
|
|
||||||
protected override void Down(MigrationBuilder migrationBuilder)
|
|
||||||
{
|
|
||||||
migrationBuilder.DropTable(
|
|
||||||
name: "streamonlinemessages");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
File diff suppressed because it is too large
Load Diff
@@ -1,25 +0,0 @@
|
|||||||
using Microsoft.EntityFrameworkCore.Migrations;
|
|
||||||
|
|
||||||
#nullable disable
|
|
||||||
|
|
||||||
namespace NadekoBot.Migrations.Mysql
|
|
||||||
{
|
|
||||||
public partial class logwarns : Migration
|
|
||||||
{
|
|
||||||
protected override void Up(MigrationBuilder migrationBuilder)
|
|
||||||
{
|
|
||||||
migrationBuilder.AddColumn<ulong>(
|
|
||||||
name: "logwarnsid",
|
|
||||||
table: "logsettings",
|
|
||||||
type: "bigint unsigned",
|
|
||||||
nullable: true);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected override void Down(MigrationBuilder migrationBuilder)
|
|
||||||
{
|
|
||||||
migrationBuilder.DropColumn(
|
|
||||||
name: "logwarnsid",
|
|
||||||
table: "logsettings");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
File diff suppressed because it is too large
Load Diff
@@ -1,44 +0,0 @@
|
|||||||
using Microsoft.EntityFrameworkCore.Metadata;
|
|
||||||
using Microsoft.EntityFrameworkCore.Migrations;
|
|
||||||
|
|
||||||
#nullable disable
|
|
||||||
|
|
||||||
namespace NadekoBot.Migrations.Mysql
|
|
||||||
{
|
|
||||||
public partial class xpitemshop : Migration
|
|
||||||
{
|
|
||||||
protected override void Up(MigrationBuilder migrationBuilder)
|
|
||||||
{
|
|
||||||
migrationBuilder.CreateTable(
|
|
||||||
name: "xpshopowneditem",
|
|
||||||
columns: table => new
|
|
||||||
{
|
|
||||||
id = table.Column<int>(type: "int", nullable: false)
|
|
||||||
.Annotation("MySql:ValueGenerationStrategy", MySqlValueGenerationStrategy.IdentityColumn),
|
|
||||||
userid = table.Column<ulong>(type: "bigint unsigned", nullable: false),
|
|
||||||
itemtype = table.Column<int>(type: "int", nullable: false),
|
|
||||||
isusing = table.Column<bool>(type: "tinyint(1)", nullable: false),
|
|
||||||
itemkey = table.Column<string>(type: "varchar(255)", nullable: false)
|
|
||||||
.Annotation("MySql:CharSet", "utf8mb4"),
|
|
||||||
dateadded = table.Column<DateTime>(type: "datetime(6)", nullable: true)
|
|
||||||
},
|
|
||||||
constraints: table =>
|
|
||||||
{
|
|
||||||
table.PrimaryKey("pk_xpshopowneditem", x => x.id);
|
|
||||||
})
|
|
||||||
.Annotation("MySql:CharSet", "utf8mb4");
|
|
||||||
|
|
||||||
migrationBuilder.CreateIndex(
|
|
||||||
name: "ix_xpshopowneditem_userid_itemtype_itemkey",
|
|
||||||
table: "xpshopowneditem",
|
|
||||||
columns: new[] { "userid", "itemtype", "itemkey" },
|
|
||||||
unique: true);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected override void Down(MigrationBuilder migrationBuilder)
|
|
||||||
{
|
|
||||||
migrationBuilder.DropTable(
|
|
||||||
name: "xpshopowneditem");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
File diff suppressed because it is too large
Load Diff
@@ -1,26 +0,0 @@
|
|||||||
using Microsoft.EntityFrameworkCore.Migrations;
|
|
||||||
|
|
||||||
#nullable disable
|
|
||||||
|
|
||||||
namespace NadekoBot.Migrations.Mysql
|
|
||||||
{
|
|
||||||
public partial class linkonlychannels : Migration
|
|
||||||
{
|
|
||||||
protected override void Up(MigrationBuilder migrationBuilder)
|
|
||||||
{
|
|
||||||
migrationBuilder.AddColumn<int>(
|
|
||||||
name: "type",
|
|
||||||
table: "imageonlychannels",
|
|
||||||
type: "int",
|
|
||||||
nullable: false,
|
|
||||||
defaultValue: 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected override void Down(MigrationBuilder migrationBuilder)
|
|
||||||
{
|
|
||||||
migrationBuilder.DropColumn(
|
|
||||||
name: "type",
|
|
||||||
table: "imageonlychannels");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
File diff suppressed because it is too large
Load Diff
@@ -1,48 +0,0 @@
|
|||||||
using Microsoft.EntityFrameworkCore.Migrations;
|
|
||||||
|
|
||||||
#nullable disable
|
|
||||||
|
|
||||||
namespace NadekoBot.Migrations.Mysql
|
|
||||||
{
|
|
||||||
public partial class removeobsoletexpcolumns : Migration
|
|
||||||
{
|
|
||||||
protected override void Up(MigrationBuilder migrationBuilder)
|
|
||||||
{
|
|
||||||
migrationBuilder.DropColumn(
|
|
||||||
name: "lastlevelup",
|
|
||||||
table: "userxpstats");
|
|
||||||
|
|
||||||
migrationBuilder.DropColumn(
|
|
||||||
name: "lastlevelup",
|
|
||||||
table: "discorduser");
|
|
||||||
|
|
||||||
migrationBuilder.DropColumn(
|
|
||||||
name: "lastxpgain",
|
|
||||||
table: "discorduser");
|
|
||||||
}
|
|
||||||
|
|
||||||
protected override void Down(MigrationBuilder migrationBuilder)
|
|
||||||
{
|
|
||||||
migrationBuilder.AddColumn<DateTime>(
|
|
||||||
name: "lastlevelup",
|
|
||||||
table: "userxpstats",
|
|
||||||
type: "datetime(6)",
|
|
||||||
nullable: false,
|
|
||||||
defaultValueSql: "(UTC_TIMESTAMP)");
|
|
||||||
|
|
||||||
migrationBuilder.AddColumn<DateTime>(
|
|
||||||
name: "lastlevelup",
|
|
||||||
table: "discorduser",
|
|
||||||
type: "datetime(6)",
|
|
||||||
nullable: false,
|
|
||||||
defaultValueSql: "(UTC_TIMESTAMP)");
|
|
||||||
|
|
||||||
migrationBuilder.AddColumn<DateTime>(
|
|
||||||
name: "lastxpgain",
|
|
||||||
table: "discorduser",
|
|
||||||
type: "datetime(6)",
|
|
||||||
nullable: false,
|
|
||||||
defaultValueSql: "(UTC_TIMESTAMP - INTERVAL 1 year)");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
File diff suppressed because it is too large
Load Diff
@@ -1,25 +0,0 @@
|
|||||||
using Microsoft.EntityFrameworkCore.Migrations;
|
|
||||||
|
|
||||||
#nullable disable
|
|
||||||
|
|
||||||
namespace NadekoBot.Migrations.Mysql
|
|
||||||
{
|
|
||||||
public partial class banprune : Migration
|
|
||||||
{
|
|
||||||
protected override void Up(MigrationBuilder migrationBuilder)
|
|
||||||
{
|
|
||||||
migrationBuilder.AddColumn<int>(
|
|
||||||
name: "prunedays",
|
|
||||||
table: "bantemplates",
|
|
||||||
type: "int",
|
|
||||||
nullable: true);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected override void Down(MigrationBuilder migrationBuilder)
|
|
||||||
{
|
|
||||||
migrationBuilder.DropColumn(
|
|
||||||
name: "prunedays",
|
|
||||||
table: "bantemplates");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
File diff suppressed because it is too large
Load Diff
@@ -1,25 +0,0 @@
|
|||||||
using Microsoft.EntityFrameworkCore.Migrations;
|
|
||||||
|
|
||||||
#nullable disable
|
|
||||||
|
|
||||||
namespace NadekoBot.Migrations.Mysql
|
|
||||||
{
|
|
||||||
public partial class shoprolereq : Migration
|
|
||||||
{
|
|
||||||
protected override void Up(MigrationBuilder migrationBuilder)
|
|
||||||
{
|
|
||||||
migrationBuilder.AddColumn<ulong>(
|
|
||||||
name: "rolerequirement",
|
|
||||||
table: "shopentry",
|
|
||||||
type: "bigint unsigned",
|
|
||||||
nullable: true);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected override void Down(MigrationBuilder migrationBuilder)
|
|
||||||
{
|
|
||||||
migrationBuilder.DropColumn(
|
|
||||||
name: "rolerequirement",
|
|
||||||
table: "shopentry");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
File diff suppressed because it is too large
Load Diff
@@ -1,41 +0,0 @@
|
|||||||
using Microsoft.EntityFrameworkCore.Metadata;
|
|
||||||
using Microsoft.EntityFrameworkCore.Migrations;
|
|
||||||
|
|
||||||
#nullable disable
|
|
||||||
|
|
||||||
namespace NadekoBot.Migrations.Mysql
|
|
||||||
{
|
|
||||||
public partial class autopub : Migration
|
|
||||||
{
|
|
||||||
protected override void Up(MigrationBuilder migrationBuilder)
|
|
||||||
{
|
|
||||||
migrationBuilder.CreateTable(
|
|
||||||
name: "autopublishchannel",
|
|
||||||
columns: table => new
|
|
||||||
{
|
|
||||||
id = table.Column<int>(type: "int", nullable: false)
|
|
||||||
.Annotation("MySql:ValueGenerationStrategy", MySqlValueGenerationStrategy.IdentityColumn),
|
|
||||||
guildid = table.Column<ulong>(type: "bigint unsigned", nullable: false),
|
|
||||||
channelid = table.Column<ulong>(type: "bigint unsigned", nullable: false),
|
|
||||||
dateadded = table.Column<DateTime>(type: "datetime(6)", nullable: true)
|
|
||||||
},
|
|
||||||
constraints: table =>
|
|
||||||
{
|
|
||||||
table.PrimaryKey("pk_autopublishchannel", x => x.id);
|
|
||||||
})
|
|
||||||
.Annotation("MySql:CharSet", "utf8mb4");
|
|
||||||
|
|
||||||
migrationBuilder.CreateIndex(
|
|
||||||
name: "ix_autopublishchannel_guildid",
|
|
||||||
table: "autopublishchannel",
|
|
||||||
column: "guildid",
|
|
||||||
unique: true);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected override void Down(MigrationBuilder migrationBuilder)
|
|
||||||
{
|
|
||||||
migrationBuilder.DropTable(
|
|
||||||
name: "autopublishchannel");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
File diff suppressed because it is too large
Load Diff
@@ -1,43 +0,0 @@
|
|||||||
using Microsoft.EntityFrameworkCore.Metadata;
|
|
||||||
using Microsoft.EntityFrameworkCore.Migrations;
|
|
||||||
|
|
||||||
#nullable disable
|
|
||||||
|
|
||||||
namespace NadekoBot.Migrations.Mysql
|
|
||||||
{
|
|
||||||
public partial class gamblingstats : Migration
|
|
||||||
{
|
|
||||||
protected override void Up(MigrationBuilder migrationBuilder)
|
|
||||||
{
|
|
||||||
migrationBuilder.CreateTable(
|
|
||||||
name: "gamblingstats",
|
|
||||||
columns: table => new
|
|
||||||
{
|
|
||||||
id = table.Column<int>(type: "int", nullable: false)
|
|
||||||
.Annotation("MySql:ValueGenerationStrategy", MySqlValueGenerationStrategy.IdentityColumn),
|
|
||||||
feature = table.Column<string>(type: "varchar(255)", nullable: true)
|
|
||||||
.Annotation("MySql:CharSet", "utf8mb4"),
|
|
||||||
bet = table.Column<decimal>(type: "decimal(65,30)", nullable: false),
|
|
||||||
paidout = table.Column<decimal>(type: "decimal(65,30)", nullable: false),
|
|
||||||
dateadded = table.Column<DateTime>(type: "datetime(6)", nullable: true)
|
|
||||||
},
|
|
||||||
constraints: table =>
|
|
||||||
{
|
|
||||||
table.PrimaryKey("pk_gamblingstats", x => x.id);
|
|
||||||
})
|
|
||||||
.Annotation("MySql:CharSet", "utf8mb4");
|
|
||||||
|
|
||||||
migrationBuilder.CreateIndex(
|
|
||||||
name: "ix_gamblingstats_feature",
|
|
||||||
table: "gamblingstats",
|
|
||||||
column: "feature",
|
|
||||||
unique: true);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected override void Down(MigrationBuilder migrationBuilder)
|
|
||||||
{
|
|
||||||
migrationBuilder.DropTable(
|
|
||||||
name: "gamblingstats");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
File diff suppressed because it is too large
Load Diff
@@ -1,26 +0,0 @@
|
|||||||
using Microsoft.EntityFrameworkCore.Migrations;
|
|
||||||
|
|
||||||
#nullable disable
|
|
||||||
|
|
||||||
namespace NadekoBot.Migrations.Mysql
|
|
||||||
{
|
|
||||||
public partial class toggleglobalexpressions : Migration
|
|
||||||
{
|
|
||||||
protected override void Up(MigrationBuilder migrationBuilder)
|
|
||||||
{
|
|
||||||
migrationBuilder.AddColumn<bool>(
|
|
||||||
name: "disableglobalexpressions",
|
|
||||||
table: "guildconfigs",
|
|
||||||
type: "tinyint(1)",
|
|
||||||
nullable: false,
|
|
||||||
defaultValue: false);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected override void Down(MigrationBuilder migrationBuilder)
|
|
||||||
{
|
|
||||||
migrationBuilder.DropColumn(
|
|
||||||
name: "disableglobalexpressions",
|
|
||||||
table: "guildconfigs");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
File diff suppressed because it is too large
Load Diff
@@ -1,35 +0,0 @@
|
|||||||
using Microsoft.EntityFrameworkCore.Migrations;
|
|
||||||
|
|
||||||
#nullable disable
|
|
||||||
|
|
||||||
namespace NadekoBot.Migrations.Mysql
|
|
||||||
{
|
|
||||||
public partial class logthread : Migration
|
|
||||||
{
|
|
||||||
protected override void Up(MigrationBuilder migrationBuilder)
|
|
||||||
{
|
|
||||||
migrationBuilder.AddColumn<ulong>(
|
|
||||||
name: "threadcreatedid",
|
|
||||||
table: "logsettings",
|
|
||||||
type: "bigint unsigned",
|
|
||||||
nullable: true);
|
|
||||||
|
|
||||||
migrationBuilder.AddColumn<ulong>(
|
|
||||||
name: "threaddeletedid",
|
|
||||||
table: "logsettings",
|
|
||||||
type: "bigint unsigned",
|
|
||||||
nullable: true);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected override void Down(MigrationBuilder migrationBuilder)
|
|
||||||
{
|
|
||||||
migrationBuilder.DropColumn(
|
|
||||||
name: "threadcreatedid",
|
|
||||||
table: "logsettings");
|
|
||||||
|
|
||||||
migrationBuilder.DropColumn(
|
|
||||||
name: "threaddeletedid",
|
|
||||||
table: "logsettings");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
File diff suppressed because it is too large
Load Diff
@@ -1,26 +0,0 @@
|
|||||||
using Microsoft.EntityFrameworkCore.Migrations;
|
|
||||||
|
|
||||||
#nullable disable
|
|
||||||
|
|
||||||
namespace NadekoBot.Migrations.Mysql
|
|
||||||
{
|
|
||||||
public partial class feedtext : Migration
|
|
||||||
{
|
|
||||||
protected override void Up(MigrationBuilder migrationBuilder)
|
|
||||||
{
|
|
||||||
migrationBuilder.AddColumn<string>(
|
|
||||||
name: "message",
|
|
||||||
table: "feedsub",
|
|
||||||
type: "longtext",
|
|
||||||
nullable: true)
|
|
||||||
.Annotation("MySql:CharSet", "utf8mb4");
|
|
||||||
}
|
|
||||||
|
|
||||||
protected override void Down(MigrationBuilder migrationBuilder)
|
|
||||||
{
|
|
||||||
migrationBuilder.DropColumn(
|
|
||||||
name: "message",
|
|
||||||
table: "feedsub");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
3830
src/NadekoBot/Migrations/Mysql/20240502233216_v5.Designer.cs
generated
3830
src/NadekoBot/Migrations/Mysql/20240502233216_v5.Designer.cs
generated
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -1,702 +0,0 @@
|
|||||||
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");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
File diff suppressed because it is too large
Load Diff
@@ -1,44 +0,0 @@
|
|||||||
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");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@@ -1,36 +0,0 @@
|
|||||||
using Microsoft.EntityFrameworkCore.Metadata;
|
|
||||||
using Microsoft.EntityFrameworkCore.Migrations;
|
|
||||||
|
|
||||||
#nullable disable
|
|
||||||
|
|
||||||
namespace NadekoBot.Migrations.Mysql
|
|
||||||
{
|
|
||||||
/// <inheritdoc />
|
|
||||||
public partial class honeypot : Migration
|
|
||||||
{
|
|
||||||
/// <inheritdoc />
|
|
||||||
protected override void Up(MigrationBuilder migrationBuilder)
|
|
||||||
{
|
|
||||||
migrationBuilder.CreateTable(
|
|
||||||
name: "honeypotchannels",
|
|
||||||
columns: table => new
|
|
||||||
{
|
|
||||||
guildid = table.Column<ulong>(type: "bigint unsigned", nullable: false)
|
|
||||||
.Annotation("MySql:ValueGenerationStrategy", MySqlValueGenerationStrategy.IdentityColumn),
|
|
||||||
channelid = table.Column<ulong>(type: "bigint unsigned", nullable: false)
|
|
||||||
},
|
|
||||||
constraints: table =>
|
|
||||||
{
|
|
||||||
table.PrimaryKey("pk_honeypotchannels", x => x.guildid);
|
|
||||||
})
|
|
||||||
.Annotation("MySql:CharSet", "utf8mb4");
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <inheritdoc />
|
|
||||||
protected override void Down(MigrationBuilder migrationBuilder)
|
|
||||||
{
|
|
||||||
migrationBuilder.DropTable(
|
|
||||||
name: "honeypotchannels");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
File diff suppressed because it is too large
Load Diff
@@ -9,12 +9,6 @@ namespace NadekoBot.Migrations.PostgreSql
|
|||||||
{
|
{
|
||||||
protected override void Up(MigrationBuilder migrationBuilder)
|
protected override void Up(MigrationBuilder migrationBuilder)
|
||||||
{
|
{
|
||||||
migrationBuilder.AddColumn<decimal>(
|
|
||||||
name: "rolerequirement",
|
|
||||||
table: "shopentry",
|
|
||||||
type: "numeric(20,0)",
|
|
||||||
nullable: true);
|
|
||||||
|
|
||||||
migrationBuilder.CreateTable(
|
migrationBuilder.CreateTable(
|
||||||
name: "autopublishchannel",
|
name: "autopublishchannel",
|
||||||
columns: table => new
|
columns: table => new
|
||||||
@@ -41,10 +35,6 @@ namespace NadekoBot.Migrations.PostgreSql
|
|||||||
{
|
{
|
||||||
migrationBuilder.DropTable(
|
migrationBuilder.DropTable(
|
||||||
name: "autopublishchannel");
|
name: "autopublishchannel");
|
||||||
|
|
||||||
migrationBuilder.DropColumn(
|
|
||||||
name: "rolerequirement",
|
|
||||||
table: "shopentry");
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,199 @@
|
|||||||
|
using Microsoft.EntityFrameworkCore.Migrations;
|
||||||
|
using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata;
|
||||||
|
|
||||||
|
#nullable disable
|
||||||
|
|
||||||
|
namespace NadekoBot.Migrations.PostgreSql
|
||||||
|
{
|
||||||
|
/// <inheritdoc />
|
||||||
|
public partial class greetsettings : Migration
|
||||||
|
{
|
||||||
|
/// <inheritdoc />
|
||||||
|
protected override void Up(MigrationBuilder migrationBuilder)
|
||||||
|
{
|
||||||
|
migrationBuilder.CreateTable(
|
||||||
|
name: "greetsettings",
|
||||||
|
columns: table => new
|
||||||
|
{
|
||||||
|
id = table.Column<int>(type: "integer", nullable: false)
|
||||||
|
.Annotation("Npgsql:ValueGenerationStrategy",
|
||||||
|
NpgsqlValueGenerationStrategy.IdentityByDefaultColumn),
|
||||||
|
guildid = table.Column<decimal>(type: "numeric(20,0)", nullable: false),
|
||||||
|
greettype = table.Column<int>(type: "integer", nullable: false),
|
||||||
|
messagetext = table.Column<string>(type: "text", nullable: true),
|
||||||
|
isenabled = table.Column<bool>(type: "boolean", nullable: false, defaultValue: false),
|
||||||
|
channelid = table.Column<decimal>(type: "numeric(20,0)", nullable: true),
|
||||||
|
autodeletetimer = table.Column<int>(type: "integer", nullable: false, defaultValue: 0)
|
||||||
|
},
|
||||||
|
constraints: table =>
|
||||||
|
{
|
||||||
|
table.PrimaryKey("pk_greetsettings", x => x.id);
|
||||||
|
});
|
||||||
|
|
||||||
|
migrationBuilder.CreateIndex(
|
||||||
|
name: "ix_greetsettings_guildid_greettype",
|
||||||
|
table: "greetsettings",
|
||||||
|
columns: new[] { "guildid", "greettype" },
|
||||||
|
unique: true);
|
||||||
|
|
||||||
|
MigrationQueries.GreetSettingsCopy(migrationBuilder);
|
||||||
|
|
||||||
|
migrationBuilder.DropColumn(
|
||||||
|
name: "autodeletebyemessagestimer",
|
||||||
|
table: "guildconfigs");
|
||||||
|
|
||||||
|
migrationBuilder.DropColumn(
|
||||||
|
name: "autodeletegreetmessagestimer",
|
||||||
|
table: "guildconfigs");
|
||||||
|
|
||||||
|
migrationBuilder.DropColumn(
|
||||||
|
name: "boostmessage",
|
||||||
|
table: "guildconfigs");
|
||||||
|
|
||||||
|
migrationBuilder.DropColumn(
|
||||||
|
name: "boostmessagechannelid",
|
||||||
|
table: "guildconfigs");
|
||||||
|
|
||||||
|
migrationBuilder.DropColumn(
|
||||||
|
name: "boostmessagedeleteafter",
|
||||||
|
table: "guildconfigs");
|
||||||
|
|
||||||
|
migrationBuilder.DropColumn(
|
||||||
|
name: "byemessagechannelid",
|
||||||
|
table: "guildconfigs");
|
||||||
|
|
||||||
|
migrationBuilder.DropColumn(
|
||||||
|
name: "channelbyemessagetext",
|
||||||
|
table: "guildconfigs");
|
||||||
|
|
||||||
|
migrationBuilder.DropColumn(
|
||||||
|
name: "channelgreetmessagetext",
|
||||||
|
table: "guildconfigs");
|
||||||
|
|
||||||
|
migrationBuilder.DropColumn(
|
||||||
|
name: "dmgreetmessagetext",
|
||||||
|
table: "guildconfigs");
|
||||||
|
|
||||||
|
migrationBuilder.DropColumn(
|
||||||
|
name: "greetmessagechannelid",
|
||||||
|
table: "guildconfigs");
|
||||||
|
|
||||||
|
migrationBuilder.DropColumn(
|
||||||
|
name: "sendboostmessage",
|
||||||
|
table: "guildconfigs");
|
||||||
|
|
||||||
|
migrationBuilder.DropColumn(
|
||||||
|
name: "sendchannelbyemessage",
|
||||||
|
table: "guildconfigs");
|
||||||
|
|
||||||
|
migrationBuilder.DropColumn(
|
||||||
|
name: "sendchannelgreetmessage",
|
||||||
|
table: "guildconfigs");
|
||||||
|
|
||||||
|
migrationBuilder.DropColumn(
|
||||||
|
name: "senddmgreetmessage",
|
||||||
|
table: "guildconfigs");
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
protected override void Down(MigrationBuilder migrationBuilder)
|
||||||
|
{
|
||||||
|
migrationBuilder.DropTable(
|
||||||
|
name: "greetsettings");
|
||||||
|
|
||||||
|
migrationBuilder.AddColumn<int>(
|
||||||
|
name: "autodeletebyemessagestimer",
|
||||||
|
table: "guildconfigs",
|
||||||
|
type: "integer",
|
||||||
|
nullable: false,
|
||||||
|
defaultValue: 0);
|
||||||
|
|
||||||
|
migrationBuilder.AddColumn<int>(
|
||||||
|
name: "autodeletegreetmessagestimer",
|
||||||
|
table: "guildconfigs",
|
||||||
|
type: "integer",
|
||||||
|
nullable: false,
|
||||||
|
defaultValue: 0);
|
||||||
|
|
||||||
|
migrationBuilder.AddColumn<string>(
|
||||||
|
name: "boostmessage",
|
||||||
|
table: "guildconfigs",
|
||||||
|
type: "text",
|
||||||
|
nullable: true);
|
||||||
|
|
||||||
|
migrationBuilder.AddColumn<decimal>(
|
||||||
|
name: "boostmessagechannelid",
|
||||||
|
table: "guildconfigs",
|
||||||
|
type: "numeric(20,0)",
|
||||||
|
nullable: false,
|
||||||
|
defaultValue: 0m);
|
||||||
|
|
||||||
|
migrationBuilder.AddColumn<int>(
|
||||||
|
name: "boostmessagedeleteafter",
|
||||||
|
table: "guildconfigs",
|
||||||
|
type: "integer",
|
||||||
|
nullable: false,
|
||||||
|
defaultValue: 0);
|
||||||
|
|
||||||
|
migrationBuilder.AddColumn<decimal>(
|
||||||
|
name: "byemessagechannelid",
|
||||||
|
table: "guildconfigs",
|
||||||
|
type: "numeric(20,0)",
|
||||||
|
nullable: false,
|
||||||
|
defaultValue: 0m);
|
||||||
|
|
||||||
|
migrationBuilder.AddColumn<string>(
|
||||||
|
name: "channelbyemessagetext",
|
||||||
|
table: "guildconfigs",
|
||||||
|
type: "text",
|
||||||
|
nullable: true);
|
||||||
|
|
||||||
|
migrationBuilder.AddColumn<string>(
|
||||||
|
name: "channelgreetmessagetext",
|
||||||
|
table: "guildconfigs",
|
||||||
|
type: "text",
|
||||||
|
nullable: true);
|
||||||
|
|
||||||
|
migrationBuilder.AddColumn<string>(
|
||||||
|
name: "dmgreetmessagetext",
|
||||||
|
table: "guildconfigs",
|
||||||
|
type: "text",
|
||||||
|
nullable: true);
|
||||||
|
|
||||||
|
migrationBuilder.AddColumn<decimal>(
|
||||||
|
name: "greetmessagechannelid",
|
||||||
|
table: "guildconfigs",
|
||||||
|
type: "numeric(20,0)",
|
||||||
|
nullable: false,
|
||||||
|
defaultValue: 0m);
|
||||||
|
|
||||||
|
migrationBuilder.AddColumn<bool>(
|
||||||
|
name: "sendboostmessage",
|
||||||
|
table: "guildconfigs",
|
||||||
|
type: "boolean",
|
||||||
|
nullable: false,
|
||||||
|
defaultValue: false);
|
||||||
|
|
||||||
|
migrationBuilder.AddColumn<bool>(
|
||||||
|
name: "sendchannelbyemessage",
|
||||||
|
table: "guildconfigs",
|
||||||
|
type: "boolean",
|
||||||
|
nullable: false,
|
||||||
|
defaultValue: false);
|
||||||
|
|
||||||
|
migrationBuilder.AddColumn<bool>(
|
||||||
|
name: "sendchannelgreetmessage",
|
||||||
|
table: "guildconfigs",
|
||||||
|
type: "boolean",
|
||||||
|
nullable: false,
|
||||||
|
defaultValue: false);
|
||||||
|
|
||||||
|
migrationBuilder.AddColumn<bool>(
|
||||||
|
name: "senddmgreetmessage",
|
||||||
|
table: "guildconfigs",
|
||||||
|
type: "boolean",
|
||||||
|
nullable: false,
|
||||||
|
defaultValue: false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@@ -17,7 +17,7 @@ namespace NadekoBot.Migrations.PostgreSql
|
|||||||
{
|
{
|
||||||
#pragma warning disable 612, 618
|
#pragma warning disable 612, 618
|
||||||
modelBuilder
|
modelBuilder
|
||||||
.HasAnnotation("ProductVersion", "8.0.4")
|
.HasAnnotation("ProductVersion", "8.0.8")
|
||||||
.HasAnnotation("Relational:MaxIdentifierLength", 63);
|
.HasAnnotation("Relational:MaxIdentifierLength", 63);
|
||||||
|
|
||||||
NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder);
|
NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder);
|
||||||
@@ -1220,42 +1220,10 @@ namespace NadekoBot.Migrations.PostgreSql
|
|||||||
.HasColumnType("text")
|
.HasColumnType("text")
|
||||||
.HasColumnName("autoassignroleids");
|
.HasColumnName("autoassignroleids");
|
||||||
|
|
||||||
b.Property<int>("AutoDeleteByeMessagesTimer")
|
|
||||||
.HasColumnType("integer")
|
|
||||||
.HasColumnName("autodeletebyemessagestimer");
|
|
||||||
|
|
||||||
b.Property<int>("AutoDeleteGreetMessagesTimer")
|
|
||||||
.HasColumnType("integer")
|
|
||||||
.HasColumnName("autodeletegreetmessagestimer");
|
|
||||||
|
|
||||||
b.Property<bool>("AutoDeleteSelfAssignedRoleMessages")
|
b.Property<bool>("AutoDeleteSelfAssignedRoleMessages")
|
||||||
.HasColumnType("boolean")
|
.HasColumnType("boolean")
|
||||||
.HasColumnName("autodeleteselfassignedrolemessages");
|
.HasColumnName("autodeleteselfassignedrolemessages");
|
||||||
|
|
||||||
b.Property<string>("BoostMessage")
|
|
||||||
.HasColumnType("text")
|
|
||||||
.HasColumnName("boostmessage");
|
|
||||||
|
|
||||||
b.Property<decimal>("BoostMessageChannelId")
|
|
||||||
.HasColumnType("numeric(20,0)")
|
|
||||||
.HasColumnName("boostmessagechannelid");
|
|
||||||
|
|
||||||
b.Property<int>("BoostMessageDeleteAfter")
|
|
||||||
.HasColumnType("integer")
|
|
||||||
.HasColumnName("boostmessagedeleteafter");
|
|
||||||
|
|
||||||
b.Property<decimal>("ByeMessageChannelId")
|
|
||||||
.HasColumnType("numeric(20,0)")
|
|
||||||
.HasColumnName("byemessagechannelid");
|
|
||||||
|
|
||||||
b.Property<string>("ChannelByeMessageText")
|
|
||||||
.HasColumnType("text")
|
|
||||||
.HasColumnName("channelbyemessagetext");
|
|
||||||
|
|
||||||
b.Property<string>("ChannelGreetMessageText")
|
|
||||||
.HasColumnType("text")
|
|
||||||
.HasColumnName("channelgreetmessagetext");
|
|
||||||
|
|
||||||
b.Property<bool>("CleverbotEnabled")
|
b.Property<bool>("CleverbotEnabled")
|
||||||
.HasColumnType("boolean")
|
.HasColumnType("boolean")
|
||||||
.HasColumnName("cleverbotenabled");
|
.HasColumnName("cleverbotenabled");
|
||||||
@@ -1276,10 +1244,6 @@ namespace NadekoBot.Migrations.PostgreSql
|
|||||||
.HasColumnType("boolean")
|
.HasColumnType("boolean")
|
||||||
.HasColumnName("disableglobalexpressions");
|
.HasColumnName("disableglobalexpressions");
|
||||||
|
|
||||||
b.Property<string>("DmGreetMessageText")
|
|
||||||
.HasColumnType("text")
|
|
||||||
.HasColumnName("dmgreetmessagetext");
|
|
||||||
|
|
||||||
b.Property<bool>("ExclusiveSelfAssignedRoles")
|
b.Property<bool>("ExclusiveSelfAssignedRoles")
|
||||||
.HasColumnType("boolean")
|
.HasColumnType("boolean")
|
||||||
.HasColumnName("exclusiveselfassignedroles");
|
.HasColumnName("exclusiveselfassignedroles");
|
||||||
@@ -1300,10 +1264,6 @@ namespace NadekoBot.Migrations.PostgreSql
|
|||||||
.HasColumnType("numeric(20,0)")
|
.HasColumnType("numeric(20,0)")
|
||||||
.HasColumnName("gamevoicechannel");
|
.HasColumnName("gamevoicechannel");
|
||||||
|
|
||||||
b.Property<decimal>("GreetMessageChannelId")
|
|
||||||
.HasColumnType("numeric(20,0)")
|
|
||||||
.HasColumnName("greetmessagechannelid");
|
|
||||||
|
|
||||||
b.Property<decimal>("GuildId")
|
b.Property<decimal>("GuildId")
|
||||||
.HasColumnType("numeric(20,0)")
|
.HasColumnType("numeric(20,0)")
|
||||||
.HasColumnName("guildid");
|
.HasColumnName("guildid");
|
||||||
@@ -1328,22 +1288,6 @@ namespace NadekoBot.Migrations.PostgreSql
|
|||||||
.HasColumnType("text")
|
.HasColumnType("text")
|
||||||
.HasColumnName("prefix");
|
.HasColumnName("prefix");
|
||||||
|
|
||||||
b.Property<bool>("SendBoostMessage")
|
|
||||||
.HasColumnType("boolean")
|
|
||||||
.HasColumnName("sendboostmessage");
|
|
||||||
|
|
||||||
b.Property<bool>("SendChannelByeMessage")
|
|
||||||
.HasColumnType("boolean")
|
|
||||||
.HasColumnName("sendchannelbyemessage");
|
|
||||||
|
|
||||||
b.Property<bool>("SendChannelGreetMessage")
|
|
||||||
.HasColumnType("boolean")
|
|
||||||
.HasColumnName("sendchannelgreetmessage");
|
|
||||||
|
|
||||||
b.Property<bool>("SendDmGreetMessage")
|
|
||||||
.HasColumnType("boolean")
|
|
||||||
.HasColumnName("senddmgreetmessage");
|
|
||||||
|
|
||||||
b.Property<bool>("StickyRoles")
|
b.Property<bool>("StickyRoles")
|
||||||
.HasColumnType("boolean")
|
.HasColumnType("boolean")
|
||||||
.HasColumnName("stickyroles");
|
.HasColumnName("stickyroles");
|
||||||
@@ -3163,6 +3107,53 @@ namespace NadekoBot.Migrations.PostgreSql
|
|||||||
b.ToTable("xpshopowneditem", (string)null);
|
b.ToTable("xpshopowneditem", (string)null);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("NadekoBot.Services.GreetSettings", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("integer")
|
||||||
|
.HasColumnName("id");
|
||||||
|
|
||||||
|
NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id"));
|
||||||
|
|
||||||
|
b.Property<int>("AutoDeleteTimer")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("integer")
|
||||||
|
.HasDefaultValue(0)
|
||||||
|
.HasColumnName("autodeletetimer");
|
||||||
|
|
||||||
|
b.Property<decimal?>("ChannelId")
|
||||||
|
.HasColumnType("numeric(20,0)")
|
||||||
|
.HasColumnName("channelid");
|
||||||
|
|
||||||
|
b.Property<int>("GreetType")
|
||||||
|
.HasColumnType("integer")
|
||||||
|
.HasColumnName("greettype");
|
||||||
|
|
||||||
|
b.Property<decimal>("GuildId")
|
||||||
|
.HasColumnType("numeric(20,0)")
|
||||||
|
.HasColumnName("guildid");
|
||||||
|
|
||||||
|
b.Property<bool>("IsEnabled")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("boolean")
|
||||||
|
.HasDefaultValue(false)
|
||||||
|
.HasColumnName("isenabled");
|
||||||
|
|
||||||
|
b.Property<string>("MessageText")
|
||||||
|
.HasColumnType("text")
|
||||||
|
.HasColumnName("messagetext");
|
||||||
|
|
||||||
|
b.HasKey("Id")
|
||||||
|
.HasName("pk_greetsettings");
|
||||||
|
|
||||||
|
b.HasIndex("GuildId", "GreetType")
|
||||||
|
.IsUnique()
|
||||||
|
.HasDatabaseName("ix_greetsettings_guildid_greettype");
|
||||||
|
|
||||||
|
b.ToTable("greetsettings", (string)null);
|
||||||
|
});
|
||||||
|
|
||||||
modelBuilder.Entity("NadekoBot.Db.Models.AntiAltSetting", b =>
|
modelBuilder.Entity("NadekoBot.Db.Models.AntiAltSetting", b =>
|
||||||
{
|
{
|
||||||
b.HasOne("NadekoBot.Db.Models.GuildConfig", null)
|
b.HasOne("NadekoBot.Db.Models.GuildConfig", null)
|
||||||
|
2929
src/NadekoBot/Migrations/Sqlite/20240912124710_greet-settings.Designer.cs
generated
Normal file
2929
src/NadekoBot/Migrations/Sqlite/20240912124710_greet-settings.Designer.cs
generated
Normal file
File diff suppressed because it is too large
Load Diff
197
src/NadekoBot/Migrations/Sqlite/20240912124710_greet-settings.cs
Normal file
197
src/NadekoBot/Migrations/Sqlite/20240912124710_greet-settings.cs
Normal file
@@ -0,0 +1,197 @@
|
|||||||
|
using Microsoft.EntityFrameworkCore.Migrations;
|
||||||
|
|
||||||
|
#nullable disable
|
||||||
|
|
||||||
|
namespace NadekoBot.Migrations
|
||||||
|
{
|
||||||
|
/// <inheritdoc />
|
||||||
|
public partial class greetsettings : Migration
|
||||||
|
{
|
||||||
|
/// <inheritdoc />
|
||||||
|
protected override void Up(MigrationBuilder migrationBuilder)
|
||||||
|
{
|
||||||
|
migrationBuilder.CreateTable(
|
||||||
|
name: "GreetSettings",
|
||||||
|
columns: table => new
|
||||||
|
{
|
||||||
|
Id = table.Column<int>(type: "INTEGER", nullable: false)
|
||||||
|
.Annotation("Sqlite:Autoincrement", true),
|
||||||
|
GuildId = table.Column<ulong>(type: "INTEGER", nullable: false),
|
||||||
|
GreetType = table.Column<int>(type: "INTEGER", nullable: false),
|
||||||
|
MessageText = table.Column<string>(type: "TEXT", nullable: true),
|
||||||
|
IsEnabled = table.Column<bool>(type: "INTEGER", nullable: false, defaultValue: false),
|
||||||
|
ChannelId = table.Column<ulong>(type: "INTEGER", nullable: true),
|
||||||
|
AutoDeleteTimer = table.Column<int>(type: "INTEGER", nullable: false, defaultValue: 0)
|
||||||
|
},
|
||||||
|
constraints: table =>
|
||||||
|
{
|
||||||
|
table.PrimaryKey("PK_GreetSettings", x => x.Id);
|
||||||
|
});
|
||||||
|
|
||||||
|
migrationBuilder.CreateIndex(
|
||||||
|
name: "IX_GreetSettings_GuildId_GreetType",
|
||||||
|
table: "GreetSettings",
|
||||||
|
columns: new[] { "GuildId", "GreetType" },
|
||||||
|
unique: true);
|
||||||
|
|
||||||
|
MigrationQueries.GreetSettingsCopy(migrationBuilder);
|
||||||
|
|
||||||
|
migrationBuilder.DropColumn(
|
||||||
|
name: "AutoDeleteByeMessagesTimer",
|
||||||
|
table: "GuildConfigs");
|
||||||
|
|
||||||
|
migrationBuilder.DropColumn(
|
||||||
|
name: "AutoDeleteGreetMessagesTimer",
|
||||||
|
table: "GuildConfigs");
|
||||||
|
|
||||||
|
migrationBuilder.DropColumn(
|
||||||
|
name: "BoostMessage",
|
||||||
|
table: "GuildConfigs");
|
||||||
|
|
||||||
|
migrationBuilder.DropColumn(
|
||||||
|
name: "BoostMessageChannelId",
|
||||||
|
table: "GuildConfigs");
|
||||||
|
|
||||||
|
migrationBuilder.DropColumn(
|
||||||
|
name: "BoostMessageDeleteAfter",
|
||||||
|
table: "GuildConfigs");
|
||||||
|
|
||||||
|
migrationBuilder.DropColumn(
|
||||||
|
name: "ByeMessageChannelId",
|
||||||
|
table: "GuildConfigs");
|
||||||
|
|
||||||
|
migrationBuilder.DropColumn(
|
||||||
|
name: "ChannelByeMessageText",
|
||||||
|
table: "GuildConfigs");
|
||||||
|
|
||||||
|
migrationBuilder.DropColumn(
|
||||||
|
name: "ChannelGreetMessageText",
|
||||||
|
table: "GuildConfigs");
|
||||||
|
|
||||||
|
migrationBuilder.DropColumn(
|
||||||
|
name: "DmGreetMessageText",
|
||||||
|
table: "GuildConfigs");
|
||||||
|
|
||||||
|
migrationBuilder.DropColumn(
|
||||||
|
name: "GreetMessageChannelId",
|
||||||
|
table: "GuildConfigs");
|
||||||
|
|
||||||
|
migrationBuilder.DropColumn(
|
||||||
|
name: "SendBoostMessage",
|
||||||
|
table: "GuildConfigs");
|
||||||
|
|
||||||
|
migrationBuilder.DropColumn(
|
||||||
|
name: "SendChannelByeMessage",
|
||||||
|
table: "GuildConfigs");
|
||||||
|
|
||||||
|
migrationBuilder.DropColumn(
|
||||||
|
name: "SendChannelGreetMessage",
|
||||||
|
table: "GuildConfigs");
|
||||||
|
|
||||||
|
migrationBuilder.DropColumn(
|
||||||
|
name: "SendDmGreetMessage",
|
||||||
|
table: "GuildConfigs");
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
protected override void Down(MigrationBuilder migrationBuilder)
|
||||||
|
{
|
||||||
|
migrationBuilder.DropTable(
|
||||||
|
name: "GreetSettings");
|
||||||
|
|
||||||
|
migrationBuilder.AddColumn<int>(
|
||||||
|
name: "AutoDeleteByeMessagesTimer",
|
||||||
|
table: "GuildConfigs",
|
||||||
|
type: "INTEGER",
|
||||||
|
nullable: false,
|
||||||
|
defaultValue: 0);
|
||||||
|
|
||||||
|
migrationBuilder.AddColumn<int>(
|
||||||
|
name: "AutoDeleteGreetMessagesTimer",
|
||||||
|
table: "GuildConfigs",
|
||||||
|
type: "INTEGER",
|
||||||
|
nullable: false,
|
||||||
|
defaultValue: 0);
|
||||||
|
|
||||||
|
migrationBuilder.AddColumn<string>(
|
||||||
|
name: "BoostMessage",
|
||||||
|
table: "GuildConfigs",
|
||||||
|
type: "TEXT",
|
||||||
|
nullable: true);
|
||||||
|
|
||||||
|
migrationBuilder.AddColumn<ulong>(
|
||||||
|
name: "BoostMessageChannelId",
|
||||||
|
table: "GuildConfigs",
|
||||||
|
type: "INTEGER",
|
||||||
|
nullable: false,
|
||||||
|
defaultValue: 0ul);
|
||||||
|
|
||||||
|
migrationBuilder.AddColumn<int>(
|
||||||
|
name: "BoostMessageDeleteAfter",
|
||||||
|
table: "GuildConfigs",
|
||||||
|
type: "INTEGER",
|
||||||
|
nullable: false,
|
||||||
|
defaultValue: 0);
|
||||||
|
|
||||||
|
migrationBuilder.AddColumn<ulong>(
|
||||||
|
name: "ByeMessageChannelId",
|
||||||
|
table: "GuildConfigs",
|
||||||
|
type: "INTEGER",
|
||||||
|
nullable: false,
|
||||||
|
defaultValue: 0ul);
|
||||||
|
|
||||||
|
migrationBuilder.AddColumn<string>(
|
||||||
|
name: "ChannelByeMessageText",
|
||||||
|
table: "GuildConfigs",
|
||||||
|
type: "TEXT",
|
||||||
|
nullable: true);
|
||||||
|
|
||||||
|
migrationBuilder.AddColumn<string>(
|
||||||
|
name: "ChannelGreetMessageText",
|
||||||
|
table: "GuildConfigs",
|
||||||
|
type: "TEXT",
|
||||||
|
nullable: true);
|
||||||
|
|
||||||
|
migrationBuilder.AddColumn<string>(
|
||||||
|
name: "DmGreetMessageText",
|
||||||
|
table: "GuildConfigs",
|
||||||
|
type: "TEXT",
|
||||||
|
nullable: true);
|
||||||
|
|
||||||
|
migrationBuilder.AddColumn<ulong>(
|
||||||
|
name: "GreetMessageChannelId",
|
||||||
|
table: "GuildConfigs",
|
||||||
|
type: "INTEGER",
|
||||||
|
nullable: false,
|
||||||
|
defaultValue: 0ul);
|
||||||
|
|
||||||
|
migrationBuilder.AddColumn<bool>(
|
||||||
|
name: "SendBoostMessage",
|
||||||
|
table: "GuildConfigs",
|
||||||
|
type: "INTEGER",
|
||||||
|
nullable: false,
|
||||||
|
defaultValue: false);
|
||||||
|
|
||||||
|
migrationBuilder.AddColumn<bool>(
|
||||||
|
name: "SendChannelByeMessage",
|
||||||
|
table: "GuildConfigs",
|
||||||
|
type: "INTEGER",
|
||||||
|
nullable: false,
|
||||||
|
defaultValue: false);
|
||||||
|
|
||||||
|
migrationBuilder.AddColumn<bool>(
|
||||||
|
name: "SendChannelGreetMessage",
|
||||||
|
table: "GuildConfigs",
|
||||||
|
type: "INTEGER",
|
||||||
|
nullable: false,
|
||||||
|
defaultValue: false);
|
||||||
|
|
||||||
|
migrationBuilder.AddColumn<bool>(
|
||||||
|
name: "SendDmGreetMessage",
|
||||||
|
table: "GuildConfigs",
|
||||||
|
type: "INTEGER",
|
||||||
|
nullable: false,
|
||||||
|
defaultValue: false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@@ -15,7 +15,7 @@ namespace NadekoBot.Migrations
|
|||||||
protected override void BuildModel(ModelBuilder modelBuilder)
|
protected override void BuildModel(ModelBuilder modelBuilder)
|
||||||
{
|
{
|
||||||
#pragma warning disable 612, 618
|
#pragma warning disable 612, 618
|
||||||
modelBuilder.HasAnnotation("ProductVersion", "8.0.4");
|
modelBuilder.HasAnnotation("ProductVersion", "8.0.8");
|
||||||
|
|
||||||
modelBuilder.Entity("NadekoBot.Db.Models.AntiAltSetting", b =>
|
modelBuilder.Entity("NadekoBot.Db.Models.AntiAltSetting", b =>
|
||||||
{
|
{
|
||||||
@@ -907,33 +907,9 @@ namespace NadekoBot.Migrations
|
|||||||
b.Property<string>("AutoAssignRoleIds")
|
b.Property<string>("AutoAssignRoleIds")
|
||||||
.HasColumnType("TEXT");
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
b.Property<int>("AutoDeleteByeMessagesTimer")
|
|
||||||
.HasColumnType("INTEGER");
|
|
||||||
|
|
||||||
b.Property<int>("AutoDeleteGreetMessagesTimer")
|
|
||||||
.HasColumnType("INTEGER");
|
|
||||||
|
|
||||||
b.Property<bool>("AutoDeleteSelfAssignedRoleMessages")
|
b.Property<bool>("AutoDeleteSelfAssignedRoleMessages")
|
||||||
.HasColumnType("INTEGER");
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
b.Property<string>("BoostMessage")
|
|
||||||
.HasColumnType("TEXT");
|
|
||||||
|
|
||||||
b.Property<ulong>("BoostMessageChannelId")
|
|
||||||
.HasColumnType("INTEGER");
|
|
||||||
|
|
||||||
b.Property<int>("BoostMessageDeleteAfter")
|
|
||||||
.HasColumnType("INTEGER");
|
|
||||||
|
|
||||||
b.Property<ulong>("ByeMessageChannelId")
|
|
||||||
.HasColumnType("INTEGER");
|
|
||||||
|
|
||||||
b.Property<string>("ChannelByeMessageText")
|
|
||||||
.HasColumnType("TEXT");
|
|
||||||
|
|
||||||
b.Property<string>("ChannelGreetMessageText")
|
|
||||||
.HasColumnType("TEXT");
|
|
||||||
|
|
||||||
b.Property<bool>("CleverbotEnabled")
|
b.Property<bool>("CleverbotEnabled")
|
||||||
.HasColumnType("INTEGER");
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
@@ -949,9 +925,6 @@ namespace NadekoBot.Migrations
|
|||||||
b.Property<bool>("DisableGlobalExpressions")
|
b.Property<bool>("DisableGlobalExpressions")
|
||||||
.HasColumnType("INTEGER");
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
b.Property<string>("DmGreetMessageText")
|
|
||||||
.HasColumnType("TEXT");
|
|
||||||
|
|
||||||
b.Property<bool>("ExclusiveSelfAssignedRoles")
|
b.Property<bool>("ExclusiveSelfAssignedRoles")
|
||||||
.HasColumnType("INTEGER");
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
@@ -967,9 +940,6 @@ namespace NadekoBot.Migrations
|
|||||||
b.Property<ulong?>("GameVoiceChannel")
|
b.Property<ulong?>("GameVoiceChannel")
|
||||||
.HasColumnType("INTEGER");
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
b.Property<ulong>("GreetMessageChannelId")
|
|
||||||
.HasColumnType("INTEGER");
|
|
||||||
|
|
||||||
b.Property<ulong>("GuildId")
|
b.Property<ulong>("GuildId")
|
||||||
.HasColumnType("INTEGER");
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
@@ -988,18 +958,6 @@ namespace NadekoBot.Migrations
|
|||||||
b.Property<string>("Prefix")
|
b.Property<string>("Prefix")
|
||||||
.HasColumnType("TEXT");
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
b.Property<bool>("SendBoostMessage")
|
|
||||||
.HasColumnType("INTEGER");
|
|
||||||
|
|
||||||
b.Property<bool>("SendChannelByeMessage")
|
|
||||||
.HasColumnType("INTEGER");
|
|
||||||
|
|
||||||
b.Property<bool>("SendChannelGreetMessage")
|
|
||||||
.HasColumnType("INTEGER");
|
|
||||||
|
|
||||||
b.Property<bool>("SendDmGreetMessage")
|
|
||||||
.HasColumnType("INTEGER");
|
|
||||||
|
|
||||||
b.Property<bool>("StickyRoles")
|
b.Property<bool>("StickyRoles")
|
||||||
.HasColumnType("INTEGER");
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
@@ -2351,6 +2309,42 @@ namespace NadekoBot.Migrations
|
|||||||
b.ToTable("XpShopOwnedItem");
|
b.ToTable("XpShopOwnedItem");
|
||||||
});
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("NadekoBot.Services.GreetSettings", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<int>("AutoDeleteTimer")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("INTEGER")
|
||||||
|
.HasDefaultValue(0);
|
||||||
|
|
||||||
|
b.Property<ulong?>("ChannelId")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<int>("GreetType")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<ulong>("GuildId")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<bool>("IsEnabled")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("INTEGER")
|
||||||
|
.HasDefaultValue(false);
|
||||||
|
|
||||||
|
b.Property<string>("MessageText")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.HasIndex("GuildId", "GreetType")
|
||||||
|
.IsUnique();
|
||||||
|
|
||||||
|
b.ToTable("GreetSettings");
|
||||||
|
});
|
||||||
|
|
||||||
modelBuilder.Entity("NadekoBot.Db.Models.AntiAltSetting", b =>
|
modelBuilder.Entity("NadekoBot.Db.Models.AntiAltSetting", b =>
|
||||||
{
|
{
|
||||||
b.HasOne("NadekoBot.Db.Models.GuildConfig", null)
|
b.HasOne("NadekoBot.Db.Models.GuildConfig", null)
|
||||||
|
@@ -36,6 +36,8 @@ public class AutoPublishService : IExecNoCommand, IReadyExecutor, INService
|
|||||||
RetryMode = RetryMode.AlwaysFail
|
RetryMode = RetryMode.AlwaysFail
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// todo GUILDS
|
||||||
|
|
||||||
public async Task OnReadyAsync()
|
public async Task OnReadyAsync()
|
||||||
{
|
{
|
||||||
|
@@ -1,14 +1,20 @@
|
|||||||
namespace NadekoBot.Modules.Administration.DangerousCommands;
|
using NadekoBot.Modules.Administration.DangerousCommands;
|
||||||
|
|
||||||
public partial class Administration
|
namespace NadekoBot.Modules.Administration;
|
||||||
|
|
||||||
|
public partial class Administration
|
||||||
{
|
{
|
||||||
[Group]
|
[Group]
|
||||||
public class CleanupCommands : CleanupModuleBase
|
public partial class CleanupCommands : CleanupModuleBase
|
||||||
{
|
{
|
||||||
private readonly ICleanupService _svc;
|
private readonly ICleanupService _svc;
|
||||||
|
private readonly IBotCredsProvider _creds;
|
||||||
|
|
||||||
public CleanupCommands(ICleanupService svc)
|
public CleanupCommands(ICleanupService svc, IBotCredsProvider creds)
|
||||||
=> _svc = svc;
|
{
|
||||||
|
_svc = svc;
|
||||||
|
_creds = creds;
|
||||||
|
}
|
||||||
|
|
||||||
[Cmd]
|
[Cmd]
|
||||||
[OwnerOnly]
|
[OwnerOnly]
|
||||||
@@ -37,5 +43,32 @@ public partial class Administration
|
|||||||
|
|
||||||
await Response().Text("This guild's bot data will be saved.").SendAsync();
|
await Response().Text("This guild's bot data will be saved.").SendAsync();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Cmd]
|
||||||
|
[OwnerOnly]
|
||||||
|
public async Task LeaveUnkeptServers(int startShardId, int shardMultiplier = 3000)
|
||||||
|
{
|
||||||
|
var keptGuildCount = await _svc.GetKeptGuildCount();
|
||||||
|
|
||||||
|
var response = await PromptUserConfirmAsync(new EmbedBuilder()
|
||||||
|
.WithDescription($"""
|
||||||
|
Do you want the bot to leave all unkept servers?
|
||||||
|
|
||||||
|
There are currently {keptGuildCount} kept servers.
|
||||||
|
|
||||||
|
**This is a highly destructive and irreversible action.**
|
||||||
|
"""));
|
||||||
|
|
||||||
|
if (!response)
|
||||||
|
return;
|
||||||
|
|
||||||
|
for (var shardId = startShardId; shardId < _creds.GetCreds().TotalShards; shardId++)
|
||||||
|
{
|
||||||
|
await _svc.StartLeavingUnkeptServers(shardId);
|
||||||
|
await Task.Delay(shardMultiplier * 1000);
|
||||||
|
}
|
||||||
|
|
||||||
|
await ctx.OkAsync();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
@@ -9,9 +9,12 @@ namespace NadekoBot.Modules.Administration.DangerousCommands;
|
|||||||
|
|
||||||
public sealed class CleanupService : ICleanupService, IReadyExecutor, INService
|
public sealed class CleanupService : ICleanupService, IReadyExecutor, INService
|
||||||
{
|
{
|
||||||
|
private TypedKey<KeepReport> _cleanupReportKey = new("cleanup:report");
|
||||||
|
private TypedKey<bool> _cleanupTriggerKey = new("cleanup:trigger");
|
||||||
|
|
||||||
|
private TypedKey<int> _keepTriggerKey = new("keep:trigger");
|
||||||
|
|
||||||
private readonly IPubSub _pubSub;
|
private readonly IPubSub _pubSub;
|
||||||
private TypedKey<KeepReport> _keepReportKey = new("cleanup:report");
|
|
||||||
private TypedKey<bool> _keepTriggerKey = new("cleanup:trigger");
|
|
||||||
private readonly DiscordSocketClient _client;
|
private readonly DiscordSocketClient _client;
|
||||||
private ConcurrentDictionary<int, ulong[]> guildIds = new();
|
private ConcurrentDictionary<int, ulong[]> guildIds = new();
|
||||||
private readonly IBotCredsProvider _creds;
|
private readonly IBotCredsProvider _creds;
|
||||||
@@ -29,11 +32,90 @@ public sealed class CleanupService : ICleanupService, IReadyExecutor, INService
|
|||||||
_db = db;
|
_db = db;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public async Task OnReadyAsync()
|
||||||
|
{
|
||||||
|
await _pubSub.Sub(_cleanupTriggerKey, OnCleanupTrigger);
|
||||||
|
await _pubSub.Sub(_keepTriggerKey, InternalTriggerKeep);
|
||||||
|
|
||||||
|
_client.JoinedGuild += ClientOnJoinedGuild;
|
||||||
|
|
||||||
|
if (_client.ShardId == 0)
|
||||||
|
await _pubSub.Sub(_cleanupReportKey, OnKeepReport);
|
||||||
|
}
|
||||||
|
|
||||||
|
private bool keepTriggered = false;
|
||||||
|
|
||||||
|
private async ValueTask InternalTriggerKeep(int shardId)
|
||||||
|
{
|
||||||
|
if (_client.ShardId != shardId)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (keepTriggered)
|
||||||
|
return;
|
||||||
|
|
||||||
|
keepTriggered = true;
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var allGuildIds = _client.Guilds.Select(x => x.Id).ToArray();
|
||||||
|
|
||||||
|
HashSet<ulong> dontDelete;
|
||||||
|
await using (var db = _db.GetDbContext())
|
||||||
|
{
|
||||||
|
await using var ctx = db.CreateLinqToDBContext();
|
||||||
|
var table = ctx.CreateTable<KeptGuilds>(tableOptions: TableOptions.CheckExistence);
|
||||||
|
|
||||||
|
var dontDeleteList = await table
|
||||||
|
.Where(x => allGuildIds.Contains(x.GuildId))
|
||||||
|
.Select(x => x.GuildId)
|
||||||
|
.ToListAsyncLinqToDB();
|
||||||
|
|
||||||
|
dontDelete = dontDeleteList.ToHashSet();
|
||||||
|
}
|
||||||
|
|
||||||
|
Log.Information("Leaving {RemainingCount} guilds, 1 every second. {DontDeleteCount} will remain",
|
||||||
|
allGuildIds.Length - dontDelete.Count,
|
||||||
|
dontDelete.Count);
|
||||||
|
|
||||||
|
foreach (var guildId in allGuildIds)
|
||||||
|
{
|
||||||
|
if (dontDelete.Contains(guildId))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
await Task.Delay(1016);
|
||||||
|
|
||||||
|
SocketGuild? guild = null;
|
||||||
|
try
|
||||||
|
{
|
||||||
|
guild = _client.GetGuild(guildId);
|
||||||
|
|
||||||
|
if (guild is null)
|
||||||
|
{
|
||||||
|
Log.Warning("Unable to find guild {GuildId}", guildId);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
await guild.LeaveAsync();
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
Log.Warning("Unable to leave guild {GuildName} [{GuildId}]: {ErrorMessage}",
|
||||||
|
guild?.Name,
|
||||||
|
guildId,
|
||||||
|
ex.Message);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
keepTriggered = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public async Task<KeepResult?> DeleteMissingGuildDataAsync()
|
public async Task<KeepResult?> DeleteMissingGuildDataAsync()
|
||||||
{
|
{
|
||||||
guildIds = new();
|
guildIds = new();
|
||||||
var totalShards = _creds.GetCreds().TotalShards;
|
var totalShards = _creds.GetCreds().TotalShards;
|
||||||
await _pubSub.Pub(_keepTriggerKey, true);
|
await _pubSub.Pub(_cleanupTriggerKey, true);
|
||||||
var counter = 0;
|
var counter = 0;
|
||||||
while (guildIds.Keys.Count < totalShards)
|
while (guildIds.Keys.Count < totalShards)
|
||||||
{
|
{
|
||||||
@@ -135,9 +217,7 @@ public sealed class CleanupService : ICleanupService, IReadyExecutor, INService
|
|||||||
{
|
{
|
||||||
await using var db = _db.GetDbContext();
|
await using var db = _db.GetDbContext();
|
||||||
await using var ctx = db.CreateLinqToDBContext();
|
await using var ctx = db.CreateLinqToDBContext();
|
||||||
|
|
||||||
var table = ctx.CreateTable<KeptGuilds>(tableOptions: TableOptions.CheckExistence);
|
var table = ctx.CreateTable<KeptGuilds>(tableOptions: TableOptions.CheckExistence);
|
||||||
|
|
||||||
if (await table.AnyAsyncLinqToDB(x => x.GuildId == guildId))
|
if (await table.AnyAsyncLinqToDB(x => x.GuildId == guildId))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
@@ -149,30 +229,31 @@ public sealed class CleanupService : ICleanupService, IReadyExecutor, INService
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public async Task<int> GetKeptGuildCount()
|
||||||
|
{
|
||||||
|
await using var db = _db.GetDbContext();
|
||||||
|
await using var ctx = db.CreateLinqToDBContext();
|
||||||
|
var table = ctx.CreateTable<KeptGuilds>(tableOptions: TableOptions.CheckExistence);
|
||||||
|
return await table.CountAsync();
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task StartLeavingUnkeptServers(int shardId)
|
||||||
|
=> await _pubSub.Pub(_keepTriggerKey, shardId);
|
||||||
|
|
||||||
private ValueTask OnKeepReport(KeepReport report)
|
private ValueTask OnKeepReport(KeepReport report)
|
||||||
{
|
{
|
||||||
guildIds[report.ShardId] = report.GuildIds;
|
guildIds[report.ShardId] = report.GuildIds;
|
||||||
return default;
|
return default;
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task OnReadyAsync()
|
|
||||||
{
|
|
||||||
await _pubSub.Sub(_keepTriggerKey, OnKeepTrigger);
|
|
||||||
|
|
||||||
_client.JoinedGuild += ClientOnJoinedGuild;
|
|
||||||
|
|
||||||
if (_client.ShardId == 0)
|
|
||||||
await _pubSub.Sub(_keepReportKey, OnKeepReport);
|
|
||||||
}
|
|
||||||
|
|
||||||
private async Task ClientOnJoinedGuild(SocketGuild arg)
|
private async Task ClientOnJoinedGuild(SocketGuild arg)
|
||||||
{
|
{
|
||||||
await KeepGuild(arg.Id);
|
await KeepGuild(arg.Id);
|
||||||
}
|
}
|
||||||
|
|
||||||
private ValueTask OnKeepTrigger(bool arg)
|
private ValueTask OnCleanupTrigger(bool arg)
|
||||||
{
|
{
|
||||||
_pubSub.Pub(_keepReportKey,
|
_pubSub.Pub(_cleanupReportKey,
|
||||||
new KeepReport()
|
new KeepReport()
|
||||||
{
|
{
|
||||||
ShardId = _client.ShardId,
|
ShardId = _client.ShardId,
|
||||||
|
@@ -4,4 +4,6 @@ public interface ICleanupService
|
|||||||
{
|
{
|
||||||
Task<KeepResult?> DeleteMissingGuildDataAsync();
|
Task<KeepResult?> DeleteMissingGuildDataAsync();
|
||||||
Task<bool> KeepGuild(ulong guildId);
|
Task<bool> KeepGuild(ulong guildId);
|
||||||
|
Task<int> GetKeptGuildCount();
|
||||||
|
Task StartLeavingUnkeptServers(int shardId);
|
||||||
}
|
}
|
@@ -8,236 +8,237 @@ public partial class Administration
|
|||||||
[Cmd]
|
[Cmd]
|
||||||
[RequireContext(ContextType.Guild)]
|
[RequireContext(ContextType.Guild)]
|
||||||
[UserPerm(GuildPerm.ManageGuild)]
|
[UserPerm(GuildPerm.ManageGuild)]
|
||||||
public async Task Boost()
|
public Task Boost()
|
||||||
{
|
=> Toggle(GreetType.Boost);
|
||||||
var enabled = await _service.ToggleBoost(ctx.Guild.Id, ctx.Channel.Id);
|
|
||||||
|
|
||||||
if (enabled)
|
|
||||||
await Response().Confirm(strs.boost_on).SendAsync();
|
|
||||||
else
|
|
||||||
await Response().Pending(strs.boost_off).SendAsync();
|
|
||||||
}
|
|
||||||
|
|
||||||
[Cmd]
|
[Cmd]
|
||||||
[RequireContext(ContextType.Guild)]
|
[RequireContext(ContextType.Guild)]
|
||||||
[UserPerm(GuildPerm.ManageGuild)]
|
[UserPerm(GuildPerm.ManageGuild)]
|
||||||
public async Task BoostDel(int timer = 30)
|
public Task BoostDel(int timer = 30)
|
||||||
|
=> SetDel(GreetType.Boost, timer);
|
||||||
|
|
||||||
|
[Cmd]
|
||||||
|
[RequireContext(ContextType.Guild)]
|
||||||
|
[UserPerm(GuildPerm.ManageGuild)]
|
||||||
|
public Task BoostMsg([Leftover] string? text = null)
|
||||||
|
=> SetMsg(GreetType.Boost, text);
|
||||||
|
|
||||||
|
[Cmd]
|
||||||
|
[RequireContext(ContextType.Guild)]
|
||||||
|
[UserPerm(GuildPerm.ManageGuild)]
|
||||||
|
public Task Greet()
|
||||||
|
=> Toggle(GreetType.Greet);
|
||||||
|
|
||||||
|
[Cmd]
|
||||||
|
[RequireContext(ContextType.Guild)]
|
||||||
|
[UserPerm(GuildPerm.ManageGuild)]
|
||||||
|
public Task GreetDel(int timer = 30)
|
||||||
|
=> SetDel(GreetType.Greet, timer);
|
||||||
|
|
||||||
|
[Cmd]
|
||||||
|
[RequireContext(ContextType.Guild)]
|
||||||
|
[UserPerm(GuildPerm.ManageGuild)]
|
||||||
|
public Task GreetMsg([Leftover] string? text = null)
|
||||||
|
=> SetMsg(GreetType.Greet, text);
|
||||||
|
|
||||||
|
[Cmd]
|
||||||
|
[RequireContext(ContextType.Guild)]
|
||||||
|
[UserPerm(GuildPerm.ManageGuild)]
|
||||||
|
public Task GreetDm()
|
||||||
|
=> Toggle(GreetType.GreetDm);
|
||||||
|
|
||||||
|
[Cmd]
|
||||||
|
[RequireContext(ContextType.Guild)]
|
||||||
|
[UserPerm(GuildPerm.ManageGuild)]
|
||||||
|
public Task GreetDmMsg([Leftover] string? text = null)
|
||||||
|
=> SetMsg(GreetType.GreetDm, text);
|
||||||
|
|
||||||
|
[Cmd]
|
||||||
|
[RequireContext(ContextType.Guild)]
|
||||||
|
[UserPerm(GuildPerm.ManageGuild)]
|
||||||
|
public Task Bye()
|
||||||
|
=> Toggle(GreetType.Bye);
|
||||||
|
|
||||||
|
[Cmd]
|
||||||
|
[RequireContext(ContextType.Guild)]
|
||||||
|
[UserPerm(GuildPerm.ManageGuild)]
|
||||||
|
public Task ByeDel(int timer = 30)
|
||||||
|
=> SetDel(GreetType.Bye, timer);
|
||||||
|
|
||||||
|
[Cmd]
|
||||||
|
[RequireContext(ContextType.Guild)]
|
||||||
|
[UserPerm(GuildPerm.ManageGuild)]
|
||||||
|
public Task ByeMsg([Leftover] string? text = null)
|
||||||
|
=> SetMsg(GreetType.Bye, text);
|
||||||
|
|
||||||
|
[Cmd]
|
||||||
|
[RequireContext(ContextType.Guild)]
|
||||||
|
[UserPerm(GuildPerm.ManageGuild)]
|
||||||
|
public Task GreetTest([Leftover] IGuildUser? user = null)
|
||||||
|
=> Test(GreetType.Greet, user);
|
||||||
|
|
||||||
|
[Cmd]
|
||||||
|
[RequireContext(ContextType.Guild)]
|
||||||
|
[UserPerm(GuildPerm.ManageGuild)]
|
||||||
|
public Task GreetDmTest([Leftover] IGuildUser? user = null)
|
||||||
|
=> Test(GreetType.GreetDm, user);
|
||||||
|
|
||||||
|
[Cmd]
|
||||||
|
[RequireContext(ContextType.Guild)]
|
||||||
|
[UserPerm(GuildPerm.ManageGuild)]
|
||||||
|
[Ratelimit(5)]
|
||||||
|
public Task ByeTest([Leftover] IGuildUser? user = null)
|
||||||
|
=> Test(GreetType.Bye, user);
|
||||||
|
|
||||||
|
[Cmd]
|
||||||
|
[RequireContext(ContextType.Guild)]
|
||||||
|
[UserPerm(GuildPerm.ManageGuild)]
|
||||||
|
[Ratelimit(5)]
|
||||||
|
public Task BoostTest([Leftover] IGuildUser? user = null)
|
||||||
|
=> Test(GreetType.Boost, user);
|
||||||
|
|
||||||
|
|
||||||
|
public async Task Toggle(GreetType type)
|
||||||
|
{
|
||||||
|
var enabled = await _service.SetGreet(ctx.Guild.Id, ctx.Channel.Id, type);
|
||||||
|
|
||||||
|
if (enabled)
|
||||||
|
await Response()
|
||||||
|
.Confirm(
|
||||||
|
type switch
|
||||||
|
{
|
||||||
|
GreetType.Boost => strs.boost_on,
|
||||||
|
GreetType.Greet => strs.greet_on,
|
||||||
|
GreetType.Bye => strs.bye_on,
|
||||||
|
GreetType.GreetDm => strs.greetdm_on,
|
||||||
|
_ => strs.error
|
||||||
|
}
|
||||||
|
)
|
||||||
|
.SendAsync();
|
||||||
|
else
|
||||||
|
await Response()
|
||||||
|
.Pending(
|
||||||
|
type switch
|
||||||
|
{
|
||||||
|
GreetType.Boost => strs.boost_off,
|
||||||
|
GreetType.Greet => strs.greet_off,
|
||||||
|
GreetType.Bye => strs.bye_off,
|
||||||
|
GreetType.GreetDm => strs.greetdm_off,
|
||||||
|
_ => strs.error
|
||||||
|
}
|
||||||
|
)
|
||||||
|
.SendAsync();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public async Task SetDel(GreetType type, int timer)
|
||||||
{
|
{
|
||||||
if (timer is < 0 or > 600)
|
if (timer is < 0 or > 600)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
await _service.SetBoostDel(ctx.Guild.Id, timer);
|
await _service.SetDeleteTimer(ctx.Guild.Id, type, timer);
|
||||||
|
|
||||||
if (timer > 0)
|
if (timer > 0)
|
||||||
await Response().Confirm(strs.boostdel_on(timer)).SendAsync();
|
await Response()
|
||||||
|
.Confirm(
|
||||||
|
type switch
|
||||||
|
{
|
||||||
|
GreetType.Boost => strs.boostdel_on(timer),
|
||||||
|
GreetType.Greet => strs.greetdel_on(timer),
|
||||||
|
GreetType.Bye => strs.byedel_on(timer),
|
||||||
|
_ => strs.error
|
||||||
|
}
|
||||||
|
)
|
||||||
|
.SendAsync();
|
||||||
else
|
else
|
||||||
await Response().Pending(strs.boostdel_off).SendAsync();
|
await Response()
|
||||||
|
.Pending(
|
||||||
|
type switch
|
||||||
|
{
|
||||||
|
GreetType.Boost => strs.boostdel_off,
|
||||||
|
GreetType.Greet => strs.greetdel_off,
|
||||||
|
GreetType.Bye => strs.byedel_off,
|
||||||
|
_ => strs.error
|
||||||
|
})
|
||||||
|
.SendAsync();
|
||||||
}
|
}
|
||||||
|
|
||||||
[Cmd]
|
|
||||||
[RequireContext(ContextType.Guild)]
|
public async Task SetMsg(GreetType type, string? text = null)
|
||||||
[UserPerm(GuildPerm.ManageGuild)]
|
|
||||||
public async Task BoostMsg([Leftover] string? text = null)
|
|
||||||
{
|
{
|
||||||
if (string.IsNullOrWhiteSpace(text))
|
if (string.IsNullOrWhiteSpace(text))
|
||||||
{
|
{
|
||||||
var boostMessage = _service.GetBoostMessage(ctx.Guild.Id);
|
var conf = await _service.GetGreetSettingsAsync(ctx.Guild.Id, type);
|
||||||
await Response().Confirm(strs.boostmsg_cur(boostMessage?.SanitizeMentions())).SendAsync();
|
var msg = conf?.MessageText ?? GreetService.GetDefaultGreet(type);
|
||||||
|
await Response()
|
||||||
|
.Confirm(
|
||||||
|
type switch
|
||||||
|
{
|
||||||
|
GreetType.Boost => strs.boostmsg_cur(msg),
|
||||||
|
GreetType.Greet => strs.greetmsg_cur(msg),
|
||||||
|
GreetType.Bye => strs.byemsg_cur(msg),
|
||||||
|
GreetType.GreetDm => strs.greetdmmsg_cur(msg),
|
||||||
|
_ => strs.error
|
||||||
|
})
|
||||||
|
.SendAsync();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
var sendBoostEnabled = _service.SetBoostMessage(ctx.Guild.Id, ref text);
|
var isEnabled = await _service.SetMessage(ctx.Guild.Id, type, text);
|
||||||
|
|
||||||
await Response().Confirm(strs.boostmsg_new).SendAsync();
|
await Response()
|
||||||
if (!sendBoostEnabled)
|
.Confirm(type switch
|
||||||
await Response().Pending(strs.boostmsg_enable($"`{prefix}boost`")).SendAsync();
|
{
|
||||||
}
|
GreetType.Boost => strs.boostmsg_new,
|
||||||
|
GreetType.Greet => strs.greetmsg_new,
|
||||||
|
GreetType.Bye => strs.byemsg_new,
|
||||||
|
GreetType.GreetDm => strs.greetdmmsg_new,
|
||||||
|
_ => strs.error
|
||||||
|
})
|
||||||
|
.SendAsync();
|
||||||
|
|
||||||
[Cmd]
|
|
||||||
[RequireContext(ContextType.Guild)]
|
|
||||||
[UserPerm(GuildPerm.ManageGuild)]
|
|
||||||
public async Task GreetDel(int timer = 30)
|
|
||||||
{
|
|
||||||
if (timer is < 0 or > 600)
|
|
||||||
return;
|
|
||||||
|
|
||||||
await _service.SetGreetDel(ctx.Guild.Id, timer);
|
if (!isEnabled)
|
||||||
|
|
||||||
if (timer > 0)
|
|
||||||
await Response().Confirm(strs.greetdel_on(timer)).SendAsync();
|
|
||||||
else
|
|
||||||
await Response().Pending(strs.greetdel_off).SendAsync();
|
|
||||||
}
|
|
||||||
|
|
||||||
[Cmd]
|
|
||||||
[RequireContext(ContextType.Guild)]
|
|
||||||
[UserPerm(GuildPerm.ManageGuild)]
|
|
||||||
public async Task Greet()
|
|
||||||
{
|
|
||||||
var enabled = await _service.SetGreet(ctx.Guild.Id, ctx.Channel.Id);
|
|
||||||
|
|
||||||
if (enabled)
|
|
||||||
await Response().Confirm(strs.greet_on).SendAsync();
|
|
||||||
else
|
|
||||||
await Response().Pending(strs.greet_off).SendAsync();
|
|
||||||
}
|
|
||||||
|
|
||||||
[Cmd]
|
|
||||||
[RequireContext(ContextType.Guild)]
|
|
||||||
[UserPerm(GuildPerm.ManageGuild)]
|
|
||||||
public async Task GreetMsg([Leftover] string? text = null)
|
|
||||||
{
|
|
||||||
if (string.IsNullOrWhiteSpace(text))
|
|
||||||
{
|
{
|
||||||
var greetMsg = _service.GetGreetMsg(ctx.Guild.Id);
|
var cmdName = GetCmdName(type);
|
||||||
await Response().Confirm(strs.greetmsg_cur(greetMsg?.SanitizeMentions())).SendAsync();
|
|
||||||
return;
|
await Response().Pending(strs.boostmsg_enable($"`{prefix}{cmdName}`")).SendAsync();
|
||||||
}
|
}
|
||||||
|
|
||||||
var sendGreetEnabled = _service.SetGreetMessage(ctx.Guild.Id, ref text);
|
|
||||||
|
|
||||||
await Response().Confirm(strs.greetmsg_new).SendAsync();
|
|
||||||
|
|
||||||
if (!sendGreetEnabled)
|
|
||||||
await Response().Pending(strs.greetmsg_enable($"`{prefix}greet`")).SendAsync();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
[Cmd]
|
private static string GetCmdName(GreetType type)
|
||||||
[RequireContext(ContextType.Guild)]
|
|
||||||
[UserPerm(GuildPerm.ManageGuild)]
|
|
||||||
public async Task GreetDm()
|
|
||||||
{
|
{
|
||||||
var enabled = await _service.SetGreetDm(ctx.Guild.Id);
|
var cmdName = type switch
|
||||||
|
|
||||||
if (enabled)
|
|
||||||
await Response().Confirm(strs.greetdm_on).SendAsync();
|
|
||||||
else
|
|
||||||
await Response().Confirm(strs.greetdm_off).SendAsync();
|
|
||||||
}
|
|
||||||
|
|
||||||
[Cmd]
|
|
||||||
[RequireContext(ContextType.Guild)]
|
|
||||||
[UserPerm(GuildPerm.ManageGuild)]
|
|
||||||
public async Task GreetDmMsg([Leftover] string? text = null)
|
|
||||||
{
|
|
||||||
if (string.IsNullOrWhiteSpace(text))
|
|
||||||
{
|
{
|
||||||
var dmGreetMsg = _service.GetDmGreetMsg(ctx.Guild.Id);
|
GreetType.Greet => "greet",
|
||||||
await Response().Confirm(strs.greetdmmsg_cur(dmGreetMsg?.SanitizeMentions())).SendAsync();
|
GreetType.Bye => "bye",
|
||||||
return;
|
GreetType.Boost => "boost",
|
||||||
}
|
GreetType.GreetDm => "greetdm",
|
||||||
|
_ => "unknown_command"
|
||||||
var sendGreetEnabled = _service.SetGreetDmMessage(ctx.Guild.Id, ref text);
|
};
|
||||||
|
return cmdName;
|
||||||
await Response().Confirm(strs.greetdmmsg_new).SendAsync();
|
|
||||||
if (!sendGreetEnabled)
|
|
||||||
await Response().Pending(strs.greetdmmsg_enable($"`{prefix}greetdm`")).SendAsync();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
[Cmd]
|
public async Task Test(GreetType type, IGuildUser? user = null)
|
||||||
[RequireContext(ContextType.Guild)]
|
|
||||||
[UserPerm(GuildPerm.ManageGuild)]
|
|
||||||
public async Task Bye()
|
|
||||||
{
|
{
|
||||||
var enabled = await _service.SetBye(ctx.Guild.Id, ctx.Channel.Id);
|
user ??= (IGuildUser)ctx.User;
|
||||||
|
|
||||||
if (enabled)
|
await _service.Test(ctx.Guild.Id, type, (ITextChannel)ctx.Channel, user);
|
||||||
await Response().Confirm(strs.bye_on).SendAsync();
|
var conf = await _service.GetGreetSettingsAsync(ctx.Guild.Id, type);
|
||||||
else
|
|
||||||
await Response().Confirm(strs.bye_off).SendAsync();
|
|
||||||
}
|
|
||||||
|
|
||||||
[Cmd]
|
var cmd = $"`{prefix}{GetCmdName(type)}`";
|
||||||
[RequireContext(ContextType.Guild)]
|
|
||||||
[UserPerm(GuildPerm.ManageGuild)]
|
var str = type switch
|
||||||
public async Task ByeMsg([Leftover] string? text = null)
|
|
||||||
{
|
|
||||||
if (string.IsNullOrWhiteSpace(text))
|
|
||||||
{
|
{
|
||||||
var byeMsg = _service.GetByeMessage(ctx.Guild.Id);
|
GreetType.Greet => strs.boostmsg_enable(cmd),
|
||||||
await Response().Confirm(strs.byemsg_cur(byeMsg?.SanitizeMentions())).SendAsync();
|
GreetType.Bye => strs.greetmsg_enable(cmd),
|
||||||
return;
|
GreetType.Boost => strs.byemsg_enable(cmd),
|
||||||
}
|
GreetType.GreetDm => strs.greetdmmsg_enable(cmd),
|
||||||
|
_ => strs.error
|
||||||
|
};
|
||||||
|
|
||||||
var sendByeEnabled = _service.SetByeMessage(ctx.Guild.Id, ref text);
|
if (conf?.IsEnabled is not true)
|
||||||
|
await Response().Pending(str).SendAsync();
|
||||||
await Response().Confirm(strs.byemsg_new).SendAsync();
|
|
||||||
if (!sendByeEnabled)
|
|
||||||
await Response().Pending(strs.byemsg_enable($"`{prefix}bye`")).SendAsync();
|
|
||||||
}
|
|
||||||
|
|
||||||
[Cmd]
|
|
||||||
[RequireContext(ContextType.Guild)]
|
|
||||||
[UserPerm(GuildPerm.ManageGuild)]
|
|
||||||
public async Task ByeDel(int timer = 30)
|
|
||||||
{
|
|
||||||
await _service.SetByeDel(ctx.Guild.Id, timer);
|
|
||||||
|
|
||||||
if (timer > 0)
|
|
||||||
await Response().Confirm(strs.byedel_on(timer)).SendAsync();
|
|
||||||
else
|
|
||||||
await Response().Pending(strs.byedel_off).SendAsync();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
[Cmd]
|
|
||||||
[RequireContext(ContextType.Guild)]
|
|
||||||
[UserPerm(GuildPerm.ManageGuild)]
|
|
||||||
[Ratelimit(5)]
|
|
||||||
public async Task ByeTest([Leftover] IGuildUser? user = null)
|
|
||||||
{
|
|
||||||
user ??= (IGuildUser)ctx.User;
|
|
||||||
|
|
||||||
await _service.ByeTest((ITextChannel)ctx.Channel, user);
|
|
||||||
var enabled = _service.GetByeEnabled(ctx.Guild.Id);
|
|
||||||
if (!enabled)
|
|
||||||
await Response().Pending(strs.byemsg_enable($"`{prefix}bye`")).SendAsync();
|
|
||||||
}
|
|
||||||
|
|
||||||
[Cmd]
|
|
||||||
[RequireContext(ContextType.Guild)]
|
|
||||||
[UserPerm(GuildPerm.ManageGuild)]
|
|
||||||
[Ratelimit(5)]
|
|
||||||
public async Task GreetTest([Leftover] IGuildUser? user = null)
|
|
||||||
{
|
|
||||||
user ??= (IGuildUser)ctx.User;
|
|
||||||
|
|
||||||
await _service.GreetTest((ITextChannel)ctx.Channel, user);
|
|
||||||
var enabled = _service.GetGreetEnabled(ctx.Guild.Id);
|
|
||||||
if (!enabled)
|
|
||||||
await Response().Pending(strs.greetmsg_enable($"`{prefix}greet`")).SendAsync();
|
|
||||||
}
|
|
||||||
|
|
||||||
[Cmd]
|
|
||||||
[RequireContext(ContextType.Guild)]
|
|
||||||
[UserPerm(GuildPerm.ManageGuild)]
|
|
||||||
[Ratelimit(5)]
|
|
||||||
public async Task GreetDmTest([Leftover] IGuildUser? user = null)
|
|
||||||
{
|
|
||||||
user ??= (IGuildUser)ctx.User;
|
|
||||||
|
|
||||||
var success = await _service.GreetDmTest(user);
|
|
||||||
if (success)
|
|
||||||
await ctx.OkAsync();
|
|
||||||
else
|
|
||||||
await ctx.WarningAsync();
|
|
||||||
var enabled = _service.GetGreetDmEnabled(ctx.Guild.Id);
|
|
||||||
if (!enabled)
|
|
||||||
await Response().Pending(strs.greetdmmsg_enable($"`{prefix}greetdm`")).SendAsync();
|
|
||||||
}
|
|
||||||
|
|
||||||
[Cmd]
|
|
||||||
[RequireContext(ContextType.Guild)]
|
|
||||||
[UserPerm(GuildPerm.ManageGuild)]
|
|
||||||
[Ratelimit(5)]
|
|
||||||
public async Task BoostTest([Leftover] IGuildUser? user = null)
|
|
||||||
{
|
|
||||||
user ??= (IGuildUser)ctx.User;
|
|
||||||
|
|
||||||
await _service.BoostTest((ITextChannel)ctx.Channel, user);
|
|
||||||
var enabled = _service.GetBoostEnabled(ctx.Guild.Id);
|
|
||||||
if (!enabled)
|
|
||||||
await Response().Pending(strs.boostmsg_enable($"`{prefix}boost`")).SendAsync();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
@@ -1,71 +0,0 @@
|
|||||||
namespace NadekoBot.Services;
|
|
||||||
|
|
||||||
public class GreetGrouper<T>
|
|
||||||
{
|
|
||||||
private readonly Dictionary<ulong, HashSet<T>> _group;
|
|
||||||
private readonly object _locker = new();
|
|
||||||
|
|
||||||
public GreetGrouper()
|
|
||||||
=> _group = new();
|
|
||||||
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Creates a group, if group already exists, adds the specified user
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="guildId">Id of the server for which to create group for</param>
|
|
||||||
/// <param name="toAddIfExists">User to add if group already exists</param>
|
|
||||||
/// <returns></returns>
|
|
||||||
public bool CreateOrAdd(ulong guildId, T toAddIfExists)
|
|
||||||
{
|
|
||||||
lock (_locker)
|
|
||||||
{
|
|
||||||
if (_group.TryGetValue(guildId, out var list))
|
|
||||||
{
|
|
||||||
list.Add(toAddIfExists);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
_group[guildId] = new();
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Remove the specified amount of items from the group. If all items are removed, group will be removed.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="guildId">Id of the group</param>
|
|
||||||
/// <param name="count">Maximum number of items to retrieve</param>
|
|
||||||
/// <param name="items">Items retrieved</param>
|
|
||||||
/// <returns>Whether the group has no more items left and is deleted</returns>
|
|
||||||
public bool ClearGroup(ulong guildId, int count, out IReadOnlyCollection<T> items)
|
|
||||||
{
|
|
||||||
lock (_locker)
|
|
||||||
{
|
|
||||||
if (_group.TryGetValue(guildId, out var set))
|
|
||||||
{
|
|
||||||
// if we want more than there are, return everything
|
|
||||||
if (count >= set.Count)
|
|
||||||
{
|
|
||||||
items = set;
|
|
||||||
_group.Remove(guildId);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
// if there are more in the group than what's needed
|
|
||||||
// take the requested number, remove them from the set
|
|
||||||
// and return them
|
|
||||||
var toReturn = set.TakeWhile(_ => count-- != 0).ToList();
|
|
||||||
foreach (var item in toReturn)
|
|
||||||
set.Remove(item);
|
|
||||||
|
|
||||||
items = toReturn;
|
|
||||||
// returning falsemeans group is not yet deleted
|
|
||||||
// because there are items left
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
items = Array.Empty<T>();
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@@ -1,58 +1,93 @@
|
|||||||
|
using LinqToDB;
|
||||||
|
using LinqToDB.EntityFrameworkCore;
|
||||||
|
using LinqToDB.Tools;
|
||||||
using NadekoBot.Common.ModuleBehaviors;
|
using NadekoBot.Common.ModuleBehaviors;
|
||||||
using NadekoBot.Db.Models;
|
|
||||||
using System.Threading.Channels;
|
using System.Threading.Channels;
|
||||||
|
|
||||||
namespace NadekoBot.Services;
|
namespace NadekoBot.Services;
|
||||||
|
|
||||||
public class GreetService : INService, IReadyExecutor
|
public class GreetService : INService, IReadyExecutor
|
||||||
{
|
{
|
||||||
public bool GroupGreets
|
|
||||||
=> _bss.Data.GroupGreets;
|
|
||||||
|
|
||||||
private readonly DbService _db;
|
private readonly DbService _db;
|
||||||
|
|
||||||
private readonly ConcurrentDictionary<ulong, GreetSettings> _guildConfigsCache;
|
private ConcurrentDictionary<GreetType, ConcurrentHashSet<ulong>> _enabled = new();
|
||||||
|
|
||||||
private readonly DiscordSocketClient _client;
|
private readonly DiscordSocketClient _client;
|
||||||
|
|
||||||
private readonly GreetGrouper<IGuildUser> _greets = new();
|
|
||||||
private readonly GreetGrouper<IUser> _byes = new();
|
|
||||||
private readonly BotConfigService _bss;
|
|
||||||
private readonly IReplacementService _repSvc;
|
private readonly IReplacementService _repSvc;
|
||||||
|
private readonly IBotCache _cache;
|
||||||
private readonly IMessageSenderService _sender;
|
private readonly IMessageSenderService _sender;
|
||||||
|
|
||||||
|
private readonly Channel<(GreetSettings, IUser, ITextChannel?)> _greetQueue =
|
||||||
|
Channel.CreateBounded<(GreetSettings, IUser, ITextChannel?)>(
|
||||||
|
new BoundedChannelOptions(60)
|
||||||
|
{
|
||||||
|
FullMode = BoundedChannelFullMode.DropOldest
|
||||||
|
});
|
||||||
|
|
||||||
public GreetService(
|
public GreetService(
|
||||||
DiscordSocketClient client,
|
DiscordSocketClient client,
|
||||||
IBot bot,
|
|
||||||
DbService db,
|
DbService db,
|
||||||
BotConfigService bss,
|
|
||||||
IMessageSenderService sender,
|
IMessageSenderService sender,
|
||||||
IReplacementService repSvc)
|
IReplacementService repSvc,
|
||||||
|
IBotCache cache
|
||||||
|
)
|
||||||
{
|
{
|
||||||
_db = db;
|
_db = db;
|
||||||
_client = client;
|
_client = client;
|
||||||
_bss = bss;
|
|
||||||
_repSvc = repSvc;
|
_repSvc = repSvc;
|
||||||
|
_cache = cache;
|
||||||
_sender = sender;
|
_sender = sender;
|
||||||
|
|
||||||
_guildConfigsCache = new(bot.AllGuildConfigs.ToDictionary(g => g.GuildId, GreetSettings.Create));
|
|
||||||
|
|
||||||
_client.UserJoined += OnUserJoined;
|
foreach (var type in Enum.GetValues<GreetType>())
|
||||||
_client.UserLeft += OnUserLeft;
|
{
|
||||||
|
_enabled[type] = new();
|
||||||
bot.JoinedGuild += OnBotJoinedGuild;
|
}
|
||||||
_client.LeftGuild += OnClientLeftGuild;
|
|
||||||
|
|
||||||
_client.GuildMemberUpdated += ClientOnGuildMemberUpdated;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task OnReadyAsync()
|
public async Task OnReadyAsync()
|
||||||
{
|
{
|
||||||
|
// cache all enabled guilds
|
||||||
|
await using (var uow = _db.GetDbContext())
|
||||||
|
{
|
||||||
|
var guilds = _client.Guilds.Select(x => x.Id).ToList();
|
||||||
|
var enabled = await uow.GetTable<GreetSettings>()
|
||||||
|
.Where(x => x.GuildId.In(guilds))
|
||||||
|
.Where(x => x.IsEnabled)
|
||||||
|
.Select(x => new
|
||||||
|
{
|
||||||
|
x.GuildId,
|
||||||
|
x.GreetType
|
||||||
|
})
|
||||||
|
.ToListAsync();
|
||||||
|
|
||||||
|
foreach (var e in enabled)
|
||||||
|
{
|
||||||
|
_enabled[e.GreetType].Add(e.GuildId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
_client.UserJoined += OnUserJoined;
|
||||||
|
_client.UserLeft += OnUserLeft;
|
||||||
|
|
||||||
|
_client.LeftGuild += OnClientLeftGuild;
|
||||||
|
|
||||||
|
_client.GuildMemberUpdated += ClientOnGuildMemberUpdated;
|
||||||
|
|
||||||
while (true)
|
while (true)
|
||||||
{
|
{
|
||||||
var (conf, user, compl) = await _greetDmQueue.Reader.ReadAsync();
|
try
|
||||||
var res = await GreetDmUserInternal(conf, user);
|
{
|
||||||
compl.TrySetResult(res);
|
var (conf, user, ch) = await _greetQueue.Reader.ReadAsync();
|
||||||
await Task.Delay(2000);
|
await GreetUsers(conf, ch, user);
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
Log.Error(ex, "Greet Loop almost crashed. Please report this!");
|
||||||
|
}
|
||||||
|
|
||||||
|
await Task.Delay(2016);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -65,61 +100,38 @@ public class GreetService : INService, IReadyExecutor
|
|||||||
&& newUser.PremiumSince is { } newDate
|
&& newUser.PremiumSince is { } newDate
|
||||||
&& newDate > oldDate))
|
&& newDate > oldDate))
|
||||||
{
|
{
|
||||||
var conf = GetOrAddSettingsForGuild(newUser.Guild.Id);
|
_ = Task.Run(async () =>
|
||||||
if (!conf.SendBoostMessage)
|
{
|
||||||
return Task.CompletedTask;
|
var conf = await GetGreetSettingsAsync(newUser.Guild.Id, GreetType.Boost);
|
||||||
|
|
||||||
_ = Task.Run(TriggerBoostMessage(conf, newUser));
|
if (conf is null || !conf.IsEnabled)
|
||||||
|
return;
|
||||||
|
|
||||||
|
ITextChannel? channel = null;
|
||||||
|
if (conf.ChannelId is { } cid)
|
||||||
|
channel = newUser.Guild.GetTextChannel(cid);
|
||||||
|
|
||||||
|
if (channel is null)
|
||||||
|
return;
|
||||||
|
|
||||||
|
await GreetUsers(conf, channel, newUser);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
return Task.CompletedTask;
|
return Task.CompletedTask;
|
||||||
}
|
}
|
||||||
|
|
||||||
private Func<Task> TriggerBoostMessage(GreetSettings conf, SocketGuildUser user)
|
private async Task OnClientLeftGuild(SocketGuild guild)
|
||||||
=> async () =>
|
|
||||||
{
|
|
||||||
var channel = user.Guild.GetTextChannel(conf.BoostMessageChannelId);
|
|
||||||
if (channel is null)
|
|
||||||
return;
|
|
||||||
|
|
||||||
await SendBoostMessage(conf, user, channel);
|
|
||||||
};
|
|
||||||
|
|
||||||
private async Task<bool> SendBoostMessage(GreetSettings conf, IGuildUser user, ITextChannel channel)
|
|
||||||
{
|
{
|
||||||
if (string.IsNullOrWhiteSpace(conf.BoostMessage))
|
foreach (var gt in Enum.GetValues<GreetType>())
|
||||||
return false;
|
|
||||||
|
|
||||||
var toSend = SmartText.CreateFrom(conf.BoostMessage);
|
|
||||||
|
|
||||||
try
|
|
||||||
{
|
{
|
||||||
var newContent = await _repSvc.ReplaceAsync(toSend,
|
_enabled[gt].TryRemove(guild.Id);
|
||||||
new(client: _client, guild: user.Guild, channel: channel, users: user));
|
|
||||||
var toDelete = await _sender.Response(channel).Text(newContent).Sanitize(false).SendAsync();
|
|
||||||
if (conf.BoostMessageDeleteAfter > 0)
|
|
||||||
toDelete.DeleteAfter(conf.BoostMessageDeleteAfter);
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
Log.Error(ex, "Error sending boost message");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
await using var uow = _db.GetDbContext();
|
||||||
}
|
await uow.GetTable<GreetSettings>()
|
||||||
|
.Where(x => x.GuildId == guild.Id)
|
||||||
private Task OnClientLeftGuild(SocketGuild arg)
|
.DeleteAsync();
|
||||||
{
|
|
||||||
_guildConfigsCache.TryRemove(arg.Id, out _);
|
|
||||||
return Task.CompletedTask;
|
|
||||||
}
|
|
||||||
|
|
||||||
private Task OnBotJoinedGuild(GuildConfig gc)
|
|
||||||
{
|
|
||||||
_guildConfigsCache[gc.GuildId] = GreetSettings.Create(gc);
|
|
||||||
return Task.CompletedTask;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private Task OnUserLeft(SocketGuild guild, SocketUser user)
|
private Task OnUserLeft(SocketGuild guild, SocketUser user)
|
||||||
@@ -128,35 +140,20 @@ public class GreetService : INService, IReadyExecutor
|
|||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
var conf = GetOrAddSettingsForGuild(guild.Id);
|
var conf = await GetGreetSettingsAsync(guild.Id, GreetType.Bye);
|
||||||
|
|
||||||
if (!conf.SendChannelByeMessage)
|
if (conf is null)
|
||||||
return;
|
return;
|
||||||
var channel = guild.TextChannels.FirstOrDefault(c => c.Id == conf.ByeMessageChannelId);
|
|
||||||
|
var channel = guild.TextChannels.FirstOrDefault(c => c.Id == conf.ChannelId);
|
||||||
|
|
||||||
if (channel is null) //maybe warn the server owner that the channel is missing
|
if (channel is null) //maybe warn the server owner that the channel is missing
|
||||||
return;
|
|
||||||
|
|
||||||
if (GroupGreets)
|
|
||||||
{
|
{
|
||||||
// if group is newly created, greet that user right away,
|
await SetGreet(guild.Id, null, GreetType.Bye, false);
|
||||||
// but any user which joins in the next 5 seconds will
|
return;
|
||||||
// be greeted in a group greet
|
|
||||||
if (_byes.CreateOrAdd(guild.Id, user))
|
|
||||||
{
|
|
||||||
// greet single user
|
|
||||||
await ByeUsers(conf, channel, new[] { user });
|
|
||||||
var groupClear = false;
|
|
||||||
while (!groupClear)
|
|
||||||
{
|
|
||||||
await Task.Delay(5000);
|
|
||||||
groupClear = _byes.ClearGroup(guild.Id, 5, out var toBye);
|
|
||||||
await ByeUsers(conf, channel, toBye);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
else
|
|
||||||
await ByeUsers(conf, channel, new[] { user });
|
await _greetQueue.Writer.WriteAsync((conf, user, channel));
|
||||||
}
|
}
|
||||||
catch
|
catch
|
||||||
{
|
{
|
||||||
@@ -166,98 +163,62 @@ public class GreetService : INService, IReadyExecutor
|
|||||||
return Task.CompletedTask;
|
return Task.CompletedTask;
|
||||||
}
|
}
|
||||||
|
|
||||||
public string? GetDmGreetMsg(ulong id)
|
private TypedKey<GreetSettings?> GreetSettingsKey(GreetType type)
|
||||||
|
=> new($"greet_settings:{type}");
|
||||||
|
|
||||||
|
public async Task<GreetSettings?> GetGreetSettingsAsync(ulong gid, GreetType type)
|
||||||
|
=> await _cache.GetOrAddAsync<GreetSettings?>(GreetSettingsKey(type),
|
||||||
|
() => InternalGetGreetSettingsAsync(gid, type),
|
||||||
|
TimeSpan.FromSeconds(3));
|
||||||
|
|
||||||
|
private async Task<GreetSettings?> InternalGetGreetSettingsAsync(ulong gid, GreetType type)
|
||||||
{
|
{
|
||||||
using var uow = _db.GetDbContext();
|
await using var uow = _db.GetDbContext();
|
||||||
return uow.GuildConfigsForId(id, set => set).DmGreetMessageText;
|
var res = await uow.GetTable<GreetSettings>()
|
||||||
|
.Where(x => x.GuildId == gid && x.GreetType == type)
|
||||||
|
.FirstOrDefaultAsync();
|
||||||
|
|
||||||
|
if (res is not null)
|
||||||
|
res.MessageText ??= GetDefaultGreet(type);
|
||||||
|
|
||||||
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
public string? GetGreetMsg(ulong gid)
|
private async Task GreetUsers(GreetSettings conf, ITextChannel? channel, IUser user)
|
||||||
{
|
{
|
||||||
using var uow = _db.GetDbContext();
|
if (conf.GreetType == GreetType.GreetDm)
|
||||||
return uow.GuildConfigsForId(gid, set => set).ChannelGreetMessageText;
|
{
|
||||||
}
|
if (user is not IGuildUser gu)
|
||||||
|
return;
|
||||||
|
|
||||||
public string? GetBoostMessage(ulong gid)
|
await GreetDmUserInternal(conf, gu);
|
||||||
{
|
return;
|
||||||
using var uow = _db.GetDbContext();
|
}
|
||||||
return uow.GuildConfigsForId(gid, set => set).BoostMessage;
|
|
||||||
}
|
|
||||||
|
|
||||||
public GreetSettings GetGreetSettings(ulong gid)
|
if (channel is null)
|
||||||
{
|
|
||||||
if (_guildConfigsCache.TryGetValue(gid, out var gs))
|
|
||||||
return gs;
|
|
||||||
|
|
||||||
using var uow = _db.GetDbContext();
|
|
||||||
return GreetSettings.Create(uow.GuildConfigsForId(gid, set => set));
|
|
||||||
}
|
|
||||||
|
|
||||||
private Task ByeUsers(GreetSettings conf, ITextChannel channel, IUser user)
|
|
||||||
=> ByeUsers(conf, channel, new[] { user });
|
|
||||||
|
|
||||||
private async Task ByeUsers(GreetSettings conf, ITextChannel channel, IReadOnlyCollection<IUser> users)
|
|
||||||
{
|
|
||||||
if (!users.Any())
|
|
||||||
return;
|
return;
|
||||||
|
|
||||||
var repCtx = new ReplacementContext(client: _client,
|
var repCtx = new ReplacementContext(client: _client,
|
||||||
guild: channel.Guild,
|
guild: channel.Guild,
|
||||||
channel: channel,
|
channel: channel,
|
||||||
users: users.ToArray());
|
user: user);
|
||||||
|
|
||||||
var text = SmartText.CreateFrom(conf.ChannelByeMessageText);
|
var text = SmartText.CreateFrom(conf.MessageText);
|
||||||
text = await _repSvc.ReplaceAsync(text, repCtx);
|
text = await _repSvc.ReplaceAsync(text, repCtx);
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
var toDelete = await _sender.Response(channel).Text(text).Sanitize(false).SendAsync();
|
var toDelete = await _sender.Response(channel).Text(text).Sanitize(false).SendAsync();
|
||||||
if (conf.AutoDeleteByeMessagesTimer > 0)
|
if (conf.AutoDeleteTimer > 0)
|
||||||
toDelete.DeleteAfter(conf.AutoDeleteByeMessagesTimer);
|
toDelete.DeleteAfter(conf.AutoDeleteTimer);
|
||||||
}
|
}
|
||||||
catch (HttpException ex) when (ex.DiscordCode == DiscordErrorCode.InsufficientPermissions
|
catch (HttpException ex) when (ex.DiscordCode is DiscordErrorCode.InsufficientPermissions
|
||||||
|| ex.DiscordCode == DiscordErrorCode.MissingPermissions
|
or DiscordErrorCode.MissingPermissions
|
||||||
|| ex.DiscordCode == DiscordErrorCode.UnknownChannel)
|
or DiscordErrorCode.UnknownChannel)
|
||||||
{
|
|
||||||
Log.Warning(ex,
|
|
||||||
"Missing permissions to send a bye message, the bye message will be disabled on server: {GuildId}",
|
|
||||||
channel.GuildId);
|
|
||||||
await SetBye(channel.GuildId, channel.Id, false);
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
Log.Warning(ex, "Error embeding bye message");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private Task GreetUsers(GreetSettings conf, ITextChannel channel, IGuildUser user)
|
|
||||||
=> GreetUsers(conf, channel, new[] { user });
|
|
||||||
|
|
||||||
private async Task GreetUsers(GreetSettings conf, ITextChannel channel, IReadOnlyCollection<IGuildUser> users)
|
|
||||||
{
|
|
||||||
if (users.Count == 0)
|
|
||||||
return;
|
|
||||||
|
|
||||||
var repCtx = new ReplacementContext(client: _client,
|
|
||||||
guild: channel.Guild,
|
|
||||||
channel: channel,
|
|
||||||
users: users.ToArray());
|
|
||||||
|
|
||||||
var text = SmartText.CreateFrom(conf.ChannelGreetMessageText);
|
|
||||||
text = await _repSvc.ReplaceAsync(text, repCtx);
|
|
||||||
try
|
|
||||||
{
|
|
||||||
var toDelete = await _sender.Response(channel).Text(text).Sanitize(false).SendAsync();
|
|
||||||
if (conf.AutoDeleteGreetMessagesTimer > 0)
|
|
||||||
toDelete.DeleteAfter(conf.AutoDeleteGreetMessagesTimer);
|
|
||||||
}
|
|
||||||
catch (HttpException ex) when (ex.DiscordCode == DiscordErrorCode.InsufficientPermissions
|
|
||||||
|| ex.DiscordCode == DiscordErrorCode.MissingPermissions
|
|
||||||
|| ex.DiscordCode == DiscordErrorCode.UnknownChannel)
|
|
||||||
{
|
{
|
||||||
Log.Warning(ex,
|
Log.Warning(ex,
|
||||||
"Missing permissions to send a bye message, the greet message will be disabled on server: {GuildId}",
|
"Missing permissions to send a bye message, the greet message will be disabled on server: {GuildId}",
|
||||||
channel.GuildId);
|
channel.GuildId);
|
||||||
await SetGreet(channel.GuildId, channel.Id, false);
|
await SetGreet(channel.GuildId, channel.Id, GreetType.Greet, false);
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
@@ -265,33 +226,12 @@ public class GreetService : INService, IReadyExecutor
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private readonly Channel<(GreetSettings, IGuildUser, TaskCompletionSource<bool>)> _greetDmQueue =
|
|
||||||
Channel.CreateBounded<(GreetSettings, IGuildUser, TaskCompletionSource<bool>)>(new BoundedChannelOptions(60)
|
|
||||||
{
|
|
||||||
// The limit of 60 users should be only hit when there's a raid. In that case
|
|
||||||
// probably the best thing to do is to drop newest (raiding) users
|
|
||||||
FullMode = BoundedChannelFullMode.DropNewest
|
|
||||||
});
|
|
||||||
|
|
||||||
|
|
||||||
private async Task<bool> GreetDmUser(GreetSettings conf, IGuildUser user)
|
|
||||||
{
|
|
||||||
var completionSource = new TaskCompletionSource<bool>(TaskCreationOptions.RunContinuationsAsynchronously);
|
|
||||||
await _greetDmQueue.Writer.WriteAsync((conf, user, completionSource));
|
|
||||||
return await completionSource.Task;
|
|
||||||
}
|
|
||||||
|
|
||||||
private async Task<bool> GreetDmUserInternal(GreetSettings conf, IGuildUser user)
|
private async Task<bool> GreetDmUserInternal(GreetSettings conf, IGuildUser user)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
// var rep = new ReplacementBuilder()
|
var repCtx = new ReplacementContext(client: _client, guild: user.Guild, user: user);
|
||||||
// .WithUser(user)
|
var smartText = SmartText.CreateFrom(conf.MessageText);
|
||||||
// .WithServer(_client, (SocketGuild)user.Guild)
|
|
||||||
// .Build();
|
|
||||||
|
|
||||||
var repCtx = new ReplacementContext(client: _client, guild: user.Guild, users: user);
|
|
||||||
var smartText = SmartText.CreateFrom(conf.DmGreetMessageText);
|
|
||||||
smartText = await _repSvc.ReplaceAsync(smartText, repCtx);
|
smartText = await _repSvc.ReplaceAsync(smartText, repCtx);
|
||||||
|
|
||||||
if (smartText is SmartPlainText pt)
|
if (smartText is SmartPlainText pt)
|
||||||
@@ -351,8 +291,9 @@ public class GreetService : INService, IReadyExecutor
|
|||||||
|
|
||||||
await _sender.Response(user).Text(smartText).Sanitize(false).SendAsync();
|
await _sender.Response(user).Text(smartText).Sanitize(false).SendAsync();
|
||||||
}
|
}
|
||||||
catch
|
catch(Exception ex)
|
||||||
{
|
{
|
||||||
|
Log.Error(ex, "Error sending greet dm");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -372,297 +313,187 @@ public class GreetService : INService, IReadyExecutor
|
|||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
var conf = GetOrAddSettingsForGuild(user.GuildId);
|
if (_enabled[GreetType.Greet].Contains(user.GuildId))
|
||||||
|
|
||||||
if (conf.SendChannelGreetMessage)
|
|
||||||
{
|
{
|
||||||
var channel = await user.Guild.GetTextChannelAsync(conf.GreetMessageChannelId);
|
var conf = await GetGreetSettingsAsync(user.GuildId, GreetType.Greet);
|
||||||
if (channel is not null)
|
if (conf?.ChannelId is ulong cid)
|
||||||
{
|
{
|
||||||
if (GroupGreets)
|
var channel = await user.Guild.GetTextChannelAsync(cid);
|
||||||
|
if (channel is not null)
|
||||||
{
|
{
|
||||||
// if group is newly created, greet that user right away,
|
await _greetQueue.Writer.WriteAsync((conf, user, channel));
|
||||||
// but any user which joins in the next 5 seconds will
|
|
||||||
// be greeted in a group greet
|
|
||||||
if (_greets.CreateOrAdd(user.GuildId, user))
|
|
||||||
{
|
|
||||||
// greet single user
|
|
||||||
await GreetUsers(conf, channel, new[] { user });
|
|
||||||
var groupClear = false;
|
|
||||||
while (!groupClear)
|
|
||||||
{
|
|
||||||
await Task.Delay(5000);
|
|
||||||
groupClear = _greets.ClearGroup(user.GuildId, 5, out var toGreet);
|
|
||||||
await GreetUsers(conf, channel, toGreet);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
else
|
|
||||||
await GreetUsers(conf, channel, new[] { user });
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (conf.SendDmGreetMessage)
|
|
||||||
await GreetDmUser(conf, user);
|
if (_enabled[GreetType.GreetDm].Contains(user.GuildId))
|
||||||
|
{
|
||||||
|
var confDm = await GetGreetSettingsAsync(user.GuildId, GreetType.GreetDm);
|
||||||
|
if (confDm is not null)
|
||||||
|
{
|
||||||
|
await _greetQueue.Writer.WriteAsync((confDm, user, null));
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
catch
|
catch(Exception ex)
|
||||||
{
|
{
|
||||||
// ignored
|
Log.Error(ex, "Error in GreetService.OnUserJoined. This should not happen. Please report it");
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
return Task.CompletedTask;
|
return Task.CompletedTask;
|
||||||
}
|
}
|
||||||
|
|
||||||
public string? GetByeMessage(ulong gid)
|
|
||||||
{
|
|
||||||
using var uow = _db.GetDbContext();
|
|
||||||
return uow.GuildConfigsForId(gid, set => set).ChannelByeMessageText;
|
|
||||||
}
|
|
||||||
|
|
||||||
public GreetSettings GetOrAddSettingsForGuild(ulong guildId)
|
public static string GetDefaultGreet(GreetType greetType)
|
||||||
{
|
=> greetType switch
|
||||||
if (_guildConfigsCache.TryGetValue(guildId, out var settings))
|
|
||||||
return settings;
|
|
||||||
|
|
||||||
using (var uow = _db.GetDbContext())
|
|
||||||
{
|
{
|
||||||
var gc = uow.GuildConfigsForId(guildId, set => set);
|
GreetType.Boost => "%user.mention% has boosted the server!",
|
||||||
settings = GreetSettings.Create(gc);
|
GreetType.Greet => "%user.mention% has joined the server!",
|
||||||
|
GreetType.Bye => "%user.name% has left the server!",
|
||||||
|
GreetType.GreetDm => "Welcome to the server %user.name%",
|
||||||
|
_ => "%user.name% did something new!"
|
||||||
|
};
|
||||||
|
|
||||||
|
public async Task<bool> SetGreet(
|
||||||
|
ulong guildId,
|
||||||
|
ulong? channelId,
|
||||||
|
GreetType greetType,
|
||||||
|
bool? value = null)
|
||||||
|
{
|
||||||
|
await using var uow = _db.GetDbContext();
|
||||||
|
var q = uow.GetTable<GreetSettings>();
|
||||||
|
|
||||||
|
if (value is null)
|
||||||
|
value = !_enabled[greetType].Contains(guildId);
|
||||||
|
|
||||||
|
if (value is { } v)
|
||||||
|
{
|
||||||
|
await q
|
||||||
|
.InsertOrUpdateAsync(() => new()
|
||||||
|
{
|
||||||
|
GuildId = guildId,
|
||||||
|
GreetType = greetType,
|
||||||
|
IsEnabled = v,
|
||||||
|
ChannelId = channelId,
|
||||||
|
},
|
||||||
|
(old) => new()
|
||||||
|
{
|
||||||
|
IsEnabled = v,
|
||||||
|
ChannelId = channelId,
|
||||||
|
},
|
||||||
|
() => new()
|
||||||
|
{
|
||||||
|
GuildId = guildId,
|
||||||
|
GreetType = greetType,
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
_guildConfigsCache.TryAdd(guildId, settings);
|
if (value is true)
|
||||||
return settings;
|
{
|
||||||
|
_enabled[greetType].Add(guildId);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
_enabled[greetType].TryRemove(guildId);
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<bool> SetGreet(ulong guildId, ulong channelId, bool? value = null)
|
|
||||||
|
public async Task<bool> SetMessage(ulong guildId, GreetType greetType, string? message)
|
||||||
{
|
{
|
||||||
await using var uow = _db.GetDbContext();
|
await using (var uow = _db.GetDbContext())
|
||||||
var conf = uow.GuildConfigsForId(guildId, set => set);
|
{
|
||||||
var enabled = conf.SendChannelGreetMessage = value ?? !conf.SendChannelGreetMessage;
|
await uow.GetTable<GreetSettings>()
|
||||||
conf.GreetMessageChannelId = channelId;
|
.InsertOrUpdateAsync(() => new()
|
||||||
|
{
|
||||||
|
GuildId = guildId,
|
||||||
|
GreetType = greetType,
|
||||||
|
MessageText = message
|
||||||
|
},
|
||||||
|
x => new()
|
||||||
|
{
|
||||||
|
MessageText = message
|
||||||
|
},
|
||||||
|
() => new()
|
||||||
|
{
|
||||||
|
GuildId = guildId,
|
||||||
|
GreetType = greetType
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
var toAdd = GreetSettings.Create(conf);
|
var conf = await GetGreetSettingsAsync(guildId, greetType);
|
||||||
_guildConfigsCache[guildId] = toAdd;
|
|
||||||
|
|
||||||
await uow.SaveChangesAsync();
|
return conf?.IsEnabled ?? false;
|
||||||
return enabled;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool SetGreetMessage(ulong guildId, ref string message)
|
public async Task<bool> SetDeleteTimer(ulong guildId, GreetType greetType, int timer)
|
||||||
{
|
{
|
||||||
message = message.SanitizeMentions();
|
if (timer < 0 || timer > 3600)
|
||||||
|
|
||||||
if (string.IsNullOrWhiteSpace(message))
|
|
||||||
throw new ArgumentNullException(nameof(message));
|
|
||||||
|
|
||||||
using var uow = _db.GetDbContext();
|
|
||||||
var conf = uow.GuildConfigsForId(guildId, set => set);
|
|
||||||
conf.ChannelGreetMessageText = message;
|
|
||||||
var greetMsgEnabled = conf.SendChannelGreetMessage;
|
|
||||||
|
|
||||||
var toAdd = GreetSettings.Create(conf);
|
|
||||||
_guildConfigsCache.AddOrUpdate(guildId, toAdd, (_, _) => toAdd);
|
|
||||||
|
|
||||||
uow.SaveChanges();
|
|
||||||
return greetMsgEnabled;
|
|
||||||
}
|
|
||||||
|
|
||||||
public async Task<bool> SetGreetDm(ulong guildId, bool? value = null)
|
|
||||||
{
|
|
||||||
await using var uow = _db.GetDbContext();
|
|
||||||
var conf = uow.GuildConfigsForId(guildId, set => set);
|
|
||||||
var enabled = conf.SendDmGreetMessage = value ?? !conf.SendDmGreetMessage;
|
|
||||||
|
|
||||||
var toAdd = GreetSettings.Create(conf);
|
|
||||||
_guildConfigsCache[guildId] = toAdd;
|
|
||||||
|
|
||||||
await uow.SaveChangesAsync();
|
|
||||||
return enabled;
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool SetGreetDmMessage(ulong guildId, ref string? message)
|
|
||||||
{
|
|
||||||
message = message?.SanitizeMentions();
|
|
||||||
|
|
||||||
if (string.IsNullOrWhiteSpace(message))
|
|
||||||
throw new ArgumentNullException(nameof(message));
|
|
||||||
|
|
||||||
using var uow = _db.GetDbContext();
|
|
||||||
var conf = uow.GuildConfigsForId(guildId, set => set);
|
|
||||||
conf.DmGreetMessageText = message;
|
|
||||||
|
|
||||||
var toAdd = GreetSettings.Create(conf);
|
|
||||||
_guildConfigsCache[guildId] = toAdd;
|
|
||||||
|
|
||||||
uow.SaveChanges();
|
|
||||||
return conf.SendDmGreetMessage;
|
|
||||||
}
|
|
||||||
|
|
||||||
public async Task<bool> SetBye(ulong guildId, ulong channelId, bool? value = null)
|
|
||||||
{
|
|
||||||
await using var uow = _db.GetDbContext();
|
|
||||||
var conf = uow.GuildConfigsForId(guildId, set => set);
|
|
||||||
var enabled = conf.SendChannelByeMessage = value ?? !conf.SendChannelByeMessage;
|
|
||||||
conf.ByeMessageChannelId = channelId;
|
|
||||||
|
|
||||||
var toAdd = GreetSettings.Create(conf);
|
|
||||||
_guildConfigsCache[guildId] = toAdd;
|
|
||||||
|
|
||||||
await uow.SaveChangesAsync();
|
|
||||||
return enabled;
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool SetByeMessage(ulong guildId, ref string? message)
|
|
||||||
{
|
|
||||||
message = message?.SanitizeMentions();
|
|
||||||
|
|
||||||
if (string.IsNullOrWhiteSpace(message))
|
|
||||||
throw new ArgumentNullException(nameof(message));
|
|
||||||
|
|
||||||
using var uow = _db.GetDbContext();
|
|
||||||
var conf = uow.GuildConfigsForId(guildId, set => set);
|
|
||||||
conf.ChannelByeMessageText = message;
|
|
||||||
|
|
||||||
var toAdd = GreetSettings.Create(conf);
|
|
||||||
_guildConfigsCache[guildId] = toAdd;
|
|
||||||
|
|
||||||
uow.SaveChanges();
|
|
||||||
return conf.SendChannelByeMessage;
|
|
||||||
}
|
|
||||||
|
|
||||||
public async Task SetByeDel(ulong guildId, int timer)
|
|
||||||
{
|
|
||||||
if (timer is < 0 or > 600)
|
|
||||||
return;
|
|
||||||
|
|
||||||
await using var uow = _db.GetDbContext();
|
|
||||||
var conf = uow.GuildConfigsForId(guildId, set => set);
|
|
||||||
conf.AutoDeleteByeMessagesTimer = timer;
|
|
||||||
|
|
||||||
var toAdd = GreetSettings.Create(conf);
|
|
||||||
_guildConfigsCache[guildId] = toAdd;
|
|
||||||
|
|
||||||
await uow.SaveChangesAsync();
|
|
||||||
}
|
|
||||||
|
|
||||||
public async Task SetGreetDel(ulong guildId, int timer)
|
|
||||||
{
|
|
||||||
if (timer is < 0 or > 600)
|
|
||||||
return;
|
|
||||||
|
|
||||||
await using var uow = _db.GetDbContext();
|
|
||||||
var conf = uow.GuildConfigsForId(guildId, set => set);
|
|
||||||
conf.AutoDeleteGreetMessagesTimer = timer;
|
|
||||||
|
|
||||||
var toAdd = GreetSettings.Create(conf);
|
|
||||||
_guildConfigsCache[guildId] = toAdd;
|
|
||||||
|
|
||||||
await uow.SaveChangesAsync();
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool SetBoostMessage(ulong guildId, ref string message)
|
|
||||||
{
|
|
||||||
using var uow = _db.GetDbContext();
|
|
||||||
var conf = uow.GuildConfigsForId(guildId, set => set);
|
|
||||||
conf.BoostMessage = message;
|
|
||||||
|
|
||||||
var toAdd = GreetSettings.Create(conf);
|
|
||||||
_guildConfigsCache[guildId] = toAdd;
|
|
||||||
|
|
||||||
uow.SaveChanges();
|
|
||||||
return conf.SendBoostMessage;
|
|
||||||
}
|
|
||||||
|
|
||||||
public async Task SetBoostDel(ulong guildId, int timer)
|
|
||||||
{
|
|
||||||
if (timer is < 0 or > 600)
|
|
||||||
throw new ArgumentOutOfRangeException(nameof(timer));
|
throw new ArgumentOutOfRangeException(nameof(timer));
|
||||||
|
|
||||||
await using var uow = _db.GetDbContext();
|
await using (var uow = _db.GetDbContext())
|
||||||
var conf = uow.GuildConfigsForId(guildId, set => set);
|
{
|
||||||
conf.BoostMessageDeleteAfter = timer;
|
await uow.GetTable<GreetSettings>()
|
||||||
|
.InsertOrUpdateAsync(() => new()
|
||||||
|
{
|
||||||
|
GuildId = guildId,
|
||||||
|
GreetType = greetType,
|
||||||
|
AutoDeleteTimer = timer,
|
||||||
|
},
|
||||||
|
x => new()
|
||||||
|
{
|
||||||
|
AutoDeleteTimer = timer
|
||||||
|
},
|
||||||
|
() => new()
|
||||||
|
{
|
||||||
|
GuildId = guildId,
|
||||||
|
GreetType = greetType
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
var toAdd = GreetSettings.Create(conf);
|
var conf = await GetGreetSettingsAsync(guildId, greetType);
|
||||||
_guildConfigsCache[guildId] = toAdd;
|
|
||||||
|
|
||||||
await uow.SaveChangesAsync();
|
return conf?.IsEnabled ?? false;
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<bool> ToggleBoost(ulong guildId, ulong channelId, bool? forceState = null)
|
|
||||||
|
public async Task<bool> Test(
|
||||||
|
ulong guildId,
|
||||||
|
GreetType type,
|
||||||
|
IMessageChannel channel,
|
||||||
|
IGuildUser user)
|
||||||
{
|
{
|
||||||
await using var uow = _db.GetDbContext();
|
var conf = await GetGreetSettingsAsync(guildId, type);
|
||||||
var conf = uow.GuildConfigsForId(guildId, set => set);
|
if (conf is null)
|
||||||
|
{
|
||||||
|
conf = new GreetSettings()
|
||||||
|
{
|
||||||
|
ChannelId = channel.Id,
|
||||||
|
GreetType = type,
|
||||||
|
IsEnabled = false,
|
||||||
|
GuildId = guildId,
|
||||||
|
AutoDeleteTimer = 30,
|
||||||
|
MessageText = GetDefaultGreet(type)
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
if (forceState is not bool fs)
|
await SendMessage(conf, channel, user);
|
||||||
conf.SendBoostMessage = !conf.SendBoostMessage;
|
return true;
|
||||||
else
|
|
||||||
conf.SendBoostMessage = fs;
|
|
||||||
|
|
||||||
conf.BoostMessageChannelId = channelId;
|
|
||||||
await uow.SaveChangesAsync();
|
|
||||||
|
|
||||||
var toAdd = GreetSettings.Create(conf);
|
|
||||||
_guildConfigsCache[guildId] = toAdd;
|
|
||||||
return conf.SendBoostMessage;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#region Get Enabled Status
|
public async Task<bool> SendMessage(GreetSettings conf, IMessageChannel channel, IGuildUser user)
|
||||||
|
|
||||||
public bool GetGreetDmEnabled(ulong guildId)
|
|
||||||
{
|
{
|
||||||
using var uow = _db.GetDbContext();
|
if (conf.GreetType == GreetType.GreetDm)
|
||||||
var conf = uow.GuildConfigsForId(guildId, set => set);
|
{
|
||||||
return conf.SendDmGreetMessage;
|
await _greetQueue.Writer.WriteAsync((conf, user, null));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (channel is not ITextChannel ch)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
await GreetUsers(conf, ch, user);
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool GetGreetEnabled(ulong guildId)
|
|
||||||
{
|
|
||||||
using var uow = _db.GetDbContext();
|
|
||||||
var conf = uow.GuildConfigsForId(guildId, set => set);
|
|
||||||
return conf.SendChannelGreetMessage;
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool GetByeEnabled(ulong guildId)
|
|
||||||
{
|
|
||||||
using var uow = _db.GetDbContext();
|
|
||||||
var conf = uow.GuildConfigsForId(guildId, set => set);
|
|
||||||
return conf.SendChannelByeMessage;
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool GetBoostEnabled(ulong guildId)
|
|
||||||
{
|
|
||||||
using var uow = _db.GetDbContext();
|
|
||||||
var conf = uow.GuildConfigsForId(guildId, set => set);
|
|
||||||
return conf.SendBoostMessage;
|
|
||||||
}
|
|
||||||
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
#region Test Messages
|
|
||||||
|
|
||||||
public Task ByeTest(ITextChannel channel, IGuildUser user)
|
|
||||||
{
|
|
||||||
var conf = GetOrAddSettingsForGuild(user.GuildId);
|
|
||||||
return ByeUsers(conf, channel, user);
|
|
||||||
}
|
|
||||||
|
|
||||||
public Task GreetTest(ITextChannel channel, IGuildUser user)
|
|
||||||
{
|
|
||||||
var conf = GetOrAddSettingsForGuild(user.GuildId);
|
|
||||||
return GreetUsers(conf, channel, user);
|
|
||||||
}
|
|
||||||
|
|
||||||
public Task<bool> GreetDmTest(IGuildUser user)
|
|
||||||
{
|
|
||||||
var conf = GetOrAddSettingsForGuild(user.GuildId);
|
|
||||||
return GreetDmUser(conf, user);
|
|
||||||
}
|
|
||||||
|
|
||||||
public Task<bool> BoostTest(ITextChannel channel, IGuildUser user)
|
|
||||||
{
|
|
||||||
var conf = GetOrAddSettingsForGuild(user.GuildId);
|
|
||||||
return SendBoostMessage(conf, user, channel);
|
|
||||||
}
|
|
||||||
|
|
||||||
#endregion
|
|
||||||
}
|
}
|
@@ -1,45 +1,21 @@
|
|||||||
using NadekoBot.Db.Models;
|
|
||||||
|
|
||||||
namespace NadekoBot.Services;
|
namespace NadekoBot.Services;
|
||||||
|
|
||||||
|
public enum GreetType
|
||||||
|
{
|
||||||
|
Greet,
|
||||||
|
GreetDm,
|
||||||
|
Bye,
|
||||||
|
Boost,
|
||||||
|
}
|
||||||
|
|
||||||
public class GreetSettings
|
public class GreetSettings
|
||||||
{
|
{
|
||||||
public int AutoDeleteGreetMessagesTimer { get; set; }
|
public int Id { get; set; }
|
||||||
public int AutoDeleteByeMessagesTimer { get; set; }
|
|
||||||
|
public ulong GuildId { get; set; }
|
||||||
public ulong GreetMessageChannelId { get; set; }
|
public GreetType GreetType { get; set; }
|
||||||
public ulong ByeMessageChannelId { get; set; }
|
public string? MessageText { get; set; }
|
||||||
|
public bool IsEnabled { get; set; }
|
||||||
public bool SendDmGreetMessage { get; set; }
|
public ulong? ChannelId { get; set; }
|
||||||
public string? DmGreetMessageText { get; set; }
|
public int AutoDeleteTimer { get; set; }
|
||||||
|
|
||||||
public bool SendChannelGreetMessage { get; set; }
|
|
||||||
public string? ChannelGreetMessageText { get; set; }
|
|
||||||
|
|
||||||
public bool SendChannelByeMessage { get; set; }
|
|
||||||
public string? ChannelByeMessageText { get; set; }
|
|
||||||
|
|
||||||
public bool SendBoostMessage { get; set; }
|
|
||||||
public string? BoostMessage { get; set; }
|
|
||||||
public int BoostMessageDeleteAfter { get; set; }
|
|
||||||
public ulong BoostMessageChannelId { get; set; }
|
|
||||||
|
|
||||||
public static GreetSettings Create(GuildConfig g)
|
|
||||||
=> new()
|
|
||||||
{
|
|
||||||
AutoDeleteByeMessagesTimer = g.AutoDeleteByeMessagesTimer,
|
|
||||||
AutoDeleteGreetMessagesTimer = g.AutoDeleteGreetMessagesTimer,
|
|
||||||
GreetMessageChannelId = g.GreetMessageChannelId,
|
|
||||||
ByeMessageChannelId = g.ByeMessageChannelId,
|
|
||||||
SendDmGreetMessage = g.SendDmGreetMessage,
|
|
||||||
DmGreetMessageText = g.DmGreetMessageText,
|
|
||||||
SendChannelGreetMessage = g.SendChannelGreetMessage,
|
|
||||||
ChannelGreetMessageText = g.ChannelGreetMessageText,
|
|
||||||
SendChannelByeMessage = g.SendChannelByeMessage,
|
|
||||||
ChannelByeMessageText = g.ChannelByeMessageText,
|
|
||||||
SendBoostMessage = g.SendBoostMessage,
|
|
||||||
BoostMessage = g.BoostMessage,
|
|
||||||
BoostMessageDeleteAfter = g.BoostMessageDeleteAfter,
|
|
||||||
BoostMessageChannelId = g.BoostMessageChannelId
|
|
||||||
};
|
|
||||||
}
|
}
|
@@ -18,11 +18,17 @@ public partial class Administration
|
|||||||
await Response().Confirm(strs.ropl_disabled).SendAsync();
|
await Response().Confirm(strs.ropl_disabled).SendAsync();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
[Cmd]
|
[Cmd]
|
||||||
[OwnerOnly]
|
[OwnerOnly]
|
||||||
public async Task AddPlaying(ActivityType t, [Leftover] string status)
|
public Task AddPlaying([Leftover] string status)
|
||||||
|
=> AddPlaying(ActivityType.CustomStatus, status);
|
||||||
|
|
||||||
|
[Cmd]
|
||||||
|
[OwnerOnly]
|
||||||
|
public async Task AddPlaying(ActivityType statusType, [Leftover] string status)
|
||||||
{
|
{
|
||||||
await _service.AddPlaying(t, status);
|
await _service.AddPlaying(statusType, status);
|
||||||
|
|
||||||
await Response().Confirm(strs.ropl_added).SendAsync();
|
await Response().Confirm(strs.ropl_added).SendAsync();
|
||||||
}
|
}
|
||||||
|
@@ -58,7 +58,7 @@ public sealed class PlayingRotateService : INService, IReadyExecutor
|
|||||||
: rotatingStatuses[index++];
|
: rotatingStatuses[index++];
|
||||||
|
|
||||||
var statusText = await _repService.ReplaceAsync(playingStatus.Status, new (client: _client));
|
var statusText = await _repService.ReplaceAsync(playingStatus.Status, new (client: _client));
|
||||||
await _selfService.SetGameAsync(statusText, (ActivityType)playingStatus.Type);
|
await _selfService.SetActivityAsync(statusText, (ActivityType)playingStatus.Type);
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
|
@@ -459,7 +459,7 @@ public partial class Administration
|
|||||||
|
|
||||||
await Response().Confirm(strs.bot_name(Format.Bold(newName))).SendAsync();
|
await Response().Confirm(strs.bot_name(Format.Bold(newName))).SendAsync();
|
||||||
}
|
}
|
||||||
|
|
||||||
[Cmd]
|
[Cmd]
|
||||||
[OwnerOnly]
|
[OwnerOnly]
|
||||||
public async Task SetStatus([Leftover] SettableUserStatus status)
|
public async Task SetStatus([Leftover] SettableUserStatus status)
|
||||||
@@ -491,14 +491,25 @@ public partial class Administration
|
|||||||
|
|
||||||
[Cmd]
|
[Cmd]
|
||||||
[OwnerOnly]
|
[OwnerOnly]
|
||||||
public async Task SetGame(ActivityType type, [Leftover] string game = null)
|
public async Task SetActivity(ActivityType? type, [Leftover] string game = null)
|
||||||
{
|
{
|
||||||
// var rep = new ReplacementBuilder().WithDefault(Context).Build();
|
// var rep = new ReplacementBuilder().WithDefault(Context).Build();
|
||||||
|
|
||||||
var repCtx = new ReplacementContext(ctx);
|
var repCtx = new ReplacementContext(ctx);
|
||||||
await _service.SetGameAsync(game is null ? game : await repSvc.ReplaceAsync(game, repCtx), type);
|
await _service.SetActivityAsync(game is null ? game : await repSvc.ReplaceAsync(game, repCtx), type);
|
||||||
|
|
||||||
await Response().Confirm(strs.set_game).SendAsync();
|
await Response().Confirm(strs.set_activity).SendAsync();
|
||||||
|
}
|
||||||
|
|
||||||
|
[Cmd]
|
||||||
|
[OwnerOnly]
|
||||||
|
public Task SetActivity([Leftover] string game = null)
|
||||||
|
=> SetActivity(null, game);
|
||||||
|
|
||||||
|
public class SetActivityOptions
|
||||||
|
{
|
||||||
|
public ActivityType? Type { get; set; }
|
||||||
|
public string Game { get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
[Cmd]
|
[Cmd]
|
||||||
@@ -541,11 +552,11 @@ public partial class Administration
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
var repCtx = new ReplacementContext(ctx);
|
var repCtx = new ReplacementContext(ctx);
|
||||||
text = await repSvc.ReplaceAsync(text, repCtx);
|
text = await repSvc.ReplaceAsync(text, repCtx);
|
||||||
await Response().Channel(ch).Text(text).SendAsync();
|
await Response().Channel(ch).Text(text).SendAsync();
|
||||||
|
|
||||||
await ctx.OkAsync();
|
await ctx.OkAsync();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -85,13 +85,14 @@ public sealed class SelfService : IExecNoCommand, IReadyExecutor, INService
|
|||||||
{
|
{
|
||||||
await using var uow = _db.GetDbContext();
|
await using var uow = _db.GetDbContext();
|
||||||
|
|
||||||
autoCommands = uow.Set<AutoCommand>().AsNoTracking()
|
autoCommands = uow.Set<AutoCommand>()
|
||||||
.Where(x => x.Interval >= 5)
|
.AsNoTracking()
|
||||||
.AsEnumerable()
|
.Where(x => x.Interval >= 5)
|
||||||
.GroupBy(x => x.GuildId)
|
.AsEnumerable()
|
||||||
.ToDictionary(x => x.Key,
|
.GroupBy(x => x.GuildId)
|
||||||
y => y.ToDictionary(x => x.Id, TimerFromAutoCommand).ToConcurrent())
|
.ToDictionary(x => x.Key,
|
||||||
.ToConcurrent();
|
y => y.ToDictionary(x => x.Id, TimerFromAutoCommand).ToConcurrent())
|
||||||
|
.ToConcurrent();
|
||||||
|
|
||||||
var startupCommands = uow.Set<AutoCommand>().AsNoTracking().Where(x => x.Interval == 0);
|
var startupCommands = uow.Set<AutoCommand>().AsNoTracking().Where(x => x.Interval == 0);
|
||||||
foreach (var cmd in startupCommands)
|
foreach (var cmd in startupCommands)
|
||||||
@@ -170,18 +171,18 @@ public sealed class SelfService : IExecNoCommand, IReadyExecutor, INService
|
|||||||
private async Task LoadOwnerChannels()
|
private async Task LoadOwnerChannels()
|
||||||
{
|
{
|
||||||
var channels = await _creds.OwnerIds.Select(id =>
|
var channels = await _creds.OwnerIds.Select(id =>
|
||||||
{
|
{
|
||||||
var user = _client.GetUser(id);
|
var user = _client.GetUser(id);
|
||||||
if (user is null)
|
if (user is null)
|
||||||
return Task.FromResult<IDMChannel>(null);
|
return Task.FromResult<IDMChannel>(null);
|
||||||
|
|
||||||
return user.CreateDMChannelAsync();
|
return user.CreateDMChannelAsync();
|
||||||
})
|
})
|
||||||
.WhenAll();
|
.WhenAll();
|
||||||
|
|
||||||
ownerChannels = channels.Where(x => x is not null)
|
ownerChannels = channels.Where(x => x is not null)
|
||||||
.ToDictionary(x => x.Recipient.Id, x => x)
|
.ToDictionary(x => x.Recipient.Id, x => x)
|
||||||
.ToImmutableDictionary();
|
.ToImmutableDictionary();
|
||||||
|
|
||||||
if (!ownerChannels.Any())
|
if (!ownerChannels.Any())
|
||||||
{
|
{
|
||||||
@@ -400,7 +401,10 @@ public sealed class SelfService : IExecNoCommand, IReadyExecutor, INService
|
|||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
await _client.SetGameAsync(data.Name, data.Link, data.Type);
|
if (data.Type is { } activityType)
|
||||||
|
await _client.SetGameAsync(data.Name, data.Link, activityType);
|
||||||
|
else
|
||||||
|
await _client.SetCustomStatusAsync(data.Name);
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
@@ -408,7 +412,7 @@ public sealed class SelfService : IExecNoCommand, IReadyExecutor, INService
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
public Task SetGameAsync(string game, ActivityType type)
|
public Task SetActivityAsync(string game, ActivityType? type)
|
||||||
=> _pubSub.Pub(_activitySetKey,
|
=> _pubSub.Pub(_activitySetKey,
|
||||||
new()
|
new()
|
||||||
{
|
{
|
||||||
@@ -430,10 +434,10 @@ public sealed class SelfService : IExecNoCommand, IReadyExecutor, INService
|
|||||||
{
|
{
|
||||||
public string Name { get; init; }
|
public string Name { get; init; }
|
||||||
public string Link { get; init; }
|
public string Link { get; init; }
|
||||||
public ActivityType Type { get; init; }
|
public ActivityType? Type { get; init; }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Adds the specified <paramref name="users"/> to the database. If a database user with placeholder name
|
/// Adds the specified <paramref name="users"/> to the database. If a database user with placeholder name
|
||||||
/// and discriminator is present in <paramref name="users"/>, their name and discriminator get updated accordingly.
|
/// and discriminator is present in <paramref name="users"/>, their name and discriminator get updated accordingly.
|
||||||
@@ -443,41 +447,46 @@ public sealed class SelfService : IExecNoCommand, IReadyExecutor, INService
|
|||||||
/// <returns>A tuple with the amount of new users added and old users updated.</returns>
|
/// <returns>A tuple with the amount of new users added and old users updated.</returns>
|
||||||
public async Task<(long UsersAdded, long UsersUpdated)> RefreshUsersAsync(List<IUser> users)
|
public async Task<(long UsersAdded, long UsersUpdated)> RefreshUsersAsync(List<IUser> users)
|
||||||
{
|
{
|
||||||
await using var ctx = _db.GetDbContext();
|
await using var ctx = _db.GetDbContext();
|
||||||
var presentDbUsers = await ctx.GetTable<DiscordUser>()
|
var presentDbUsers = await ctx.GetTable<DiscordUser>()
|
||||||
.Select(x => new { x.UserId, x.Username, x.Discriminator })
|
.Select(x => new
|
||||||
.Where(x => users.Select(y => y.Id).Contains(x.UserId))
|
{
|
||||||
.ToArrayAsyncEF();
|
x.UserId,
|
||||||
|
x.Username,
|
||||||
|
x.Discriminator
|
||||||
|
})
|
||||||
|
.Where(x => users.Select(y => y.Id).Contains(x.UserId))
|
||||||
|
.ToArrayAsyncEF();
|
||||||
|
|
||||||
var usersToAdd = users
|
var usersToAdd = users
|
||||||
.Where(x => !presentDbUsers.Select(x => x.UserId).Contains(x.Id))
|
.Where(x => !presentDbUsers.Select(x => x.UserId).Contains(x.Id))
|
||||||
.Select(x => new DiscordUser()
|
.Select(x => new DiscordUser()
|
||||||
{
|
{
|
||||||
UserId = x.Id,
|
UserId = x.Id,
|
||||||
AvatarId = x.AvatarId,
|
AvatarId = x.AvatarId,
|
||||||
Username = x.Username,
|
Username = x.Username,
|
||||||
Discriminator = x.Discriminator
|
Discriminator = x.Discriminator
|
||||||
});
|
});
|
||||||
|
|
||||||
var added = (await ctx.BulkCopyAsync(usersToAdd)).RowsCopied;
|
var added = (await ctx.BulkCopyAsync(usersToAdd)).RowsCopied;
|
||||||
var toUpdateUserIds = presentDbUsers
|
var toUpdateUserIds = presentDbUsers
|
||||||
.Where(x => x.Username == "Unknown" && x.Discriminator == "????")
|
.Where(x => x.Username == "Unknown" && x.Discriminator == "????")
|
||||||
.Select(x => x.UserId)
|
.Select(x => x.UserId)
|
||||||
.ToArray();
|
.ToArray();
|
||||||
|
|
||||||
foreach (var user in users.Where(x => toUpdateUserIds.Contains(x.Id)))
|
foreach (var user in users.Where(x => toUpdateUserIds.Contains(x.Id)))
|
||||||
{
|
{
|
||||||
await ctx.GetTable<DiscordUser>()
|
await ctx.GetTable<DiscordUser>()
|
||||||
.Where(x => x.UserId == user.Id)
|
.Where(x => x.UserId == user.Id)
|
||||||
.UpdateAsync(x => new DiscordUser()
|
.UpdateAsync(x => new DiscordUser()
|
||||||
{
|
{
|
||||||
Username = user.Username,
|
Username = user.Username,
|
||||||
Discriminator = user.Discriminator,
|
Discriminator = user.Discriminator,
|
||||||
|
|
||||||
// .award tends to set AvatarId and DateAdded to NULL, so account for that.
|
// .award tends to set AvatarId and DateAdded to NULL, so account for that.
|
||||||
AvatarId = user.AvatarId,
|
AvatarId = user.AvatarId,
|
||||||
DateAdded = x.DateAdded ?? DateTime.UtcNow
|
DateAdded = x.DateAdded ?? DateTime.UtcNow
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
return (added, toUpdateUserIds.Length);
|
return (added, toUpdateUserIds.Length);
|
||||||
|
@@ -243,43 +243,54 @@ public class UserPunishService : INService, IReadyExecutor
|
|||||||
public async Task CheckAllWarnExpiresAsync()
|
public async Task CheckAllWarnExpiresAsync()
|
||||||
{
|
{
|
||||||
await using var uow = _db.GetDbContext();
|
await using var uow = _db.GetDbContext();
|
||||||
var cleared = await uow.Set<Warning>()
|
|
||||||
.Where(x => uow.Set<GuildConfig>()
|
var toClear = await uow.GetTable<Warning>()
|
||||||
.Any(y => y.GuildId == x.GuildId
|
.Where(x => uow.GetTable<GuildConfig>()
|
||||||
&& y.WarnExpireHours > 0
|
.Count(y => y.GuildId == x.GuildId
|
||||||
&& y.WarnExpireAction == WarnExpireAction.Clear)
|
&& y.WarnExpireHours > 0
|
||||||
|
&& y.WarnExpireAction == WarnExpireAction.Clear)
|
||||||
|
> 0
|
||||||
&& x.Forgiven == false
|
&& x.Forgiven == false
|
||||||
&& x.DateAdded
|
&& x.DateAdded
|
||||||
< DateTime.UtcNow.AddHours(-uow.Set<GuildConfig>()
|
< DateTime.UtcNow.AddHours(-uow.GetTable<GuildConfig>()
|
||||||
.Where(y => x.GuildId == y.GuildId)
|
.Where(y => x.GuildId == y.GuildId)
|
||||||
.Select(y => y.WarnExpireHours)
|
.Select(y => y.WarnExpireHours)
|
||||||
.First()))
|
.First()))
|
||||||
.UpdateAsync(_ => new()
|
.Select(x => x.Id)
|
||||||
{
|
.ToListAsyncLinqToDB();
|
||||||
Forgiven = true,
|
|
||||||
ForgivenBy = "expiry"
|
|
||||||
});
|
|
||||||
|
|
||||||
var deleted = await uow.Set<Warning>()
|
var cleared = await uow.GetTable<Warning>()
|
||||||
.Where(x => uow.Set<GuildConfig>()
|
.Where(x => toClear.Contains(x.Id))
|
||||||
.Any(y => y.GuildId == x.GuildId
|
.UpdateAsync(_ => new()
|
||||||
&& y.WarnExpireHours > 0
|
{
|
||||||
&& y.WarnExpireAction == WarnExpireAction.Delete)
|
Forgiven = true,
|
||||||
&& x.DateAdded
|
ForgivenBy = "expiry"
|
||||||
< DateTime.UtcNow.AddHours(-uow.Set<GuildConfig>()
|
});
|
||||||
.Where(y => x.GuildId == y.GuildId)
|
|
||||||
.Select(y => y.WarnExpireHours)
|
var toDelete = await uow.GetTable<Warning>()
|
||||||
.First()))
|
.Where(x => uow.GetTable<GuildConfig>()
|
||||||
.DeleteAsync();
|
.Count(y => y.GuildId == x.GuildId
|
||||||
|
&& y.WarnExpireHours > 0
|
||||||
|
&& y.WarnExpireAction == WarnExpireAction.Delete)
|
||||||
|
> 0
|
||||||
|
&& x.DateAdded
|
||||||
|
< DateTime.UtcNow.AddHours(-uow.GetTable<GuildConfig>()
|
||||||
|
.Where(y => x.GuildId == y.GuildId)
|
||||||
|
.Select(y => y.WarnExpireHours)
|
||||||
|
.First()))
|
||||||
|
.Select(x => x.Id)
|
||||||
|
.ToListAsyncLinqToDB();
|
||||||
|
|
||||||
|
var deleted = await uow.GetTable<Warning>()
|
||||||
|
.Where(x => toDelete.Contains(x.Id))
|
||||||
|
.DeleteAsync();
|
||||||
|
|
||||||
if (cleared > 0 || deleted > 0)
|
if (cleared > 0 || deleted > 0)
|
||||||
{
|
{
|
||||||
Log.Information("Cleared {ClearedWarnings} warnings and deleted {DeletedWarnings} warnings due to expiry",
|
Log.Information("Cleared {ClearedWarnings} warnings and deleted {DeletedWarnings} warnings due to expiry",
|
||||||
cleared,
|
cleared,
|
||||||
deleted);
|
toDelete.Count);
|
||||||
}
|
}
|
||||||
|
|
||||||
await uow.SaveChangesAsync();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task CheckWarnExpiresAsync(ulong guildId)
|
public async Task CheckWarnExpiresAsync(ulong guildId)
|
||||||
|
@@ -36,7 +36,7 @@ public static class NadekoExpressionExtensions
|
|||||||
var repCtx = new ReplacementContext(client: client,
|
var repCtx = new ReplacementContext(client: client,
|
||||||
guild: (ctx.Channel as ITextChannel)?.Guild as SocketGuild,
|
guild: (ctx.Channel as ITextChannel)?.Guild as SocketGuild,
|
||||||
channel: ctx.Channel,
|
channel: ctx.Channel,
|
||||||
users: ctx.Author
|
user: ctx.Author
|
||||||
)
|
)
|
||||||
.WithOverride("%target%",
|
.WithOverride("%target%",
|
||||||
() => canMentionEveryone
|
() => canMentionEveryone
|
||||||
|
@@ -58,14 +58,14 @@ public partial class NadekoExpressions : NadekoModule<NadekoExpressionsService>
|
|||||||
|
|
||||||
[Cmd]
|
[Cmd]
|
||||||
[UserPerm(GuildPerm.Administrator)]
|
[UserPerm(GuildPerm.Administrator)]
|
||||||
public async Task ExprAddServer(string key, [Leftover] string message)
|
public async Task ExprAddServer(string trigger, [Leftover] string response)
|
||||||
{
|
{
|
||||||
if (string.IsNullOrWhiteSpace(message) || string.IsNullOrWhiteSpace(key))
|
if (string.IsNullOrWhiteSpace(response) || string.IsNullOrWhiteSpace(trigger))
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
await ExprAddInternalAsync(key, message);
|
await ExprAddInternalAsync(trigger, response);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -402,10 +402,9 @@ public partial class NadekoExpressions : NadekoModule<NadekoExpressionsService>
|
|||||||
}
|
}
|
||||||
|
|
||||||
[Cmd]
|
[Cmd]
|
||||||
|
[Ratelimit(300)]
|
||||||
public async Task ExprsImport([Leftover] string input = null)
|
public async Task ExprsImport([Leftover] string input = null)
|
||||||
{
|
{
|
||||||
// todo cooldown on public bot for 1 day, limit 100
|
|
||||||
|
|
||||||
if (!AdminInGuildOrOwnerInDm())
|
if (!AdminInGuildOrOwnerInDm())
|
||||||
{
|
{
|
||||||
await Response().Error(strs.expr_insuff_perms).SendAsync();
|
await Response().Error(strs.expr_insuff_perms).SendAsync();
|
||||||
|
@@ -27,17 +27,13 @@ public class GameStatusEvent : ICurrencyEvent
|
|||||||
|
|
||||||
private readonly string _code;
|
private readonly string _code;
|
||||||
|
|
||||||
private readonly char[] _sneakyGameStatusChars = Enumerable.Range(48, 10)
|
|
||||||
.Concat(Enumerable.Range(65, 26))
|
|
||||||
.Concat(Enumerable.Range(97, 26))
|
|
||||||
.Select(x => (char)x)
|
|
||||||
.ToArray();
|
|
||||||
|
|
||||||
private readonly object _stopLock = new();
|
private readonly object _stopLock = new();
|
||||||
|
|
||||||
private readonly object _potLock = new();
|
private readonly object _potLock = new();
|
||||||
private readonly IMessageSenderService _sender;
|
private readonly IMessageSenderService _sender;
|
||||||
|
|
||||||
|
private static readonly NadekoRandom _rng = new NadekoRandom();
|
||||||
|
|
||||||
public GameStatusEvent(
|
public GameStatusEvent(
|
||||||
DiscordSocketClient client,
|
DiscordSocketClient client,
|
||||||
ICurrencyService cs,
|
ICurrencyService cs,
|
||||||
@@ -58,7 +54,8 @@ public class GameStatusEvent : ICurrencyEvent
|
|||||||
_opts = opt;
|
_opts = opt;
|
||||||
_sender = sender;
|
_sender = sender;
|
||||||
// generate code
|
// generate code
|
||||||
_code = new(_sneakyGameStatusChars.Shuffle().Take(5).ToArray());
|
|
||||||
|
_code = new kwum(_rng.Next(1_000_000, 10_000_000)).ToString();
|
||||||
|
|
||||||
_t = new(OnTimerTick, null, Timeout.InfiniteTimeSpan, TimeSpan.FromSeconds(2));
|
_t = new(OnTimerTick, null, Timeout.InfiniteTimeSpan, TimeSpan.FromSeconds(2));
|
||||||
if (_opts.Hours > 0)
|
if (_opts.Hours > 0)
|
||||||
@@ -88,9 +85,9 @@ public class GameStatusEvent : ICurrencyEvent
|
|||||||
if (_isPotLimited)
|
if (_isPotLimited)
|
||||||
{
|
{
|
||||||
await msg.ModifyAsync(m =>
|
await msg.ModifyAsync(m =>
|
||||||
{
|
{
|
||||||
m.Embed = GetEmbed(PotSize).Build();
|
m.Embed = GetEmbed(PotSize).Build();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
Log.Information("Game status event awarded {Count} users {Amount} currency.{Remaining}",
|
Log.Information("Game status event awarded {Count} users {Amount} currency.{Remaining}",
|
||||||
|
@@ -11,7 +11,7 @@ namespace NadekoBot.Modules.Gambling.Common;
|
|||||||
public sealed partial class GamblingConfig : ICloneable<GamblingConfig>
|
public sealed partial class GamblingConfig : ICloneable<GamblingConfig>
|
||||||
{
|
{
|
||||||
[Comment("""DO NOT CHANGE""")]
|
[Comment("""DO NOT CHANGE""")]
|
||||||
public int Version { get; set; } = 2;
|
public int Version { get; set; } = 8;
|
||||||
|
|
||||||
[Comment("""Currency settings""")]
|
[Comment("""Currency settings""")]
|
||||||
public CurrencyConfig Currency { get; set; }
|
public CurrencyConfig Currency { get; set; }
|
||||||
@@ -20,9 +20,9 @@ public sealed partial class GamblingConfig : ICloneable<GamblingConfig>
|
|||||||
public int MinBet { get; set; } = 0;
|
public int MinBet { get; set; } = 0;
|
||||||
|
|
||||||
[Comment("""
|
[Comment("""
|
||||||
Maximum amount users can bet
|
Maximum amount users can bet
|
||||||
Set 0 for unlimited
|
Set 0 for unlimited
|
||||||
""")]
|
""")]
|
||||||
public int MaxBet { get; set; } = 0;
|
public int MaxBet { get; set; } = 0;
|
||||||
|
|
||||||
[Comment("""Settings for betflip command""")]
|
[Comment("""Settings for betflip command""")]
|
||||||
@@ -35,14 +35,14 @@ public sealed partial class GamblingConfig : ICloneable<GamblingConfig>
|
|||||||
public GenerationConfig Generation { get; set; }
|
public GenerationConfig Generation { get; set; }
|
||||||
|
|
||||||
[Comment("""
|
[Comment("""
|
||||||
Settings for timely command
|
Settings for timely command
|
||||||
(letting people claim X amount of currency every Y hours)
|
(letting people claim X amount of currency every Y hours)
|
||||||
""")]
|
""")]
|
||||||
public TimelyConfig Timely { get; set; }
|
public TimelyConfig Timely { get; set; }
|
||||||
|
|
||||||
[Comment("""How much will each user's owned currency decay over time.""")]
|
[Comment("""How much will each user's owned currency decay over time.""")]
|
||||||
public DecayConfig Decay { get; set; }
|
public DecayConfig Decay { get; set; }
|
||||||
|
|
||||||
[Comment("""What is the bot's cut on some transactions""")]
|
[Comment("""What is the bot's cut on some transactions""")]
|
||||||
public BotCutConfig BotCuts { get; set; }
|
public BotCutConfig BotCuts { get; set; }
|
||||||
|
|
||||||
@@ -53,15 +53,15 @@ public sealed partial class GamblingConfig : ICloneable<GamblingConfig>
|
|||||||
public WaifuConfig Waifu { get; set; }
|
public WaifuConfig Waifu { get; set; }
|
||||||
|
|
||||||
[Comment("""
|
[Comment("""
|
||||||
Amount of currency selfhosters will get PER pledged dollar CENT.
|
Amount of currency selfhosters will get PER pledged dollar CENT.
|
||||||
1 = 100 currency per $. Used almost exclusively on public nadeko.
|
1 = 100 currency per $. Used almost exclusively on public nadeko.
|
||||||
""")]
|
""")]
|
||||||
public decimal PatreonCurrencyPerCent { get; set; } = 1;
|
public decimal PatreonCurrencyPerCent { get; set; } = 1;
|
||||||
|
|
||||||
[Comment("""
|
[Comment("""
|
||||||
Currency reward per vote.
|
Currency reward per vote.
|
||||||
This will work only if you've set up VotesApi and correct credentials for topgg and/or discords voting
|
This will work only if you've set up VotesApi and correct credentials for topgg and/or discords voting
|
||||||
""")]
|
""")]
|
||||||
public long VoteReward { get; set; } = 100;
|
public long VoteReward { get; set; } = 100;
|
||||||
|
|
||||||
[Comment("""Slot config""")]
|
[Comment("""Slot config""")]
|
||||||
@@ -91,9 +91,9 @@ public class CurrencyConfig
|
|||||||
public string Name { get; set; } = "Nadeko Flower";
|
public string Name { get; set; } = "Nadeko Flower";
|
||||||
|
|
||||||
[Comment("""
|
[Comment("""
|
||||||
For how long (in days) will the transactions be kept in the database (curtrs)
|
For how long (in days) will the transactions be kept in the database (curtrs)
|
||||||
Set 0 to disable cleanup (keep transactions forever)
|
Set 0 to disable cleanup (keep transactions forever)
|
||||||
""")]
|
""")]
|
||||||
public int TransactionsLifetime { get; set; } = 0;
|
public int TransactionsLifetime { get; set; } = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -101,15 +101,15 @@ public class CurrencyConfig
|
|||||||
public partial class TimelyConfig
|
public partial class TimelyConfig
|
||||||
{
|
{
|
||||||
[Comment("""
|
[Comment("""
|
||||||
How much currency will the users get every time they run .timely command
|
How much currency will the users get every time they run .timely command
|
||||||
setting to 0 or less will disable this feature
|
setting to 0 or less will disable this feature
|
||||||
""")]
|
""")]
|
||||||
public int Amount { get; set; } = 0;
|
public int Amount { get; set; } = 0;
|
||||||
|
|
||||||
[Comment("""
|
[Comment("""
|
||||||
How often (in hours) can users claim currency with .timely command
|
How often (in hours) can users claim currency with .timely command
|
||||||
setting to 0 or less will disable this feature
|
setting to 0 or less will disable this feature
|
||||||
""")]
|
""")]
|
||||||
public int Cooldown { get; set; } = 24;
|
public int Cooldown { get; set; } = 24;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -124,10 +124,10 @@ public partial class BetFlipConfig
|
|||||||
public partial class BetRollConfig
|
public partial class BetRollConfig
|
||||||
{
|
{
|
||||||
[Comment("""
|
[Comment("""
|
||||||
When betroll is played, user will roll a number 0-100.
|
When betroll is played, user will roll a number 0-100.
|
||||||
This setting will describe which multiplier is used for when the roll is higher than the given number.
|
This setting will describe which multiplier is used for when the roll is higher than the given number.
|
||||||
Doesn't have to be ordered.
|
Doesn't have to be ordered.
|
||||||
""")]
|
""")]
|
||||||
public BetRollPair[] Pairs { get; set; } = Array.Empty<BetRollPair>();
|
public BetRollPair[] Pairs { get; set; } = Array.Empty<BetRollPair>();
|
||||||
|
|
||||||
public BetRollConfig()
|
public BetRollConfig()
|
||||||
@@ -155,17 +155,17 @@ public partial class BetRollConfig
|
|||||||
public partial class GenerationConfig
|
public partial class GenerationConfig
|
||||||
{
|
{
|
||||||
[Comment("""
|
[Comment("""
|
||||||
when currency is generated, should it also have a random password
|
when currency is generated, should it also have a random password
|
||||||
associated with it which users have to type after the .pick command
|
associated with it which users have to type after the .pick command
|
||||||
in order to get it
|
in order to get it
|
||||||
""")]
|
""")]
|
||||||
public bool HasPassword { get; set; } = true;
|
public bool HasPassword { get; set; } = true;
|
||||||
|
|
||||||
[Comment("""
|
[Comment("""
|
||||||
Every message sent has a certain % chance to generate the currency
|
Every message sent has a certain % chance to generate the currency
|
||||||
specify the percentage here (1 being 100%, 0 being 0% - for example
|
specify the percentage here (1 being 100%, 0 being 0% - for example
|
||||||
default is 0.02, which is 2%
|
default is 0.02, which is 2%
|
||||||
""")]
|
""")]
|
||||||
public decimal Chance { get; set; } = 0.02M;
|
public decimal Chance { get; set; } = 0.02M;
|
||||||
|
|
||||||
[Comment("""How many seconds have to pass for the next message to have a chance to spawn currency""")]
|
[Comment("""How many seconds have to pass for the next message to have a chance to spawn currency""")]
|
||||||
@@ -175,9 +175,9 @@ public partial class GenerationConfig
|
|||||||
public int MinAmount { get; set; } = 1;
|
public int MinAmount { get; set; } = 1;
|
||||||
|
|
||||||
[Comment("""
|
[Comment("""
|
||||||
Maximum amount of currency that can spawn.
|
Maximum amount of currency that can spawn.
|
||||||
Set to the same value as MinAmount to always spawn the same amount
|
Set to the same value as MinAmount to always spawn the same amount
|
||||||
""")]
|
""")]
|
||||||
public int MaxAmount { get; set; } = 1;
|
public int MaxAmount { get; set; } = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -185,9 +185,9 @@ public partial class GenerationConfig
|
|||||||
public partial class DecayConfig
|
public partial class DecayConfig
|
||||||
{
|
{
|
||||||
[Comment("""
|
[Comment("""
|
||||||
Percentage of user's current currency which will be deducted every 24h.
|
Percentage of user's current currency which will be deducted every 24h.
|
||||||
0 - 1 (1 is 100%, 0.5 50%, 0 disabled)
|
0 - 1 (1 is 100%, 0.5 50%, 0 disabled)
|
||||||
""")]
|
""")]
|
||||||
public decimal Percent { get; set; } = 0;
|
public decimal Percent { get; set; } = 0;
|
||||||
|
|
||||||
[Comment("""Maximum amount of user's currency that can decay at each interval. 0 for unlimited.""")]
|
[Comment("""Maximum amount of user's currency that can decay at each interval. 0 for unlimited.""")]
|
||||||
@@ -219,15 +219,15 @@ public sealed partial class WaifuConfig
|
|||||||
public MultipliersData Multipliers { get; set; } = new();
|
public MultipliersData Multipliers { get; set; } = new();
|
||||||
|
|
||||||
[Comment("""
|
[Comment("""
|
||||||
Settings for periodic waifu price decay.
|
Settings for periodic waifu price decay.
|
||||||
Waifu price decays only if the waifu has no claimer.
|
Waifu price decays only if the waifu has no claimer.
|
||||||
""")]
|
""")]
|
||||||
public WaifuDecayConfig Decay { get; set; } = new();
|
public WaifuDecayConfig Decay { get; set; } = new();
|
||||||
|
|
||||||
[Comment("""
|
[Comment("""
|
||||||
List of items available for gifting.
|
List of items available for gifting.
|
||||||
If negative is true, gift will instead reduce waifu value.
|
If negative is true, gift will instead reduce waifu value.
|
||||||
""")]
|
""")]
|
||||||
public List<WaifuItemModel> Items { get; set; } = [];
|
public List<WaifuItemModel> Items { get; set; } = [];
|
||||||
|
|
||||||
public WaifuConfig()
|
public WaifuConfig()
|
||||||
@@ -274,19 +274,26 @@ public sealed partial class WaifuConfig
|
|||||||
public class WaifuDecayConfig
|
public class WaifuDecayConfig
|
||||||
{
|
{
|
||||||
[Comment("""
|
[Comment("""
|
||||||
Percentage (0 - 100) of the waifu value to reduce.
|
Unclaimed waifus will decay by this percentage (0 - 100).
|
||||||
Set 0 to disable
|
Default is 0 (disabled)
|
||||||
For example if a waifu has a price of 500$, setting this value to 10 would reduce the waifu value by 10% (50$)
|
For example if a waifu has a price of 500$, setting this value to 10 would reduce the waifu value by 10% (50$)
|
||||||
""")]
|
""")]
|
||||||
public int Percent { get; set; } = 0;
|
public int UnclaimedDecayPercent { get; set; } = 0;
|
||||||
|
|
||||||
|
[Comment("""
|
||||||
|
Claimed waifus will decay by this percentage (0 - 100).
|
||||||
|
Default is 0 (disabled)
|
||||||
|
For example if a waifu has a price of 500$, setting this value to 10 would reduce the waifu value by 10% (50$)
|
||||||
|
""")]
|
||||||
|
public int ClaimedDecayPercent { get; set; } = 0;
|
||||||
|
|
||||||
[Comment("""How often to decay waifu values, in hours""")]
|
[Comment("""How often to decay waifu values, in hours""")]
|
||||||
public int HourInterval { get; set; } = 24;
|
public int HourInterval { get; set; } = 24;
|
||||||
|
|
||||||
[Comment("""
|
[Comment("""
|
||||||
Minimum waifu price required for the decay to be applied.
|
Minimum waifu price required for the decay to be applied.
|
||||||
For example if this value is set to 300, any waifu with the price 300 or less will not experience decay.
|
For example if this value is set to 300, any waifu with the price 300 or less will not experience decay.
|
||||||
""")]
|
""")]
|
||||||
public long MinPrice { get; set; } = 300;
|
public long MinPrice { get; set; } = 300;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -295,54 +302,54 @@ public sealed partial class WaifuConfig
|
|||||||
public sealed partial class MultipliersData
|
public sealed partial class MultipliersData
|
||||||
{
|
{
|
||||||
[Comment("""
|
[Comment("""
|
||||||
Multiplier for waifureset. Default 150.
|
Multiplier for waifureset. Default 150.
|
||||||
Formula (at the time of writing this):
|
Formula (at the time of writing this):
|
||||||
price = (waifu_price * 1.25f) + ((number_of_divorces + changes_of_heart + 2) * WaifuReset) rounded up
|
price = (waifu_price * 1.25f) + ((number_of_divorces + changes_of_heart + 2) * WaifuReset) rounded up
|
||||||
""")]
|
""")]
|
||||||
public int WaifuReset { get; set; } = 150;
|
public int WaifuReset { get; set; } = 150;
|
||||||
|
|
||||||
[Comment("""
|
[Comment("""
|
||||||
The minimum amount of currency that you have to pay
|
The minimum amount of currency that you have to pay
|
||||||
in order to buy a waifu who doesn't have a crush on you.
|
in order to buy a waifu who doesn't have a crush on you.
|
||||||
Default is 1.1
|
Default is 1.1
|
||||||
Example: If a waifu is worth 100, you will have to pay at least 100 * NormalClaim currency to claim her.
|
Example: If a waifu is worth 100, you will have to pay at least 100 * NormalClaim currency to claim her.
|
||||||
(100 * 1.1 = 110)
|
(100 * 1.1 = 110)
|
||||||
""")]
|
""")]
|
||||||
public decimal NormalClaim { get; set; } = 1.1m;
|
public decimal NormalClaim { get; set; } = 1.1m;
|
||||||
|
|
||||||
[Comment("""
|
[Comment("""
|
||||||
The minimum amount of currency that you have to pay
|
The minimum amount of currency that you have to pay
|
||||||
in order to buy a waifu that has a crush on you.
|
in order to buy a waifu that has a crush on you.
|
||||||
Default is 0.88
|
Default is 0.88
|
||||||
Example: If a waifu is worth 100, you will have to pay at least 100 * CrushClaim currency to claim her.
|
Example: If a waifu is worth 100, you will have to pay at least 100 * CrushClaim currency to claim her.
|
||||||
(100 * 0.88 = 88)
|
(100 * 0.88 = 88)
|
||||||
""")]
|
""")]
|
||||||
public decimal CrushClaim { get; set; } = 0.88M;
|
public decimal CrushClaim { get; set; } = 0.88M;
|
||||||
|
|
||||||
[Comment("""
|
[Comment("""
|
||||||
When divorcing a waifu, her new value will be her current value multiplied by this number.
|
When divorcing a waifu, her new value will be her current value multiplied by this number.
|
||||||
Default 0.75 (meaning will lose 25% of her value)
|
Default 0.75 (meaning will lose 25% of her value)
|
||||||
""")]
|
""")]
|
||||||
public decimal DivorceNewValue { get; set; } = 0.75M;
|
public decimal DivorceNewValue { get; set; } = 0.75M;
|
||||||
|
|
||||||
[Comment("""
|
[Comment("""
|
||||||
All gift prices will be multiplied by this number.
|
All gift prices will be multiplied by this number.
|
||||||
Default 1 (meaning no effect)
|
Default 1 (meaning no effect)
|
||||||
""")]
|
""")]
|
||||||
public decimal AllGiftPrices { get; set; } = 1.0M;
|
public decimal AllGiftPrices { get; set; } = 1.0M;
|
||||||
|
|
||||||
[Comment("""
|
[Comment("""
|
||||||
What percentage of the value of the gift will a waifu gain when she's gifted.
|
What percentage of the value of the gift will a waifu gain when she's gifted.
|
||||||
Default 0.95 (meaning 95%)
|
Default 0.95 (meaning 95%)
|
||||||
Example: If a waifu is worth 1000, and she receives a gift worth 100, her new value will be 1095)
|
Example: If a waifu is worth 1000, and she receives a gift worth 100, her new value will be 1095)
|
||||||
""")]
|
""")]
|
||||||
public decimal GiftEffect { get; set; } = 0.95M;
|
public decimal GiftEffect { get; set; } = 0.95M;
|
||||||
|
|
||||||
[Comment("""
|
[Comment("""
|
||||||
What percentage of the value of the gift will a waifu lose when she's gifted a gift marked as 'negative'.
|
What percentage of the value of the gift will a waifu lose when she's gifted a gift marked as 'negative'.
|
||||||
Default 0.5 (meaning 50%)
|
Default 0.5 (meaning 50%)
|
||||||
Example: If a waifu is worth 1000, and she receives a negative gift worth 100, her new value will be 950)
|
Example: If a waifu is worth 1000, and she receives a negative gift worth 100, her new value will be 950)
|
||||||
""")]
|
""")]
|
||||||
public decimal NegativeGiftEffect { get; set; } = 0.50M;
|
public decimal NegativeGiftEffect { get; set; } = 0.50M;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -174,7 +174,7 @@ public sealed class GamblingConfigService : ConfigServiceBase<GamblingConfig>
|
|||||||
c.Version = 5;
|
c.Version = 5;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
if (data.Version < 6)
|
if (data.Version < 6)
|
||||||
{
|
{
|
||||||
ModifyConfig(c =>
|
ModifyConfig(c =>
|
||||||
@@ -190,5 +190,14 @@ public sealed class GamblingConfigService : ConfigServiceBase<GamblingConfig>
|
|||||||
c.Version = 7;
|
c.Version = 7;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (data.Version < 8)
|
||||||
|
{
|
||||||
|
ModifyConfig(c =>
|
||||||
|
{
|
||||||
|
c.Version = 8;
|
||||||
|
c.Waifu.Decay.UnclaimedDecayPercent = 0;
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
@@ -48,7 +48,7 @@ public class PlantPickService : INService, IExecNoCommand
|
|||||||
_rng = new();
|
_rng = new();
|
||||||
_client = client;
|
_client = client;
|
||||||
_gss = gss;
|
_gss = gss;
|
||||||
|
|
||||||
using var uow = db.GetDbContext();
|
using var uow = db.GetDbContext();
|
||||||
var guildIds = client.Guilds.Select(x => x.Id).ToList();
|
var guildIds = client.Guilds.Select(x => x.Id).ToList();
|
||||||
var configs = uow.Set<GuildConfig>()
|
var configs = uow.Set<GuildConfig>()
|
||||||
@@ -111,13 +111,17 @@ public class PlantPickService : INService, IExecNoCommand
|
|||||||
{
|
{
|
||||||
var curImg = await _images.GetCurrencyImageAsync();
|
var curImg = await _images.GetCurrencyImageAsync();
|
||||||
|
|
||||||
|
if (curImg is null)
|
||||||
|
return (new MemoryStream(), null);
|
||||||
|
|
||||||
if (string.IsNullOrWhiteSpace(pass))
|
if (string.IsNullOrWhiteSpace(pass))
|
||||||
{
|
{
|
||||||
// determine the extension
|
// determine the extension
|
||||||
using var load = _ = Image.Load(curImg, out var format);
|
using var load = Image.Load(curImg);
|
||||||
|
|
||||||
|
var format = load.Metadata.DecodedImageFormat;
|
||||||
// return the image
|
// return the image
|
||||||
return (curImg.ToStream(), format.FileExtensions.FirstOrDefault() ?? "png");
|
return (curImg.ToStream(), format?.FileExtensions.FirstOrDefault() ?? "png");
|
||||||
}
|
}
|
||||||
|
|
||||||
// get the image stream and extension
|
// get the image stream and extension
|
||||||
@@ -134,16 +138,17 @@ public class PlantPickService : INService, IExecNoCommand
|
|||||||
{
|
{
|
||||||
// draw lower, it looks better
|
// draw lower, it looks better
|
||||||
pass = pass.TrimTo(10, true).ToLowerInvariant();
|
pass = pass.TrimTo(10, true).ToLowerInvariant();
|
||||||
using var img = Image.Load<Rgba32>(curImg, out var format);
|
using var img = Image.Load<Rgba32>(curImg);
|
||||||
// choose font size based on the image height, so that it's visible
|
// choose font size based on the image height, so that it's visible
|
||||||
var font = _fonts.NotoSans.CreateFont(img.Height / 12.0f, FontStyle.Bold);
|
var font = _fonts.NotoSans.CreateFont(img.Height / 12.0f, FontStyle.Bold);
|
||||||
img.Mutate(x =>
|
img.Mutate(x =>
|
||||||
{
|
{
|
||||||
// measure the size of the text to be drawing
|
// measure the size of the text to be drawing
|
||||||
var size = TextMeasurer.Measure(pass, new TextOptions(font)
|
var size = TextMeasurer.MeasureSize(pass,
|
||||||
{
|
new RichTextOptions(font)
|
||||||
Origin = new PointF(0, 0)
|
{
|
||||||
});
|
Origin = new PointF(0, 0)
|
||||||
|
});
|
||||||
|
|
||||||
// fill the background with black, add 5 pixels on each side to make it look better
|
// fill the background with black, add 5 pixels on each side to make it look better
|
||||||
x.FillPolygon(Color.ParseHex("00000080"),
|
x.FillPolygon(Color.ParseHex("00000080"),
|
||||||
@@ -156,7 +161,8 @@ public class PlantPickService : INService, IExecNoCommand
|
|||||||
x.DrawText(pass, font, Color.White, new(0, 0));
|
x.DrawText(pass, font, Color.White, new(0, 0));
|
||||||
});
|
});
|
||||||
// return image as a stream for easy sending
|
// return image as a stream for easy sending
|
||||||
return (img.ToStream(format), format.FileExtensions.FirstOrDefault() ?? "png");
|
var format = img.Metadata.DecodedImageFormat;
|
||||||
|
return (img.ToStream(format), format?.FileExtensions.FirstOrDefault() ?? "png");
|
||||||
}
|
}
|
||||||
|
|
||||||
private Task PotentialFlowerGeneration(IUserMessage imsg)
|
private Task PotentialFlowerGeneration(IUserMessage imsg)
|
||||||
@@ -256,7 +262,8 @@ public class PlantPickService : INService, IExecNoCommand
|
|||||||
|
|
||||||
pass = pass?.Trim().TrimTo(10, true).ToUpperInvariant();
|
pass = pass?.Trim().TrimTo(10, true).ToUpperInvariant();
|
||||||
// gets all plants in this channel with the same password
|
// gets all plants in this channel with the same password
|
||||||
var entries = uow.Set<PlantedCurrency>().AsQueryable()
|
var entries = uow.Set<PlantedCurrency>()
|
||||||
|
.AsQueryable()
|
||||||
.Where(x => x.ChannelId == ch.Id && pass == x.Password)
|
.Where(x => x.ChannelId == ch.Id && pass == x.Password)
|
||||||
.ToList();
|
.ToList();
|
||||||
// sum how much currency that is, and get all of the message ids (so that i can delete them)
|
// sum how much currency that is, and get all of the message ids (so that i can delete them)
|
||||||
@@ -368,15 +375,16 @@ public class PlantPickService : INService, IExecNoCommand
|
|||||||
string pass)
|
string pass)
|
||||||
{
|
{
|
||||||
await using var uow = _db.GetDbContext();
|
await using var uow = _db.GetDbContext();
|
||||||
uow.Set<PlantedCurrency>().Add(new()
|
uow.Set<PlantedCurrency>()
|
||||||
{
|
.Add(new()
|
||||||
Amount = amount,
|
{
|
||||||
GuildId = gid,
|
Amount = amount,
|
||||||
ChannelId = cid,
|
GuildId = gid,
|
||||||
Password = pass,
|
ChannelId = cid,
|
||||||
UserId = uid,
|
Password = pass,
|
||||||
MessageId = mid
|
UserId = uid,
|
||||||
});
|
MessageId = mid
|
||||||
|
});
|
||||||
await uow.SaveChangesAsync();
|
await uow.SaveChangesAsync();
|
||||||
}
|
}
|
||||||
}
|
}
|
@@ -167,18 +167,19 @@ public partial class Gambling
|
|||||||
long ownedAmount;
|
long ownedAmount;
|
||||||
await using (var uow = _db.GetDbContext())
|
await using (var uow = _db.GetDbContext())
|
||||||
{
|
{
|
||||||
ownedAmount = uow.Set<DiscordUser>().FirstOrDefault(x => x.UserId == ctx.User.Id)?.CurrencyAmount
|
ownedAmount = uow.Set<DiscordUser>()
|
||||||
|
.FirstOrDefault(x => x.UserId == ctx.User.Id)?.CurrencyAmount
|
||||||
?? 0;
|
?? 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
var slotBg = await _images.GetSlotBgAsync();
|
var slotBg = await _images.GetSlotBgAsync();
|
||||||
var bgImage = Image.Load<Rgba32>(slotBg, out _);
|
var bgImage = Image.Load<Rgba32>(slotBg);
|
||||||
var numbers = new int[3];
|
var numbers = new int[3];
|
||||||
result.Rolls.CopyTo(numbers, 0);
|
result.Rolls.CopyTo(numbers, 0);
|
||||||
|
|
||||||
Color fontColor = Config.Slots.CurrencyFontColor;
|
Color fontColor = Config.Slots.CurrencyFontColor;
|
||||||
|
|
||||||
bgImage.Mutate(x => x.DrawText(new TextOptions(_fonts.DottyFont.CreateFont(65))
|
bgImage.Mutate<Rgba32>(x => x.DrawText(new RichTextOptions(_fonts.DottyFont.CreateFont(65))
|
||||||
{
|
{
|
||||||
HorizontalAlignment = HorizontalAlignment.Center,
|
HorizontalAlignment = HorizontalAlignment.Center,
|
||||||
VerticalAlignment = VerticalAlignment.Center,
|
VerticalAlignment = VerticalAlignment.Center,
|
||||||
@@ -190,7 +191,7 @@ public partial class Gambling
|
|||||||
|
|
||||||
var bottomFont = _fonts.DottyFont.CreateFont(50);
|
var bottomFont = _fonts.DottyFont.CreateFont(50);
|
||||||
|
|
||||||
bgImage.Mutate(x => x.DrawText(new TextOptions(bottomFont)
|
bgImage.Mutate(x => x.DrawText(new RichTextOptions(bottomFont)
|
||||||
{
|
{
|
||||||
HorizontalAlignment = HorizontalAlignment.Center,
|
HorizontalAlignment = HorizontalAlignment.Center,
|
||||||
VerticalAlignment = VerticalAlignment.Center,
|
VerticalAlignment = VerticalAlignment.Center,
|
||||||
|
@@ -70,7 +70,11 @@ public partial class Gambling
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
var msg = GetText(strs.waifu_claimed(Format.Bold(target.ToString()), N(amount)));
|
var msg = GetText(strs.waifu_claimed(
|
||||||
|
Format.Bold(ctx.User.ToString()),
|
||||||
|
Format.Bold(target.ToString()),
|
||||||
|
N(amount)));
|
||||||
|
|
||||||
if (w.Affinity?.UserId == ctx.User.Id)
|
if (w.Affinity?.UserId == ctx.User.Id)
|
||||||
msg += "\n" + GetText(strs.waifu_fulfilled(target, N(w.Price)));
|
msg += "\n" + GetText(strs.waifu_fulfilled(target, N(w.Price)));
|
||||||
else
|
else
|
||||||
@@ -191,13 +195,21 @@ public partial class Gambling
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (user is null)
|
if (user is null)
|
||||||
|
{
|
||||||
await Response().Confirm(strs.waifu_affinity_reset).SendAsync();
|
await Response().Confirm(strs.waifu_affinity_reset).SendAsync();
|
||||||
|
}
|
||||||
else if (oldAff is null)
|
else if (oldAff is null)
|
||||||
await Response().Confirm(strs.waifu_affinity_set(Format.Bold(user.ToString()))).SendAsync();
|
{
|
||||||
|
await Response()
|
||||||
|
.Confirm(strs.waifu_affinity_set(Format.Bold(ctx.User.ToString()), Format.Bold(user.ToString())))
|
||||||
|
.SendAsync();
|
||||||
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
await Response()
|
await Response()
|
||||||
.Confirm(strs.waifu_affinity_changed(Format.Bold(oldAff.ToString()),
|
.Confirm(strs.waifu_affinity_changed(
|
||||||
|
Format.Bold(ctx.User.ToString()),
|
||||||
|
Format.Bold(oldAff.ToString()),
|
||||||
Format.Bold(user.ToString())))
|
Format.Bold(user.ToString())))
|
||||||
.SendAsync();
|
.SendAsync();
|
||||||
}
|
}
|
||||||
|
@@ -531,11 +531,18 @@ public class WaifuService : INService, IReadyExecutor
|
|||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
var multi = _gss.Data.Waifu.Decay.Percent / 100f;
|
var decay = _gss.Data.Waifu.Decay;
|
||||||
var minPrice = _gss.Data.Waifu.Decay.MinPrice;
|
|
||||||
var decayInterval = _gss.Data.Waifu.Decay.HourInterval;
|
|
||||||
|
|
||||||
if (multi is < 0f or > 1f || decayInterval < 0)
|
var unclaimedMulti = 1 - (decay.UnclaimedDecayPercent / 100f);
|
||||||
|
var claimedMulti = 1 - (decay.ClaimedDecayPercent / 100f);
|
||||||
|
|
||||||
|
var minPrice = decay.MinPrice;
|
||||||
|
var decayInterval = decay.HourInterval;
|
||||||
|
|
||||||
|
if (decayInterval <= 0)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if ((unclaimedMulti < 0 || unclaimedMulti > 1) && (claimedMulti < 0 || claimedMulti > 1))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
var now = DateTime.UtcNow;
|
var now = DateTime.UtcNow;
|
||||||
@@ -554,14 +561,28 @@ public class WaifuService : INService, IReadyExecutor
|
|||||||
|
|
||||||
await _cache.AddAsync(_waifuDecayKey, nowB);
|
await _cache.AddAsync(_waifuDecayKey, nowB);
|
||||||
|
|
||||||
await using var uow = _db.GetDbContext();
|
if (unclaimedMulti is > 0 and <= 1)
|
||||||
|
{
|
||||||
|
await using var uow = _db.GetDbContext();
|
||||||
|
|
||||||
await uow.GetTable<WaifuInfo>()
|
await uow.GetTable<WaifuInfo>()
|
||||||
.Where(x => x.Price > minPrice && x.ClaimerId == null)
|
.Where(x => x.Price > minPrice && x.ClaimerId == null)
|
||||||
.UpdateAsync(old => new()
|
.UpdateAsync(old => new()
|
||||||
{
|
{
|
||||||
Price = (long)(old.Price * multi)
|
Price = (long)(old.Price * unclaimedMulti)
|
||||||
});
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
if (claimedMulti is > 0 and <= 1)
|
||||||
|
{
|
||||||
|
await using var uow = _db.GetDbContext();
|
||||||
|
await uow.GetTable<WaifuInfo>()
|
||||||
|
.Where(x => x.Price > minPrice && x.ClaimerId != null)
|
||||||
|
.UpdateAsync(old => new()
|
||||||
|
{
|
||||||
|
Price = (long)(old.Price * claimedMulti)
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
|
@@ -63,6 +63,8 @@ public static class WaifuExtensions
|
|||||||
|
|
||||||
public static async Task<WaifuInfoStats> GetWaifuInfoAsync(this DbContext ctx, ulong userId)
|
public static async Task<WaifuInfoStats> GetWaifuInfoAsync(this DbContext ctx, ulong userId)
|
||||||
{
|
{
|
||||||
|
await ctx.EnsureUserCreatedAsync(userId);
|
||||||
|
|
||||||
await ctx.Set<WaifuInfo>()
|
await ctx.Set<WaifuInfo>()
|
||||||
.ToLinqToDBTable()
|
.ToLinqToDBTable()
|
||||||
.InsertOrUpdateAsync(() => new()
|
.InsertOrUpdateAsync(() => new()
|
||||||
@@ -78,7 +80,8 @@ public static class WaifuExtensions
|
|||||||
WaifuId = ctx.Set<DiscordUser>().Where(x => x.UserId == userId).Select(x => x.Id).First()
|
WaifuId = ctx.Set<DiscordUser>().Where(x => x.UserId == userId).Select(x => x.Id).First()
|
||||||
});
|
});
|
||||||
|
|
||||||
var toReturn = ctx.Set<WaifuInfo>().AsQueryable()
|
var toReturn = ctx.Set<WaifuInfo>()
|
||||||
|
.AsQueryable()
|
||||||
.Where(w => w.WaifuId
|
.Where(w => w.WaifuId
|
||||||
== ctx.Set<DiscordUser>()
|
== ctx.Set<DiscordUser>()
|
||||||
.AsQueryable()
|
.AsQueryable()
|
||||||
|
@@ -175,8 +175,6 @@ public sealed partial class Help : NadekoModule<HelpService>
|
|||||||
return strs.module_description_gambling;
|
return strs.module_description_gambling;
|
||||||
case "music":
|
case "music":
|
||||||
return strs.module_description_music;
|
return strs.module_description_music;
|
||||||
case "nsfw":
|
|
||||||
return strs.module_description_nsfw;
|
|
||||||
case "permissions":
|
case "permissions":
|
||||||
return strs.module_description_permissions;
|
return strs.module_description_permissions;
|
||||||
case "xp":
|
case "xp":
|
||||||
@@ -211,8 +209,6 @@ public sealed partial class Help : NadekoModule<HelpService>
|
|||||||
return "💰";
|
return "💰";
|
||||||
case "music":
|
case "music":
|
||||||
return "🎶";
|
return "🎶";
|
||||||
case "nsfw":
|
|
||||||
return "😳";
|
|
||||||
case "permissions":
|
case "permissions":
|
||||||
return "🚓";
|
return "🚓";
|
||||||
case "xp":
|
case "xp":
|
||||||
|
@@ -31,7 +31,7 @@ public class HelpService : IExecNoCommand, INService
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
var repCtx = new ReplacementContext(guild: guild, channel: msg.Channel, users: msg.Author)
|
var repCtx = new ReplacementContext(guild: guild, channel: msg.Channel, user: msg.Author)
|
||||||
.WithOverride("%prefix%", () => _bss.Data.Prefix)
|
.WithOverride("%prefix%", () => _bss.Data.Prefix)
|
||||||
.WithOverride("%bot.prefix%", () => _bss.Data.Prefix);
|
.WithOverride("%bot.prefix%", () => _bss.Data.Prefix);
|
||||||
|
|
||||||
|
@@ -136,7 +136,7 @@ public sealed partial class Music
|
|||||||
Provider = s.Platform.ToString(),
|
Provider = s.Platform.ToString(),
|
||||||
ProviderType = (MusicType)s.Platform,
|
ProviderType = (MusicType)s.Platform,
|
||||||
Title = s.Title,
|
Title = s.Title,
|
||||||
Query = s.Platform == MusicPlatform.Local ? s.GetStreamUrl().Result!.Trim('"') : s.Url
|
Query = s.Url
|
||||||
})
|
})
|
||||||
.ToList();
|
.ToList();
|
||||||
|
|
||||||
|
@@ -1,4 +1,5 @@
|
|||||||
using NadekoBot.Db.Models;
|
using NadekoBot.Db.Models;
|
||||||
|
using NadekoBot.Modules.Music.Resolvers;
|
||||||
using System.Diagnostics.CodeAnalysis;
|
using System.Diagnostics.CodeAnalysis;
|
||||||
|
|
||||||
namespace NadekoBot.Modules.Music.Services;
|
namespace NadekoBot.Modules.Music.Services;
|
||||||
@@ -8,7 +9,7 @@ public sealed class MusicService : IMusicService, IPlaceholderProvider
|
|||||||
private readonly AyuVoiceStateService _voiceStateService;
|
private readonly AyuVoiceStateService _voiceStateService;
|
||||||
private readonly ITrackResolveProvider _trackResolveProvider;
|
private readonly ITrackResolveProvider _trackResolveProvider;
|
||||||
private readonly DbService _db;
|
private readonly DbService _db;
|
||||||
private readonly IYoutubeResolver _ytResolver;
|
private readonly IYoutubeResolverFactory _ytResolver;
|
||||||
private readonly ILocalTrackResolver _localResolver;
|
private readonly ILocalTrackResolver _localResolver;
|
||||||
private readonly DiscordSocketClient _client;
|
private readonly DiscordSocketClient _client;
|
||||||
private readonly IBotStrings _strings;
|
private readonly IBotStrings _strings;
|
||||||
@@ -24,7 +25,7 @@ public sealed class MusicService : IMusicService, IPlaceholderProvider
|
|||||||
AyuVoiceStateService voiceStateService,
|
AyuVoiceStateService voiceStateService,
|
||||||
ITrackResolveProvider trackResolveProvider,
|
ITrackResolveProvider trackResolveProvider,
|
||||||
DbService db,
|
DbService db,
|
||||||
IYoutubeResolver ytResolver,
|
IYoutubeResolverFactory ytResolver,
|
||||||
ILocalTrackResolver localResolver,
|
ILocalTrackResolver localResolver,
|
||||||
DiscordSocketClient client,
|
DiscordSocketClient client,
|
||||||
IBotStrings strings,
|
IBotStrings strings,
|
||||||
@@ -93,7 +94,7 @@ public sealed class MusicService : IMusicService, IPlaceholderProvider
|
|||||||
public async Task<int> EnqueueYoutubePlaylistAsync(IMusicPlayer mp, string query, string queuer)
|
public async Task<int> EnqueueYoutubePlaylistAsync(IMusicPlayer mp, string query, string queuer)
|
||||||
{
|
{
|
||||||
var count = 0;
|
var count = 0;
|
||||||
await foreach (var track in _ytResolver.ResolveTracksFromPlaylistAsync(query))
|
await foreach (var track in _ytResolver.GetYoutubeResolver().ResolveTracksFromPlaylistAsync(query))
|
||||||
{
|
{
|
||||||
if (mp.IsKilled)
|
if (mp.IsKilled)
|
||||||
break;
|
break;
|
||||||
@@ -139,6 +140,7 @@ public sealed class MusicService : IMusicService, IPlaceholderProvider
|
|||||||
|
|
||||||
var mp = new MusicPlayer(queue,
|
var mp = new MusicPlayer(queue,
|
||||||
resolver,
|
resolver,
|
||||||
|
_ytResolver,
|
||||||
proxy,
|
proxy,
|
||||||
_googleApiService,
|
_googleApiService,
|
||||||
settings.QualityPreset,
|
settings.QualityPreset,
|
||||||
|
@@ -8,5 +8,4 @@ public interface ITrackInfo
|
|||||||
public string Thumbnail { get; }
|
public string Thumbnail { get; }
|
||||||
public TimeSpan Duration { get; }
|
public TimeSpan Duration { get; }
|
||||||
public MusicPlatform Platform { get; }
|
public MusicPlatform Platform { get; }
|
||||||
public ValueTask<string?> GetStreamUrl();
|
|
||||||
}
|
}
|
@@ -4,8 +4,8 @@ namespace NadekoBot.Modules.Music;
|
|||||||
|
|
||||||
public interface IYoutubeResolver : IPlatformQueryResolver
|
public interface IYoutubeResolver : IPlatformQueryResolver
|
||||||
{
|
{
|
||||||
public Regex YtVideoIdRegex { get; }
|
|
||||||
public Task<ITrackInfo?> ResolveByIdAsync(string id);
|
public Task<ITrackInfo?> ResolveByIdAsync(string id);
|
||||||
IAsyncEnumerable<ITrackInfo> ResolveTracksFromPlaylistAsync(string query);
|
IAsyncEnumerable<ITrackInfo> ResolveTracksFromPlaylistAsync(string query);
|
||||||
Task<ITrackInfo?> ResolveByQueryAsync(string query, bool tryExtractingId);
|
Task<ITrackInfo?> ResolveByQueryAsync(string query, bool tryExtractingId);
|
||||||
|
Task<string?> GetStreamUrl(string query);
|
||||||
}
|
}
|
@@ -1,5 +1,6 @@
|
|||||||
using NadekoBot.Voice;
|
using NadekoBot.Voice;
|
||||||
using NadekoBot.Db.Models;
|
using NadekoBot.Db.Models;
|
||||||
|
using NadekoBot.Modules.Music.Resolvers;
|
||||||
using System.ComponentModel;
|
using System.ComponentModel;
|
||||||
using System.Diagnostics;
|
using System.Diagnostics;
|
||||||
using System.Runtime.CompilerServices;
|
using System.Runtime.CompilerServices;
|
||||||
@@ -27,6 +28,7 @@ public sealed class MusicPlayer : IMusicPlayer
|
|||||||
|
|
||||||
private readonly IMusicQueue _queue;
|
private readonly IMusicQueue _queue;
|
||||||
private readonly ITrackResolveProvider _trackResolveProvider;
|
private readonly ITrackResolveProvider _trackResolveProvider;
|
||||||
|
private readonly IYoutubeResolverFactory _ytResolverFactory;
|
||||||
private readonly IVoiceProxy _proxy;
|
private readonly IVoiceProxy _proxy;
|
||||||
private readonly IGoogleApiService _googleApiService;
|
private readonly IGoogleApiService _googleApiService;
|
||||||
private readonly ISongBuffer _songBuffer;
|
private readonly ISongBuffer _songBuffer;
|
||||||
@@ -41,6 +43,7 @@ public sealed class MusicPlayer : IMusicPlayer
|
|||||||
public MusicPlayer(
|
public MusicPlayer(
|
||||||
IMusicQueue queue,
|
IMusicQueue queue,
|
||||||
ITrackResolveProvider trackResolveProvider,
|
ITrackResolveProvider trackResolveProvider,
|
||||||
|
IYoutubeResolverFactory ytResolverFactory,
|
||||||
IVoiceProxy proxy,
|
IVoiceProxy proxy,
|
||||||
IGoogleApiService googleApiService,
|
IGoogleApiService googleApiService,
|
||||||
QualityPreset qualityPreset,
|
QualityPreset qualityPreset,
|
||||||
@@ -48,6 +51,7 @@ public sealed class MusicPlayer : IMusicPlayer
|
|||||||
{
|
{
|
||||||
_queue = queue;
|
_queue = queue;
|
||||||
_trackResolveProvider = trackResolveProvider;
|
_trackResolveProvider = trackResolveProvider;
|
||||||
|
_ytResolverFactory = ytResolverFactory;
|
||||||
_proxy = proxy;
|
_proxy = proxy;
|
||||||
_googleApiService = googleApiService;
|
_googleApiService = googleApiService;
|
||||||
AutoPlay = autoPlay;
|
AutoPlay = autoPlay;
|
||||||
@@ -118,7 +122,7 @@ public sealed class MusicPlayer : IMusicPlayer
|
|||||||
// make sure song buffer is ready to be (re)used
|
// make sure song buffer is ready to be (re)used
|
||||||
_songBuffer.Reset();
|
_songBuffer.Reset();
|
||||||
|
|
||||||
var streamUrl = await track.GetStreamUrl();
|
var streamUrl = await GetStreamUrl(track);
|
||||||
// start up the data source
|
// start up the data source
|
||||||
using var source = FfmpegTrackDataSource.CreateAsync(
|
using var source = FfmpegTrackDataSource.CreateAsync(
|
||||||
_vc.BitDepth,
|
_vc.BitDepth,
|
||||||
@@ -256,6 +260,7 @@ public sealed class MusicPlayer : IMusicPlayer
|
|||||||
IsStopped = true;
|
IsStopped = true;
|
||||||
Log.Error("Please install ffmpeg and make sure it's added to your "
|
Log.Error("Please install ffmpeg and make sure it's added to your "
|
||||||
+ "PATH environment variable before trying again");
|
+ "PATH environment variable before trying again");
|
||||||
|
|
||||||
}
|
}
|
||||||
catch (OperationCanceledException)
|
catch (OperationCanceledException)
|
||||||
{
|
{
|
||||||
@@ -264,6 +269,7 @@ public sealed class MusicPlayer : IMusicPlayer
|
|||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
Log.Error(ex, "Unknown error in music loop: {ErrorMessage}", ex.Message);
|
Log.Error(ex, "Unknown error in music loop: {ErrorMessage}", ex.Message);
|
||||||
|
await Task.Delay(3_000);
|
||||||
}
|
}
|
||||||
finally
|
finally
|
||||||
{
|
{
|
||||||
@@ -303,6 +309,14 @@ public sealed class MusicPlayer : IMusicPlayer
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private async Task<string?> GetStreamUrl(IQueuedTrackInfo track)
|
||||||
|
{
|
||||||
|
if (track.TrackInfo is SimpleTrackInfo sti)
|
||||||
|
return sti.StreamUrl;
|
||||||
|
|
||||||
|
return await _ytResolverFactory.GetYoutubeResolver().GetStreamUrl(track.TrackInfo.Id);
|
||||||
|
}
|
||||||
|
|
||||||
private bool? CopyChunkToOutput(ISongBuffer sb, VoiceClient vc)
|
private bool? CopyChunkToOutput(ISongBuffer sb, VoiceClient vc)
|
||||||
{
|
{
|
||||||
var data = sb.Read(vc.InputLength, out var length);
|
var data = sb.Read(vc.InputLength, out var length);
|
||||||
|
@@ -28,9 +28,6 @@ public sealed partial class MusicQueue
|
|||||||
TrackInfo = trackInfo;
|
TrackInfo = trackInfo;
|
||||||
Queuer = queuer;
|
Queuer = queuer;
|
||||||
}
|
}
|
||||||
|
|
||||||
public ValueTask<string?> GetStreamUrl()
|
|
||||||
=> TrackInfo.GetStreamUrl();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -6,11 +6,4 @@ public sealed record RemoteTrackInfo(
|
|||||||
string Url,
|
string Url,
|
||||||
string Thumbnail,
|
string Thumbnail,
|
||||||
TimeSpan Duration,
|
TimeSpan Duration,
|
||||||
MusicPlatform Platform,
|
MusicPlatform Platform) : ITrackInfo;
|
||||||
Func<Task<string?>> _streamFactory) : ITrackInfo
|
|
||||||
{
|
|
||||||
private readonly Func<Task<string?>> _streamFactory = _streamFactory;
|
|
||||||
|
|
||||||
public async ValueTask<string?> GetStreamUrl()
|
|
||||||
=> await _streamFactory();
|
|
||||||
}
|
|
@@ -24,7 +24,4 @@ public sealed class SimpleTrackInfo : ITrackInfo
|
|||||||
Platform = platform;
|
Platform = platform;
|
||||||
StreamUrl = streamUrl;
|
StreamUrl = streamUrl;
|
||||||
}
|
}
|
||||||
|
|
||||||
public ValueTask<string?> GetStreamUrl()
|
|
||||||
=> new(StreamUrl);
|
|
||||||
}
|
}
|
@@ -0,0 +1,12 @@
|
|||||||
|
namespace NadekoBot.Modules.Music;
|
||||||
|
|
||||||
|
public sealed class InvTrackInfo : ITrackInfo
|
||||||
|
{
|
||||||
|
public required string Id { get; init; }
|
||||||
|
public required string Title { get; init; }
|
||||||
|
public required string Url { get; init; }
|
||||||
|
public required string Thumbnail { get; init; }
|
||||||
|
public required TimeSpan Duration { get; init; }
|
||||||
|
public required MusicPlatform Platform { get; init; }
|
||||||
|
public required string? StreamUrl { get; init; }
|
||||||
|
}
|
@@ -0,0 +1,108 @@
|
|||||||
|
using NadekoBot.Modules.Searches;
|
||||||
|
using System.Net.Http.Json;
|
||||||
|
|
||||||
|
namespace NadekoBot.Modules.Music;
|
||||||
|
|
||||||
|
public sealed class InvidiousYoutubeResolver : IYoutubeResolver
|
||||||
|
{
|
||||||
|
private readonly IHttpClientFactory _httpFactory;
|
||||||
|
private readonly SearchesConfigService _sc;
|
||||||
|
private readonly NadekoRandom _rng;
|
||||||
|
|
||||||
|
private string InvidiousApiUrl
|
||||||
|
=> _sc.Data.InvidiousInstances[_rng.Next(0, _sc.Data.InvidiousInstances.Count)];
|
||||||
|
|
||||||
|
public InvidiousYoutubeResolver(IHttpClientFactory httpFactory, SearchesConfigService sc)
|
||||||
|
{
|
||||||
|
_rng = new NadekoRandom();
|
||||||
|
_httpFactory = httpFactory;
|
||||||
|
_sc = sc;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<ITrackInfo?> ResolveByQueryAsync(string query)
|
||||||
|
{
|
||||||
|
using var http = _httpFactory.CreateClient();
|
||||||
|
|
||||||
|
var items = await http.GetFromJsonAsync<List<InvidiousSearchResponse>>(
|
||||||
|
$"{InvidiousApiUrl}/api/v1/search"
|
||||||
|
+ $"?q={query}"
|
||||||
|
+ $"&type=video");
|
||||||
|
|
||||||
|
if (items is null || items.Count == 0)
|
||||||
|
return null;
|
||||||
|
|
||||||
|
|
||||||
|
var res = items.First();
|
||||||
|
|
||||||
|
return new InvTrackInfo()
|
||||||
|
{
|
||||||
|
Id = res.VideoId,
|
||||||
|
Title = res.Title,
|
||||||
|
Url = $"https://youtube.com/watch?v={res.VideoId}",
|
||||||
|
Thumbnail = res.Thumbnails?.Select(x => x.Url).FirstOrDefault() ?? string.Empty,
|
||||||
|
Duration = TimeSpan.FromSeconds(res.LengthSeconds),
|
||||||
|
Platform = MusicPlatform.Youtube,
|
||||||
|
StreamUrl = null,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<ITrackInfo?> ResolveByIdAsync(string id)
|
||||||
|
=> await InternalResolveByIdAsync(id);
|
||||||
|
|
||||||
|
private async Task<InvTrackInfo?> InternalResolveByIdAsync(string id)
|
||||||
|
{
|
||||||
|
using var http = _httpFactory.CreateClient();
|
||||||
|
|
||||||
|
var res = await http.GetFromJsonAsync<InvidiousVideoResponse>(
|
||||||
|
$"{InvidiousApiUrl}/api/v1/videos/{id}");
|
||||||
|
|
||||||
|
if (res is null)
|
||||||
|
return null;
|
||||||
|
|
||||||
|
return new InvTrackInfo()
|
||||||
|
{
|
||||||
|
Id = res.VideoId,
|
||||||
|
Title = res.Title,
|
||||||
|
Url = $"https://youtube.com/watch?v={res.VideoId}",
|
||||||
|
Thumbnail = res.Thumbnails?.Select(x => x.Url).FirstOrDefault() ?? string.Empty,
|
||||||
|
Duration = TimeSpan.FromSeconds(res.LengthSeconds),
|
||||||
|
Platform = MusicPlatform.Youtube,
|
||||||
|
StreamUrl = res.AdaptiveFormats.FirstOrDefault(x => x.AudioQuality == "AUDIO_QUALITY_HIGH")?.Url
|
||||||
|
?? res.AdaptiveFormats.FirstOrDefault(x => x.AudioQuality == "AUDIO_QUALITY_MEDIUM")?.Url
|
||||||
|
?? res.AdaptiveFormats.FirstOrDefault(x => x.AudioQuality == "AUDIO_QUALITY_LOW")?.Url
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
public async IAsyncEnumerable<ITrackInfo> ResolveTracksFromPlaylistAsync(string query)
|
||||||
|
{
|
||||||
|
using var http = _httpFactory.CreateClient();
|
||||||
|
var res = await http.GetFromJsonAsync<InvidiousPlaylistResponse>(
|
||||||
|
$"{InvidiousApiUrl}/api/v1/search?type=video&q={query}");
|
||||||
|
|
||||||
|
if (res is null)
|
||||||
|
yield break;
|
||||||
|
|
||||||
|
foreach (var video in res.Videos)
|
||||||
|
{
|
||||||
|
yield return new InvTrackInfo()
|
||||||
|
{
|
||||||
|
Id = video.VideoId,
|
||||||
|
Title = video.Title,
|
||||||
|
Url = $"https://youtube.com/watch?v={video.VideoId}",
|
||||||
|
Thumbnail = video.Thumbnails?.Select(x => x.Url).FirstOrDefault() ?? string.Empty,
|
||||||
|
Duration = TimeSpan.FromSeconds(video.LengthSeconds),
|
||||||
|
Platform = MusicPlatform.Youtube,
|
||||||
|
StreamUrl = null
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public Task<ITrackInfo?> ResolveByQueryAsync(string query, bool tryExtractingId)
|
||||||
|
=> ResolveByQueryAsync(query);
|
||||||
|
|
||||||
|
public async Task<string?> GetStreamUrl(string videoId)
|
||||||
|
{
|
||||||
|
var video = await InternalResolveByIdAsync(videoId);
|
||||||
|
return video?.StreamUrl;
|
||||||
|
}
|
||||||
|
}
|
@@ -1,13 +1,15 @@
|
|||||||
namespace NadekoBot.Modules.Music;
|
using NadekoBot.Modules.Music.Resolvers;
|
||||||
|
|
||||||
|
namespace NadekoBot.Modules.Music;
|
||||||
|
|
||||||
public sealed class TrackResolveProvider : ITrackResolveProvider
|
public sealed class TrackResolveProvider : ITrackResolveProvider
|
||||||
{
|
{
|
||||||
private readonly IYoutubeResolver _ytResolver;
|
private readonly IYoutubeResolverFactory _ytResolver;
|
||||||
private readonly ILocalTrackResolver _localResolver;
|
private readonly ILocalTrackResolver _localResolver;
|
||||||
private readonly IRadioResolver _radioResolver;
|
private readonly IRadioResolver _radioResolver;
|
||||||
|
|
||||||
public TrackResolveProvider(
|
public TrackResolveProvider(
|
||||||
IYoutubeResolver ytResolver,
|
IYoutubeResolverFactory ytResolver,
|
||||||
ILocalTrackResolver localResolver,
|
ILocalTrackResolver localResolver,
|
||||||
IRadioResolver radioResolver)
|
IRadioResolver radioResolver)
|
||||||
{
|
{
|
||||||
@@ -23,19 +25,22 @@ public sealed class TrackResolveProvider : ITrackResolveProvider
|
|||||||
case MusicPlatform.Radio:
|
case MusicPlatform.Radio:
|
||||||
return _radioResolver.ResolveByQueryAsync(query);
|
return _radioResolver.ResolveByQueryAsync(query);
|
||||||
case MusicPlatform.Youtube:
|
case MusicPlatform.Youtube:
|
||||||
return _ytResolver.ResolveByQueryAsync(query);
|
return _ytResolver.GetYoutubeResolver().ResolveByQueryAsync(query);
|
||||||
case MusicPlatform.Local:
|
case MusicPlatform.Local:
|
||||||
return _localResolver.ResolveByQueryAsync(query);
|
return _localResolver.ResolveByQueryAsync(query);
|
||||||
case null:
|
case null:
|
||||||
var match = _ytResolver.YtVideoIdRegex.Match(query);
|
var match = YoutubeHelpers.YtVideoIdRegex.Match(query);
|
||||||
|
|
||||||
if (match.Success)
|
if (match.Success)
|
||||||
return _ytResolver.ResolveByIdAsync(match.Groups["id"].Value);
|
return _ytResolver.GetYoutubeResolver().ResolveByIdAsync(match.Groups["id"].Value);
|
||||||
else if (Uri.TryCreate(query, UriKind.Absolute, out var uri) && uri.IsFile)
|
|
||||||
|
if (Uri.TryCreate(query, UriKind.Absolute, out var uri) && uri.IsFile)
|
||||||
return _localResolver.ResolveByQueryAsync(uri.AbsolutePath);
|
return _localResolver.ResolveByQueryAsync(uri.AbsolutePath);
|
||||||
else if (IsRadioLink(query))
|
|
||||||
|
if (IsRadioLink(query))
|
||||||
return _radioResolver.ResolveByQueryAsync(query);
|
return _radioResolver.ResolveByQueryAsync(query);
|
||||||
else
|
|
||||||
return _ytResolver.ResolveByQueryAsync(query, false);
|
return _ytResolver.GetYoutubeResolver().ResolveByQueryAsync(query, false);
|
||||||
default:
|
default:
|
||||||
Log.Error("Unsupported platform: {MusicPlatform}", forcePlatform);
|
Log.Error("Unsupported platform: {MusicPlatform}", forcePlatform);
|
||||||
return Task.FromResult<ITrackInfo?>(null);
|
return Task.FromResult<ITrackInfo?>(null);
|
||||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user