mirror of
https://gitlab.com/Kwoth/nadekobot.git
synced 2025-09-11 09:48:26 -04:00
Compare commits
39 Commits
Author | SHA1 | Date | |
---|---|---|---|
|
e49e3eec69 | ||
|
3992ae392b | ||
|
8f0c5fab47 | ||
|
780a260b88 | ||
|
25692b9585 | ||
|
ed3ce52865 | ||
|
f5f0f1e250 | ||
|
9d9e61fdfb | ||
|
e68e948a80 | ||
|
cb98f4aa15 | ||
|
bfec0cbcbf | ||
|
3e1268f3bb | ||
|
c28f458972 | ||
|
27ac948463 | ||
|
3f9a3c4c18 | ||
|
9a5545a951 | ||
|
584193db18 | ||
|
1a132fd234 | ||
|
fd6a51ac82 | ||
|
eb1fabb2b7 | ||
|
d079e684bd | ||
|
bf817a1436 | ||
|
78f1624aaf | ||
|
793a49fc64 | ||
|
8b6be656b3 | ||
|
89a88304dc | ||
|
a7fe9ae08f | ||
|
0469705037 | ||
|
dc568fe0e2 | ||
|
eb01bb6c08 | ||
|
71a3539d0e | ||
|
c896a0cdb8 | ||
|
8effe817ad | ||
|
eedf6998b6 | ||
|
e6b7c31a72 | ||
|
2f77fd57b0 | ||
|
fda3d92134 | ||
|
fe6f28143b | ||
|
df3909fc55 |
@@ -104,7 +104,7 @@ publish-medusa-package:
|
|||||||
- if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH || $CI_COMMIT_TAG
|
- if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH || $CI_COMMIT_TAG
|
||||||
script:
|
script:
|
||||||
- LAST_TAG=$(git describe --tags --abbrev=0)
|
- LAST_TAG=$(git describe --tags --abbrev=0)
|
||||||
- if [ $CI_COMMIT_TAG ];then MEDUSA_VERSION="$CI_COMMIT_TAG"; else MEDUSA_VERSION="$LAST_TAG-$CI_COMMIT_SHA"; fi
|
- if [ $CI_COMMIT_TAG ];then MEDUSA_VERSION="$CI_COMMIT_TAG"; else MEDUSA_VERSION="$LAST_TAG-$CI_COMMIT_SHORT_SHA"; fi
|
||||||
- cd src/Nadeko.Medusa/
|
- cd src/Nadeko.Medusa/
|
||||||
- dotnet pack -c Release /p:Version=$MEDUSA_VERSION -o bin/Release/packed
|
- dotnet pack -c Release /p:Version=$MEDUSA_VERSION -o bin/Release/packed
|
||||||
- dotnet nuget push bin/Release/packed/ --source https://www.myget.org/F/nadeko/api/v2/package --api-key "$MYGET_API_KEY"
|
- dotnet nuget push bin/Release/packed/ --source https://www.myget.org/F/nadeko/api/v2/package --api-key "$MYGET_API_KEY"
|
||||||
|
51
CHANGELOG.md
51
CHANGELOG.md
@@ -2,7 +2,56 @@
|
|||||||
|
|
||||||
Experimental changelog. Mostly based on [keepachangelog](https://keepachangelog.com/en/1.0.0/) except date format. a-c-f-r-o
|
Experimental changelog. Mostly based on [keepachangelog](https://keepachangelog.com/en/1.0.0/) except date format. a-c-f-r-o
|
||||||
|
|
||||||
## Unreleased
|
## [4.3.10] - 10.11.2022
|
||||||
|
|
||||||
|
### Added
|
||||||
|
|
||||||
|
- `.filterlist` / `.fl` command which lists link and invite filtering channels and status
|
||||||
|
- Added support for `%target%` placeholder in `.alias` command
|
||||||
|
- Added .forwardtochannel which will forward messages to the current channel. It has lower priority than fwtoall
|
||||||
|
- Added .exprtoggleglobal / .extg which can be used to toggle usage of global expressions on the server
|
||||||
|
|
||||||
|
### Changed
|
||||||
|
|
||||||
|
- .meload and .meunload are now case sensitive. Previously loaded medusae may need to be reloaded or data/medusae/medusa.yml may need to be edited manually
|
||||||
|
- Several club related command have their error messages improved
|
||||||
|
- Updated help text for .antispam and .antiraid
|
||||||
|
- You can now specify time and date (time is optional) in `.remind` command instead of relative time, in the format `HH:mm dd.MM.YYYY`
|
||||||
|
- OwnerId will be automatically added to `creds.yml` at bot startup if it's missing
|
||||||
|
|
||||||
|
### Fixed
|
||||||
|
|
||||||
|
- Fixed `.cmdcd` console error
|
||||||
|
- Fixed an error when currency is add per xp
|
||||||
|
- Fixed an issue preventing execution of expressions starting with @Bot when cleverbot is enabled on the server
|
||||||
|
- Fixed `.feedadd`
|
||||||
|
- Fixed `.prune @target` not working
|
||||||
|
- Medusa modules (sneks) should now inherit medusa description when listed in .mdls command
|
||||||
|
- Fixed command cooldown calculation
|
||||||
|
|
||||||
|
## [4.3.9] - 12.10.2022
|
||||||
|
|
||||||
|
### Added
|
||||||
|
|
||||||
|
- `.betstats` shows sum of all bets, payouts and the payout rate in %. Updates once an hour
|
||||||
|
|
||||||
|
### Changed
|
||||||
|
|
||||||
|
- `.betstats` looks way better (except on Mac)
|
||||||
|
- `.feedadd` errors clarified and separated in individual error messages for each issue.
|
||||||
|
- `.clubban` and `.clubunban` errors clarified and separated in individual error messages for each issue.
|
||||||
|
- `.clubapply` better error messages
|
||||||
|
|
||||||
|
### Fixed
|
||||||
|
|
||||||
|
- `.timely` 'Remind' button fixed in DMs
|
||||||
|
- `.cmdcd` database bugs fixed
|
||||||
|
- Fixed bugged mysql and postgresql migrations
|
||||||
|
- Fixed issues with lodaing medusae due to strict versioning
|
||||||
|
|
||||||
|
### Removed
|
||||||
|
|
||||||
|
- `.slotstats` Superseded by `.betstats`
|
||||||
|
|
||||||
## [4.3.8] - 02.10.2022
|
## [4.3.8] - 02.10.2022
|
||||||
|
|
||||||
|
@@ -7,7 +7,7 @@ Open Terminal (if you don't know how to, click on the magnifying glass on the to
|
|||||||
###### Homebrew/wget
|
###### Homebrew/wget
|
||||||
*Skip this step if you already have homebrew installed*
|
*Skip this step if you already have homebrew installed*
|
||||||
- Copy and paste this command, then press Enter:
|
- Copy and paste this command, then press Enter:
|
||||||
- `/usr/bin/ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)"`
|
- `/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"`
|
||||||
- Install wget
|
- Install wget
|
||||||
- `brew install wget`
|
- `brew install wget`
|
||||||
|
|
||||||
|
@@ -155,7 +155,7 @@ This section will guide you through how to create a simple custom medusa. You ca
|
|||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<!-- Base medusa package. You MUST reference this in order to have a working medusa -->
|
<!-- Base medusa package. You MUST reference this in order to have a working medusa -->
|
||||||
<!-- Also, this package comes from MyGet, which requires you to have a NuGet.Config file next to your .csproj -->
|
<!-- Also, this package comes from MyGet, which requires you to have a NuGet.Config file next to your .csproj -->
|
||||||
<PackageReference Include="Nadeko.Medusa" Version="1.0.1">
|
<PackageReference Include="Nadeko.Medusa" Version="4.3.9">
|
||||||
<PrivateAssets>all</PrivateAssets>
|
<PrivateAssets>all</PrivateAssets>
|
||||||
</PackageReference>
|
</PackageReference>
|
||||||
|
|
||||||
|
@@ -17,4 +17,7 @@
|
|||||||
<PackageReference Include="YamlDotNet" Version="11.2.1" />
|
<PackageReference Include="YamlDotNet" Version="11.2.1" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
|
<PropertyGroup Condition=" '$(Version)' == '' ">
|
||||||
|
<Version>5.0.0</Version>
|
||||||
|
</PropertyGroup>
|
||||||
</Project>
|
</Project>
|
||||||
|
@@ -313,10 +313,29 @@ public sealed class Bot
|
|||||||
await _commandService.AddModulesAsync(typeof(Bot).Assembly, Services);
|
await _commandService.AddModulesAsync(typeof(Bot).Assembly, Services);
|
||||||
// await _interactionService.AddModulesAsync(typeof(Bot).Assembly, Services);
|
// await _interactionService.AddModulesAsync(typeof(Bot).Assembly, Services);
|
||||||
IsReady = true;
|
IsReady = true;
|
||||||
|
|
||||||
|
await EnsureBotOwnershipAsync();
|
||||||
_ = Task.Run(ExecuteReadySubscriptions);
|
_ = Task.Run(ExecuteReadySubscriptions);
|
||||||
Log.Information("Shard {ShardId} ready", Client.ShardId);
|
Log.Information("Shard {ShardId} ready", Client.ShardId);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private async ValueTask EnsureBotOwnershipAsync()
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
if (_creds.OwnerIds.Count != 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
Log.Information("Initializing Owner Id...");
|
||||||
|
var info = await Client.GetApplicationInfoAsync();
|
||||||
|
_credsProvider.ModifyCredsFile(x => x.OwnerIds = new[] { info.Owner.Id });
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
Log.Warning("Getting application info failed: {ErrorMessage}", ex.Message);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private Task ExecuteReadySubscriptions()
|
private Task ExecuteReadySubscriptions()
|
||||||
{
|
{
|
||||||
var readyExecutors = Services.GetServices<IReadyExecutor>();
|
var readyExecutors = Services.GetServices<IReadyExecutor>();
|
||||||
|
@@ -12,7 +12,7 @@ namespace NadekoBot.Common.Configs;
|
|||||||
public sealed partial class BotConfig : ICloneable<BotConfig>
|
public sealed partial class BotConfig : ICloneable<BotConfig>
|
||||||
{
|
{
|
||||||
[Comment(@"DO NOT CHANGE")]
|
[Comment(@"DO NOT CHANGE")]
|
||||||
public int Version { get; set; } = 4;
|
public int Version { get; set; } = 5;
|
||||||
|
|
||||||
[Comment(@"Most commands, when executed, have a small colored line
|
[Comment(@"Most commands, when executed, have a small colored line
|
||||||
next to the response. The color depends whether the command
|
next to the response. The color depends whether the command
|
||||||
@@ -40,6 +40,10 @@ Allowed values: Simple, Normal, None")]
|
|||||||
or all owners? (this might cause the bot to lag if there's a lot of owners specified)")]
|
or all owners? (this might cause the bot to lag if there's a lot of owners specified)")]
|
||||||
public bool ForwardToAllOwners { get; set; }
|
public bool ForwardToAllOwners { get; set; }
|
||||||
|
|
||||||
|
[Comment(@"Any messages sent by users in Bot's DM to be forwarded to the specified channel.
|
||||||
|
This option will only work when ForwardToAllOwners is set to false")]
|
||||||
|
public ulong? ForwardToChannel { get; set; }
|
||||||
|
|
||||||
[Comment(@"When a user DMs the bot with a message which is not a command
|
[Comment(@"When a user DMs the bot with a message which is not a command
|
||||||
they will receive this message. Leave empty for no response. The string which will be sent whenever someone DMs the bot.
|
they will receive this message. Leave empty for no response. The string which will be sent whenever someone DMs the bot.
|
||||||
Supports embeds. How it looks: https://puu.sh/B0BLV.png")]
|
Supports embeds. How it looks: https://puu.sh/B0BLV.png")]
|
||||||
|
@@ -186,7 +186,6 @@ public sealed class MedusaLoaderService : IMedusaLoaderService, IReadyExecutor,
|
|||||||
return MedusaLoadResult.AlreadyLoaded;
|
return MedusaLoadResult.AlreadyLoaded;
|
||||||
|
|
||||||
var safeName = Uri.EscapeDataString(name);
|
var safeName = Uri.EscapeDataString(name);
|
||||||
name = name.ToLowerInvariant();
|
|
||||||
|
|
||||||
await _lock.WaitAsync();
|
await _lock.WaitAsync();
|
||||||
try
|
try
|
||||||
@@ -525,7 +524,6 @@ public sealed class MedusaLoaderService : IMedusaLoaderService, IReadyExecutor,
|
|||||||
[MethodImpl(MethodImplOptions.NoInlining)]
|
[MethodImpl(MethodImplOptions.NoInlining)]
|
||||||
private async Task<MedusaUnloadResult> InternalUnloadAsync(string name)
|
private async Task<MedusaUnloadResult> InternalUnloadAsync(string name)
|
||||||
{
|
{
|
||||||
name = name.ToLowerInvariant();
|
|
||||||
if (!_resolved.Remove(name, out var lsi))
|
if (!_resolved.Remove(name, out var lsi))
|
||||||
return MedusaUnloadResult.NotLoaded;
|
return MedusaUnloadResult.NotLoaded;
|
||||||
|
|
||||||
|
@@ -1,15 +1,14 @@
|
|||||||
#nullable disable
|
using CommandLine;
|
||||||
using CommandLine;
|
|
||||||
|
|
||||||
namespace NadekoBot.Common;
|
namespace NadekoBot.Common;
|
||||||
|
|
||||||
public static class OptionsParser
|
public static class OptionsParser
|
||||||
{
|
{
|
||||||
public static T ParseFrom<T>(string[] args)
|
public static T ParseFrom<T>(string[]? args)
|
||||||
where T : INadekoCommandOptions, new()
|
where T : INadekoCommandOptions, new()
|
||||||
=> ParseFrom(new T(), args).Item1;
|
=> ParseFrom(new T(), args).Item1;
|
||||||
|
|
||||||
public static (T, bool) ParseFrom<T>(T options, string[] args)
|
public static (T, bool) ParseFrom<T>(T options, string[]? args)
|
||||||
where T : INadekoCommandOptions
|
where T : INadekoCommandOptions
|
||||||
{
|
{
|
||||||
using var p = new Parser(x =>
|
using var p = new Parser(x =>
|
||||||
|
9
src/NadekoBot/Db/Models/GamblingStats.cs
Normal file
9
src/NadekoBot/Db/Models/GamblingStats.cs
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
#nullable disable
|
||||||
|
namespace NadekoBot.Services.Database.Models;
|
||||||
|
|
||||||
|
public class GamblingStats : DbEntity
|
||||||
|
{
|
||||||
|
public string Feature { get; set; }
|
||||||
|
public decimal Bet { get; set; }
|
||||||
|
public decimal PaidOut { get; set; }
|
||||||
|
}
|
@@ -95,6 +95,8 @@ public class GuildConfig : DbEntity
|
|||||||
public int WarnExpireHours { get; set; }
|
public int WarnExpireHours { get; set; }
|
||||||
public WarnExpireAction WarnExpireAction { get; set; } = WarnExpireAction.Clear;
|
public WarnExpireAction WarnExpireAction { get; set; } = WarnExpireAction.Clear;
|
||||||
|
|
||||||
|
public bool DisableGlobalExpressions { get; set; } = false;
|
||||||
|
|
||||||
#region Boost Message
|
#region Boost Message
|
||||||
|
|
||||||
public bool SendBoostMessage { get; set; }
|
public bool SendBoostMessage { get; set; }
|
||||||
|
@@ -472,6 +472,14 @@ public abstract class NadekoContext : DbContext
|
|||||||
.IsUnique());
|
.IsUnique());
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
|
#region GamblingStats
|
||||||
|
|
||||||
|
modelBuilder.Entity<GamblingStats>(gs => gs
|
||||||
|
.HasIndex(x => x.Feature)
|
||||||
|
.IsUnique());
|
||||||
|
|
||||||
|
#endregion
|
||||||
}
|
}
|
||||||
|
|
||||||
#if DEBUG
|
#if DEBUG
|
||||||
|
@@ -2,6 +2,7 @@
|
|||||||
using System;
|
using System;
|
||||||
using Microsoft.EntityFrameworkCore;
|
using Microsoft.EntityFrameworkCore;
|
||||||
using Microsoft.EntityFrameworkCore.Infrastructure;
|
using Microsoft.EntityFrameworkCore.Infrastructure;
|
||||||
|
using Microsoft.EntityFrameworkCore.Migrations;
|
||||||
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
|
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
|
||||||
using NadekoBot.Services.Database;
|
using NadekoBot.Services.Database;
|
||||||
|
|
||||||
@@ -10,15 +11,45 @@ using NadekoBot.Services.Database;
|
|||||||
namespace NadekoBot.Migrations.Mysql
|
namespace NadekoBot.Migrations.Mysql
|
||||||
{
|
{
|
||||||
[DbContext(typeof(MysqlContext))]
|
[DbContext(typeof(MysqlContext))]
|
||||||
partial class MysqlContextModelSnapshot : ModelSnapshot
|
[Migration("20221003175743_gambling-stats")]
|
||||||
|
partial class gamblingstats
|
||||||
{
|
{
|
||||||
protected override void BuildModel(ModelBuilder modelBuilder)
|
protected override void BuildTargetModel(ModelBuilder modelBuilder)
|
||||||
{
|
{
|
||||||
#pragma warning disable 612, 618
|
#pragma warning disable 612, 618
|
||||||
modelBuilder
|
modelBuilder
|
||||||
.HasAnnotation("ProductVersion", "6.0.7")
|
.HasAnnotation("ProductVersion", "6.0.7")
|
||||||
.HasAnnotation("Relational:MaxIdentifierLength", 64);
|
.HasAnnotation("Relational:MaxIdentifierLength", 64);
|
||||||
|
|
||||||
|
modelBuilder.Entity("NadekoBot.Db.Models.AutoPublishChannel", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("int")
|
||||||
|
.HasColumnName("id");
|
||||||
|
|
||||||
|
b.Property<ulong>("ChannelId")
|
||||||
|
.HasColumnType("bigint unsigned")
|
||||||
|
.HasColumnName("channelid");
|
||||||
|
|
||||||
|
b.Property<DateTime?>("DateAdded")
|
||||||
|
.HasColumnType("datetime(6)")
|
||||||
|
.HasColumnName("dateadded");
|
||||||
|
|
||||||
|
b.Property<ulong>("GuildId")
|
||||||
|
.HasColumnType("bigint unsigned")
|
||||||
|
.HasColumnName("guildid");
|
||||||
|
|
||||||
|
b.HasKey("Id")
|
||||||
|
.HasName("pk_autopublishchannel");
|
||||||
|
|
||||||
|
b.HasIndex("GuildId")
|
||||||
|
.IsUnique()
|
||||||
|
.HasDatabaseName("ix_autopublishchannel_guildid");
|
||||||
|
|
||||||
|
b.ToTable("autopublishchannel", (string)null);
|
||||||
|
});
|
||||||
|
|
||||||
modelBuilder.Entity("NadekoBot.Db.Models.BankUser", b =>
|
modelBuilder.Entity("NadekoBot.Db.Models.BankUser", b =>
|
||||||
{
|
{
|
||||||
b.Property<int>("Id")
|
b.Property<int>("Id")
|
||||||
@@ -1072,6 +1103,39 @@ namespace NadekoBot.Migrations.Mysql
|
|||||||
b.ToTable("filterwordschannelid", (string)null);
|
b.ToTable("filterwordschannelid", (string)null);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("NadekoBot.Services.Database.Models.GamblingStats", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("int")
|
||||||
|
.HasColumnName("id");
|
||||||
|
|
||||||
|
b.Property<decimal>("Bet")
|
||||||
|
.HasColumnType("decimal(65,30)")
|
||||||
|
.HasColumnName("bet");
|
||||||
|
|
||||||
|
b.Property<DateTime?>("DateAdded")
|
||||||
|
.HasColumnType("datetime(6)")
|
||||||
|
.HasColumnName("dateadded");
|
||||||
|
|
||||||
|
b.Property<string>("Feature")
|
||||||
|
.HasColumnType("varchar(255)")
|
||||||
|
.HasColumnName("feature");
|
||||||
|
|
||||||
|
b.Property<decimal>("PaidOut")
|
||||||
|
.HasColumnType("decimal(65,30)")
|
||||||
|
.HasColumnName("paidout");
|
||||||
|
|
||||||
|
b.HasKey("Id")
|
||||||
|
.HasName("pk_gamblingstats");
|
||||||
|
|
||||||
|
b.HasIndex("Feature")
|
||||||
|
.IsUnique()
|
||||||
|
.HasDatabaseName("ix_gamblingstats_feature");
|
||||||
|
|
||||||
|
b.ToTable("gamblingstats", (string)null);
|
||||||
|
});
|
||||||
|
|
||||||
modelBuilder.Entity("NadekoBot.Services.Database.Models.GCChannelId", b =>
|
modelBuilder.Entity("NadekoBot.Services.Database.Models.GCChannelId", b =>
|
||||||
{
|
{
|
||||||
b.Property<int>("Id")
|
b.Property<int>("Id")
|
||||||
@@ -2236,6 +2300,10 @@ namespace NadekoBot.Migrations.Mysql
|
|||||||
.HasColumnType("longtext")
|
.HasColumnType("longtext")
|
||||||
.HasColumnName("rolename");
|
.HasColumnName("rolename");
|
||||||
|
|
||||||
|
b.Property<ulong?>("RoleRequirement")
|
||||||
|
.HasColumnType("bigint unsigned")
|
||||||
|
.HasColumnName("rolerequirement");
|
||||||
|
|
||||||
b.Property<int>("Type")
|
b.Property<int>("Type")
|
||||||
.HasColumnType("int")
|
.HasColumnType("int")
|
||||||
.HasColumnName("type");
|
.HasColumnName("type");
|
@@ -0,0 +1,44 @@
|
|||||||
|
using System;
|
||||||
|
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");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
3616
src/NadekoBot/Migrations/Mysql/20221021192758_toggle-global-expressions.Designer.cs
generated
Normal file
3616
src/NadekoBot/Migrations/Mysql/20221021192758_toggle-global-expressions.Designer.cs
generated
Normal file
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,26 @@
|
|||||||
|
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");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@@ -1101,6 +1101,39 @@ namespace NadekoBot.Migrations.Mysql
|
|||||||
b.ToTable("filterwordschannelid", (string)null);
|
b.ToTable("filterwordschannelid", (string)null);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("NadekoBot.Services.Database.Models.GamblingStats", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("int")
|
||||||
|
.HasColumnName("id");
|
||||||
|
|
||||||
|
b.Property<decimal>("Bet")
|
||||||
|
.HasColumnType("decimal(65,30)")
|
||||||
|
.HasColumnName("bet");
|
||||||
|
|
||||||
|
b.Property<DateTime?>("DateAdded")
|
||||||
|
.HasColumnType("datetime(6)")
|
||||||
|
.HasColumnName("dateadded");
|
||||||
|
|
||||||
|
b.Property<string>("Feature")
|
||||||
|
.HasColumnType("varchar(255)")
|
||||||
|
.HasColumnName("feature");
|
||||||
|
|
||||||
|
b.Property<decimal>("PaidOut")
|
||||||
|
.HasColumnType("decimal(65,30)")
|
||||||
|
.HasColumnName("paidout");
|
||||||
|
|
||||||
|
b.HasKey("Id")
|
||||||
|
.HasName("pk_gamblingstats");
|
||||||
|
|
||||||
|
b.HasIndex("Feature")
|
||||||
|
.IsUnique()
|
||||||
|
.HasDatabaseName("ix_gamblingstats_feature");
|
||||||
|
|
||||||
|
b.ToTable("gamblingstats", (string)null);
|
||||||
|
});
|
||||||
|
|
||||||
modelBuilder.Entity("NadekoBot.Services.Database.Models.GCChannelId", b =>
|
modelBuilder.Entity("NadekoBot.Services.Database.Models.GCChannelId", b =>
|
||||||
{
|
{
|
||||||
b.Property<int>("Id")
|
b.Property<int>("Id")
|
||||||
@@ -1225,6 +1258,10 @@ namespace NadekoBot.Migrations.Mysql
|
|||||||
.HasColumnType("tinyint(1)")
|
.HasColumnType("tinyint(1)")
|
||||||
.HasColumnName("deletestreamonlinemessage");
|
.HasColumnName("deletestreamonlinemessage");
|
||||||
|
|
||||||
|
b.Property<bool>("DisableGlobalExpressions")
|
||||||
|
.HasColumnType("tinyint(1)")
|
||||||
|
.HasColumnName("disableglobalexpressions");
|
||||||
|
|
||||||
b.Property<string>("DmGreetMessageText")
|
b.Property<string>("DmGreetMessageText")
|
||||||
.HasColumnType("longtext")
|
.HasColumnType("longtext")
|
||||||
.HasColumnName("dmgreetmessagetext");
|
.HasColumnName("dmgreetmessagetext");
|
||||||
|
@@ -2,6 +2,7 @@
|
|||||||
using System;
|
using System;
|
||||||
using Microsoft.EntityFrameworkCore;
|
using Microsoft.EntityFrameworkCore;
|
||||||
using Microsoft.EntityFrameworkCore.Infrastructure;
|
using Microsoft.EntityFrameworkCore.Infrastructure;
|
||||||
|
using Microsoft.EntityFrameworkCore.Migrations;
|
||||||
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
|
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
|
||||||
using NadekoBot.Services.Database;
|
using NadekoBot.Services.Database;
|
||||||
using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata;
|
using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata;
|
||||||
@@ -11,9 +12,10 @@ using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata;
|
|||||||
namespace NadekoBot.Migrations.PostgreSql
|
namespace NadekoBot.Migrations.PostgreSql
|
||||||
{
|
{
|
||||||
[DbContext(typeof(PostgreSqlContext))]
|
[DbContext(typeof(PostgreSqlContext))]
|
||||||
partial class PostgreSqlContextModelSnapshot : ModelSnapshot
|
[Migration("20221003175752_gambling-stats")]
|
||||||
|
partial class gamblingstats
|
||||||
{
|
{
|
||||||
protected override void BuildModel(ModelBuilder modelBuilder)
|
protected override void BuildTargetModel(ModelBuilder modelBuilder)
|
||||||
{
|
{
|
||||||
#pragma warning disable 612, 618
|
#pragma warning disable 612, 618
|
||||||
modelBuilder
|
modelBuilder
|
||||||
@@ -22,6 +24,37 @@ namespace NadekoBot.Migrations.PostgreSql
|
|||||||
|
|
||||||
NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder);
|
NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder);
|
||||||
|
|
||||||
|
modelBuilder.Entity("NadekoBot.Db.Models.AutoPublishChannel", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("integer")
|
||||||
|
.HasColumnName("id");
|
||||||
|
|
||||||
|
NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id"));
|
||||||
|
|
||||||
|
b.Property<decimal>("ChannelId")
|
||||||
|
.HasColumnType("numeric(20,0)")
|
||||||
|
.HasColumnName("channelid");
|
||||||
|
|
||||||
|
b.Property<DateTime?>("DateAdded")
|
||||||
|
.HasColumnType("timestamp without time zone")
|
||||||
|
.HasColumnName("dateadded");
|
||||||
|
|
||||||
|
b.Property<decimal>("GuildId")
|
||||||
|
.HasColumnType("numeric(20,0)")
|
||||||
|
.HasColumnName("guildid");
|
||||||
|
|
||||||
|
b.HasKey("Id")
|
||||||
|
.HasName("pk_autopublishchannel");
|
||||||
|
|
||||||
|
b.HasIndex("GuildId")
|
||||||
|
.IsUnique()
|
||||||
|
.HasDatabaseName("ix_autopublishchannel_guildid");
|
||||||
|
|
||||||
|
b.ToTable("autopublishchannel", (string)null);
|
||||||
|
});
|
||||||
|
|
||||||
modelBuilder.Entity("NadekoBot.Db.Models.BankUser", b =>
|
modelBuilder.Entity("NadekoBot.Db.Models.BankUser", b =>
|
||||||
{
|
{
|
||||||
b.Property<int>("Id")
|
b.Property<int>("Id")
|
||||||
@@ -1126,6 +1159,41 @@ namespace NadekoBot.Migrations.PostgreSql
|
|||||||
b.ToTable("filterwordschannelid", (string)null);
|
b.ToTable("filterwordschannelid", (string)null);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("NadekoBot.Services.Database.Models.GamblingStats", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("integer")
|
||||||
|
.HasColumnName("id");
|
||||||
|
|
||||||
|
NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id"));
|
||||||
|
|
||||||
|
b.Property<decimal>("Bet")
|
||||||
|
.HasColumnType("numeric")
|
||||||
|
.HasColumnName("bet");
|
||||||
|
|
||||||
|
b.Property<DateTime?>("DateAdded")
|
||||||
|
.HasColumnType("timestamp without time zone")
|
||||||
|
.HasColumnName("dateadded");
|
||||||
|
|
||||||
|
b.Property<string>("Feature")
|
||||||
|
.HasColumnType("text")
|
||||||
|
.HasColumnName("feature");
|
||||||
|
|
||||||
|
b.Property<decimal>("PaidOut")
|
||||||
|
.HasColumnType("numeric")
|
||||||
|
.HasColumnName("paidout");
|
||||||
|
|
||||||
|
b.HasKey("Id")
|
||||||
|
.HasName("pk_gamblingstats");
|
||||||
|
|
||||||
|
b.HasIndex("Feature")
|
||||||
|
.IsUnique()
|
||||||
|
.HasDatabaseName("ix_gamblingstats_feature");
|
||||||
|
|
||||||
|
b.ToTable("gamblingstats", (string)null);
|
||||||
|
});
|
||||||
|
|
||||||
modelBuilder.Entity("NadekoBot.Services.Database.Models.GCChannelId", b =>
|
modelBuilder.Entity("NadekoBot.Services.Database.Models.GCChannelId", b =>
|
||||||
{
|
{
|
||||||
b.Property<int>("Id")
|
b.Property<int>("Id")
|
||||||
@@ -2342,6 +2410,10 @@ namespace NadekoBot.Migrations.PostgreSql
|
|||||||
.HasColumnType("text")
|
.HasColumnType("text")
|
||||||
.HasColumnName("rolename");
|
.HasColumnName("rolename");
|
||||||
|
|
||||||
|
b.Property<decimal?>("RoleRequirement")
|
||||||
|
.HasColumnType("numeric(20,0)")
|
||||||
|
.HasColumnName("rolerequirement");
|
||||||
|
|
||||||
b.Property<int>("Type")
|
b.Property<int>("Type")
|
||||||
.HasColumnType("integer")
|
.HasColumnType("integer")
|
||||||
.HasColumnName("type");
|
.HasColumnName("type");
|
@@ -0,0 +1,42 @@
|
|||||||
|
using System;
|
||||||
|
using Microsoft.EntityFrameworkCore.Migrations;
|
||||||
|
using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata;
|
||||||
|
|
||||||
|
#nullable disable
|
||||||
|
|
||||||
|
namespace NadekoBot.Migrations.PostgreSql
|
||||||
|
{
|
||||||
|
public partial class gamblingstats : Migration
|
||||||
|
{
|
||||||
|
protected override void Up(MigrationBuilder migrationBuilder)
|
||||||
|
{
|
||||||
|
migrationBuilder.CreateTable(
|
||||||
|
name: "gamblingstats",
|
||||||
|
columns: table => new
|
||||||
|
{
|
||||||
|
id = table.Column<int>(type: "integer", nullable: false)
|
||||||
|
.Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn),
|
||||||
|
feature = table.Column<string>(type: "text", nullable: true),
|
||||||
|
bet = table.Column<decimal>(type: "numeric", nullable: false),
|
||||||
|
paidout = table.Column<decimal>(type: "numeric", nullable: false),
|
||||||
|
dateadded = table.Column<DateTime>(type: "timestamp without time zone", nullable: true)
|
||||||
|
},
|
||||||
|
constraints: table =>
|
||||||
|
{
|
||||||
|
table.PrimaryKey("pk_gamblingstats", x => x.id);
|
||||||
|
});
|
||||||
|
|
||||||
|
migrationBuilder.CreateIndex(
|
||||||
|
name: "ix_gamblingstats_feature",
|
||||||
|
table: "gamblingstats",
|
||||||
|
column: "feature",
|
||||||
|
unique: true);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void Down(MigrationBuilder migrationBuilder)
|
||||||
|
{
|
||||||
|
migrationBuilder.DropTable(
|
||||||
|
name: "gamblingstats");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
3764
src/NadekoBot/Migrations/PostgreSql/20221021192807_toggle-global-expressions.Designer.cs
generated
Normal file
3764
src/NadekoBot/Migrations/PostgreSql/20221021192807_toggle-global-expressions.Designer.cs
generated
Normal file
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,26 @@
|
|||||||
|
using Microsoft.EntityFrameworkCore.Migrations;
|
||||||
|
|
||||||
|
#nullable disable
|
||||||
|
|
||||||
|
namespace NadekoBot.Migrations.PostgreSql
|
||||||
|
{
|
||||||
|
public partial class toggleglobalexpressions : Migration
|
||||||
|
{
|
||||||
|
protected override void Up(MigrationBuilder migrationBuilder)
|
||||||
|
{
|
||||||
|
migrationBuilder.AddColumn<bool>(
|
||||||
|
name: "disableglobalexpressions",
|
||||||
|
table: "guildconfigs",
|
||||||
|
type: "boolean",
|
||||||
|
nullable: false,
|
||||||
|
defaultValue: false);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void Down(MigrationBuilder migrationBuilder)
|
||||||
|
{
|
||||||
|
migrationBuilder.DropColumn(
|
||||||
|
name: "disableglobalexpressions",
|
||||||
|
table: "guildconfigs");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@@ -1157,6 +1157,41 @@ namespace NadekoBot.Migrations.PostgreSql
|
|||||||
b.ToTable("filterwordschannelid", (string)null);
|
b.ToTable("filterwordschannelid", (string)null);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("NadekoBot.Services.Database.Models.GamblingStats", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("integer")
|
||||||
|
.HasColumnName("id");
|
||||||
|
|
||||||
|
NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id"));
|
||||||
|
|
||||||
|
b.Property<decimal>("Bet")
|
||||||
|
.HasColumnType("numeric")
|
||||||
|
.HasColumnName("bet");
|
||||||
|
|
||||||
|
b.Property<DateTime?>("DateAdded")
|
||||||
|
.HasColumnType("timestamp without time zone")
|
||||||
|
.HasColumnName("dateadded");
|
||||||
|
|
||||||
|
b.Property<string>("Feature")
|
||||||
|
.HasColumnType("text")
|
||||||
|
.HasColumnName("feature");
|
||||||
|
|
||||||
|
b.Property<decimal>("PaidOut")
|
||||||
|
.HasColumnType("numeric")
|
||||||
|
.HasColumnName("paidout");
|
||||||
|
|
||||||
|
b.HasKey("Id")
|
||||||
|
.HasName("pk_gamblingstats");
|
||||||
|
|
||||||
|
b.HasIndex("Feature")
|
||||||
|
.IsUnique()
|
||||||
|
.HasDatabaseName("ix_gamblingstats_feature");
|
||||||
|
|
||||||
|
b.ToTable("gamblingstats", (string)null);
|
||||||
|
});
|
||||||
|
|
||||||
modelBuilder.Entity("NadekoBot.Services.Database.Models.GCChannelId", b =>
|
modelBuilder.Entity("NadekoBot.Services.Database.Models.GCChannelId", b =>
|
||||||
{
|
{
|
||||||
b.Property<int>("Id")
|
b.Property<int>("Id")
|
||||||
@@ -1287,6 +1322,10 @@ namespace NadekoBot.Migrations.PostgreSql
|
|||||||
.HasColumnType("boolean")
|
.HasColumnType("boolean")
|
||||||
.HasColumnName("deletestreamonlinemessage");
|
.HasColumnName("deletestreamonlinemessage");
|
||||||
|
|
||||||
|
b.Property<bool>("DisableGlobalExpressions")
|
||||||
|
.HasColumnType("boolean")
|
||||||
|
.HasColumnName("disableglobalexpressions");
|
||||||
|
|
||||||
b.Property<string>("DmGreetMessageText")
|
b.Property<string>("DmGreetMessageText")
|
||||||
.HasColumnType("text")
|
.HasColumnType("text")
|
||||||
.HasColumnName("dmgreetmessagetext");
|
.HasColumnName("dmgreetmessagetext");
|
||||||
|
2898
src/NadekoBot/Migrations/Sqlite/20221003111019_gambling-stats.Designer.cs
generated
Normal file
2898
src/NadekoBot/Migrations/Sqlite/20221003111019_gambling-stats.Designer.cs
generated
Normal file
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,41 @@
|
|||||||
|
using System;
|
||||||
|
using Microsoft.EntityFrameworkCore.Migrations;
|
||||||
|
|
||||||
|
#nullable disable
|
||||||
|
|
||||||
|
namespace NadekoBot.Migrations
|
||||||
|
{
|
||||||
|
public partial class gamblingstats : Migration
|
||||||
|
{
|
||||||
|
protected override void Up(MigrationBuilder migrationBuilder)
|
||||||
|
{
|
||||||
|
migrationBuilder.CreateTable(
|
||||||
|
name: "GamblingStats",
|
||||||
|
columns: table => new
|
||||||
|
{
|
||||||
|
Id = table.Column<int>(type: "INTEGER", nullable: false)
|
||||||
|
.Annotation("Sqlite:Autoincrement", true),
|
||||||
|
Feature = table.Column<string>(type: "TEXT", nullable: true),
|
||||||
|
Bet = table.Column<decimal>(type: "TEXT", nullable: false),
|
||||||
|
PaidOut = table.Column<decimal>(type: "TEXT", nullable: false),
|
||||||
|
DateAdded = table.Column<DateTime>(type: "TEXT", nullable: true)
|
||||||
|
},
|
||||||
|
constraints: table =>
|
||||||
|
{
|
||||||
|
table.PrimaryKey("PK_GamblingStats", x => x.Id);
|
||||||
|
});
|
||||||
|
|
||||||
|
migrationBuilder.CreateIndex(
|
||||||
|
name: "IX_GamblingStats_Feature",
|
||||||
|
table: "GamblingStats",
|
||||||
|
column: "Feature",
|
||||||
|
unique: true);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void Down(MigrationBuilder migrationBuilder)
|
||||||
|
{
|
||||||
|
migrationBuilder.DropTable(
|
||||||
|
name: "GamblingStats");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
2901
src/NadekoBot/Migrations/Sqlite/20221021192121_toggle-global-expressions.Designer.cs
generated
Normal file
2901
src/NadekoBot/Migrations/Sqlite/20221021192121_toggle-global-expressions.Designer.cs
generated
Normal file
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,26 @@
|
|||||||
|
using Microsoft.EntityFrameworkCore.Migrations;
|
||||||
|
|
||||||
|
#nullable disable
|
||||||
|
|
||||||
|
namespace NadekoBot.Migrations
|
||||||
|
{
|
||||||
|
public partial class toggleglobalexpressions : Migration
|
||||||
|
{
|
||||||
|
protected override void Up(MigrationBuilder migrationBuilder)
|
||||||
|
{
|
||||||
|
migrationBuilder.AddColumn<bool>(
|
||||||
|
name: "DisableGlobalExpressions",
|
||||||
|
table: "GuildConfigs",
|
||||||
|
type: "INTEGER",
|
||||||
|
nullable: false,
|
||||||
|
defaultValue: false);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void Down(MigrationBuilder migrationBuilder)
|
||||||
|
{
|
||||||
|
migrationBuilder.DropColumn(
|
||||||
|
name: "DisableGlobalExpressions",
|
||||||
|
table: "GuildConfigs");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@@ -864,6 +864,32 @@ namespace NadekoBot.Migrations
|
|||||||
b.ToTable("FilterWordsChannelId");
|
b.ToTable("FilterWordsChannelId");
|
||||||
});
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("NadekoBot.Services.Database.Models.GamblingStats", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<decimal>("Bet")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<DateTime?>("DateAdded")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<string>("Feature")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<decimal>("PaidOut")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.HasIndex("Feature")
|
||||||
|
.IsUnique();
|
||||||
|
|
||||||
|
b.ToTable("GamblingStats");
|
||||||
|
});
|
||||||
|
|
||||||
modelBuilder.Entity("NadekoBot.Services.Database.Models.GCChannelId", b =>
|
modelBuilder.Entity("NadekoBot.Services.Database.Models.GCChannelId", b =>
|
||||||
{
|
{
|
||||||
b.Property<int>("Id")
|
b.Property<int>("Id")
|
||||||
@@ -960,6 +986,9 @@ namespace NadekoBot.Migrations
|
|||||||
b.Property<bool>("DeleteStreamOnlineMessage")
|
b.Property<bool>("DeleteStreamOnlineMessage")
|
||||||
.HasColumnType("INTEGER");
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<bool>("DisableGlobalExpressions")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
b.Property<string>("DmGreetMessageText")
|
b.Property<string>("DmGreetMessageText")
|
||||||
.HasColumnType("TEXT");
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
@@ -72,7 +72,7 @@ public partial class Administration
|
|||||||
[BotPerm(ChannelPerm.ManageMessages)]
|
[BotPerm(ChannelPerm.ManageMessages)]
|
||||||
[NadekoOptions(typeof(PruneOptions))]
|
[NadekoOptions(typeof(PruneOptions))]
|
||||||
[Priority(0)]
|
[Priority(0)]
|
||||||
public Task Prune(IGuildUser user, int count = 100, string args = null)
|
public Task Prune(IGuildUser user, int count = 100, params string[] args)
|
||||||
=> Prune(user.Id, count, args);
|
=> Prune(user.Id, count, args);
|
||||||
|
|
||||||
//prune userid [x]
|
//prune userid [x]
|
||||||
|
@@ -230,6 +230,19 @@ public partial class Administration
|
|||||||
await ReplyPendingLocalizedAsync(strs.fwall_stop);
|
await ReplyPendingLocalizedAsync(strs.fwall_stop);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Cmd]
|
||||||
|
[RequireContext(ContextType.Guild)]
|
||||||
|
[OwnerOnly]
|
||||||
|
public async Task ForwardToChannel()
|
||||||
|
{
|
||||||
|
var enabled = _service.ForwardToChannel(ctx.Channel.Id);
|
||||||
|
|
||||||
|
if (enabled)
|
||||||
|
await ReplyConfirmLocalizedAsync(strs.fwch_start);
|
||||||
|
else
|
||||||
|
await ReplyPendingLocalizedAsync(strs.fwch_stop);
|
||||||
|
}
|
||||||
|
|
||||||
[Cmd]
|
[Cmd]
|
||||||
public async Task ShardStats(int page = 1)
|
public async Task ShardStats(int page = 1)
|
||||||
{
|
{
|
||||||
|
@@ -85,12 +85,12 @@ public sealed class SelfService : IExecNoCommand, IReadyExecutor, INService
|
|||||||
await using var uow = _db.GetDbContext();
|
await using var uow = _db.GetDbContext();
|
||||||
|
|
||||||
autoCommands = uow.AutoCommands.AsNoTracking()
|
autoCommands = uow.AutoCommands.AsNoTracking()
|
||||||
.Where(x => x.Interval >= 5)
|
.Where(x => x.Interval >= 5)
|
||||||
.AsEnumerable()
|
.AsEnumerable()
|
||||||
.GroupBy(x => x.GuildId)
|
.GroupBy(x => x.GuildId)
|
||||||
.ToDictionary(x => x.Key,
|
.ToDictionary(x => x.Key,
|
||||||
y => y.ToDictionary(x => x.Id, TimerFromAutoCommand).ToConcurrent())
|
y => y.ToDictionary(x => x.Id, TimerFromAutoCommand).ToConcurrent())
|
||||||
.ToConcurrent();
|
.ToConcurrent();
|
||||||
|
|
||||||
var startupCommands = uow.AutoCommands.AsNoTracking().Where(x => x.Interval == 0);
|
var startupCommands = uow.AutoCommands.AsNoTracking().Where(x => x.Interval == 0);
|
||||||
foreach (var cmd in startupCommands)
|
foreach (var cmd in startupCommands)
|
||||||
@@ -169,18 +169,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())
|
||||||
{
|
{
|
||||||
@@ -202,7 +202,7 @@ public sealed class SelfService : IExecNoCommand, IReadyExecutor, INService
|
|||||||
public async Task ExecOnNoCommandAsync(IGuild guild, IUserMessage msg)
|
public async Task ExecOnNoCommandAsync(IGuild guild, IUserMessage msg)
|
||||||
{
|
{
|
||||||
var bs = _bss.Data;
|
var bs = _bss.Data;
|
||||||
if (msg.Channel is IDMChannel && bs.ForwardMessages && ownerChannels.Any())
|
if (msg.Channel is IDMChannel && bs.ForwardMessages && (ownerChannels.Any() || bs.ForwardToChannel is not null))
|
||||||
{
|
{
|
||||||
var title = _strings.GetText(strs.dm_from) + $" [{msg.Author}]({msg.Author.Id})";
|
var title = _strings.GetText(strs.dm_from) + $" [{msg.Author}]({msg.Author.Id})";
|
||||||
|
|
||||||
@@ -232,6 +232,18 @@ public sealed class SelfService : IExecNoCommand, IReadyExecutor, INService
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
else if (bs.ForwardToChannel is ulong cid)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
if (_client.GetChannel(cid) is ITextChannel ch)
|
||||||
|
await ch.SendConfirmAsync(_eb, title, toSend);
|
||||||
|
}
|
||||||
|
catch
|
||||||
|
{
|
||||||
|
Log.Warning("Error forwarding message to the channel");
|
||||||
|
}
|
||||||
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
var firstOwnerChannel = ownerChannels.Values.First();
|
var firstOwnerChannel = ownerChannels.Values.First();
|
||||||
@@ -333,6 +345,20 @@ public sealed class SelfService : IExecNoCommand, IReadyExecutor, INService
|
|||||||
return isToAll;
|
return isToAll;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public bool ForwardToChannel(ulong? channelId)
|
||||||
|
{
|
||||||
|
using var uow = _db.GetDbContext();
|
||||||
|
|
||||||
|
_bss.ModifyConfig(config =>
|
||||||
|
{
|
||||||
|
config.ForwardToChannel = channelId == config.ForwardToChannel
|
||||||
|
? null
|
||||||
|
: channelId;
|
||||||
|
});
|
||||||
|
|
||||||
|
return channelId is not null;
|
||||||
|
}
|
||||||
|
|
||||||
private void HandleStatusChanges()
|
private void HandleStatusChanges()
|
||||||
=> _pubSub.Sub(_activitySetKey,
|
=> _pubSub.Sub(_activitySetKey,
|
||||||
async data =>
|
async data =>
|
||||||
|
@@ -41,6 +41,17 @@ public partial class NadekoExpressions : NadekoModule<NadekoExpressionsService>
|
|||||||
message.Length > 1024 ? GetText(strs.redacted_too_long) : message));
|
message.Length > 1024 ? GetText(strs.redacted_too_long) : message));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Cmd]
|
||||||
|
[UserPerm(GuildPerm.Administrator)]
|
||||||
|
public async Task ExprToggleGlobal()
|
||||||
|
{
|
||||||
|
var result = await _service.ToggleGlobalExpressionsAsync(ctx.Guild.Id);
|
||||||
|
if (result)
|
||||||
|
await ReplyConfirmLocalizedAsync(strs.expr_global_disabled);
|
||||||
|
else
|
||||||
|
await ReplyConfirmLocalizedAsync(strs.expr_global_enabled);
|
||||||
|
}
|
||||||
|
|
||||||
[Cmd]
|
[Cmd]
|
||||||
[UserPerm(GuildPerm.Administrator)]
|
[UserPerm(GuildPerm.Administrator)]
|
||||||
public async Task ExprAddServer(string key, [Leftover] string message)
|
public async Task ExprAddServer(string key, [Leftover] string message)
|
@@ -7,6 +7,7 @@ using NadekoBot.Modules.Permissions.Common;
|
|||||||
using NadekoBot.Modules.Permissions.Services;
|
using NadekoBot.Modules.Permissions.Services;
|
||||||
using NadekoBot.Services.Database.Models;
|
using NadekoBot.Services.Database.Models;
|
||||||
using System.Runtime.CompilerServices;
|
using System.Runtime.CompilerServices;
|
||||||
|
using LinqToDB.EntityFrameworkCore;
|
||||||
using Nadeko.Common;
|
using Nadeko.Common;
|
||||||
using YamlDotNet.Serialization;
|
using YamlDotNet.Serialization;
|
||||||
using YamlDotNet.Serialization.NamingConventions;
|
using YamlDotNet.Serialization.NamingConventions;
|
||||||
@@ -56,8 +57,8 @@ public sealed class NadekoExpressionsService : IExecOnMessage, IReadyExecutor
|
|||||||
// 1. expressions are almost never added (compared to how many times they are being looped through)
|
// 1. expressions are almost never added (compared to how many times they are being looped through)
|
||||||
// 2. only need write locks for this as we'll rebuild+replace the array on every edit
|
// 2. only need write locks for this as we'll rebuild+replace the array on every edit
|
||||||
// 3. there's never many of them (at most a thousand, usually < 100)
|
// 3. there's never many of them (at most a thousand, usually < 100)
|
||||||
private NadekoExpression[] globalReactions;
|
private NadekoExpression[] globalExpressions;
|
||||||
private ConcurrentDictionary<ulong, NadekoExpression[]> newGuildReactions;
|
private ConcurrentDictionary<ulong, NadekoExpression[]> newguildExpressions;
|
||||||
|
|
||||||
private readonly DbService _db;
|
private readonly DbService _db;
|
||||||
private readonly DiscordSocketClient _client;
|
private readonly DiscordSocketClient _client;
|
||||||
@@ -72,6 +73,7 @@ public sealed class NadekoExpressionsService : IExecOnMessage, IReadyExecutor
|
|||||||
private readonly Random _rng;
|
private readonly Random _rng;
|
||||||
|
|
||||||
private bool ready;
|
private bool ready;
|
||||||
|
private ConcurrentHashSet<ulong> _disabledGlobalExpressionGuilds;
|
||||||
|
|
||||||
public NadekoExpressionsService(
|
public NadekoExpressionsService(
|
||||||
PermissionService perms,
|
PermissionService perms,
|
||||||
@@ -113,7 +115,7 @@ public sealed class NadekoExpressionsService : IExecOnMessage, IReadyExecutor
|
|||||||
.Where(x => allGuildIds.Contains(x.GuildId.Value))
|
.Where(x => allGuildIds.Contains(x.GuildId.Value))
|
||||||
.ToListAsync();
|
.ToListAsync();
|
||||||
|
|
||||||
newGuildReactions = guildItems.GroupBy(k => k.GuildId!.Value)
|
newguildExpressions = guildItems.GroupBy(k => k.GuildId!.Value)
|
||||||
.ToDictionary(g => g.Key,
|
.ToDictionary(g => g.Key,
|
||||||
g => g.Select(x =>
|
g => g.Select(x =>
|
||||||
{
|
{
|
||||||
@@ -123,6 +125,11 @@ public sealed class NadekoExpressionsService : IExecOnMessage, IReadyExecutor
|
|||||||
.ToArray())
|
.ToArray())
|
||||||
.ToConcurrent();
|
.ToConcurrent();
|
||||||
|
|
||||||
|
_disabledGlobalExpressionGuilds = new (await uow.GuildConfigs
|
||||||
|
.Where(x => x.DisableGlobalExpressions)
|
||||||
|
.Select(x => x.GuildId)
|
||||||
|
.ToListAsyncLinqToDB());
|
||||||
|
|
||||||
lock (_gexprWriteLock)
|
lock (_gexprWriteLock)
|
||||||
{
|
{
|
||||||
var globalItems = uow.Expressions.AsNoTracking()
|
var globalItems = uow.Expressions.AsNoTracking()
|
||||||
@@ -135,7 +142,7 @@ public sealed class NadekoExpressionsService : IExecOnMessage, IReadyExecutor
|
|||||||
})
|
})
|
||||||
.ToArray();
|
.ToArray();
|
||||||
|
|
||||||
globalReactions = globalItems;
|
globalExpressions = globalItems;
|
||||||
}
|
}
|
||||||
|
|
||||||
ready = true;
|
ready = true;
|
||||||
@@ -151,14 +158,17 @@ public sealed class NadekoExpressionsService : IExecOnMessage, IReadyExecutor
|
|||||||
|
|
||||||
var content = umsg.Content.Trim().ToLowerInvariant();
|
var content = umsg.Content.Trim().ToLowerInvariant();
|
||||||
|
|
||||||
if (newGuildReactions.TryGetValue(channel.Guild.Id, out var reactions) && reactions.Length > 0)
|
if (newguildExpressions.TryGetValue(channel.Guild.Id, out var expressions) && expressions.Length > 0)
|
||||||
{
|
{
|
||||||
var expr = MatchExpressions(content, reactions);
|
var expr = MatchExpressions(content, expressions);
|
||||||
if (expr is not null)
|
if (expr is not null)
|
||||||
return expr;
|
return expr;
|
||||||
}
|
}
|
||||||
|
|
||||||
var localGrs = globalReactions;
|
if (_disabledGlobalExpressionGuilds.Contains(channel.Guild.Id))
|
||||||
|
return null;
|
||||||
|
|
||||||
|
var localGrs = globalExpressions;
|
||||||
|
|
||||||
return MatchExpressions(content, localGrs);
|
return MatchExpressions(content, localGrs);
|
||||||
}
|
}
|
||||||
@@ -345,7 +355,7 @@ public sealed class NadekoExpressionsService : IExecOnMessage, IReadyExecutor
|
|||||||
{
|
{
|
||||||
if (maybeGuildId is { } guildId)
|
if (maybeGuildId is { } guildId)
|
||||||
{
|
{
|
||||||
newGuildReactions.AddOrUpdate(guildId,
|
newguildExpressions.AddOrUpdate(guildId,
|
||||||
new[] { expr },
|
new[] { expr },
|
||||||
(_, old) =>
|
(_, old) =>
|
||||||
{
|
{
|
||||||
@@ -363,7 +373,7 @@ public sealed class NadekoExpressionsService : IExecOnMessage, IReadyExecutor
|
|||||||
{
|
{
|
||||||
lock (_gexprWriteLock)
|
lock (_gexprWriteLock)
|
||||||
{
|
{
|
||||||
var exprs = globalReactions;
|
var exprs = globalExpressions;
|
||||||
for (var i = 0; i < exprs.Length; i++)
|
for (var i = 0; i < exprs.Length; i++)
|
||||||
{
|
{
|
||||||
if (exprs[i].Id == expr.Id)
|
if (exprs[i].Id == expr.Id)
|
||||||
@@ -379,7 +389,7 @@ public sealed class NadekoExpressionsService : IExecOnMessage, IReadyExecutor
|
|||||||
expr.Trigger = expr.Trigger.Replace(MENTION_PH, _client.CurrentUser.Mention);
|
expr.Trigger = expr.Trigger.Replace(MENTION_PH, _client.CurrentUser.Mention);
|
||||||
|
|
||||||
if (maybeGuildId is { } guildId)
|
if (maybeGuildId is { } guildId)
|
||||||
newGuildReactions.AddOrUpdate(guildId, new[] { expr }, (_, old) => old.With(expr));
|
newguildExpressions.AddOrUpdate(guildId, new[] { expr }, (_, old) => old.With(expr));
|
||||||
else
|
else
|
||||||
return _pubSub.Pub(_gexprAddedKey, expr);
|
return _pubSub.Pub(_gexprAddedKey, expr);
|
||||||
|
|
||||||
@@ -390,7 +400,7 @@ public sealed class NadekoExpressionsService : IExecOnMessage, IReadyExecutor
|
|||||||
{
|
{
|
||||||
if (maybeGuildId is { } guildId)
|
if (maybeGuildId is { } guildId)
|
||||||
{
|
{
|
||||||
newGuildReactions.AddOrUpdate(guildId,
|
newguildExpressions.AddOrUpdate(guildId,
|
||||||
Array.Empty<NadekoExpression>(),
|
Array.Empty<NadekoExpression>(),
|
||||||
(key, old) => DeleteInternal(old, id, out _));
|
(key, old) => DeleteInternal(old, id, out _));
|
||||||
|
|
||||||
@@ -399,7 +409,7 @@ public sealed class NadekoExpressionsService : IExecOnMessage, IReadyExecutor
|
|||||||
|
|
||||||
lock (_gexprWriteLock)
|
lock (_gexprWriteLock)
|
||||||
{
|
{
|
||||||
var expr = Array.Find(globalReactions, item => item.Id == id);
|
var expr = Array.Find(globalExpressions, item => item.Id == id);
|
||||||
if (expr is not null)
|
if (expr is not null)
|
||||||
return _pubSub.Pub(_gexprDeletedkey, expr.Id);
|
return _pubSub.Pub(_gexprDeletedkey, expr.Id);
|
||||||
}
|
}
|
||||||
@@ -492,7 +502,7 @@ public sealed class NadekoExpressionsService : IExecOnMessage, IReadyExecutor
|
|||||||
var count = uow.Expressions.ClearFromGuild(guildId);
|
var count = uow.Expressions.ClearFromGuild(guildId);
|
||||||
uow.SaveChanges();
|
uow.SaveChanges();
|
||||||
|
|
||||||
newGuildReactions.TryRemove(guildId, out _);
|
newguildExpressions.TryRemove(guildId, out _);
|
||||||
|
|
||||||
return count;
|
return count;
|
||||||
}
|
}
|
||||||
@@ -562,10 +572,10 @@ public sealed class NadekoExpressionsService : IExecOnMessage, IReadyExecutor
|
|||||||
{
|
{
|
||||||
lock (_gexprWriteLock)
|
lock (_gexprWriteLock)
|
||||||
{
|
{
|
||||||
var newGlobalReactions = new NadekoExpression[globalReactions.Length + 1];
|
var newGlobalReactions = new NadekoExpression[globalExpressions.Length + 1];
|
||||||
Array.Copy(globalReactions, newGlobalReactions, globalReactions.Length);
|
Array.Copy(globalExpressions, newGlobalReactions, globalExpressions.Length);
|
||||||
newGlobalReactions[globalReactions.Length] = c;
|
newGlobalReactions[globalExpressions.Length] = c;
|
||||||
globalReactions = newGlobalReactions;
|
globalExpressions = newGlobalReactions;
|
||||||
}
|
}
|
||||||
|
|
||||||
return default;
|
return default;
|
||||||
@@ -575,11 +585,11 @@ public sealed class NadekoExpressionsService : IExecOnMessage, IReadyExecutor
|
|||||||
{
|
{
|
||||||
lock (_gexprWriteLock)
|
lock (_gexprWriteLock)
|
||||||
{
|
{
|
||||||
for (var i = 0; i < globalReactions.Length; i++)
|
for (var i = 0; i < globalExpressions.Length; i++)
|
||||||
{
|
{
|
||||||
if (globalReactions[i].Id == c.Id)
|
if (globalExpressions[i].Id == c.Id)
|
||||||
{
|
{
|
||||||
globalReactions[i] = c;
|
globalExpressions[i] = c;
|
||||||
return default;
|
return default;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -596,8 +606,8 @@ public sealed class NadekoExpressionsService : IExecOnMessage, IReadyExecutor
|
|||||||
{
|
{
|
||||||
lock (_gexprWriteLock)
|
lock (_gexprWriteLock)
|
||||||
{
|
{
|
||||||
var newGlobalReactions = DeleteInternal(globalReactions, id, out _);
|
var newGlobalReactions = DeleteInternal(globalExpressions, id, out _);
|
||||||
globalReactions = newGlobalReactions;
|
globalExpressions = newGlobalReactions;
|
||||||
}
|
}
|
||||||
|
|
||||||
return default;
|
return default;
|
||||||
@@ -612,7 +622,7 @@ public sealed class NadekoExpressionsService : IExecOnMessage, IReadyExecutor
|
|||||||
|
|
||||||
private Task OnLeftGuild(SocketGuild arg)
|
private Task OnLeftGuild(SocketGuild arg)
|
||||||
{
|
{
|
||||||
newGuildReactions.TryRemove(arg.Id, out _);
|
newguildExpressions.TryRemove(arg.Id, out _);
|
||||||
|
|
||||||
return Task.CompletedTask;
|
return Task.CompletedTask;
|
||||||
}
|
}
|
||||||
@@ -622,7 +632,7 @@ public sealed class NadekoExpressionsService : IExecOnMessage, IReadyExecutor
|
|||||||
await using var uow = _db.GetDbContext();
|
await using var uow = _db.GetDbContext();
|
||||||
var exprs = await uow.Expressions.AsNoTracking().Where(x => x.GuildId == gc.GuildId).ToArrayAsync();
|
var exprs = await uow.Expressions.AsNoTracking().Where(x => x.GuildId == gc.GuildId).ToArrayAsync();
|
||||||
|
|
||||||
newGuildReactions[gc.GuildId] = exprs;
|
newguildExpressions[gc.GuildId] = exprs;
|
||||||
}
|
}
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
@@ -702,10 +712,25 @@ public sealed class NadekoExpressionsService : IExecOnMessage, IReadyExecutor
|
|||||||
public NadekoExpression[] GetExpressionsFor(ulong? maybeGuildId)
|
public NadekoExpression[] GetExpressionsFor(ulong? maybeGuildId)
|
||||||
{
|
{
|
||||||
if (maybeGuildId is { } guildId)
|
if (maybeGuildId is { } guildId)
|
||||||
return newGuildReactions.TryGetValue(guildId, out var exprs) ? exprs : Array.Empty<NadekoExpression>();
|
return newguildExpressions.TryGetValue(guildId, out var exprs) ? exprs : Array.Empty<NadekoExpression>();
|
||||||
|
|
||||||
return globalReactions;
|
return globalExpressions;
|
||||||
}
|
}
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
|
public async Task<bool> ToggleGlobalExpressionsAsync(ulong guildId)
|
||||||
|
{
|
||||||
|
await using var ctx = _db.GetDbContext();
|
||||||
|
var gc = ctx.GuildConfigsForId(guildId, set => set);
|
||||||
|
var toReturn = gc.DisableGlobalExpressions = !gc.DisableGlobalExpressions;
|
||||||
|
await ctx.SaveChangesAsync();
|
||||||
|
|
||||||
|
if (toReturn)
|
||||||
|
_disabledGlobalExpressionGuilds.Add(guildId);
|
||||||
|
else
|
||||||
|
_disabledGlobalExpressionGuilds.TryRemove(guildId);
|
||||||
|
|
||||||
|
return toReturn;
|
||||||
|
}
|
||||||
}
|
}
|
@@ -29,6 +29,7 @@ public partial class Gambling : GamblingModule<GamblingService>
|
|||||||
private readonly IBankService _bank;
|
private readonly IBankService _bank;
|
||||||
private readonly IPatronageService _ps;
|
private readonly IPatronageService _ps;
|
||||||
private readonly RemindService _remind;
|
private readonly RemindService _remind;
|
||||||
|
private readonly GamblingTxTracker _gamblingTxTracker;
|
||||||
|
|
||||||
private IUserMessage rdMsg;
|
private IUserMessage rdMsg;
|
||||||
|
|
||||||
@@ -41,7 +42,8 @@ public partial class Gambling : GamblingModule<GamblingService>
|
|||||||
GamblingConfigService configService,
|
GamblingConfigService configService,
|
||||||
IBankService bank,
|
IBankService bank,
|
||||||
IPatronageService ps,
|
IPatronageService ps,
|
||||||
RemindService remind)
|
RemindService remind,
|
||||||
|
GamblingTxTracker gamblingTxTracker)
|
||||||
: base(configService)
|
: base(configService)
|
||||||
{
|
{
|
||||||
_gs = gs;
|
_gs = gs;
|
||||||
@@ -51,6 +53,7 @@ public partial class Gambling : GamblingModule<GamblingService>
|
|||||||
_bank = bank;
|
_bank = bank;
|
||||||
_ps = ps;
|
_ps = ps;
|
||||||
_remind = remind;
|
_remind = remind;
|
||||||
|
_gamblingTxTracker = gamblingTxTracker;
|
||||||
|
|
||||||
_enUsCulture = new CultureInfo("en-US", false).NumberFormat;
|
_enUsCulture = new CultureInfo("en-US", false).NumberFormat;
|
||||||
_enUsCulture.NumberDecimalDigits = 0;
|
_enUsCulture.NumberDecimalDigits = 0;
|
||||||
@@ -65,6 +68,43 @@ public partial class Gambling : GamblingModule<GamblingService>
|
|||||||
return N(bal);
|
return N(bal);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Cmd]
|
||||||
|
public async Task BetStats()
|
||||||
|
{
|
||||||
|
var stats = await _gamblingTxTracker.GetAllAsync();
|
||||||
|
|
||||||
|
var eb = _eb.Create(ctx)
|
||||||
|
.WithOkColor();
|
||||||
|
|
||||||
|
var str = "` Feature `|` Bet `|`Paid Out`|` RoI `\n";
|
||||||
|
str += "――――――――――――――――――――\n";
|
||||||
|
foreach (var stat in stats)
|
||||||
|
{
|
||||||
|
var perc = (stat.PaidOut / stat.Bet).ToString("P2", Culture);
|
||||||
|
str += $"`{stat.Feature.PadBoth(9)}`" +
|
||||||
|
$"|`{stat.Bet.ToString("N0").PadLeft(8, ' ')}`" +
|
||||||
|
$"|`{stat.PaidOut.ToString("N0").PadLeft(8, ' ')}`" +
|
||||||
|
$"|`{perc.PadLeft(6, ' ')}`\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
var bet = stats.Sum(x => x.Bet);
|
||||||
|
var paidOut = stats.Sum(x => x.PaidOut);
|
||||||
|
|
||||||
|
if (bet == 0)
|
||||||
|
bet = 1;
|
||||||
|
|
||||||
|
var tPerc = (paidOut / bet).ToString("P2", Culture);
|
||||||
|
str += "――――――――――――――――――――\n";
|
||||||
|
str += $"` {("TOTAL").PadBoth(7)}` " +
|
||||||
|
$"|**{N(bet).PadLeft(8, ' ')}**" +
|
||||||
|
$"|**{N(paidOut).PadLeft(8, ' ')}**" +
|
||||||
|
$"|`{tPerc.PadLeft(6, ' ')}`";
|
||||||
|
|
||||||
|
eb.WithDescription(str);
|
||||||
|
|
||||||
|
await ctx.Channel.EmbedAsync(eb);
|
||||||
|
}
|
||||||
|
|
||||||
[Cmd]
|
[Cmd]
|
||||||
public async Task Economy()
|
public async Task Economy()
|
||||||
{
|
{
|
||||||
@@ -79,15 +119,15 @@ public partial class Gambling : GamblingModule<GamblingService>
|
|||||||
|
|
||||||
// [21:03] Bob Page: Kinda remids me of US economy
|
// [21:03] Bob Page: Kinda remids me of US economy
|
||||||
var embed = _eb.Create()
|
var embed = _eb.Create()
|
||||||
.WithTitle(GetText(strs.economy_state))
|
.WithTitle(GetText(strs.economy_state))
|
||||||
.AddField(GetText(strs.currency_owned), N(ec.Cash - ec.Bot))
|
.AddField(GetText(strs.currency_owned), N(ec.Cash - ec.Bot))
|
||||||
.AddField(GetText(strs.currency_one_percent), (onePercent * 100).ToString("F2") + "%")
|
.AddField(GetText(strs.currency_one_percent), (onePercent * 100).ToString("F2") + "%")
|
||||||
.AddField(GetText(strs.currency_planted), N(ec.Planted))
|
.AddField(GetText(strs.currency_planted), N(ec.Planted))
|
||||||
.AddField(GetText(strs.owned_waifus_total), N(ec.Waifus))
|
.AddField(GetText(strs.owned_waifus_total), N(ec.Waifus))
|
||||||
.AddField(GetText(strs.bot_currency), N(ec.Bot))
|
.AddField(GetText(strs.bot_currency), N(ec.Bot))
|
||||||
.AddField(GetText(strs.bank_accounts), N(ec.Bank))
|
.AddField(GetText(strs.bank_accounts), N(ec.Bank))
|
||||||
.AddField(GetText(strs.total), N(ec.Cash + ec.Planted + ec.Waifus + ec.Bank))
|
.AddField(GetText(strs.total), N(ec.Cash + ec.Planted + ec.Waifus + ec.Bank))
|
||||||
.WithOkColor();
|
.WithOkColor();
|
||||||
|
|
||||||
// ec.Cash already contains ec.Bot as it's the total of all values in the CurrencyAmount column of the DiscordUser table
|
// ec.Cash already contains ec.Bot as it's the total of all values in the CurrencyAmount column of the DiscordUser table
|
||||||
await ctx.Channel.EmbedAsync(embed);
|
await ctx.Channel.EmbedAsync(embed);
|
||||||
@@ -105,7 +145,7 @@ public partial class Gambling : GamblingModule<GamblingService>
|
|||||||
|
|
||||||
await _remind.AddReminderAsync(ctx.User.Id,
|
await _remind.AddReminderAsync(ctx.User.Id,
|
||||||
ctx.User.Id,
|
ctx.User.Id,
|
||||||
ctx.Guild.Id,
|
ctx.Guild?.Id,
|
||||||
true,
|
true,
|
||||||
when,
|
when,
|
||||||
GetText(strs.timely_time));
|
GetText(strs.timely_time));
|
||||||
@@ -253,9 +293,9 @@ public partial class Gambling : GamblingModule<GamblingService>
|
|||||||
}
|
}
|
||||||
|
|
||||||
var embed = _eb.Create()
|
var embed = _eb.Create()
|
||||||
.WithTitle(GetText(strs.transactions(((SocketGuild)ctx.Guild)?.GetUser(userId)?.ToString()
|
.WithTitle(GetText(strs.transactions(((SocketGuild)ctx.Guild)?.GetUser(userId)?.ToString()
|
||||||
?? $"{userId}")))
|
?? $"{userId}")))
|
||||||
.WithOkColor();
|
.WithOkColor();
|
||||||
|
|
||||||
var sb = new StringBuilder();
|
var sb = new StringBuilder();
|
||||||
foreach (var tr in trs)
|
foreach (var tr in trs)
|
||||||
@@ -292,8 +332,8 @@ public partial class Gambling : GamblingModule<GamblingService>
|
|||||||
await using var uow = _db.GetDbContext();
|
await using var uow = _db.GetDbContext();
|
||||||
|
|
||||||
var tr = await uow.CurrencyTransactions.ToLinqToDBTable()
|
var tr = await uow.CurrencyTransactions.ToLinqToDBTable()
|
||||||
.Where(x => x.Id == intId && x.UserId == ctx.User.Id)
|
.Where(x => x.Id == intId && x.UserId == ctx.User.Id)
|
||||||
.FirstOrDefaultAsync();
|
.FirstOrDefaultAsync();
|
||||||
|
|
||||||
if (tr is null)
|
if (tr is null)
|
||||||
{
|
{
|
||||||
@@ -354,9 +394,9 @@ public partial class Gambling : GamblingModule<GamblingService>
|
|||||||
var balance = await _bank.GetBalanceAsync(ctx.User.Id);
|
var balance = await _bank.GetBalanceAsync(ctx.User.Id);
|
||||||
|
|
||||||
await N(balance)
|
await N(balance)
|
||||||
.Pipe(strs.bank_balance)
|
.Pipe(strs.bank_balance)
|
||||||
.Pipe(GetText)
|
.Pipe(GetText)
|
||||||
.Pipe(text => smc.RespondConfirmAsync(_eb, text, ephemeral: true));
|
.Pipe(text => smc.RespondConfirmAsync(_eb, text, ephemeral: true));
|
||||||
}
|
}
|
||||||
|
|
||||||
private NadekoInteraction CreateCashInteraction()
|
private NadekoInteraction CreateCashInteraction()
|
||||||
@@ -799,8 +839,8 @@ public partial class Gambling : GamblingModule<GamblingService>
|
|||||||
}
|
}
|
||||||
else if (result.Result == RpsResultType.Win)
|
else if (result.Result == RpsResultType.Win)
|
||||||
{
|
{
|
||||||
if((long)result.Won > 0)
|
if ((long)result.Won > 0)
|
||||||
embed.AddField(GetText(strs.won), N(amount.Value));
|
embed.AddField(GetText(strs.won), N(amount.Value));
|
||||||
|
|
||||||
msg = GetText(strs.rps_win(ctx.User.Mention,
|
msg = GetText(strs.rps_win(ctx.User.Mention,
|
||||||
GetRpsPick(pick),
|
GetRpsPick(pick),
|
||||||
@@ -863,99 +903,98 @@ public partial class Gambling : GamblingModule<GamblingService>
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public enum GambleTestTarget
|
public enum GambleTestTarget
|
||||||
|
{
|
||||||
|
Slot,
|
||||||
|
Betroll,
|
||||||
|
Betflip,
|
||||||
|
BetflipT,
|
||||||
|
BetDraw,
|
||||||
|
BetDrawHL,
|
||||||
|
BetDrawRB,
|
||||||
|
Lula,
|
||||||
|
Rps,
|
||||||
|
}
|
||||||
|
|
||||||
|
[Cmd]
|
||||||
|
[OwnerOnly]
|
||||||
|
public async Task BetTest()
|
||||||
|
{
|
||||||
|
await SendConfirmAsync(GetText(strs.available_tests),
|
||||||
|
Enum.GetValues<GambleTestTarget>()
|
||||||
|
.Select(x => $"`{x}`")
|
||||||
|
.Join(", "));
|
||||||
|
}
|
||||||
|
|
||||||
|
[Cmd]
|
||||||
|
[OwnerOnly]
|
||||||
|
public async Task BetTest(GambleTestTarget target, int tests = 1000)
|
||||||
|
{
|
||||||
|
if (tests <= 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
await ctx.Channel.TriggerTypingAsync();
|
||||||
|
|
||||||
|
var streak = 0;
|
||||||
|
var maxW = 0;
|
||||||
|
var maxL = 0;
|
||||||
|
|
||||||
|
var dict = new Dictionary<decimal, int>();
|
||||||
|
for (var i = 0; i < tests; i++)
|
||||||
{
|
{
|
||||||
Slot,
|
var multi = target switch
|
||||||
Betroll,
|
|
||||||
Betflip,
|
|
||||||
BetflipT,
|
|
||||||
BetDraw,
|
|
||||||
BetDrawHL,
|
|
||||||
BetDrawRB,
|
|
||||||
Lula,
|
|
||||||
Rps,
|
|
||||||
}
|
|
||||||
|
|
||||||
[Cmd]
|
|
||||||
[OwnerOnly]
|
|
||||||
public async Task BetTest()
|
|
||||||
{
|
|
||||||
await SendConfirmAsync(GetText(strs.available_tests),
|
|
||||||
Enum.GetValues<GambleTestTarget>()
|
|
||||||
.Select(x => $"`{x}`")
|
|
||||||
.Join(", "));
|
|
||||||
}
|
|
||||||
|
|
||||||
[Cmd]
|
|
||||||
[OwnerOnly]
|
|
||||||
public async Task BetTest(GambleTestTarget target, int tests = 1000)
|
|
||||||
{
|
|
||||||
if (tests <= 0)
|
|
||||||
return;
|
|
||||||
|
|
||||||
await ctx.Channel.TriggerTypingAsync();
|
|
||||||
|
|
||||||
var streak = 0;
|
|
||||||
var maxW = 0;
|
|
||||||
var maxL = 0;
|
|
||||||
|
|
||||||
var dict = new Dictionary<decimal, int>();
|
|
||||||
for (var i = 0; i < tests; i++)
|
|
||||||
{
|
{
|
||||||
var multi = target switch
|
GambleTestTarget.BetDraw => (await _gs.BetDrawAsync(ctx.User.Id, 0, 1, 0)).AsT0.Multiplier,
|
||||||
{
|
GambleTestTarget.BetDrawRB => (await _gs.BetDrawAsync(ctx.User.Id, 0, null, 1)).AsT0.Multiplier,
|
||||||
GambleTestTarget.BetDraw => (await _gs.BetDrawAsync(ctx.User.Id, 0, 1, 0)).AsT0.Multiplier,
|
GambleTestTarget.BetDrawHL => (await _gs.BetDrawAsync(ctx.User.Id, 0, 0, null)).AsT0.Multiplier,
|
||||||
GambleTestTarget.BetDrawRB => (await _gs.BetDrawAsync(ctx.User.Id, 0, null, 1)).AsT0.Multiplier,
|
GambleTestTarget.Slot => (await _gs.SlotAsync(ctx.User.Id, 0)).AsT0.Multiplier,
|
||||||
GambleTestTarget.BetDrawHL => (await _gs.BetDrawAsync(ctx.User.Id, 0, 0, null)).AsT0.Multiplier,
|
GambleTestTarget.Betflip => (await _gs.BetFlipAsync(ctx.User.Id, 0, 0)).AsT0.Multiplier,
|
||||||
GambleTestTarget.Slot => (await _gs.SlotAsync(ctx.User.Id, 0)).AsT0.Multiplier,
|
GambleTestTarget.BetflipT => (await _gs.BetFlipAsync(ctx.User.Id, 0, 1)).AsT0.Multiplier,
|
||||||
GambleTestTarget.Betflip => (await _gs.BetFlipAsync(ctx.User.Id, 0, 0)).AsT0.Multiplier,
|
GambleTestTarget.Lula => (await _gs.LulaAsync(ctx.User.Id, 0)).AsT0.Multiplier,
|
||||||
GambleTestTarget.BetflipT => (await _gs.BetFlipAsync(ctx.User.Id, 0, 1)).AsT0.Multiplier,
|
GambleTestTarget.Rps => (await _gs.RpsAsync(ctx.User.Id, 0, (byte)(i % 3))).AsT0.Multiplier,
|
||||||
GambleTestTarget.Lula => (await _gs.LulaAsync(ctx.User.Id, 0)).AsT0.Multiplier,
|
GambleTestTarget.Betroll => (await _gs.BetRollAsync(ctx.User.Id, 0)).AsT0.Multiplier,
|
||||||
GambleTestTarget.Rps => (await _gs.RpsAsync(ctx.User.Id, 0, (byte)(i % 3))).AsT0.Multiplier,
|
_ => throw new ArgumentOutOfRangeException(nameof(target))
|
||||||
GambleTestTarget.Betroll => (await _gs.BetRollAsync(ctx.User.Id, 0)).AsT0.Multiplier,
|
};
|
||||||
_ => throw new ArgumentOutOfRangeException(nameof(target))
|
|
||||||
};
|
|
||||||
|
|
||||||
if (dict.ContainsKey(multi))
|
if (dict.ContainsKey(multi))
|
||||||
dict[multi] += 1;
|
dict[multi] += 1;
|
||||||
|
else
|
||||||
|
dict.Add(multi, 1);
|
||||||
|
|
||||||
|
if (multi < 1)
|
||||||
|
{
|
||||||
|
if (streak <= 0)
|
||||||
|
--streak;
|
||||||
else
|
else
|
||||||
dict.Add(multi, 1);
|
streak = -1;
|
||||||
|
|
||||||
if (multi < 1)
|
maxL = Math.Max(maxL, -streak);
|
||||||
{
|
|
||||||
if (streak <= 0)
|
|
||||||
--streak;
|
|
||||||
else
|
|
||||||
streak = -1;
|
|
||||||
|
|
||||||
maxL = Math.Max(maxL, -streak);
|
|
||||||
}
|
|
||||||
else if (multi > 1)
|
|
||||||
{
|
|
||||||
if (streak >= 0)
|
|
||||||
++streak;
|
|
||||||
else
|
|
||||||
streak = 1;
|
|
||||||
|
|
||||||
maxW = Math.Max(maxW, streak);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
else if (multi > 1)
|
||||||
var sb = new StringBuilder();
|
|
||||||
decimal payout = 0;
|
|
||||||
foreach (var key in dict.Keys.OrderByDescending(x => x))
|
|
||||||
{
|
{
|
||||||
sb.AppendLine($"x**{key}** occured `{dict[key]}` times. {dict[key] * 1.0f / tests * 100}%");
|
if (streak >= 0)
|
||||||
payout += key * dict[key];
|
++streak;
|
||||||
|
else
|
||||||
|
streak = 1;
|
||||||
|
|
||||||
|
maxW = Math.Max(maxW, streak);
|
||||||
}
|
}
|
||||||
|
|
||||||
sb.AppendLine();
|
|
||||||
sb.AppendLine($"Longest win streak: `{maxW}`");
|
|
||||||
sb.AppendLine($"Longest lose streak: `{maxL}`");
|
|
||||||
|
|
||||||
await SendConfirmAsync(GetText(strs.test_results_for(target)),
|
|
||||||
sb.ToString(),
|
|
||||||
footer: $"Total Bet: {tests} | Payout: {payout:F0} | {payout * 1.0M / tests * 100}%");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var sb = new StringBuilder();
|
||||||
|
decimal payout = 0;
|
||||||
|
foreach (var key in dict.Keys.OrderByDescending(x => x))
|
||||||
|
{
|
||||||
|
sb.AppendLine($"x**{key}** occured `{dict[key]}` times. {dict[key] * 1.0f / tests * 100}%");
|
||||||
|
payout += key * dict[key];
|
||||||
|
}
|
||||||
|
|
||||||
|
sb.AppendLine();
|
||||||
|
sb.AppendLine($"Longest win streak: `{maxW}`");
|
||||||
|
sb.AppendLine($"Longest lose streak: `{maxL}`");
|
||||||
|
|
||||||
|
await SendConfirmAsync(GetText(strs.test_results_for(target)),
|
||||||
|
sb.ToString(),
|
||||||
|
footer: $"Total Bet: {tests} | Payout: {payout:F0} | {payout * 1.0M / tests * 100}%");
|
||||||
|
}
|
||||||
}
|
}
|
@@ -47,27 +47,6 @@ public partial class Gambling
|
|||||||
public Task Test()
|
public Task Test()
|
||||||
=> Task.CompletedTask;
|
=> Task.CompletedTask;
|
||||||
|
|
||||||
[Cmd]
|
|
||||||
[OwnerOnly]
|
|
||||||
public async Task SlotStats()
|
|
||||||
{
|
|
||||||
//i remembered to not be a moron
|
|
||||||
var paid = totalPaidOut;
|
|
||||||
var bet = totalBet;
|
|
||||||
|
|
||||||
if (bet <= 0)
|
|
||||||
bet = 1;
|
|
||||||
|
|
||||||
var embed = _eb.Create()
|
|
||||||
.WithOkColor()
|
|
||||||
.WithTitle("Slot Stats")
|
|
||||||
.AddField("Total Bet", N(bet), true)
|
|
||||||
.AddField("Paid Out", N(paid), true)
|
|
||||||
.WithFooter($"Payout Rate: {paid * 1.0M / bet * 100:f4}%");
|
|
||||||
|
|
||||||
await ctx.Channel.EmbedAsync(embed);
|
|
||||||
}
|
|
||||||
|
|
||||||
[Cmd]
|
[Cmd]
|
||||||
public async Task Slot(ShmartNumber amount)
|
public async Task Slot(ShmartNumber amount)
|
||||||
{
|
{
|
||||||
|
@@ -126,7 +126,7 @@ public class ChatterBotService : IExecOnMessage
|
|||||||
Log.Information("{PermissionMessage}", returnMsg);
|
Log.Information("{PermissionMessage}", returnMsg);
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (await _ccs.TryBlock(sg, usrMsg.Author, CleverBotResponseStr.CLEVERBOT_RESPONSE))
|
if (await _ccs.TryBlock(sg, usrMsg.Author, CleverBotResponseStr.CLEVERBOT_RESPONSE))
|
||||||
|
@@ -92,7 +92,7 @@ public partial class Help : NadekoModule<HelpService>
|
|||||||
localModules.OrderBy(module => module.Name)
|
localModules.OrderBy(module => module.Name)
|
||||||
.ToList()
|
.ToList()
|
||||||
.ForEach(module => embed.AddField($"{GetModuleEmoji(module.Name)} {module.Name}",
|
.ForEach(module => embed.AddField($"{GetModuleEmoji(module.Name)} {module.Name}",
|
||||||
GetText(GetModuleLocStr(module.Name))
|
GetModuleDescription(module.Name)
|
||||||
+ "\n"
|
+ "\n"
|
||||||
+ Format.Code(GetText(strs.module_footer(prefix, module.Name.ToLowerInvariant()))),
|
+ Format.Code(GetText(strs.module_footer(prefix, module.Name.ToLowerInvariant()))),
|
||||||
true));
|
true));
|
||||||
@@ -104,6 +104,25 @@ public partial class Help : NadekoModule<HelpService>
|
|||||||
false);
|
false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private string GetModuleDescription(string moduleName)
|
||||||
|
{
|
||||||
|
var key = GetModuleLocStr(moduleName);
|
||||||
|
|
||||||
|
if (key.Key == strs.module_description_missing.Key)
|
||||||
|
{
|
||||||
|
var desc = _medusae
|
||||||
|
.GetLoadedMedusae(Culture)
|
||||||
|
.FirstOrDefault(m => m.Sneks
|
||||||
|
.Any(x => x.Name.Equals(moduleName, StringComparison.InvariantCultureIgnoreCase)))
|
||||||
|
?.Description;
|
||||||
|
|
||||||
|
if (desc is not null)
|
||||||
|
return desc;
|
||||||
|
}
|
||||||
|
|
||||||
|
return GetText(key);
|
||||||
|
}
|
||||||
|
|
||||||
private LocStr GetModuleLocStr(string moduleName)
|
private LocStr GetModuleLocStr(string moduleName)
|
||||||
{
|
{
|
||||||
switch (moduleName.ToLowerInvariant())
|
switch (moduleName.ToLowerInvariant())
|
||||||
|
@@ -1,10 +1,12 @@
|
|||||||
#nullable disable
|
using Microsoft.EntityFrameworkCore;
|
||||||
using NadekoBot.Common.ModuleBehaviors;
|
using NadekoBot.Common.ModuleBehaviors;
|
||||||
|
using NadekoBot.Db;
|
||||||
|
|
||||||
namespace NadekoBot.Modules.Permissions.Services;
|
namespace NadekoBot.Modules.Permissions.Services;
|
||||||
|
|
||||||
public sealed class CmdCdService : IExecPreCommand, IReadyExecutor, INService
|
public sealed class CmdCdService : IExecPreCommand, IReadyExecutor, INService
|
||||||
{
|
{
|
||||||
|
private readonly DbService _db;
|
||||||
private readonly ConcurrentDictionary<ulong, ConcurrentDictionary<string, int>> _settings = new();
|
private readonly ConcurrentDictionary<ulong, ConcurrentDictionary<string, int>> _settings = new();
|
||||||
|
|
||||||
private readonly ConcurrentDictionary<(ulong, string), ConcurrentDictionary<ulong, DateTime>> _activeCooldowns =
|
private readonly ConcurrentDictionary<(ulong, string), ConcurrentDictionary<ulong, DateTime>> _activeCooldowns =
|
||||||
@@ -12,11 +14,13 @@ public sealed class CmdCdService : IExecPreCommand, IReadyExecutor, INService
|
|||||||
|
|
||||||
public int Priority => 0;
|
public int Priority => 0;
|
||||||
|
|
||||||
public CmdCdService(Bot bot)
|
public CmdCdService(Bot bot, DbService db)
|
||||||
{
|
{
|
||||||
|
_db = db;
|
||||||
_settings = bot
|
_settings = bot
|
||||||
.AllGuildConfigs
|
.AllGuildConfigs
|
||||||
.ToDictionary(x => x.GuildId, x => x.CommandCooldowns
|
.ToDictionary(x => x.GuildId, x => x.CommandCooldowns
|
||||||
|
.DistinctBy(x => x.CommandName.ToLowerInvariant())
|
||||||
.ToDictionary(c => c.CommandName, c => c.Seconds)
|
.ToDictionary(c => c.CommandName, c => c.Seconds)
|
||||||
.ToConcurrent())
|
.ToConcurrent())
|
||||||
.ToConcurrent();
|
.ToConcurrent();
|
||||||
@@ -25,13 +29,16 @@ public sealed class CmdCdService : IExecPreCommand, IReadyExecutor, INService
|
|||||||
public Task<bool> ExecPreCommandAsync(ICommandContext context, string moduleName, CommandInfo command)
|
public Task<bool> ExecPreCommandAsync(ICommandContext context, string moduleName, CommandInfo command)
|
||||||
=> TryBlock(context.Guild, context.User, command.Name.ToLowerInvariant());
|
=> TryBlock(context.Guild, context.User, command.Name.ToLowerInvariant());
|
||||||
|
|
||||||
public async Task<bool> TryBlock(IGuild guild, IUser user, string commandName)
|
public Task<bool> TryBlock(IGuild? guild, IUser user, string commandName)
|
||||||
{
|
{
|
||||||
|
if (guild is null)
|
||||||
|
return Task.FromResult(false);
|
||||||
|
|
||||||
if (!_settings.TryGetValue(guild.Id, out var cooldownSettings))
|
if (!_settings.TryGetValue(guild.Id, out var cooldownSettings))
|
||||||
return false;
|
return Task.FromResult(false);
|
||||||
|
|
||||||
if (!cooldownSettings.TryGetValue(commandName, out var cdSeconds))
|
if (!cooldownSettings.TryGetValue(commandName, out var cdSeconds))
|
||||||
return false;
|
return Task.FromResult(false);
|
||||||
|
|
||||||
var cooldowns = _activeCooldowns.GetOrAdd(
|
var cooldowns = _activeCooldowns.GetOrAdd(
|
||||||
(guild.Id, commandName),
|
(guild.Id, commandName),
|
||||||
@@ -40,7 +47,7 @@ public sealed class CmdCdService : IExecPreCommand, IReadyExecutor, INService
|
|||||||
// if user is not already on cooldown, add
|
// if user is not already on cooldown, add
|
||||||
if (cooldowns.TryAdd(user.Id, DateTime.UtcNow))
|
if (cooldowns.TryAdd(user.Id, DateTime.UtcNow))
|
||||||
{
|
{
|
||||||
return false;
|
return Task.FromResult(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
// if there is an entry, maybe it expired. Try to check if it expired and don't fail if it did
|
// if there is an entry, maybe it expired. Try to check if it expired and don't fail if it did
|
||||||
@@ -48,14 +55,14 @@ public sealed class CmdCdService : IExecPreCommand, IReadyExecutor, INService
|
|||||||
if (cooldowns.TryGetValue(user.Id, out var oldValue))
|
if (cooldowns.TryGetValue(user.Id, out var oldValue))
|
||||||
{
|
{
|
||||||
var diff = DateTime.UtcNow - oldValue;
|
var diff = DateTime.UtcNow - oldValue;
|
||||||
if (diff.Seconds > cdSeconds)
|
if (diff.TotalSeconds > cdSeconds)
|
||||||
{
|
{
|
||||||
if (cooldowns.TryUpdate(user.Id, DateTime.UtcNow, oldValue))
|
if (cooldowns.TryUpdate(user.Id, DateTime.UtcNow, oldValue))
|
||||||
return false;
|
return Task.FromResult(false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return Task.FromResult(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task OnReadyAsync()
|
public async Task OnReadyAsync()
|
||||||
@@ -64,7 +71,6 @@ public sealed class CmdCdService : IExecPreCommand, IReadyExecutor, INService
|
|||||||
|
|
||||||
while (await timer.WaitForNextTickAsync())
|
while (await timer.WaitForNextTickAsync())
|
||||||
{
|
{
|
||||||
var now = DateTime.UtcNow;
|
|
||||||
// once per hour delete expired entries
|
// once per hour delete expired entries
|
||||||
foreach (var ((guildId, commandName), dict) in _activeCooldowns)
|
foreach (var ((guildId, commandName), dict) in _activeCooldowns)
|
||||||
{
|
{
|
||||||
@@ -85,7 +91,7 @@ public sealed class CmdCdService : IExecPreCommand, IReadyExecutor, INService
|
|||||||
private void Cleanup(ConcurrentDictionary<ulong, DateTime> dict, int cdSeconds)
|
private void Cleanup(ConcurrentDictionary<ulong, DateTime> dict, int cdSeconds)
|
||||||
{
|
{
|
||||||
var now = DateTime.UtcNow;
|
var now = DateTime.UtcNow;
|
||||||
foreach (var (key, _) in dict.Where(x => (now - x.Value).Seconds > cdSeconds).ToArray())
|
foreach (var (key, _) in dict.Where(x => (now - x.Value).TotalSeconds > cdSeconds).ToArray())
|
||||||
{
|
{
|
||||||
dict.TryRemove(key, out _);
|
dict.TryRemove(key, out _);
|
||||||
}
|
}
|
||||||
@@ -97,16 +103,34 @@ public sealed class CmdCdService : IExecPreCommand, IReadyExecutor, INService
|
|||||||
dict.TryRemove(cmdName, out _);
|
dict.TryRemove(cmdName, out _);
|
||||||
|
|
||||||
_activeCooldowns.TryRemove((guildId, cmdName), out _);
|
_activeCooldowns.TryRemove((guildId, cmdName), out _);
|
||||||
|
|
||||||
|
using var ctx = _db.GetDbContext();
|
||||||
|
var gc = ctx.GuildConfigsForId(guildId, x => x.Include(x => x.CommandCooldowns));
|
||||||
|
gc.CommandCooldowns.RemoveWhere(x => x.CommandName == cmdName);
|
||||||
|
ctx.SaveChanges();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void AddCooldown(ulong guildId, string name, int secs)
|
public void AddCooldown(ulong guildId, string name, int secs)
|
||||||
{
|
{
|
||||||
|
if (secs <= 0)
|
||||||
|
throw new ArgumentOutOfRangeException(nameof(secs));
|
||||||
|
|
||||||
var sett = _settings.GetOrAdd(guildId, static _ => new());
|
var sett = _settings.GetOrAdd(guildId, static _ => new());
|
||||||
sett[name] = secs;
|
sett[name] = secs;
|
||||||
|
|
||||||
// force cleanup
|
// force cleanup
|
||||||
if (_activeCooldowns.TryGetValue((guildId, name), out var dict))
|
if (_activeCooldowns.TryGetValue((guildId, name), out var dict))
|
||||||
Cleanup(dict, secs);
|
Cleanup(dict, secs);
|
||||||
|
|
||||||
|
using var ctx = _db.GetDbContext();
|
||||||
|
var gc = ctx.GuildConfigsForId(guildId, x => x.Include(x => x.CommandCooldowns));
|
||||||
|
gc.CommandCooldowns.RemoveWhere(x => x.CommandName == name);
|
||||||
|
gc.CommandCooldowns.Add(new()
|
||||||
|
{
|
||||||
|
Seconds = secs,
|
||||||
|
CommandName = name
|
||||||
|
});
|
||||||
|
ctx.SaveChanges();
|
||||||
}
|
}
|
||||||
|
|
||||||
public IReadOnlyCollection<(string CommandName, int Seconds)> GetCommandCooldowns(ulong guildId)
|
public IReadOnlyCollection<(string CommandName, int Seconds)> GetCommandCooldowns(ulong guildId)
|
||||||
|
@@ -25,6 +25,47 @@ public partial class Permissions
|
|||||||
await ReplyConfirmLocalizedAsync(strs.fw_cleared);
|
await ReplyConfirmLocalizedAsync(strs.fw_cleared);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Cmd]
|
||||||
|
[RequireContext(ContextType.Guild)]
|
||||||
|
public async Task FilterList()
|
||||||
|
{
|
||||||
|
var embed = _eb.Create(ctx)
|
||||||
|
.WithOkColor()
|
||||||
|
.WithTitle("Server filter settings");
|
||||||
|
|
||||||
|
var config = await _service.GetFilterSettings(ctx.Guild.Id);
|
||||||
|
|
||||||
|
string GetEnabledEmoji(bool value)
|
||||||
|
=> value ? "\\🟢" : "\\🔴";
|
||||||
|
|
||||||
|
async Task<string> GetChannelListAsync(IReadOnlyCollection<ulong> channels)
|
||||||
|
{
|
||||||
|
var toReturn = (await channels
|
||||||
|
.Select(async cid =>
|
||||||
|
{
|
||||||
|
var ch = await ctx.Guild.GetChannelAsync(cid);
|
||||||
|
return ch is null
|
||||||
|
? $"{cid} *missing*"
|
||||||
|
: $"<#{cid}>";
|
||||||
|
})
|
||||||
|
.WhenAll())
|
||||||
|
.Join('\n');
|
||||||
|
|
||||||
|
if (string.IsNullOrWhiteSpace(toReturn))
|
||||||
|
return GetText(strs.no_channel_found);
|
||||||
|
|
||||||
|
return toReturn;
|
||||||
|
}
|
||||||
|
|
||||||
|
embed.AddField($"{GetEnabledEmoji(config.FilterLinksEnabled)} Filter Links",
|
||||||
|
await GetChannelListAsync(config.FilterLinksChannels));
|
||||||
|
|
||||||
|
embed.AddField($"{GetEnabledEmoji(config.FilterInvitesEnabled)} Filter Invites",
|
||||||
|
await GetChannelListAsync(config.FilterInvitesChannels));
|
||||||
|
|
||||||
|
await ctx.Channel.EmbedAsync(embed);
|
||||||
|
}
|
||||||
|
|
||||||
[Cmd]
|
[Cmd]
|
||||||
[RequireContext(ContextType.Guild)]
|
[RequireContext(ContextType.Guild)]
|
||||||
public async Task SrvrFilterInv()
|
public async Task SrvrFilterInv()
|
||||||
|
@@ -1,4 +1,5 @@
|
|||||||
#nullable disable
|
#nullable disable
|
||||||
|
using AngleSharp.Dom;
|
||||||
using Microsoft.EntityFrameworkCore;
|
using Microsoft.EntityFrameworkCore;
|
||||||
using NadekoBot.Common.ModuleBehaviors;
|
using NadekoBot.Common.ModuleBehaviors;
|
||||||
using NadekoBot.Db;
|
using NadekoBot.Db;
|
||||||
@@ -222,4 +223,20 @@ public sealed class FilterService : IExecOnMessage
|
|||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public async Task<ServerFilterSettings> GetFilterSettings(ulong guildId)
|
||||||
|
{
|
||||||
|
await using var uow = _db.GetDbContext();
|
||||||
|
var gc = uow.GuildConfigsForId(guildId, set => set
|
||||||
|
.Include(x => x.FilterInvitesChannelIds)
|
||||||
|
.Include(x => x.FilterLinksChannelIds));
|
||||||
|
|
||||||
|
return new()
|
||||||
|
{
|
||||||
|
FilterInvitesChannels = gc.FilterInvitesChannelIds.Map(x => x.ChannelId),
|
||||||
|
FilterLinksChannels = gc.FilterLinksChannelIds.Map(x => x.ChannelId),
|
||||||
|
FilterInvitesEnabled = gc.FilterInvites,
|
||||||
|
FilterLinksEnabled = gc.FilterLinks,
|
||||||
|
};
|
||||||
|
}
|
||||||
}
|
}
|
@@ -0,0 +1,10 @@
|
|||||||
|
#nullable disable
|
||||||
|
namespace NadekoBot.Modules.Permissions.Services;
|
||||||
|
|
||||||
|
public readonly struct ServerFilterSettings
|
||||||
|
{
|
||||||
|
public bool FilterInvitesEnabled { get; init; }
|
||||||
|
public bool FilterLinksEnabled { get; init; }
|
||||||
|
public IReadOnlyCollection<ulong> FilterInvitesChannels { get; init; }
|
||||||
|
public IReadOnlyCollection<ulong> FilterLinksChannels { get; init; }
|
||||||
|
}
|
@@ -32,33 +32,43 @@ public partial class Searches
|
|||||||
[UserPerm(GuildPerm.ManageMessages)]
|
[UserPerm(GuildPerm.ManageMessages)]
|
||||||
public async Task Feed(string url, [Leftover] ITextChannel channel = null)
|
public async Task Feed(string url, [Leftover] ITextChannel channel = null)
|
||||||
{
|
{
|
||||||
var success = Uri.TryCreate(url, UriKind.Absolute, out var uri)
|
if (!Uri.TryCreate(url, UriKind.Absolute, out var uri)
|
||||||
&& (uri.Scheme == Uri.UriSchemeHttp || uri.Scheme == Uri.UriSchemeHttps);
|
|| (uri.Scheme != Uri.UriSchemeHttp && uri.Scheme != Uri.UriSchemeHttps))
|
||||||
if (success)
|
|
||||||
{
|
{
|
||||||
channel ??= (ITextChannel)ctx.Channel;
|
await ReplyErrorLocalizedAsync(strs.feed_invalid_url);
|
||||||
try
|
return;
|
||||||
{
|
|
||||||
await FeedReader.ReadAsync(url);
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
Log.Information(ex, "Unable to get feeds from that url");
|
|
||||||
success = false;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (success)
|
channel ??= (ITextChannel)ctx.Channel;
|
||||||
|
try
|
||||||
{
|
{
|
||||||
success = _service.AddFeed(ctx.Guild.Id, channel.Id, url);
|
await FeedReader.ReadAsync(url);
|
||||||
if (success)
|
}
|
||||||
{
|
catch (Exception ex)
|
||||||
await ReplyConfirmLocalizedAsync(strs.feed_added);
|
{
|
||||||
return;
|
Log.Information(ex, "Unable to get feeds from that url");
|
||||||
}
|
await ReplyErrorLocalizedAsync(strs.feed_cant_parse);
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
await ReplyConfirmLocalizedAsync(strs.feed_not_valid);
|
var result = _service.AddFeed(ctx.Guild.Id, channel.Id, url);
|
||||||
|
if (result == FeedAddResult.Success)
|
||||||
|
{
|
||||||
|
await ReplyConfirmLocalizedAsync(strs.feed_added);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (result == FeedAddResult.Duplicate)
|
||||||
|
{
|
||||||
|
await ReplyErrorLocalizedAsync(strs.feed_duplicate);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (result == FeedAddResult.LimitReached)
|
||||||
|
{
|
||||||
|
await ReplyErrorLocalizedAsync(strs.feed_limit_reached);
|
||||||
|
return;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
[Cmd]
|
[Cmd]
|
||||||
|
@@ -207,7 +207,7 @@ public class FeedsService : INService
|
|||||||
.ToList();
|
.ToList();
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool AddFeed(ulong guildId, ulong channelId, string rssFeed)
|
public FeedAddResult AddFeed(ulong guildId, ulong channelId, string rssFeed)
|
||||||
{
|
{
|
||||||
ArgumentNullException.ThrowIfNull(rssFeed, nameof(rssFeed));
|
ArgumentNullException.ThrowIfNull(rssFeed, nameof(rssFeed));
|
||||||
|
|
||||||
@@ -221,9 +221,9 @@ public class FeedsService : INService
|
|||||||
var gc = uow.GuildConfigsForId(guildId, set => set.Include(x => x.FeedSubs));
|
var gc = uow.GuildConfigsForId(guildId, set => set.Include(x => x.FeedSubs));
|
||||||
|
|
||||||
if (gc.FeedSubs.Any(x => x.Url.ToLower() == fs.Url.ToLower()))
|
if (gc.FeedSubs.Any(x => x.Url.ToLower() == fs.Url.ToLower()))
|
||||||
return false;
|
return FeedAddResult.Duplicate;
|
||||||
if (gc.FeedSubs.Count >= 10)
|
if (gc.FeedSubs.Count >= 10)
|
||||||
return false;
|
return FeedAddResult.LimitReached;
|
||||||
|
|
||||||
gc.FeedSubs.Add(fs);
|
gc.FeedSubs.Add(fs);
|
||||||
uow.SaveChanges();
|
uow.SaveChanges();
|
||||||
@@ -242,7 +242,7 @@ public class FeedsService : INService
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return FeedAddResult.Success;
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool RemoveFeed(ulong guildId, int index)
|
public bool RemoveFeed(ulong guildId, int index)
|
||||||
@@ -271,3 +271,11 @@ public class FeedsService : INService
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public enum FeedAddResult
|
||||||
|
{
|
||||||
|
Success,
|
||||||
|
LimitReached,
|
||||||
|
Invalid,
|
||||||
|
Duplicate,
|
||||||
|
}
|
@@ -9,7 +9,7 @@ namespace NadekoBot.Modules.Utility;
|
|||||||
public partial class Utility
|
public partial class Utility
|
||||||
{
|
{
|
||||||
[Group]
|
[Group]
|
||||||
public partial class CommandMapCommands : NadekoModule<CommandMapService>
|
public partial class CommandMapCommands : NadekoModule<AliasService>
|
||||||
{
|
{
|
||||||
private readonly DbService _db;
|
private readonly DbService _db;
|
||||||
private readonly DiscordSocketClient _client;
|
private readonly DiscordSocketClient _client;
|
@@ -6,15 +6,14 @@ using NadekoBot.Services.Database.Models;
|
|||||||
|
|
||||||
namespace NadekoBot.Modules.Utility.Services;
|
namespace NadekoBot.Modules.Utility.Services;
|
||||||
|
|
||||||
public class CommandMapService : IInputTransformer, INService
|
public class AliasService : IInputTransformer, INService
|
||||||
{
|
{
|
||||||
public ConcurrentDictionary<ulong, ConcurrentDictionary<string, string>> AliasMaps { get; } = new();
|
public ConcurrentDictionary<ulong, ConcurrentDictionary<string, string>> AliasMaps { get; } = new();
|
||||||
private readonly IEmbedBuilderService _eb;
|
private readonly IEmbedBuilderService _eb;
|
||||||
|
|
||||||
private readonly DbService _db;
|
private readonly DbService _db;
|
||||||
|
|
||||||
//commandmap
|
public AliasService(DiscordSocketClient client, DbService db, IEmbedBuilderService eb)
|
||||||
public CommandMapService(DiscordSocketClient client, DbService db, IEmbedBuilderService eb)
|
|
||||||
{
|
{
|
||||||
_eb = eb;
|
_eb = eb;
|
||||||
|
|
||||||
@@ -66,7 +65,10 @@ public class CommandMapService : IInputTransformer, INService
|
|||||||
}
|
}
|
||||||
else if (input.StartsWith(k + ' ', StringComparison.OrdinalIgnoreCase))
|
else if (input.StartsWith(k + ' ', StringComparison.OrdinalIgnoreCase))
|
||||||
{
|
{
|
||||||
newInput = v + ' ' + input[k.Length..];
|
if (v.Contains("%target%"))
|
||||||
|
newInput = v.Replace("%target%", input[k.Length..]);
|
||||||
|
else
|
||||||
|
newInput = v + ' ' + input[k.Length..];
|
||||||
}
|
}
|
||||||
|
|
||||||
if (newInput is not null)
|
if (newInput is not null)
|
||||||
@@ -74,17 +76,11 @@ public class CommandMapService : IInputTransformer, INService
|
|||||||
try
|
try
|
||||||
{
|
{
|
||||||
var toDelete = await channel.SendConfirmAsync(_eb, $"{input} => {newInput}");
|
var toDelete = await channel.SendConfirmAsync(_eb, $"{input} => {newInput}");
|
||||||
_ = Task.Run(async () =>
|
toDelete.DeleteAfter(1.5f);
|
||||||
{
|
|
||||||
await Task.Delay(1500);
|
|
||||||
await toDelete.DeleteAsync(new()
|
|
||||||
{
|
|
||||||
RetryMode = RetryMode.AlwaysRetry
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
catch
|
catch
|
||||||
{
|
{
|
||||||
|
// ignored
|
||||||
}
|
}
|
||||||
|
|
||||||
return newInput;
|
return newInput;
|
||||||
@@ -92,34 +88,6 @@ public class CommandMapService : IInputTransformer, INService
|
|||||||
}
|
}
|
||||||
|
|
||||||
return null;
|
return null;
|
||||||
|
|
||||||
// var keys = maps.Keys.OrderByDescending(x => x.Length);
|
|
||||||
// foreach (var k in keys)
|
|
||||||
// {
|
|
||||||
// string newInput;
|
|
||||||
// if (input.StartsWith(k + " ", StringComparison.InvariantCultureIgnoreCase))
|
|
||||||
// newInput = maps[k] + input.Substring(k.Length, input.Length - k.Length);
|
|
||||||
// else if (input.Equals(k, StringComparison.InvariantCultureIgnoreCase))
|
|
||||||
// newInput = maps[k];
|
|
||||||
// else
|
|
||||||
// continue;
|
|
||||||
//
|
|
||||||
// try
|
|
||||||
// {
|
|
||||||
// var toDelete = await channel.SendConfirmAsync(_eb, $"{input} => {newInput}");
|
|
||||||
// _ = Task.Run(async () =>
|
|
||||||
// {
|
|
||||||
// await Task.Delay(1500);
|
|
||||||
// await toDelete.DeleteAsync(new()
|
|
||||||
// {
|
|
||||||
// RetryMode = RetryMode.AlwaysRetry
|
|
||||||
// });
|
|
||||||
// });
|
|
||||||
// }
|
|
||||||
// catch { }
|
|
||||||
//
|
|
||||||
// return newInput;
|
|
||||||
// }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return null;
|
return null;
|
@@ -1,24 +1,24 @@
|
|||||||
#nullable disable
|
#nullable disable
|
||||||
|
using System.Globalization;
|
||||||
using LinqToDB;
|
using LinqToDB;
|
||||||
using LinqToDB.EntityFrameworkCore;
|
using LinqToDB.EntityFrameworkCore;
|
||||||
using NadekoBot.Common.ModuleBehaviors;
|
using NadekoBot.Common.ModuleBehaviors;
|
||||||
using NadekoBot.Services.Database.Models;
|
using NadekoBot.Services.Database.Models;
|
||||||
using System.Text.RegularExpressions;
|
using System.Text.RegularExpressions;
|
||||||
using Nadeko.Common;
|
|
||||||
|
|
||||||
namespace NadekoBot.Modules.Utility.Services;
|
namespace NadekoBot.Modules.Utility.Services;
|
||||||
|
|
||||||
public class RemindService : INService, IReadyExecutor
|
public class RemindService : INService, IReadyExecutor
|
||||||
{
|
{
|
||||||
private readonly Regex _regex =
|
private readonly Regex _regex =
|
||||||
new(
|
new(@"^(?:(?:at|on(?:\sthe)?)?\s*(?<date>(?:\d{2}:\d{2}\s)?\d{1,2}\.\d{1,2}(?:\.\d{2,4})?)|(?:in\s?)?\s*(?:(?<mo>\d+)(?:\s?(?:months?|mos?),?))?(?:(?:\sand\s|\s*)?(?<w>\d+)(?:\s?(?:weeks?|w),?))?(?:(?:\sand\s|\s*)?(?<d>\d+)(?:\s?(?:days?|d),?))?(?:(?:\sand\s|\s*)?(?<h>\d+)(?:\s?(?:hours?|h),?))?(?:(?:\sand\s|\s*)?(?<m>\d+)(?:\s?(?:minutes?|mins?|m),?))?)\s+(?:to:?\s+)?(?<what>(?:\r\n|[\r\n]|.)+)",
|
||||||
@"^(?:in\s?)?\s*(?:(?<mo>\d+)(?:\s?(?:months?|mos?),?))?(?:(?:\sand\s|\s*)?(?<w>\d+)(?:\s?(?:weeks?|w),?))?(?:(?:\sand\s|\s*)?(?<d>\d+)(?:\s?(?:days?|d),?))?(?:(?:\sand\s|\s*)?(?<h>\d+)(?:\s?(?:hours?|h),?))?(?:(?:\sand\s|\s*)?(?<m>\d+)(?:\s?(?:minutes?|mins?|m),?))?\s+(?:to:?\s+)?(?<what>(?:\r\n|[\r\n]|.)+)",
|
|
||||||
RegexOptions.Compiled | RegexOptions.Multiline);
|
RegexOptions.Compiled | RegexOptions.Multiline);
|
||||||
|
|
||||||
private readonly DiscordSocketClient _client;
|
private readonly DiscordSocketClient _client;
|
||||||
private readonly DbService _db;
|
private readonly DbService _db;
|
||||||
private readonly IBotCredentials _creds;
|
private readonly IBotCredentials _creds;
|
||||||
private readonly IEmbedBuilderService _eb;
|
private readonly IEmbedBuilderService _eb;
|
||||||
|
private readonly CultureInfo _culture;
|
||||||
|
|
||||||
public RemindService(
|
public RemindService(
|
||||||
DiscordSocketClient client,
|
DiscordSocketClient client,
|
||||||
@@ -30,6 +30,15 @@ public class RemindService : INService, IReadyExecutor
|
|||||||
_db = db;
|
_db = db;
|
||||||
_creds = creds;
|
_creds = creds;
|
||||||
_eb = eb;
|
_eb = eb;
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
_culture = new CultureInfo("en-GB");
|
||||||
|
}
|
||||||
|
catch
|
||||||
|
{
|
||||||
|
_culture = CultureInfo.InvariantCulture;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task OnReadyAsync()
|
public async Task OnReadyAsync()
|
||||||
@@ -105,32 +114,57 @@ public class RemindService : INService, IReadyExecutor
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
foreach (var groupName in _regex.GetGroupNames())
|
TimeSpan ts;
|
||||||
|
|
||||||
|
var dateString = m.Groups["date"].Value;
|
||||||
|
if (!string.IsNullOrWhiteSpace(dateString))
|
||||||
{
|
{
|
||||||
if (groupName is "0" or "what")
|
var now = DateTime.UtcNow;
|
||||||
continue;
|
|
||||||
if (string.IsNullOrWhiteSpace(m.Groups[groupName].Value))
|
|
||||||
{
|
|
||||||
values[groupName] = 0;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!int.TryParse(m.Groups[groupName].Value, out var value))
|
if (!DateTime.TryParse(dateString, _culture, DateTimeStyles.None, out var dt))
|
||||||
{
|
{
|
||||||
Log.Warning("Reminder regex group {GroupName} has invalid value", groupName);
|
Log.Warning("Invalid remind datetime format");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (value < 1)
|
if (now >= dt)
|
||||||
{
|
{
|
||||||
Log.Warning("Reminder time value has to be an integer greater than 0");
|
Log.Warning("That remind time has already passed");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
values[groupName] = value;
|
ts = dt - now;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
foreach (var groupName in _regex.GetGroupNames())
|
||||||
|
{
|
||||||
|
if (groupName is "0" or "what")
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (string.IsNullOrWhiteSpace(m.Groups[groupName].Value))
|
||||||
|
{
|
||||||
|
values[groupName] = 0;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!int.TryParse(m.Groups[groupName].Value, out var value))
|
||||||
|
{
|
||||||
|
Log.Warning("Reminder regex group {GroupName} has invalid value", groupName);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (value < 1)
|
||||||
|
{
|
||||||
|
Log.Warning("Reminder time value has to be an integer greater than 0");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
values[groupName] = value;
|
||||||
|
}
|
||||||
|
ts = new TimeSpan((30 * values["mo"]) + (7 * values["w"]) + values["d"], values["h"], values["m"], 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
var ts = new TimeSpan((30 * values["mo"]) + (7 * values["w"]) + values["d"], values["h"], values["m"], 0);
|
|
||||||
|
|
||||||
obj = new()
|
obj = new()
|
||||||
{
|
{
|
||||||
|
@@ -17,11 +17,14 @@ public partial class Xp
|
|||||||
[Cmd]
|
[Cmd]
|
||||||
public async Task ClubTransfer([Leftover] IUser newOwner)
|
public async Task ClubTransfer([Leftover] IUser newOwner)
|
||||||
{
|
{
|
||||||
var club = _service.TransferClub(ctx.User, newOwner);
|
var result = _service.TransferClub(ctx.User, newOwner);
|
||||||
|
|
||||||
if (club is null)
|
if (!result.TryPickT0(out var club, out var error))
|
||||||
{
|
{
|
||||||
await ReplyErrorLocalizedAsync(strs.club_transfer_failed);
|
if(error == ClubTransferError.NotOwner)
|
||||||
|
await ReplyErrorLocalizedAsync(strs.club_owner_only);
|
||||||
|
else
|
||||||
|
await ReplyErrorLocalizedAsync(strs.club_target_not_member);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@@ -37,15 +40,20 @@ public partial class Xp
|
|||||||
[Cmd]
|
[Cmd]
|
||||||
public async Task ClubAdmin([Leftover] IUser toAdmin)
|
public async Task ClubAdmin([Leftover] IUser toAdmin)
|
||||||
{
|
{
|
||||||
var admin = await _service.ToggleAdminAsync(ctx.User, toAdmin);
|
var result = await _service.ToggleAdminAsync(ctx.User, toAdmin);
|
||||||
|
|
||||||
if (admin is null)
|
if (result == ToggleAdminResult.AddedAdmin)
|
||||||
await ReplyErrorLocalizedAsync(strs.club_admin_error);
|
|
||||||
else if (admin is true)
|
|
||||||
await ReplyConfirmLocalizedAsync(strs.club_admin_add(Format.Bold(toAdmin.ToString())));
|
await ReplyConfirmLocalizedAsync(strs.club_admin_add(Format.Bold(toAdmin.ToString())));
|
||||||
else
|
else if (result == ToggleAdminResult.RemovedAdmin)
|
||||||
await ReplyConfirmLocalizedAsync(strs.club_admin_remove(Format.Bold(toAdmin.ToString())));
|
await ReplyConfirmLocalizedAsync(strs.club_admin_remove(Format.Bold(toAdmin.ToString())));
|
||||||
|
else if (result == ToggleAdminResult.NotOwner)
|
||||||
|
await ReplyErrorLocalizedAsync(strs.club_owner_only);
|
||||||
|
else if (result == ToggleAdminResult.CantTargetThyself)
|
||||||
|
await ReplyErrorLocalizedAsync(strs.club_admin_invalid_target);
|
||||||
|
else if (result == ToggleAdminResult.TargetNotMember)
|
||||||
|
await ReplyErrorLocalizedAsync(strs.club_target_not_member);
|
||||||
}
|
}
|
||||||
|
|
||||||
[Cmd]
|
[Cmd]
|
||||||
public async Task ClubCreate([Leftover] string clubName)
|
public async Task ClubCreate([Leftover] string clubName)
|
||||||
{
|
{
|
||||||
@@ -55,17 +63,23 @@ public partial class Xp
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
var succ = await _service.CreateClubAsync(ctx.User, clubName);
|
var result = await _service.CreateClubAsync(ctx.User, clubName);
|
||||||
|
|
||||||
if (succ is null)
|
if (result == ClubCreateResult.NameTaken)
|
||||||
{
|
{
|
||||||
await ReplyErrorLocalizedAsync(strs.club_create_error_name);
|
await ReplyErrorLocalizedAsync(strs.club_create_error_name);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (succ is false)
|
if (result == ClubCreateResult.InsufficientLevel)
|
||||||
{
|
{
|
||||||
await ReplyErrorLocalizedAsync(strs.club_create_error);
|
await ReplyErrorLocalizedAsync(strs.club_create_insuff_lvl);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (result == ClubCreateResult.AlreadyInAClub)
|
||||||
|
{
|
||||||
|
await ReplyErrorLocalizedAsync(strs.club_already_in);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -75,14 +89,21 @@ public partial class Xp
|
|||||||
[Cmd]
|
[Cmd]
|
||||||
public async Task ClubIcon([Leftover] string url = null)
|
public async Task ClubIcon([Leftover] string url = null)
|
||||||
{
|
{
|
||||||
if ((!Uri.IsWellFormedUriString(url, UriKind.Absolute) && url is not null)
|
if ((!Uri.IsWellFormedUriString(url, UriKind.Absolute) && url is not null))
|
||||||
|| !await _service.SetClubIconAsync(ctx.User.Id, url))
|
|
||||||
{
|
{
|
||||||
await ReplyErrorLocalizedAsync(strs.club_icon_error);
|
await ReplyErrorLocalizedAsync(strs.club_icon_url_format);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
await ReplyConfirmLocalizedAsync(strs.club_icon_set);
|
var result = await _service.SetClubIconAsync(ctx.User.Id, url);
|
||||||
|
if(result == SetClubIconResult.Success)
|
||||||
|
await ReplyConfirmLocalizedAsync(strs.club_icon_set);
|
||||||
|
else if (result == SetClubIconResult.NotOwner)
|
||||||
|
await ReplyErrorLocalizedAsync(strs.club_owner_only);
|
||||||
|
else if (result == SetClubIconResult.TooLarge)
|
||||||
|
await ReplyErrorLocalizedAsync(strs.club_icon_too_large);
|
||||||
|
else if (result == SetClubIconResult.InvalidFileType)
|
||||||
|
await ReplyErrorLocalizedAsync(strs.club_icon_invalid_filetype);
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task InternalClubInfoAsync(ClubInfo club)
|
private async Task InternalClubInfoAsync(ClubInfo club)
|
||||||
@@ -102,27 +123,27 @@ public partial class Xp
|
|||||||
page =>
|
page =>
|
||||||
{
|
{
|
||||||
var embed = _eb.Create()
|
var embed = _eb.Create()
|
||||||
.WithOkColor()
|
.WithOkColor()
|
||||||
.WithTitle($"{club}")
|
.WithTitle($"{club}")
|
||||||
.WithDescription(GetText(strs.level_x(lvl.Level + $" ({club.Xp} xp)")))
|
.WithDescription(GetText(strs.level_x(lvl.Level + $" ({club.Xp} xp)")))
|
||||||
.AddField(GetText(strs.desc),
|
.AddField(GetText(strs.desc),
|
||||||
string.IsNullOrWhiteSpace(club.Description) ? "-" : club.Description)
|
string.IsNullOrWhiteSpace(club.Description) ? "-" : club.Description)
|
||||||
.AddField(GetText(strs.owner), club.Owner.ToString(), true)
|
.AddField(GetText(strs.owner), club.Owner.ToString(), true)
|
||||||
// .AddField(GetText(strs.level_req), club.MinimumLevelReq.ToString(), true)
|
// .AddField(GetText(strs.level_req), club.MinimumLevelReq.ToString(), true)
|
||||||
.AddField(GetText(strs.members),
|
.AddField(GetText(strs.members),
|
||||||
string.Join("\n",
|
string.Join("\n",
|
||||||
users.Skip(page * 10)
|
users.Skip(page * 10)
|
||||||
.Take(10)
|
.Take(10)
|
||||||
.Select(x =>
|
.Select(x =>
|
||||||
{
|
{
|
||||||
var l = new LevelStats(x.TotalXp);
|
var l = new LevelStats(x.TotalXp);
|
||||||
var lvlStr = Format.Bold($" ⟪{l.Level}⟫");
|
var lvlStr = Format.Bold($" ⟪{l.Level}⟫");
|
||||||
if (club.OwnerId == x.Id)
|
if (club.OwnerId == x.Id)
|
||||||
return x + "🌟" + lvlStr;
|
return x + "🌟" + lvlStr;
|
||||||
if (x.IsClubAdmin)
|
if (x.IsClubAdmin)
|
||||||
return x + "⭐" + lvlStr;
|
return x + "⭐" + lvlStr;
|
||||||
return x + lvlStr;
|
return x + lvlStr;
|
||||||
})));
|
})));
|
||||||
|
|
||||||
if (Uri.IsWellFormedUriString(club.ImageUrl, UriKind.Absolute))
|
if (Uri.IsWellFormedUriString(club.ImageUrl, UriKind.Absolute))
|
||||||
return embed.WithThumbnailUrl(club.ImageUrl);
|
return embed.WithThumbnailUrl(club.ImageUrl);
|
||||||
@@ -175,19 +196,21 @@ public partial class Xp
|
|||||||
|
|
||||||
var club = _service.GetClubWithBansAndApplications(ctx.User.Id);
|
var club = _service.GetClubWithBansAndApplications(ctx.User.Id);
|
||||||
if (club is null)
|
if (club is null)
|
||||||
return ReplyErrorLocalizedAsync(strs.club_not_exists_owner);
|
return ReplyErrorLocalizedAsync(strs.club_admin_perms);
|
||||||
|
|
||||||
var bans = club.Bans.Select(x => x.User).ToArray();
|
var bans = club.Bans.Select(x => x.User).ToArray();
|
||||||
|
|
||||||
return ctx.SendPaginatedConfirmAsync(page,
|
return ctx.SendPaginatedConfirmAsync(page,
|
||||||
_ =>
|
_ =>
|
||||||
{
|
{
|
||||||
var toShow = string.Join("\n", bans.Skip(page * 10).Take(10).Select(x => x.ToString()));
|
var toShow = string.Join("\n", bans
|
||||||
|
.Skip(page * 10).Take(10)
|
||||||
|
.Select(x => x.ToString()));
|
||||||
|
|
||||||
return _eb.Create()
|
return _eb.Create()
|
||||||
.WithTitle(GetText(strs.club_bans_for(club.ToString())))
|
.WithTitle(GetText(strs.club_bans_for(club.ToString())))
|
||||||
.WithDescription(toShow)
|
.WithDescription(toShow)
|
||||||
.WithOkColor();
|
.WithOkColor();
|
||||||
},
|
},
|
||||||
bans.Length,
|
bans.Length,
|
||||||
10);
|
10);
|
||||||
@@ -201,7 +224,7 @@ public partial class Xp
|
|||||||
|
|
||||||
var club = _service.GetClubWithBansAndApplications(ctx.User.Id);
|
var club = _service.GetClubWithBansAndApplications(ctx.User.Id);
|
||||||
if (club is null)
|
if (club is null)
|
||||||
return ReplyErrorLocalizedAsync(strs.club_not_exists_owner);
|
return ReplyErrorLocalizedAsync(strs.club_admin_perms);
|
||||||
|
|
||||||
var apps = club.Applicants.Select(x => x.User).ToArray();
|
var apps = club.Applicants.Select(x => x.User).ToArray();
|
||||||
|
|
||||||
@@ -211,9 +234,9 @@ public partial class Xp
|
|||||||
var toShow = string.Join("\n", apps.Skip(page * 10).Take(10).Select(x => x.ToString()));
|
var toShow = string.Join("\n", apps.Skip(page * 10).Take(10).Select(x => x.ToString()));
|
||||||
|
|
||||||
return _eb.Create()
|
return _eb.Create()
|
||||||
.WithTitle(GetText(strs.club_apps_for(club.ToString())))
|
.WithTitle(GetText(strs.club_apps_for(club.ToString())))
|
||||||
.WithDescription(toShow)
|
.WithDescription(toShow)
|
||||||
.WithOkColor();
|
.WithOkColor();
|
||||||
},
|
},
|
||||||
apps.Length,
|
apps.Length,
|
||||||
10);
|
10);
|
||||||
@@ -231,10 +254,15 @@ public partial class Xp
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (_service.ApplyToClub(ctx.User, club))
|
var result = _service.ApplyToClub(ctx.User, club);
|
||||||
|
if (result == ClubApplyResult.Success)
|
||||||
await ReplyConfirmLocalizedAsync(strs.club_applied(Format.Bold(club.ToString())));
|
await ReplyConfirmLocalizedAsync(strs.club_applied(Format.Bold(club.ToString())));
|
||||||
else
|
else if (result == ClubApplyResult.Banned)
|
||||||
await ReplyErrorLocalizedAsync(strs.club_apply_error);
|
await ReplyErrorLocalizedAsync(strs.club_join_banned);
|
||||||
|
else if (result == ClubApplyResult.InsufficientLevel)
|
||||||
|
await ReplyErrorLocalizedAsync(strs.club_insuff_lvl);
|
||||||
|
else if (result == ClubApplyResult.AlreadyInAClub)
|
||||||
|
await ReplyErrorLocalizedAsync(strs.club_already_in);
|
||||||
}
|
}
|
||||||
|
|
||||||
[Cmd]
|
[Cmd]
|
||||||
@@ -246,19 +274,26 @@ public partial class Xp
|
|||||||
[Priority(0)]
|
[Priority(0)]
|
||||||
public async Task ClubAccept([Leftover] string userName)
|
public async Task ClubAccept([Leftover] string userName)
|
||||||
{
|
{
|
||||||
if (_service.AcceptApplication(ctx.User.Id, userName, out var discordUser))
|
var result = _service.AcceptApplication(ctx.User.Id, userName, out var discordUser);
|
||||||
|
if (result == ClubAcceptResult.Accepted)
|
||||||
await ReplyConfirmLocalizedAsync(strs.club_accepted(Format.Bold(discordUser.ToString())));
|
await ReplyConfirmLocalizedAsync(strs.club_accepted(Format.Bold(discordUser.ToString())));
|
||||||
else
|
else if(result == ClubAcceptResult.NoSuchApplicant)
|
||||||
await ReplyErrorLocalizedAsync(strs.club_accept_error);
|
await ReplyErrorLocalizedAsync(strs.club_accept_invalid_applicant);
|
||||||
|
else if(result == ClubAcceptResult.NotOwnerOrAdmin)
|
||||||
|
await ReplyErrorLocalizedAsync(strs.club_admin_perms);
|
||||||
}
|
}
|
||||||
|
|
||||||
[Cmd]
|
[Cmd]
|
||||||
public async Task Clubleave()
|
public async Task ClubLeave()
|
||||||
{
|
{
|
||||||
if (_service.LeaveClub(ctx.User))
|
var res = _service.LeaveClub(ctx.User);
|
||||||
|
|
||||||
|
if (res == ClubLeaveResult.Success)
|
||||||
await ReplyConfirmLocalizedAsync(strs.club_left);
|
await ReplyConfirmLocalizedAsync(strs.club_left);
|
||||||
|
else if (res == ClubLeaveResult.NotInAClub)
|
||||||
|
await ReplyErrorLocalizedAsync(strs.club_not_in_a_club);
|
||||||
else
|
else
|
||||||
await ReplyErrorLocalizedAsync(strs.club_not_in_club);
|
await ReplyErrorLocalizedAsync(strs.club_owner_cant_leave);
|
||||||
}
|
}
|
||||||
|
|
||||||
[Cmd]
|
[Cmd]
|
||||||
@@ -270,13 +305,20 @@ public partial class Xp
|
|||||||
[Priority(0)]
|
[Priority(0)]
|
||||||
public Task ClubKick([Leftover] string userName)
|
public Task ClubKick([Leftover] string userName)
|
||||||
{
|
{
|
||||||
if (_service.Kick(ctx.User.Id, userName, out var club))
|
var result = _service.Kick(ctx.User.Id, userName, out var club);
|
||||||
|
if(result == ClubKickResult.Success)
|
||||||
{
|
{
|
||||||
return ReplyConfirmLocalizedAsync(strs.club_user_kick(Format.Bold(userName),
|
return ReplyConfirmLocalizedAsync(strs.club_user_kick(Format.Bold(userName),
|
||||||
Format.Bold(club.ToString())));
|
Format.Bold(club.ToString())));
|
||||||
}
|
}
|
||||||
|
|
||||||
return ReplyErrorLocalizedAsync(strs.club_user_kick_fail);
|
if (result == ClubKickResult.Hierarchy)
|
||||||
|
return ReplyErrorLocalizedAsync(strs.club_kick_hierarchy);
|
||||||
|
|
||||||
|
if (result == ClubKickResult.NotOwnerOrAdmin)
|
||||||
|
return ReplyErrorLocalizedAsync(strs.club_admin_perms);
|
||||||
|
|
||||||
|
return ReplyErrorLocalizedAsync(strs.club_target_not_member);
|
||||||
}
|
}
|
||||||
|
|
||||||
[Cmd]
|
[Cmd]
|
||||||
@@ -288,13 +330,20 @@ public partial class Xp
|
|||||||
[Priority(0)]
|
[Priority(0)]
|
||||||
public Task ClubBan([Leftover] string userName)
|
public Task ClubBan([Leftover] string userName)
|
||||||
{
|
{
|
||||||
if (_service.Ban(ctx.User.Id, userName, out var club))
|
var result = _service.Ban(ctx.User.Id, userName, out var club);
|
||||||
|
if (result == ClubBanResult.Success)
|
||||||
{
|
{
|
||||||
return ReplyConfirmLocalizedAsync(strs.club_user_banned(Format.Bold(userName),
|
return ReplyConfirmLocalizedAsync(strs.club_user_banned(Format.Bold(userName),
|
||||||
Format.Bold(club.ToString())));
|
Format.Bold(club.ToString())));
|
||||||
}
|
}
|
||||||
|
|
||||||
return ReplyErrorLocalizedAsync(strs.club_user_ban_fail);
|
if (result == ClubBanResult.Unbannable)
|
||||||
|
return ReplyErrorLocalizedAsync(strs.club_ban_fail_unbannable);
|
||||||
|
|
||||||
|
if (result == ClubBanResult.WrongUser)
|
||||||
|
return ReplyErrorLocalizedAsync(strs.club_ban_fail_user_not_found);
|
||||||
|
|
||||||
|
return ReplyErrorLocalizedAsync(strs.club_admin_perms);
|
||||||
}
|
}
|
||||||
|
|
||||||
[Cmd]
|
[Cmd]
|
||||||
@@ -306,13 +355,20 @@ public partial class Xp
|
|||||||
[Priority(0)]
|
[Priority(0)]
|
||||||
public Task ClubUnBan([Leftover] string userName)
|
public Task ClubUnBan([Leftover] string userName)
|
||||||
{
|
{
|
||||||
if (_service.UnBan(ctx.User.Id, userName, out var club))
|
var result = _service.UnBan(ctx.User.Id, userName, out var club);
|
||||||
|
|
||||||
|
if (result == ClubUnbanResult.Success)
|
||||||
{
|
{
|
||||||
return ReplyConfirmLocalizedAsync(strs.club_user_unbanned(Format.Bold(userName),
|
return ReplyConfirmLocalizedAsync(strs.club_user_unbanned(Format.Bold(userName),
|
||||||
Format.Bold(club.ToString())));
|
Format.Bold(club.ToString())));
|
||||||
}
|
}
|
||||||
|
|
||||||
return ReplyErrorLocalizedAsync(strs.club_user_unban_fail);
|
if (result == ClubUnbanResult.WrongUser)
|
||||||
|
{
|
||||||
|
return ReplyErrorLocalizedAsync(strs.club_unban_fail_user_not_found);
|
||||||
|
}
|
||||||
|
|
||||||
|
return ReplyErrorLocalizedAsync(strs.club_admin_perms);
|
||||||
}
|
}
|
||||||
|
|
||||||
[Cmd]
|
[Cmd]
|
||||||
@@ -325,10 +381,10 @@ public partial class Xp
|
|||||||
: desc;
|
: desc;
|
||||||
|
|
||||||
var eb = _eb.Create(ctx)
|
var eb = _eb.Create(ctx)
|
||||||
.WithAuthor(ctx.User)
|
.WithAuthor(ctx.User)
|
||||||
.WithTitle(GetText(strs.club_desc_update))
|
.WithTitle(GetText(strs.club_desc_update))
|
||||||
.WithOkColor()
|
.WithOkColor()
|
||||||
.WithDescription(desc);
|
.WithDescription(desc);
|
||||||
|
|
||||||
await ctx.Channel.EmbedAsync(eb);
|
await ctx.Channel.EmbedAsync(eb);
|
||||||
}
|
}
|
||||||
|
@@ -2,9 +2,9 @@
|
|||||||
using LinqToDB;
|
using LinqToDB;
|
||||||
using LinqToDB.EntityFrameworkCore;
|
using LinqToDB.EntityFrameworkCore;
|
||||||
using Microsoft.EntityFrameworkCore;
|
using Microsoft.EntityFrameworkCore;
|
||||||
using Nadeko.Common;
|
|
||||||
using NadekoBot.Db;
|
using NadekoBot.Db;
|
||||||
using NadekoBot.Db.Models;
|
using NadekoBot.Db.Models;
|
||||||
|
using OneOf;
|
||||||
|
|
||||||
namespace NadekoBot.Modules.Xp.Services;
|
namespace NadekoBot.Modules.Xp.Services;
|
||||||
|
|
||||||
@@ -19,7 +19,8 @@ public class ClubService : INService, IClubService
|
|||||||
_httpFactory = httpFactory;
|
_httpFactory = httpFactory;
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<bool?> CreateClubAsync(IUser user, string clubName)
|
|
||||||
|
public async Task<ClubCreateResult> CreateClubAsync(IUser user, string clubName)
|
||||||
{
|
{
|
||||||
//must be lvl 5 and must not be in a club already
|
//must be lvl 5 and must not be in a club already
|
||||||
|
|
||||||
@@ -27,11 +28,14 @@ public class ClubService : INService, IClubService
|
|||||||
var du = uow.GetOrCreateUser(user);
|
var du = uow.GetOrCreateUser(user);
|
||||||
var xp = new LevelStats(du.TotalXp);
|
var xp = new LevelStats(du.TotalXp);
|
||||||
|
|
||||||
if (xp.Level < 5 || du.ClubId is not null)
|
if (xp.Level < 5)
|
||||||
return false;
|
return ClubCreateResult.InsufficientLevel;
|
||||||
|
|
||||||
|
if (du.ClubId is not null)
|
||||||
|
return ClubCreateResult.AlreadyInAClub;
|
||||||
|
|
||||||
if (await uow.Clubs.AnyAsyncEF(x => x.Name == clubName))
|
if (await uow.Clubs.AnyAsyncEF(x => x.Name == clubName))
|
||||||
return null;
|
return ClubCreateResult.NameTaken;
|
||||||
|
|
||||||
du.IsClubAdmin = true;
|
du.IsClubAdmin = true;
|
||||||
du.Club = new()
|
du.Club = new()
|
||||||
@@ -45,17 +49,20 @@ public class ClubService : INService, IClubService
|
|||||||
await uow.GetTable<ClubApplicants>()
|
await uow.GetTable<ClubApplicants>()
|
||||||
.DeleteAsync(x => x.UserId == du.Id);
|
.DeleteAsync(x => x.UserId == du.Id);
|
||||||
|
|
||||||
return true;
|
return ClubCreateResult.Success;
|
||||||
}
|
}
|
||||||
|
|
||||||
public ClubInfo TransferClub(IUser from, IUser newOwner)
|
public OneOf<ClubInfo, ClubTransferError> TransferClub(IUser from, IUser newOwner)
|
||||||
{
|
{
|
||||||
using var uow = _db.GetDbContext();
|
using var uow = _db.GetDbContext();
|
||||||
var club = uow.Clubs.GetByOwner(@from.Id);
|
var club = uow.Clubs.GetByOwner(@from.Id);
|
||||||
var newOwnerUser = uow.GetOrCreateUser(newOwner);
|
var newOwnerUser = uow.GetOrCreateUser(newOwner);
|
||||||
|
|
||||||
if (club is null || club.Owner.UserId != from.Id || !club.Members.Contains(newOwnerUser))
|
if (club is null || club.Owner.UserId != from.Id)
|
||||||
return null;
|
return ClubTransferError.NotOwner;
|
||||||
|
|
||||||
|
if (!club.Members.Contains(newOwnerUser))
|
||||||
|
return ClubTransferError.TargetNotMember;
|
||||||
|
|
||||||
club.Owner.IsClubAdmin = true; // old owner will stay as admin
|
club.Owner.IsClubAdmin = true; // old owner will stay as admin
|
||||||
newOwnerUser.IsClubAdmin = true;
|
newOwnerUser.IsClubAdmin = true;
|
||||||
@@ -64,21 +71,24 @@ public class ClubService : INService, IClubService
|
|||||||
return club;
|
return club;
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<bool?> ToggleAdminAsync(IUser owner, IUser toAdmin)
|
public async Task<ToggleAdminResult> ToggleAdminAsync(IUser owner, IUser toAdmin)
|
||||||
{
|
{
|
||||||
|
if (owner.Id == toAdmin.Id)
|
||||||
|
return ToggleAdminResult.CantTargetThyself;
|
||||||
|
|
||||||
await using var uow = _db.GetDbContext();
|
await using var uow = _db.GetDbContext();
|
||||||
var club = uow.Clubs.GetByOwner(owner.Id);
|
var club = uow.Clubs.GetByOwner(owner.Id);
|
||||||
var adminUser = uow.GetOrCreateUser(toAdmin);
|
var adminUser = uow.GetOrCreateUser(toAdmin);
|
||||||
|
|
||||||
if (club is null || club.Owner.UserId != owner.Id || !club.Members.Contains(adminUser))
|
if (club is null)
|
||||||
return null;
|
return ToggleAdminResult.NotOwner;
|
||||||
|
|
||||||
if (club.OwnerId == adminUser.Id)
|
if(!club.Members.Contains(adminUser))
|
||||||
return true;
|
return ToggleAdminResult.TargetNotMember;
|
||||||
|
|
||||||
var newState = adminUser.IsClubAdmin = !adminUser.IsClubAdmin;
|
var newState = adminUser.IsClubAdmin = !adminUser.IsClubAdmin;
|
||||||
await uow.SaveChangesAsync();
|
await uow.SaveChangesAsync();
|
||||||
return newState;
|
return newState ? ToggleAdminResult.AddedAdmin : ToggleAdminResult.RemovedAdmin;
|
||||||
}
|
}
|
||||||
|
|
||||||
public ClubInfo GetClubByMember(IUser user)
|
public ClubInfo GetClubByMember(IUser user)
|
||||||
@@ -88,26 +98,30 @@ public class ClubService : INService, IClubService
|
|||||||
return member;
|
return member;
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<bool> SetClubIconAsync(ulong ownerUserId, string url)
|
public async Task<SetClubIconResult> SetClubIconAsync(ulong ownerUserId, string url)
|
||||||
{
|
{
|
||||||
if (url is not null)
|
if (url is not null)
|
||||||
{
|
{
|
||||||
using var http = _httpFactory.CreateClient();
|
using var http = _httpFactory.CreateClient();
|
||||||
using var temp = await http.GetAsync(url, HttpCompletionOption.ResponseHeadersRead);
|
using var temp = await http.GetAsync(url, HttpCompletionOption.ResponseHeadersRead);
|
||||||
if (!temp.IsImage() || temp.GetContentLength() > 5.Megabytes().Bytes)
|
|
||||||
return false;
|
if (!temp.IsImage())
|
||||||
|
return SetClubIconResult.InvalidFileType;
|
||||||
|
|
||||||
|
if (temp.GetContentLength() > 5.Megabytes().Bytes)
|
||||||
|
return SetClubIconResult.TooLarge;
|
||||||
}
|
}
|
||||||
|
|
||||||
await using var uow = _db.GetDbContext();
|
await using var uow = _db.GetDbContext();
|
||||||
var club = uow.Clubs.GetByOwner(ownerUserId);
|
var club = uow.Clubs.GetByOwner(ownerUserId);
|
||||||
|
|
||||||
if (club is null)
|
if (club is null)
|
||||||
return false;
|
return SetClubIconResult.NotOwner;
|
||||||
|
|
||||||
club.ImageUrl = url;
|
club.ImageUrl = url;
|
||||||
await uow.SaveChangesAsync();
|
await uow.SaveChangesAsync();
|
||||||
|
|
||||||
return true;
|
return SetClubIconResult.Success;
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool GetClubByName(string clubName, out ClubInfo club)
|
public bool GetClubByName(string clubName, out ClubInfo club)
|
||||||
@@ -118,18 +132,22 @@ public class ClubService : INService, IClubService
|
|||||||
return club is not null;
|
return club is not null;
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool ApplyToClub(IUser user, ClubInfo club)
|
public ClubApplyResult ApplyToClub(IUser user, ClubInfo club)
|
||||||
{
|
{
|
||||||
using var uow = _db.GetDbContext();
|
using var uow = _db.GetDbContext();
|
||||||
var du = uow.GetOrCreateUser(user);
|
var du = uow.GetOrCreateUser(user);
|
||||||
uow.SaveChanges();
|
uow.SaveChanges();
|
||||||
|
|
||||||
if (du.Club is not null
|
//user banned or a member of a club, or already applied,
|
||||||
|| club.Bans.Any(x => x.UserId == du.Id)
|
// or doesn't min minumum level requirement, can't apply
|
||||||
|| club.Applicants.Any(x => x.UserId == du.Id))
|
if (du.Club is not null)
|
||||||
//user banned or a member of a club, or already applied,
|
return ClubApplyResult.AlreadyInAClub;
|
||||||
// or doesn't min minumum level requirement, can't apply
|
|
||||||
return false;
|
if (club.Bans.Any(x => x.UserId == du.Id))
|
||||||
|
return ClubApplyResult.Banned;
|
||||||
|
|
||||||
|
if (club.Applicants.Any(x => x.UserId == du.Id))
|
||||||
|
return ClubApplyResult.InsufficientLevel;
|
||||||
|
|
||||||
var app = new ClubApplicants
|
var app = new ClubApplicants
|
||||||
{
|
{
|
||||||
@@ -138,23 +156,23 @@ public class ClubService : INService, IClubService
|
|||||||
};
|
};
|
||||||
|
|
||||||
uow.Set<ClubApplicants>().Add(app);
|
uow.Set<ClubApplicants>().Add(app);
|
||||||
|
|
||||||
uow.SaveChanges();
|
uow.SaveChanges();
|
||||||
return true;
|
return ClubApplyResult.Success;
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool AcceptApplication(ulong clubOwnerUserId, string userName, out DiscordUser discordUser)
|
|
||||||
|
public ClubAcceptResult AcceptApplication(ulong clubOwnerUserId, string userName, out DiscordUser discordUser)
|
||||||
{
|
{
|
||||||
discordUser = null;
|
discordUser = null;
|
||||||
using var uow = _db.GetDbContext();
|
using var uow = _db.GetDbContext();
|
||||||
var club = uow.Clubs.GetByOwnerOrAdmin(clubOwnerUserId);
|
var club = uow.Clubs.GetByOwnerOrAdmin(clubOwnerUserId);
|
||||||
if (club is null)
|
if (club is null)
|
||||||
return false;
|
return ClubAcceptResult.NotOwnerOrAdmin;
|
||||||
|
|
||||||
var applicant =
|
var applicant =
|
||||||
club.Applicants.FirstOrDefault(x => x.User.ToString().ToUpperInvariant() == userName.ToUpperInvariant());
|
club.Applicants.FirstOrDefault(x => x.User.ToString().ToUpperInvariant() == userName.ToUpperInvariant());
|
||||||
if (applicant is null)
|
if (applicant is null)
|
||||||
return false;
|
return ClubAcceptResult.NoSuchApplicant;
|
||||||
|
|
||||||
applicant.User.Club = club;
|
applicant.User.Club = club;
|
||||||
applicant.User.IsClubAdmin = false;
|
applicant.User.IsClubAdmin = false;
|
||||||
@@ -166,7 +184,7 @@ public class ClubService : INService, IClubService
|
|||||||
|
|
||||||
discordUser = applicant.User;
|
discordUser = applicant.User;
|
||||||
uow.SaveChanges();
|
uow.SaveChanges();
|
||||||
return true;
|
return ClubAcceptResult.Accepted;
|
||||||
}
|
}
|
||||||
|
|
||||||
public ClubInfo GetClubWithBansAndApplications(ulong ownerUserId)
|
public ClubInfo GetClubWithBansAndApplications(ulong ownerUserId)
|
||||||
@@ -175,17 +193,19 @@ public class ClubService : INService, IClubService
|
|||||||
return uow.Clubs.GetByOwnerOrAdmin(ownerUserId);
|
return uow.Clubs.GetByOwnerOrAdmin(ownerUserId);
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool LeaveClub(IUser user)
|
public ClubLeaveResult LeaveClub(IUser user)
|
||||||
{
|
{
|
||||||
using var uow = _db.GetDbContext();
|
using var uow = _db.GetDbContext();
|
||||||
var du = uow.GetOrCreateUser(user, x => x.Include(u => u.Club));
|
var du = uow.GetOrCreateUser(user, x => x.Include(u => u.Club));
|
||||||
if (du.Club is null || du.Club.OwnerId == du.Id)
|
if (du.Club is null)
|
||||||
return false;
|
return ClubLeaveResult.NotInAClub;
|
||||||
|
if (du.Club.OwnerId == du.Id)
|
||||||
|
return ClubLeaveResult.OwnerCantLeave;
|
||||||
|
|
||||||
du.Club = null;
|
du.Club = null;
|
||||||
du.IsClubAdmin = false;
|
du.IsClubAdmin = false;
|
||||||
uow.SaveChanges();
|
uow.SaveChanges();
|
||||||
return true;
|
return ClubLeaveResult.Success;
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool SetDescription(ulong userId, string desc)
|
public bool SetDescription(ulong userId, string desc)
|
||||||
@@ -213,23 +233,23 @@ public class ClubService : INService, IClubService
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool Ban(ulong bannerId, string userName, out ClubInfo club)
|
public ClubBanResult Ban(ulong bannerId, string userName, out ClubInfo club)
|
||||||
{
|
{
|
||||||
using var uow = _db.GetDbContext();
|
using var uow = _db.GetDbContext();
|
||||||
club = uow.Clubs.GetByOwnerOrAdmin(bannerId);
|
club = uow.Clubs.GetByOwnerOrAdmin(bannerId);
|
||||||
if (club is null)
|
if (club is null)
|
||||||
return false;
|
return ClubBanResult.NotOwnerOrAdmin;
|
||||||
|
|
||||||
var usr = club.Members.FirstOrDefault(x => x.ToString().ToUpperInvariant() == userName.ToUpperInvariant())
|
var usr = club.Members.FirstOrDefault(x => x.ToString().ToUpperInvariant() == userName.ToUpperInvariant())
|
||||||
?? club.Applicants
|
?? club.Applicants
|
||||||
.FirstOrDefault(x => x.User.ToString().ToUpperInvariant() == userName.ToUpperInvariant())
|
.FirstOrDefault(x => x.User.ToString().ToUpperInvariant() == userName.ToUpperInvariant())
|
||||||
?.User;
|
?.User;
|
||||||
if (usr is null)
|
if (usr is null)
|
||||||
return false;
|
return ClubBanResult.WrongUser;
|
||||||
|
|
||||||
if (club.OwnerId == usr.Id
|
if (club.OwnerId == usr.Id
|
||||||
|| (usr.IsClubAdmin && club.Owner.UserId != bannerId)) // can't ban the owner kek, whew
|
|| (usr.IsClubAdmin && club.Owner.UserId != bannerId)) // can't ban the owner kek, whew
|
||||||
return false;
|
return ClubBanResult.Unbannable;
|
||||||
|
|
||||||
club.Bans.Add(new()
|
club.Bans.Add(new()
|
||||||
{
|
{
|
||||||
@@ -244,39 +264,40 @@ public class ClubService : INService, IClubService
|
|||||||
|
|
||||||
uow.SaveChanges();
|
uow.SaveChanges();
|
||||||
|
|
||||||
return true;
|
return ClubBanResult.Success;
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool UnBan(ulong ownerUserId, string userName, out ClubInfo club)
|
public ClubUnbanResult UnBan(ulong ownerUserId, string userName, out ClubInfo club)
|
||||||
{
|
{
|
||||||
using var uow = _db.GetDbContext();
|
using var uow = _db.GetDbContext();
|
||||||
club = uow.Clubs.GetByOwnerOrAdmin(ownerUserId);
|
club = uow.Clubs.GetByOwnerOrAdmin(ownerUserId);
|
||||||
if (club is null)
|
if (club is null)
|
||||||
return false;
|
return ClubUnbanResult.NotOwnerOrAdmin;
|
||||||
|
|
||||||
var ban = club.Bans.FirstOrDefault(x => x.User.ToString().ToUpperInvariant() == userName.ToUpperInvariant());
|
var ban = club.Bans.FirstOrDefault(x => x.User.ToString().ToUpperInvariant() == userName.ToUpperInvariant());
|
||||||
if (ban is null)
|
if (ban is null)
|
||||||
return false;
|
return ClubUnbanResult.WrongUser;
|
||||||
|
|
||||||
club.Bans.Remove(ban);
|
club.Bans.Remove(ban);
|
||||||
uow.SaveChanges();
|
uow.SaveChanges();
|
||||||
|
|
||||||
return true;
|
return ClubUnbanResult.Success;
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool Kick(ulong kickerId, string userName, out ClubInfo club)
|
|
||||||
|
public ClubKickResult Kick(ulong kickerId, string userName, out ClubInfo club)
|
||||||
{
|
{
|
||||||
using var uow = _db.GetDbContext();
|
using var uow = _db.GetDbContext();
|
||||||
club = uow.Clubs.GetByOwnerOrAdmin(kickerId);
|
club = uow.Clubs.GetByOwnerOrAdmin(kickerId);
|
||||||
if (club is null)
|
if (club is null)
|
||||||
return false;
|
return ClubKickResult.NotOwnerOrAdmin;
|
||||||
|
|
||||||
var usr = club.Members.FirstOrDefault(x => x.ToString().ToUpperInvariant() == userName.ToUpperInvariant());
|
var usr = club.Members.FirstOrDefault(x => x.ToString().ToUpperInvariant() == userName.ToUpperInvariant());
|
||||||
if (usr is null)
|
if (usr is null)
|
||||||
return false;
|
return ClubKickResult.TargetNotAMember;
|
||||||
|
|
||||||
if (club.OwnerId == usr.Id || (usr.IsClubAdmin && club.Owner.UserId != kickerId))
|
if (club.OwnerId == usr.Id || (usr.IsClubAdmin && club.Owner.UserId != kickerId))
|
||||||
return false;
|
return ClubKickResult.Hierarchy;
|
||||||
|
|
||||||
club.Members.Remove(usr);
|
club.Members.Remove(usr);
|
||||||
var app = club.Applicants.FirstOrDefault(x => x.UserId == usr.Id);
|
var app = club.Applicants.FirstOrDefault(x => x.UserId == usr.Id);
|
||||||
@@ -284,7 +305,7 @@ public class ClubService : INService, IClubService
|
|||||||
club.Applicants.Remove(app);
|
club.Applicants.Remove(app);
|
||||||
uow.SaveChanges();
|
uow.SaveChanges();
|
||||||
|
|
||||||
return true;
|
return ClubKickResult.Success;
|
||||||
}
|
}
|
||||||
|
|
||||||
public List<ClubInfo> GetClubLeaderboardPage(int page)
|
public List<ClubInfo> GetClubLeaderboardPage(int page)
|
||||||
|
@@ -1,23 +1,33 @@
|
|||||||
using NadekoBot.Db.Models;
|
using NadekoBot.Db.Models;
|
||||||
|
using OneOf;
|
||||||
|
|
||||||
namespace NadekoBot.Modules.Xp.Services;
|
namespace NadekoBot.Modules.Xp.Services;
|
||||||
|
|
||||||
public interface IClubService
|
public interface IClubService
|
||||||
{
|
{
|
||||||
Task<bool?> CreateClubAsync(IUser user, string clubName);
|
Task<ClubCreateResult> CreateClubAsync(IUser user, string clubName);
|
||||||
ClubInfo? TransferClub(IUser from, IUser newOwner);
|
OneOf<ClubInfo,ClubTransferError> TransferClub(IUser from, IUser newOwner);
|
||||||
Task<bool?> ToggleAdminAsync(IUser owner, IUser toAdmin);
|
Task<ToggleAdminResult> ToggleAdminAsync(IUser owner, IUser toAdmin);
|
||||||
ClubInfo? GetClubByMember(IUser user);
|
ClubInfo? GetClubByMember(IUser user);
|
||||||
Task<bool> SetClubIconAsync(ulong ownerUserId, string? url);
|
Task<SetClubIconResult> SetClubIconAsync(ulong ownerUserId, string? url);
|
||||||
bool GetClubByName(string clubName, out ClubInfo club);
|
bool GetClubByName(string clubName, out ClubInfo club);
|
||||||
bool ApplyToClub(IUser user, ClubInfo club);
|
ClubApplyResult ApplyToClub(IUser user, ClubInfo club);
|
||||||
bool AcceptApplication(ulong clubOwnerUserId, string userName, out DiscordUser discordUser);
|
ClubAcceptResult AcceptApplication(ulong clubOwnerUserId, string userName, out DiscordUser discordUser);
|
||||||
ClubInfo? GetClubWithBansAndApplications(ulong ownerUserId);
|
ClubInfo? GetClubWithBansAndApplications(ulong ownerUserId);
|
||||||
bool LeaveClub(IUser user);
|
ClubLeaveResult LeaveClub(IUser user);
|
||||||
bool SetDescription(ulong userId, string? desc);
|
bool SetDescription(ulong userId, string? desc);
|
||||||
bool Disband(ulong userId, out ClubInfo club);
|
bool Disband(ulong userId, out ClubInfo club);
|
||||||
bool Ban(ulong bannerId, string userName, out ClubInfo club);
|
ClubBanResult Ban(ulong bannerId, string userName, out ClubInfo club);
|
||||||
bool UnBan(ulong ownerUserId, string userName, out ClubInfo club);
|
ClubUnbanResult UnBan(ulong ownerUserId, string userName, out ClubInfo club);
|
||||||
bool Kick(ulong kickerId, string userName, out ClubInfo club);
|
ClubKickResult Kick(ulong kickerId, string userName, out ClubInfo club);
|
||||||
List<ClubInfo> GetClubLeaderboardPage(int page);
|
List<ClubInfo> GetClubLeaderboardPage(int page);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public enum ClubApplyResult
|
||||||
|
{
|
||||||
|
Success,
|
||||||
|
|
||||||
|
AlreadyInAClub,
|
||||||
|
Banned,
|
||||||
|
InsufficientLevel
|
||||||
|
}
|
@@ -0,0 +1,8 @@
|
|||||||
|
namespace NadekoBot.Modules.Xp.Services;
|
||||||
|
|
||||||
|
public enum ClubAcceptResult
|
||||||
|
{
|
||||||
|
Accepted,
|
||||||
|
NotOwnerOrAdmin,
|
||||||
|
NoSuchApplicant,
|
||||||
|
}
|
10
src/NadekoBot/Modules/Xp/Club/Results/ClubBanResult.cs
Normal file
10
src/NadekoBot/Modules/Xp/Club/Results/ClubBanResult.cs
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
namespace NadekoBot.Modules.Xp.Services;
|
||||||
|
|
||||||
|
public enum ClubBanResult
|
||||||
|
{
|
||||||
|
Success,
|
||||||
|
NotOwnerOrAdmin,
|
||||||
|
WrongUser,
|
||||||
|
Unbannable,
|
||||||
|
|
||||||
|
}
|
@@ -0,0 +1,9 @@
|
|||||||
|
namespace NadekoBot.Modules.Xp.Services;
|
||||||
|
|
||||||
|
public enum ClubCreateResult
|
||||||
|
{
|
||||||
|
Success,
|
||||||
|
AlreadyInAClub,
|
||||||
|
NameTaken,
|
||||||
|
InsufficientLevel,
|
||||||
|
}
|
9
src/NadekoBot/Modules/Xp/Club/Results/ClubKickResult.cs
Normal file
9
src/NadekoBot/Modules/Xp/Club/Results/ClubKickResult.cs
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
namespace NadekoBot.Modules.Xp.Services;
|
||||||
|
|
||||||
|
public enum ClubKickResult
|
||||||
|
{
|
||||||
|
Success,
|
||||||
|
NotOwnerOrAdmin,
|
||||||
|
TargetNotAMember,
|
||||||
|
Hierarchy
|
||||||
|
}
|
8
src/NadekoBot/Modules/Xp/Club/Results/ClubLeaveResult.cs
Normal file
8
src/NadekoBot/Modules/Xp/Club/Results/ClubLeaveResult.cs
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
namespace NadekoBot.Modules.Xp.Services;
|
||||||
|
|
||||||
|
public enum ClubLeaveResult
|
||||||
|
{
|
||||||
|
Success,
|
||||||
|
OwnerCantLeave,
|
||||||
|
NotInAClub
|
||||||
|
}
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user