mirror of
https://gitlab.com/Kwoth/nadekobot.git
synced 2025-09-10 09:18:27 -04:00
Compare commits
101 Commits
Author | SHA1 | Date | |
---|---|---|---|
|
e036a2d3c9 | ||
|
62a16f3faf | ||
|
231451f978 | ||
|
2bed4e7eac | ||
|
22eea3fa7b | ||
|
8b1767078e | ||
|
6654ccdad5 | ||
|
99827b0fa1 | ||
|
0451551ddf | ||
|
75d0eb631d | ||
|
96ce7e23bb | ||
|
aac475be62 | ||
|
55fae53f6d | ||
|
879f196f8b | ||
|
796086538a | ||
|
3178074828 | ||
|
0a9d53d380 | ||
|
d7fbf44d53 | ||
|
cdd07d0559 | ||
|
80a41c1f38 | ||
|
1631394638 | ||
|
7eb4895570 | ||
|
9b55028ba6 | ||
|
53363d2840 | ||
|
ca5a870bf8 | ||
|
7f5e065c4d | ||
|
86b214163a | ||
|
9dbb08d85f | ||
|
89ca56c77c | ||
|
9e96679099 | ||
|
1280d2b397 | ||
|
c731127607 | ||
|
c15930306a | ||
|
701501d678 | ||
|
fa12fcea58 | ||
|
274219c40b | ||
|
96c9b47da2 | ||
|
b5d1469df1 | ||
|
d7747bd25a | ||
|
7d162d1f04 | ||
|
704d061d46 | ||
|
c39c9061fd | ||
|
619ddba4f8 | ||
|
3acef04b32 | ||
|
83a1d959b1 | ||
|
a1632722bc | ||
|
ee0a28afab | ||
|
2b301c0aab | ||
|
b6b6b4e19e | ||
|
32fc8b6e03 | ||
|
297e2fde0e | ||
|
729f26caab | ||
|
4b12e4e923 | ||
|
12f4ce7f2a | ||
|
00944e08c3 | ||
|
569abd7194 | ||
|
474a1db41d | ||
|
0f6255947e | ||
|
f68f219a25 | ||
|
8f16b11d02 | ||
|
df5eced904 | ||
|
1dcd158f43 | ||
|
757c9b564d | ||
|
07cef3eb5e | ||
|
85c525e19b | ||
|
477581f616 | ||
|
ff30105816 | ||
|
49f04a594b | ||
|
716090a132 | ||
|
c835514c7b | ||
|
b136e7ff0e | ||
|
9dd2997b0f | ||
|
fde5309ea4 | ||
|
a8e4173e9b | ||
|
74b4c4b64d | ||
|
6cc5a160a2 | ||
|
ca8e022db6 | ||
|
cd8c14c607 | ||
|
1340533c21 | ||
|
14d86b9042 | ||
|
3a504a954f | ||
|
822ce0b8de | ||
|
40490a4656 | ||
|
0cf7909fef | ||
|
de8d4b7d9e | ||
|
0123892038 | ||
|
d00e59567a | ||
|
0aba2fdcaf | ||
|
bb910a8188 | ||
|
bdad9cc17a | ||
|
5d76a15dc0 | ||
|
a7be56a562 | ||
|
3c108e531e | ||
|
c473669cbc | ||
|
b97c486b80 | ||
|
716e092fd0 | ||
|
a362ee90fc | ||
|
1de6cdb8dc | ||
|
f473014fe9 | ||
|
2c3e5fe507 | ||
|
ecc192c6a9 |
908
CHANGELOG.md
908
CHANGELOG.md
File diff suppressed because it is too large
Load Diff
@@ -30,6 +30,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Nadeko.Medusa", "src\Nadeko
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "NadekoBot.Generators", "src\NadekoBot.Generators\NadekoBot.Generators.csproj", "{92770AF3-83EE-49F1-A0BB-79124D19A13D}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "NadekoBot.GrpcApiBase", "src\NadekoBot.GrpcApiBase\NadekoBot.GrpcApiBase.csproj", "{FB74B9EA-10B9-4542-ACB1-35523A95A587}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|Any CPU = Debug|Any CPU
|
||||
@@ -79,6 +81,12 @@ Global
|
||||
{92770AF3-83EE-49F1-A0BB-79124D19A13D}.GlobalNadeko|Any CPU.Build.0 = Debug|Any CPU
|
||||
{92770AF3-83EE-49F1-A0BB-79124D19A13D}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{92770AF3-83EE-49F1-A0BB-79124D19A13D}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{FB74B9EA-10B9-4542-ACB1-35523A95A587}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{FB74B9EA-10B9-4542-ACB1-35523A95A587}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{FB74B9EA-10B9-4542-ACB1-35523A95A587}.GlobalNadeko|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{FB74B9EA-10B9-4542-ACB1-35523A95A587}.GlobalNadeko|Any CPU.Build.0 = Debug|Any CPU
|
||||
{FB74B9EA-10B9-4542-ACB1-35523A95A587}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{FB74B9EA-10B9-4542-ACB1-35523A95A587}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
@@ -91,6 +99,7 @@ Global
|
||||
{E685977E-31A4-46F4-A5D7-4E3E39E82E43} = {04929013-5BAB-42B0-B9B2-8F2BB8F16AF2}
|
||||
{92770AF3-83EE-49F1-A0BB-79124D19A13D} = {04929013-5BAB-42B0-B9B2-8F2BB8F16AF2}
|
||||
{2F4CF6D6-0C2F-4944-B204-9508CDA53195} = {04929013-5BAB-42B0-B9B2-8F2BB8F16AF2}
|
||||
{FB74B9EA-10B9-4542-ACB1-35523A95A587} = {04929013-5BAB-42B0-B9B2-8F2BB8F16AF2}
|
||||
EndGlobalSection
|
||||
GlobalSection(ExtensibilityGlobals) = postSolution
|
||||
SolutionGuid = {5F3F555C-855F-4BE8-B526-D062D3E8ACA4}
|
||||
|
@@ -1,4 +0,0 @@
|
||||
dotnet ef migrations remove -c SqliteContext -f -p src/NadekoBot/NadekoBot.csproj
|
||||
dotnet ef migrations remove -c PostgreSqlContext -f -p src/NadekoBot/NadekoBot.csproj
|
||||
dotnet ef migrations remove -c MysqlContext -f -p src/NadekoBot/NadekoBot.csproj
|
||||
|
184
src/NadekoBot.Generators/GrpcApiPermGenerator.cs
Normal file
184
src/NadekoBot.Generators/GrpcApiPermGenerator.cs
Normal file
@@ -0,0 +1,184 @@
|
||||
#nullable enable
|
||||
using System.CodeDom.Compiler;
|
||||
using System.Collections.Immutable;
|
||||
using System.Diagnostics;
|
||||
using System.Text;
|
||||
using Microsoft.CodeAnalysis;
|
||||
using Microsoft.CodeAnalysis.CSharp.Syntax;
|
||||
using Microsoft.CodeAnalysis.Text;
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace NadekoBot.Generators
|
||||
{
|
||||
public readonly record struct MethodPermData
|
||||
{
|
||||
public readonly ImmutableArray<(string Name, string Value)> MethodPerms;
|
||||
public readonly ImmutableArray<string> NoAuthRequired;
|
||||
|
||||
public MethodPermData(ImmutableArray<(string Name, string Value)> methodPerms,
|
||||
ImmutableArray<string> noAuthRequired)
|
||||
{
|
||||
MethodPerms = methodPerms;
|
||||
NoAuthRequired = noAuthRequired;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
[Generator]
|
||||
public class GrpcApiPermGenerator : IIncrementalGenerator
|
||||
{
|
||||
public const string GRPC_API_PERM_ATTRIBUTE =
|
||||
"""
|
||||
namespace NadekoBot.GrpcApi;
|
||||
|
||||
[System.AttributeUsage(System.AttributeTargets.Method)]
|
||||
public class GrpcApiPermAttribute : System.Attribute
|
||||
{
|
||||
public GuildPerm Value { get; }
|
||||
public GrpcApiPermAttribute(GuildPerm value) => Value = value;
|
||||
}
|
||||
""";
|
||||
|
||||
public const string GRPC_NO_AUTH_REQUIRED_ATTRIBUTE =
|
||||
"""
|
||||
namespace NadekoBot.GrpcApi;
|
||||
|
||||
[System.AttributeUsage(System.AttributeTargets.Method)]
|
||||
public class GrpcNoAuthRequiredAttribute : System.Attribute
|
||||
{
|
||||
}
|
||||
""";
|
||||
|
||||
public void Initialize(IncrementalGeneratorInitializationContext context)
|
||||
{
|
||||
context.RegisterPostInitializationOutput(ctx => ctx.AddSource("GrpcApiPermAttribute.cs",
|
||||
SourceText.From(GRPC_API_PERM_ATTRIBUTE, Encoding.UTF8)));
|
||||
|
||||
context.RegisterPostInitializationOutput(ctx => ctx.AddSource("GrpcNoAuthRequiredAttribute.cs",
|
||||
SourceText.From(GRPC_NO_AUTH_REQUIRED_ATTRIBUTE, Encoding.UTF8)));
|
||||
|
||||
var perms = context.SyntaxProvider
|
||||
.ForAttributeWithMetadataName(
|
||||
"NadekoBot.GrpcApi.GrpcApiPermAttribute",
|
||||
predicate: static (s, _) => s is MethodDeclarationSyntax,
|
||||
transform: static (ctx, _) => GetMethodSemanticTargets(ctx.SemanticModel, ctx.TargetNode))
|
||||
.Where(static m => m is not null)
|
||||
.Select(static (x, _) => x!.Value)
|
||||
.Collect();
|
||||
|
||||
|
||||
var all = context.SyntaxProvider
|
||||
.ForAttributeWithMetadataName(
|
||||
"NadekoBot.GrpcApi.GrpcNoAuthRequiredAttribute",
|
||||
predicate: static (s, _) => s is MethodDeclarationSyntax,
|
||||
transform: static (ctx, _) => GetNoAuthMethodName(ctx.SemanticModel, ctx.TargetNode))
|
||||
.Collect()
|
||||
.Combine(perms)
|
||||
.Select((x, _) => new MethodPermData(x.Right, x.Left));
|
||||
|
||||
context.RegisterSourceOutput(all,
|
||||
static (spc, source) => Execute(source, spc));
|
||||
}
|
||||
|
||||
private static string GetNoAuthMethodName(SemanticModel model, SyntaxNode node)
|
||||
=> ((MethodDeclarationSyntax)node).Identifier.Text;
|
||||
|
||||
private static (string Name, string Value)? GetMethodSemanticTargets(SemanticModel model, SyntaxNode node)
|
||||
{
|
||||
var method = (MethodDeclarationSyntax)node;
|
||||
|
||||
var name = method.Identifier.Text;
|
||||
var attr = method.AttributeLists
|
||||
.SelectMany(x => x.Attributes)
|
||||
.FirstOrDefault();
|
||||
|
||||
if (attr is null)
|
||||
return null;
|
||||
|
||||
return (name, attr.ArgumentList?.Arguments[0].ToString() ?? "__missing_perm__");
|
||||
}
|
||||
|
||||
private static void Execute(MethodPermData data, SourceProductionContext ctx)
|
||||
{
|
||||
using (var stringWriter = new StringWriter())
|
||||
using (var sw = new IndentedTextWriter(stringWriter))
|
||||
{
|
||||
sw.WriteLine("using System.Collections.Frozen;");
|
||||
sw.WriteLine();
|
||||
sw.WriteLine("namespace NadekoBot.GrpcApi;");
|
||||
sw.WriteLine();
|
||||
|
||||
sw.WriteLine("public partial class GrpcApiPermsInterceptor");
|
||||
sw.WriteLine("{");
|
||||
|
||||
sw.Indent++;
|
||||
|
||||
sw.WriteLine(
|
||||
"private static FrozenDictionary<string, GuildPerm> _perms = new Dictionary<string, GuildPerm>()");
|
||||
sw.WriteLine("{");
|
||||
|
||||
sw.Indent++;
|
||||
foreach (var field in data.MethodPerms)
|
||||
{
|
||||
sw.WriteLine("{{ \"{0}\", {1} }},", field.Name, field.Value);
|
||||
}
|
||||
|
||||
sw.Indent--;
|
||||
sw.WriteLine("}.ToFrozenDictionary();");
|
||||
|
||||
sw.WriteLine();
|
||||
sw.WriteLine("private static FrozenSet<string> _noAuthRequired = new HashSet<string>()");
|
||||
sw.WriteLine("{");
|
||||
|
||||
sw.Indent++;
|
||||
foreach (var noauth in data.NoAuthRequired)
|
||||
{
|
||||
sw.WriteLine("{{ \"{0}\" }},", noauth);
|
||||
}
|
||||
|
||||
sw.WriteLine("");
|
||||
|
||||
sw.Indent--;
|
||||
sw.WriteLine("}.ToFrozenSet();");
|
||||
|
||||
sw.Indent--;
|
||||
sw.WriteLine("}");
|
||||
|
||||
sw.Flush();
|
||||
ctx.AddSource("GrpcApiInterceptor.g.cs", stringWriter.ToString());
|
||||
}
|
||||
}
|
||||
|
||||
private List<TranslationPair> GetFields(string? dataText)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(dataText))
|
||||
return new();
|
||||
|
||||
Dictionary<string, string> data;
|
||||
try
|
||||
{
|
||||
var output = JsonConvert.DeserializeObject<Dictionary<string, string>>(dataText!);
|
||||
if (output is null)
|
||||
return new();
|
||||
|
||||
data = output;
|
||||
}
|
||||
catch
|
||||
{
|
||||
Debug.WriteLine("Failed parsing responses file.");
|
||||
return new();
|
||||
}
|
||||
|
||||
var list = new List<TranslationPair>();
|
||||
foreach (var entry in data)
|
||||
{
|
||||
list.Add(new(
|
||||
entry.Key,
|
||||
entry.Value
|
||||
));
|
||||
}
|
||||
|
||||
return list;
|
||||
}
|
||||
}
|
||||
}
|
@@ -9,7 +9,7 @@
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.CodeAnalysis.CSharp" Version="4.0.1" PrivateAssets="all" />
|
||||
<PackageReference Include="Microsoft.CodeAnalysis.CSharp" Version="4.4.0" PrivateAssets="all" />
|
||||
<PackageReference Include="Microsoft.CodeAnalysis.Analyzers" Version="3.3.3" PrivateAssets="all" />
|
||||
<PackageReference Include="Newtonsoft.Json" Version="13.0.3" PrivateAssets="all" GeneratePathProperty="true" />
|
||||
</ItemGroup>
|
||||
|
21
src/NadekoBot.GrpcApiBase/NadekoBot.GrpcApiBase.csproj
Normal file
21
src/NadekoBot.GrpcApiBase/NadekoBot.GrpcApiBase.csproj
Normal file
@@ -0,0 +1,21 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net8.0</TargetFramework>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<Nullable>enable</Nullable>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Google.Protobuf" Version="3.28.2" />
|
||||
<PackageReference Include="Grpc" Version="2.46.6" />
|
||||
<PackageReference Include="Grpc.Tools" Version="2.66.0" PrivateAssets="All" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Protobuf Include="protos/*.proto">
|
||||
<GrpcServices>Server</GrpcServices>
|
||||
</Protobuf>
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
47
src/NadekoBot.GrpcApiBase/protos/canvas.proto
Normal file
47
src/NadekoBot.GrpcApiBase/protos/canvas.proto
Normal file
@@ -0,0 +1,47 @@
|
||||
syntax = "proto3";
|
||||
|
||||
option csharp_namespace = "NadekoBot.GrpcApi";
|
||||
|
||||
import "google/protobuf/empty.proto";
|
||||
|
||||
package ncanvas;
|
||||
|
||||
service GrpcNCanvas {
|
||||
rpc GetCanvas(google.protobuf.Empty) returns (CanvasReply);
|
||||
rpc GetPixel(GetPixelRequest) returns (GetPixelReply);
|
||||
rpc SetPixel(SetPixelRequest) returns (SetPixelReply);
|
||||
}
|
||||
|
||||
message CanvasReply {
|
||||
repeated uint32 pixels = 1;
|
||||
int32 width = 2;
|
||||
int32 height = 3;
|
||||
}
|
||||
|
||||
message GetPixelRequest {
|
||||
int32 x = 1;
|
||||
int32 y = 2;
|
||||
}
|
||||
|
||||
message GetPixelReply {
|
||||
string color = 1;
|
||||
uint32 packedColor = 2;
|
||||
int32 positionX = 3;
|
||||
int32 positionY = 4;
|
||||
int64 price = 5;
|
||||
string text = 6;
|
||||
string position = 7;
|
||||
}
|
||||
|
||||
message SetPixelRequest {
|
||||
string position = 1;
|
||||
string color = 2;
|
||||
string text = 3;
|
||||
int64 price = 4;
|
||||
}
|
||||
|
||||
message SetPixelReply {
|
||||
string error = 1;
|
||||
bool success = 2;
|
||||
optional GetPixelReply pixel = 3;
|
||||
}
|
89
src/NadekoBot.GrpcApiBase/protos/exprs.proto
Normal file
89
src/NadekoBot.GrpcApiBase/protos/exprs.proto
Normal file
@@ -0,0 +1,89 @@
|
||||
syntax = "proto3";
|
||||
|
||||
option csharp_namespace = "NadekoBot.GrpcApi";
|
||||
|
||||
import "google/protobuf/empty.proto";
|
||||
|
||||
package exprs;
|
||||
|
||||
service GrpcExprs {
|
||||
rpc GetExprs(GetExprsRequest) returns (GetExprsReply);
|
||||
rpc AddExpr(AddExprRequest) returns (AddExprReply);
|
||||
rpc DeleteExpr(DeleteExprRequest) returns (google.protobuf.Empty);
|
||||
|
||||
rpc GetQuotes(GetQuotesRequest) returns (GetQuotesReply);
|
||||
rpc AddQuote(AddQuoteRequest) returns (AddQuoteReply);
|
||||
rpc DeleteQuote(DeleteQuoteRequest) returns (google.protobuf.Empty);
|
||||
}
|
||||
|
||||
message DeleteExprRequest {
|
||||
string id = 1;
|
||||
uint64 guildId = 2;
|
||||
}
|
||||
|
||||
message GetExprsRequest {
|
||||
uint64 guildId = 1;
|
||||
string query = 2;
|
||||
int32 page = 3;
|
||||
}
|
||||
|
||||
message GetExprsReply {
|
||||
repeated ExprDto expressions = 1;
|
||||
int32 totalCount = 2;
|
||||
}
|
||||
|
||||
message ExprDto {
|
||||
string id = 1;
|
||||
string trigger = 2;
|
||||
string response = 3;
|
||||
|
||||
bool ca = 4;
|
||||
bool ad = 5;
|
||||
bool dm = 6;
|
||||
bool at = 7;
|
||||
}
|
||||
|
||||
message AddExprRequest {
|
||||
uint64 guildId = 1;
|
||||
ExprDto expr = 2;
|
||||
}
|
||||
|
||||
message AddExprReply {
|
||||
string id = 1;
|
||||
bool success = 2;
|
||||
}
|
||||
|
||||
message GetQuotesRequest {
|
||||
uint64 guildId = 1;
|
||||
string query = 2;
|
||||
int32 page = 3;
|
||||
}
|
||||
|
||||
message GetQuotesReply {
|
||||
repeated QuoteDto quotes = 1;
|
||||
int32 totalCount = 2;
|
||||
}
|
||||
|
||||
message QuoteDto {
|
||||
string id = 1;
|
||||
string trigger = 2;
|
||||
string response = 3;
|
||||
|
||||
uint64 authorId = 4;
|
||||
string authorName = 5;
|
||||
}
|
||||
|
||||
message AddQuoteRequest {
|
||||
uint64 guildId = 1;
|
||||
QuoteDto quote = 2;
|
||||
}
|
||||
|
||||
message AddQuoteReply {
|
||||
string id = 1;
|
||||
bool success = 2;
|
||||
}
|
||||
|
||||
message DeleteQuoteRequest {
|
||||
string id = 1;
|
||||
uint64 guildId = 2;
|
||||
}
|
60
src/NadekoBot.GrpcApiBase/protos/fin.proto
Normal file
60
src/NadekoBot.GrpcApiBase/protos/fin.proto
Normal file
@@ -0,0 +1,60 @@
|
||||
syntax = "proto3";
|
||||
|
||||
option csharp_namespace = "NadekoBot.GrpcApi";
|
||||
|
||||
import "google/protobuf/timestamp.proto";
|
||||
|
||||
package fin;
|
||||
|
||||
service GrpcFin {
|
||||
rpc GetTransactions(GetTransactionsRequest) returns (GetTransactionsReply);
|
||||
rpc GetHoldings(GetHoldingsRequest) returns (GetHoldingsReply);
|
||||
rpc Withdraw(WithdrawRequest) returns (WithdrawReply);
|
||||
rpc Deposit(DepositRequest) returns (DepositReply);
|
||||
}
|
||||
|
||||
message GetTransactionsRequest {
|
||||
int32 page = 1;
|
||||
uint64 userId = 2;
|
||||
}
|
||||
|
||||
message GetTransactionsReply {
|
||||
repeated TransactionReply transactions = 1;
|
||||
int32 total = 2;
|
||||
}
|
||||
|
||||
message TransactionReply {
|
||||
int64 amount = 1;
|
||||
string note = 2;
|
||||
string type = 3;
|
||||
string extra = 4;
|
||||
google.protobuf.Timestamp timestamp = 5;
|
||||
string id = 6;
|
||||
}
|
||||
|
||||
message GetHoldingsRequest {
|
||||
uint64 userId = 1;
|
||||
}
|
||||
|
||||
message GetHoldingsReply {
|
||||
int64 cash = 1;
|
||||
int64 bank = 2;
|
||||
}
|
||||
|
||||
message WithdrawRequest {
|
||||
uint64 userId = 1;
|
||||
int64 amount = 2;
|
||||
}
|
||||
|
||||
message WithdrawReply {
|
||||
bool success = 1;
|
||||
}
|
||||
|
||||
message DepositRequest {
|
||||
uint64 userId = 1;
|
||||
int64 amount = 2;
|
||||
}
|
||||
|
||||
message DepositReply {
|
||||
bool success = 1;
|
||||
}
|
51
src/NadekoBot.GrpcApiBase/protos/greet.proto
Normal file
51
src/NadekoBot.GrpcApiBase/protos/greet.proto
Normal file
@@ -0,0 +1,51 @@
|
||||
syntax = "proto3";
|
||||
|
||||
option csharp_namespace = "NadekoBot.GrpcApi";
|
||||
|
||||
package greet;
|
||||
|
||||
service GrpcGreet {
|
||||
rpc GetGreetSettings (GetGreetRequest) returns (GrpcGreetSettings);
|
||||
rpc UpdateGreet (UpdateGreetRequest) returns (UpdateGreetReply);
|
||||
rpc TestGreet (TestGreetRequest) returns (TestGreetReply);
|
||||
}
|
||||
|
||||
message GrpcGreetSettings {
|
||||
string channelId = 1;
|
||||
string message = 2;
|
||||
bool isEnabled = 3;
|
||||
GrpcGreetType type = 4;
|
||||
}
|
||||
|
||||
message GetGreetRequest {
|
||||
uint64 guildId = 1;
|
||||
GrpcGreetType type = 2;
|
||||
}
|
||||
|
||||
message UpdateGreetRequest {
|
||||
uint64 guildId = 1;
|
||||
GrpcGreetSettings settings = 2;
|
||||
}
|
||||
|
||||
enum GrpcGreetType {
|
||||
Greet = 0;
|
||||
GreetDm = 1;
|
||||
Bye = 2;
|
||||
Boost = 3;
|
||||
}
|
||||
|
||||
message UpdateGreetReply {
|
||||
bool Success = 1;
|
||||
}
|
||||
|
||||
message TestGreetRequest {
|
||||
uint64 guildId = 1;
|
||||
uint64 channelId = 2;
|
||||
uint64 userId = 3;
|
||||
GrpcGreetType type = 4;
|
||||
}
|
||||
|
||||
message TestGreetReply {
|
||||
bool success = 1;
|
||||
string error = 2;
|
||||
}
|
144
src/NadekoBot.GrpcApiBase/protos/other.proto
Normal file
144
src/NadekoBot.GrpcApiBase/protos/other.proto
Normal file
@@ -0,0 +1,144 @@
|
||||
syntax = "proto3";
|
||||
|
||||
option csharp_namespace = "NadekoBot.GrpcApi";
|
||||
|
||||
import "google/protobuf/empty.proto";
|
||||
|
||||
package other;
|
||||
|
||||
service GrpcOther {
|
||||
rpc BotOnGuild(BotOnGuildRequest) returns (BotOnGuildReply);
|
||||
rpc GetTextChannels(GetTextChannelsRequest) returns (GetTextChannelsReply);
|
||||
rpc GetRoles(GetRolesRequest) returns (GetRolesReply);
|
||||
|
||||
rpc GetCurrencyLb(GetLbRequest) returns (CurrencyLbReply);
|
||||
rpc GetXpLb(GetLbRequest) returns (XpLbReply);
|
||||
rpc GetWaifuLb(GetLbRequest) returns (WaifuLbReply);
|
||||
|
||||
rpc GetShardStats(google.protobuf.Empty) returns (stream ShardStatsReply);
|
||||
rpc GetCommandFeed(google.protobuf.Empty) returns (stream CommandFeedEntry);
|
||||
rpc GetServerInfo(ServerInfoRequest) returns (GetServerInfoReply);
|
||||
}
|
||||
|
||||
message CommandFeedEntry {
|
||||
string command = 1;
|
||||
}
|
||||
|
||||
message GetRolesRequest {
|
||||
uint64 guildId = 1;
|
||||
}
|
||||
|
||||
message GetRolesReply {
|
||||
repeated RoleReply roles = 1;
|
||||
}
|
||||
|
||||
message BotOnGuildRequest {
|
||||
uint64 guildId = 1;
|
||||
}
|
||||
|
||||
message BotOnGuildReply {
|
||||
bool success = 1;
|
||||
}
|
||||
|
||||
message ShardStatsReply {
|
||||
int32 id = 1;
|
||||
string status = 2;
|
||||
|
||||
int32 guildCount = 3;
|
||||
string uptime = 4;
|
||||
int64 commands = 5;
|
||||
}
|
||||
|
||||
message GetTextChannelsRequest{
|
||||
uint64 guildId = 1;
|
||||
}
|
||||
|
||||
message GetTextChannelsReply {
|
||||
repeated TextChannelReply textChannels = 1;
|
||||
}
|
||||
|
||||
message TextChannelReply {
|
||||
uint64 id = 1;
|
||||
string name = 2;
|
||||
}
|
||||
|
||||
message CurrencyLbReply {
|
||||
repeated CurrencyLbEntryReply entries = 1;
|
||||
}
|
||||
|
||||
message CurrencyLbEntryReply {
|
||||
string user = 1;
|
||||
uint64 userId = 2;
|
||||
int64 amount = 3;
|
||||
string avatar = 4;
|
||||
}
|
||||
|
||||
message GetLbRequest {
|
||||
int32 page = 1;
|
||||
int32 perPage = 2;
|
||||
}
|
||||
|
||||
message XpLbReply {
|
||||
repeated XpLbEntryReply entries = 1;
|
||||
}
|
||||
|
||||
message XpLbEntryReply {
|
||||
string user = 1;
|
||||
uint64 userId = 2;
|
||||
int64 totalXp = 3;
|
||||
int64 level = 4;
|
||||
}
|
||||
|
||||
message WaifuLbReply {
|
||||
repeated WaifuLbEntry entries = 1;
|
||||
}
|
||||
|
||||
message WaifuLbEntry {
|
||||
string user = 1;
|
||||
string claimedBy = 2;
|
||||
int64 value = 3;
|
||||
bool isMutual = 4;
|
||||
}
|
||||
|
||||
message ServerInfoRequest {
|
||||
uint64 guildId = 1;
|
||||
}
|
||||
|
||||
message GetServerInfoReply {
|
||||
uint64 id = 1;
|
||||
string name = 2;
|
||||
string iconUrl = 3;
|
||||
uint64 ownerId = 4;
|
||||
string ownerName = 5;
|
||||
repeated RoleReply roles = 6;
|
||||
repeated EmojiReply emojis = 7;
|
||||
repeated string features = 8;
|
||||
int32 textChannels = 9;
|
||||
int32 voiceChannels = 10;
|
||||
int32 memberCount = 11;
|
||||
int64 createdAt = 12;
|
||||
}
|
||||
|
||||
message RoleReply {
|
||||
uint64 id = 1;
|
||||
string name = 2;
|
||||
string iconUrl = 3;
|
||||
string color = 4;
|
||||
}
|
||||
|
||||
message EmojiReply {
|
||||
string name = 1;
|
||||
string url = 2;
|
||||
string code = 3;
|
||||
}
|
||||
|
||||
message ChannelReply {
|
||||
uint64 id = 1;
|
||||
string name = 2;
|
||||
ChannelType type = 3;
|
||||
}
|
||||
|
||||
enum ChannelType {
|
||||
Text = 0;
|
||||
Voice = 1;
|
||||
}
|
107
src/NadekoBot.GrpcApiBase/protos/warn.proto
Normal file
107
src/NadekoBot.GrpcApiBase/protos/warn.proto
Normal file
@@ -0,0 +1,107 @@
|
||||
syntax = "proto3";
|
||||
|
||||
option csharp_namespace = "NadekoBot.GrpcApi";
|
||||
|
||||
package warn;
|
||||
|
||||
service GrpcWarn {
|
||||
rpc GetWarnSettings (WarnSettingsRequest) returns (WarnSettingsReply);
|
||||
|
||||
rpc SetWarnExpiry(SetWarnExpiryRequest) returns (SetWarnExpiryReply);
|
||||
rpc AddWarnp (AddWarnpRequest) returns (AddWarnpReply);
|
||||
rpc DeleteWarnp (DeleteWarnpRequest) returns (DeleteWarnpReply);
|
||||
|
||||
rpc GetLatestWarnings(GetLatestWarningsRequest) returns (GetLatestWarningsReply);
|
||||
rpc GetUserWarnings(GetUserWarningsRequest) returns (GetUserWarningsReply);
|
||||
|
||||
rpc ForgiveWarning(ForgiveWarningRequest) returns (ForgiveWarningReply);
|
||||
rpc DeleteWarning(ForgiveWarningRequest) returns (ForgiveWarningReply);
|
||||
|
||||
}
|
||||
message WarnSettingsRequest {
|
||||
uint64 guildId = 1;
|
||||
}
|
||||
|
||||
message WarnPunishment {
|
||||
int32 threshold = 1;
|
||||
string action = 2;
|
||||
int32 duration = 3;
|
||||
string role = 4;
|
||||
}
|
||||
|
||||
message WarnSettingsReply {
|
||||
repeated WarnPunishment punishments = 1;
|
||||
int32 expiryDays = 2;
|
||||
bool deleteOnExpire = 3;
|
||||
}
|
||||
|
||||
message AddWarnpRequest {
|
||||
uint64 guildId = 1;
|
||||
WarnPunishment punishment = 2;
|
||||
}
|
||||
|
||||
message AddWarnpReply {
|
||||
bool success = 1;
|
||||
}
|
||||
|
||||
message DeleteWarnpRequest {
|
||||
uint64 guildId = 1;
|
||||
int32 threshold = 2;
|
||||
}
|
||||
|
||||
message DeleteWarnpReply {
|
||||
bool success = 1;
|
||||
}
|
||||
|
||||
message GetUserWarningsRequest {
|
||||
uint64 guildId = 1;
|
||||
string user = 2;
|
||||
int32 page = 3;
|
||||
}
|
||||
|
||||
message GetUserWarningsReply {
|
||||
repeated Warning warnings = 1;
|
||||
int32 totalCount = 2;
|
||||
}
|
||||
|
||||
message Warning {
|
||||
string id = 1;
|
||||
string reason = 2;
|
||||
int64 timestamp = 3;
|
||||
int64 weight = 4;
|
||||
bool forgiven = 5;
|
||||
string forgivenBy = 6;
|
||||
string user = 7;
|
||||
uint64 userId = 8;
|
||||
string moderator = 9;
|
||||
}
|
||||
|
||||
message ForgiveWarningRequest {
|
||||
uint64 guildId = 1;
|
||||
string warnId = 2;
|
||||
string modName = 3;
|
||||
}
|
||||
|
||||
message ForgiveWarningReply {
|
||||
bool success = 1;
|
||||
}
|
||||
|
||||
message SetWarnExpiryRequest {
|
||||
uint64 guildId = 1;
|
||||
int32 expiryDays = 2;
|
||||
bool deleteOnExpire = 3;
|
||||
}
|
||||
|
||||
message SetWarnExpiryReply {
|
||||
bool success = 1;
|
||||
}
|
||||
|
||||
message GetLatestWarningsRequest {
|
||||
uint64 guildId = 1;
|
||||
int32 page = 2;
|
||||
}
|
||||
|
||||
message GetLatestWarningsReply {
|
||||
repeated Warning warnings = 1;
|
||||
int32 totalCount = 2;
|
||||
}
|
120
src/NadekoBot.GrpcApiBase/protos/xp.proto
Normal file
120
src/NadekoBot.GrpcApiBase/protos/xp.proto
Normal file
@@ -0,0 +1,120 @@
|
||||
syntax = "proto3";
|
||||
|
||||
option csharp_namespace = "NadekoBot.GrpcApi";
|
||||
|
||||
package xp;
|
||||
|
||||
service GrpcXp {
|
||||
rpc GetXpLb(GetXpLbRequest) returns (GetXpLbReply);
|
||||
rpc ResetUserXp(ResetUserXpRequest) returns (ResetUserXpReply);
|
||||
|
||||
rpc GetXpSettings(GetXpSettingsRequest) returns (GetXpSettingsReply);
|
||||
|
||||
rpc AddExclusion(AddExclusionRequest) returns (AddExclusionReply);
|
||||
rpc DeleteExclusion(DeleteExclusionRequest) returns (DeleteExclusionReply);
|
||||
|
||||
rpc AddReward(AddRewardRequest) returns (AddRewardReply);
|
||||
rpc DeleteReward(DeleteRewardRequest) returns (DeleteRewardReply);
|
||||
|
||||
rpc SetServerExclusion(SetServerExclusionRequest) returns (SetServerExclusionReply);
|
||||
}
|
||||
|
||||
message SetServerExclusionRequest {
|
||||
uint64 guildId = 1;
|
||||
bool serverExcluded = 2;
|
||||
}
|
||||
|
||||
message SetServerExclusionReply {
|
||||
bool success = 1;
|
||||
}
|
||||
|
||||
message GetXpLbRequest {
|
||||
uint64 guildId = 1;
|
||||
int32 page = 2;
|
||||
}
|
||||
|
||||
message GetXpLbReply {
|
||||
repeated XpLbUserReply users = 1;
|
||||
int32 total = 2;
|
||||
}
|
||||
|
||||
message XpLbUserReply {
|
||||
uint64 userId = 1;
|
||||
string username = 2;
|
||||
int64 xp = 3;
|
||||
int64 level = 4;
|
||||
int64 levelPercent = 5;
|
||||
string avatar = 6;
|
||||
}
|
||||
|
||||
message ResetUserXpRequest {
|
||||
uint64 guildId = 1;
|
||||
uint64 userId = 2;
|
||||
}
|
||||
|
||||
message ResetUserXpReply {
|
||||
bool success = 1;
|
||||
}
|
||||
|
||||
message GetXpSettingsReply {
|
||||
repeated ExclItemReply exclusions = 1;
|
||||
repeated RewItemReply rewards = 2;
|
||||
bool serverExcluded = 3;
|
||||
}
|
||||
|
||||
message GetXpSettingsRequest {
|
||||
uint64 guildId = 1;
|
||||
}
|
||||
|
||||
message ExclItemReply {
|
||||
string type = 1;
|
||||
uint64 id = 2;
|
||||
string name = 3;
|
||||
}
|
||||
|
||||
message RewItemReply {
|
||||
int32 level = 1;
|
||||
string type = 2;
|
||||
string value = 3;
|
||||
}
|
||||
|
||||
message AddExclusionRequest {
|
||||
uint64 guildId = 1;
|
||||
string type = 2;
|
||||
uint64 id = 3;
|
||||
}
|
||||
|
||||
message AddExclusionReply {
|
||||
bool success = 1;
|
||||
}
|
||||
|
||||
message DeleteExclusionRequest {
|
||||
uint64 guildId = 1;
|
||||
string type = 2;
|
||||
uint64 id = 3;
|
||||
}
|
||||
|
||||
message DeleteExclusionReply {
|
||||
bool success = 1;
|
||||
}
|
||||
|
||||
message AddRewardRequest {
|
||||
uint64 guildId = 1;
|
||||
int32 level = 2;
|
||||
string type = 3;
|
||||
string value = 4;
|
||||
}
|
||||
|
||||
message AddRewardReply {
|
||||
bool success = 1;
|
||||
}
|
||||
|
||||
message DeleteRewardRequest {
|
||||
uint64 guildId = 1;
|
||||
int32 level = 2;
|
||||
string type = 3;
|
||||
}
|
||||
|
||||
message DeleteRewardReply {
|
||||
bool success = 1;
|
||||
}
|
@@ -25,7 +25,7 @@ public sealed class Bot : IBot
|
||||
public bool IsReady { get; private set; }
|
||||
public int ShardId { get; set; }
|
||||
|
||||
private readonly IBotCredentials _creds;
|
||||
private readonly IBotCreds _creds;
|
||||
private readonly CommandService _commandService;
|
||||
private readonly DbService _db;
|
||||
|
||||
@@ -42,6 +42,9 @@ public sealed class Bot : IBot
|
||||
_credsProvider = new BotCredsProvider(totalShards, credPath);
|
||||
_creds = _credsProvider.GetCreds();
|
||||
|
||||
LogSetup.SetupLogger(shardId, _creds);
|
||||
Log.Information("Pid: {ProcessId}", Environment.ProcessId);
|
||||
|
||||
_db = new NadekoDbService(_credsProvider);
|
||||
|
||||
var messageCacheSize =
|
||||
@@ -115,7 +118,7 @@ public sealed class Bot : IBot
|
||||
// svcs.Components.Remove<IPlanner, Planner>();
|
||||
// svcs.Components.Add<IPlanner, RemovablePlanner>();
|
||||
|
||||
svcs.AddSingleton<IBotCredentials>(_ => _credsProvider.GetCreds());
|
||||
svcs.AddSingleton<IBotCreds>(_ => _credsProvider.GetCreds());
|
||||
svcs.AddSingleton<DbService, DbService>(_db);
|
||||
svcs.AddSingleton<IBotCredsProvider>(_credsProvider);
|
||||
svcs.AddSingleton<DiscordSocketClient>(Client);
|
||||
|
@@ -25,7 +25,6 @@ public static class DiscordUserExtensions
|
||||
{
|
||||
UserId = userId,
|
||||
Username = username,
|
||||
Discriminator = discrim,
|
||||
AvatarId = avatarId,
|
||||
TotalXp = 0,
|
||||
CurrencyAmount = 0
|
||||
@@ -33,7 +32,6 @@ public static class DiscordUserExtensions
|
||||
old => new()
|
||||
{
|
||||
Username = username,
|
||||
Discriminator = discrim,
|
||||
AvatarId = avatarId
|
||||
},
|
||||
() => new()
|
||||
@@ -49,8 +47,7 @@ public static class DiscordUserExtensions
|
||||
() => new()
|
||||
{
|
||||
UserId = userId,
|
||||
Username = "Unknown",
|
||||
Discriminator = "????",
|
||||
Username = "??Unknown",
|
||||
AvatarId = string.Empty,
|
||||
TotalXp = 0,
|
||||
CurrencyAmount = 0
|
||||
@@ -87,14 +84,7 @@ public static class DiscordUserExtensions
|
||||
> users.AsQueryable().Where(y => y.UserId == id).Select(y => y.TotalXp).FirstOrDefault())
|
||||
.Count()
|
||||
+ 1;
|
||||
|
||||
public static async Task<IReadOnlyCollection<DiscordUser>> GetUsersXpLeaderboardFor(this DbSet<DiscordUser> users, int page, int perPage)
|
||||
=> await users.ToLinqToDBTable()
|
||||
.OrderByDescending(x => x.TotalXp)
|
||||
.Skip(page * perPage)
|
||||
.Take(perPage)
|
||||
.ToArrayAsyncLinqToDB();
|
||||
|
||||
|
||||
public static Task<List<DiscordUser>> GetTopRichest(
|
||||
this DbSet<DiscordUser> users,
|
||||
ulong botId,
|
||||
|
@@ -57,8 +57,7 @@ public static class GuildConfigExtensions
|
||||
List<ulong> availableGuilds)
|
||||
{
|
||||
var result = await configs
|
||||
.AsQueryable()
|
||||
.Include(x => x.CommandCooldowns)
|
||||
.IncludeEverything()
|
||||
.Where(x => availableGuilds.Contains(x.GuildId))
|
||||
.AsNoTracking()
|
||||
.ToArrayAsync();
|
||||
@@ -96,7 +95,6 @@ public static class GuildConfigExtensions
|
||||
GuildId = guildId,
|
||||
Permissions = Permissionv2.GetDefaultPermlist,
|
||||
WarningsInitialized = true,
|
||||
WarnPunishments = DefaultWarnPunishments
|
||||
});
|
||||
ctx.SaveChanges();
|
||||
}
|
||||
@@ -104,7 +102,6 @@ public static class GuildConfigExtensions
|
||||
if (!config.WarningsInitialized)
|
||||
{
|
||||
config.WarningsInitialized = true;
|
||||
config.WarnPunishments = DefaultWarnPunishments;
|
||||
}
|
||||
|
||||
return config;
|
||||
|
@@ -1,22 +0,0 @@
|
||||
#nullable disable
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using NadekoBot.Db.Models;
|
||||
|
||||
namespace NadekoBot.Db;
|
||||
|
||||
public static class SelfAssignableRolesExtensions
|
||||
{
|
||||
public static bool DeleteByGuildAndRoleId(this DbSet<SelfAssignedRole> roles, ulong guildId, ulong roleId)
|
||||
{
|
||||
var role = roles.FirstOrDefault(s => s.GuildId == guildId && s.RoleId == roleId);
|
||||
|
||||
if (role is null)
|
||||
return false;
|
||||
|
||||
roles.Remove(role);
|
||||
return true;
|
||||
}
|
||||
|
||||
public static IReadOnlyCollection<SelfAssignedRole> GetFromGuild(this DbSet<SelfAssignedRole> roles, ulong guildId)
|
||||
=> roles.AsQueryable().Where(s => s.GuildId == guildId).ToArray();
|
||||
}
|
@@ -1,5 +1,4 @@
|
||||
#nullable disable
|
||||
using LinqToDB;
|
||||
using LinqToDB;
|
||||
using LinqToDB.EntityFrameworkCore;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using NadekoBot.Db.Models;
|
||||
@@ -8,6 +7,9 @@ namespace NadekoBot.Db;
|
||||
|
||||
public static class UserXpExtensions
|
||||
{
|
||||
public static async Task<UserXpStats?> GetGuildUserXp(this ITable<UserXpStats> table, ulong guildId, ulong userId)
|
||||
=> await table.FirstOrDefaultAsyncLinqToDB(x => x.GuildId == guildId && x.UserId == userId);
|
||||
|
||||
public static UserXpStats GetOrCreateUserXpStats(this DbContext ctx, ulong guildId, ulong userId)
|
||||
{
|
||||
var usr = ctx.Set<UserXpStats>().FirstOrDefault(x => x.UserId == userId && x.GuildId == guildId);
|
||||
@@ -26,17 +28,6 @@ public static class UserXpExtensions
|
||||
return usr;
|
||||
}
|
||||
|
||||
public static async Task<IReadOnlyCollection<UserXpStats>> GetUsersFor(
|
||||
this DbSet<UserXpStats> xps,
|
||||
ulong guildId,
|
||||
int page)
|
||||
=> await xps.ToLinqToDBTable()
|
||||
.Where(x => x.GuildId == guildId)
|
||||
.OrderByDescending(x => x.Xp + x.AwardedXp)
|
||||
.Skip(page * 9)
|
||||
.Take(9)
|
||||
.ToArrayAsyncLinqToDB();
|
||||
|
||||
public static async Task<List<UserXpStats>> GetTopUserXps(this DbSet<UserXpStats> xps, ulong guildId, int count)
|
||||
=> await xps.ToLinqToDBTable()
|
||||
.Where(x => x.GuildId == guildId)
|
||||
@@ -55,9 +46,6 @@ public static class UserXpExtensions
|
||||
.CountAsyncLinqToDB()
|
||||
+ 1;
|
||||
|
||||
public static void ResetGuildUserXp(this DbSet<UserXpStats> xps, ulong userId, ulong guildId)
|
||||
=> xps.Delete(x => x.UserId == userId && x.GuildId == guildId);
|
||||
|
||||
public static void ResetGuildXp(this DbSet<UserXpStats> xps, ulong guildId)
|
||||
=> xps.Delete(x => x.GuildId == guildId);
|
||||
|
||||
|
@@ -7,7 +7,7 @@ public class DiscordUser : DbEntity
|
||||
{
|
||||
public ulong UserId { get; set; }
|
||||
public string Username { get; set; }
|
||||
public string Discriminator { get; set; }
|
||||
// public string Discriminator { get; set; }
|
||||
public string AvatarId { get; set; }
|
||||
|
||||
public int? ClubId { get; set; }
|
||||
@@ -27,9 +27,6 @@ public class DiscordUser : DbEntity
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(Discriminator) || Discriminator == "0000")
|
||||
return Username;
|
||||
|
||||
return Username + "#" + Discriminator;
|
||||
return Username;
|
||||
}
|
||||
}
|
8
src/NadekoBot/Db/Models/FlagTranslateChannel.cs
Normal file
8
src/NadekoBot/Db/Models/FlagTranslateChannel.cs
Normal file
@@ -0,0 +1,8 @@
|
||||
#nullable disable
|
||||
namespace NadekoBot.Db.Models;
|
||||
|
||||
public class FlagTranslateChannel : DbEntity
|
||||
{
|
||||
public ulong GuildId { get; set; }
|
||||
public ulong ChannelId { get; set; }
|
||||
}
|
@@ -9,7 +9,8 @@ public class FollowedStream : DbEntity
|
||||
Picarto = 3,
|
||||
Youtube = 4,
|
||||
Facebook = 5,
|
||||
Trovo = 6
|
||||
Trovo = 6,
|
||||
Kick = 7,
|
||||
}
|
||||
|
||||
public ulong GuildId { get; set; }
|
||||
|
@@ -1,11 +0,0 @@
|
||||
#nullable disable
|
||||
namespace NadekoBot.Db.Models;
|
||||
|
||||
public class GroupName : DbEntity
|
||||
{
|
||||
public int GuildConfigId { get; set; }
|
||||
public GuildConfig GuildConfig { get; set; }
|
||||
|
||||
public int Number { get; set; }
|
||||
public string Name { get; set; }
|
||||
}
|
@@ -5,14 +5,15 @@ namespace NadekoBot.Db.Models;
|
||||
public class GuildColors
|
||||
{
|
||||
[Key]
|
||||
public int Id { get; set; }
|
||||
public ulong GuildId { get; set; }
|
||||
|
||||
[Length(0, 9)]
|
||||
[MaxLength(9)]
|
||||
public string? OkColor { get; set; }
|
||||
|
||||
[Length(0, 9)]
|
||||
[MaxLength(9)]
|
||||
public string? ErrorColor { get; set; }
|
||||
|
||||
[Length(0, 9)]
|
||||
[MaxLength(9)]
|
||||
public string? PendingColor { get; set; }
|
||||
}
|
@@ -13,28 +13,11 @@ public class GuildConfig : DbEntity
|
||||
|
||||
public string AutoAssignRoleIds { get; set; }
|
||||
|
||||
// //greet stuff
|
||||
// public int AutoDeleteGreetMessagesTimer { get; set; } = 30;
|
||||
// public int AutoDeleteByeMessagesTimer { get; set; } = 30;
|
||||
//
|
||||
// public ulong GreetMessageChannelId { get; set; }
|
||||
// public ulong ByeMessageChannelId { get; set; }
|
||||
//
|
||||
// public bool SendDmGreetMessage { get; set; }
|
||||
// public string DmGreetMessageText { get; set; } = "Welcome to the %server% server, %user%!";
|
||||
//
|
||||
// public bool SendChannelGreetMessage { get; set; }
|
||||
// public string ChannelGreetMessageText { get; set; } = "Welcome to the %server% server, %user%!";
|
||||
//
|
||||
// public bool SendChannelByeMessage { get; set; }
|
||||
// public string ChannelByeMessageText { get; set; } = "%user% has left!";
|
||||
// public bool SendBoostMessage { get; set; }
|
||||
// pulic int BoostMessageDeleteAfter { get; set; }
|
||||
|
||||
//self assignable roles
|
||||
//todo FUTURE: DELETE, UNUSED
|
||||
public bool ExclusiveSelfAssignedRoles { get; set; }
|
||||
public bool AutoDeleteSelfAssignedRoleMessages { get; set; }
|
||||
|
||||
|
||||
|
||||
//stream notifications
|
||||
public HashSet<FollowedStream> FollowedStreams { get; set; } = new();
|
||||
|
||||
@@ -77,7 +60,6 @@ public class GuildConfig : DbEntity
|
||||
public HashSet<UnroleTimer> UnroleTimer { get; set; } = new();
|
||||
public HashSet<VcRoleInfo> VcRoleInfos { get; set; }
|
||||
public HashSet<CommandAlias> CommandAliases { get; set; } = new();
|
||||
public List<WarningPunishment> WarnPunishments { get; set; } = new();
|
||||
public bool WarningsInitialized { get; set; }
|
||||
public HashSet<SlowmodeIgnoredUser> SlowmodeIgnoredUsers { get; set; }
|
||||
public HashSet<SlowmodeIgnoredRole> SlowmodeIgnoredRoles { get; set; }
|
||||
@@ -92,15 +74,10 @@ public class GuildConfig : DbEntity
|
||||
public List<FeedSub> FeedSubs { get; set; } = new();
|
||||
public bool NotifyStreamOffline { get; set; }
|
||||
public bool DeleteStreamOnlineMessage { get; set; }
|
||||
public List<GroupName> SelfAssignableRoleGroupNames { get; set; }
|
||||
public int WarnExpireHours { get; set; }
|
||||
public WarnExpireAction WarnExpireAction { get; set; } = WarnExpireAction.Clear;
|
||||
|
||||
public bool DisableGlobalExpressions { get; set; } = false;
|
||||
|
||||
#region Boost Message
|
||||
|
||||
public bool StickyRoles { get; set; }
|
||||
|
||||
#endregion
|
||||
}
|
19
src/NadekoBot/Db/Models/NCanvas/NCanvas.cs
Normal file
19
src/NadekoBot/Db/Models/NCanvas/NCanvas.cs
Normal file
@@ -0,0 +1,19 @@
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
|
||||
namespace NadekoBot.Db.Models;
|
||||
|
||||
public class NCPixel
|
||||
{
|
||||
[Key]
|
||||
public int Id { get; set; }
|
||||
|
||||
public required int Position { get; init; }
|
||||
|
||||
public required long Price { get; init; }
|
||||
|
||||
public required ulong OwnerId { get; init; }
|
||||
public required uint Color { get; init; }
|
||||
|
||||
[MaxLength(256)]
|
||||
public required string Text { get; init; }
|
||||
}
|
18
src/NadekoBot/Db/Models/SarGroup.cs
Normal file
18
src/NadekoBot/Db/Models/SarGroup.cs
Normal file
@@ -0,0 +1,18 @@
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
|
||||
namespace NadekoBot.Db.Models;
|
||||
|
||||
public sealed class SarGroup
|
||||
{
|
||||
[Key]
|
||||
public int Id { get; set; }
|
||||
|
||||
public int GroupNumber { get; set; }
|
||||
public ulong GuildId { get; set; }
|
||||
public ulong? RoleReq { get; set; }
|
||||
public ICollection<Sar> Roles { get; set; } = [];
|
||||
public bool IsExclusive { get; set; }
|
||||
|
||||
[MaxLength(100)]
|
||||
public string? Name { get; set; }
|
||||
}
|
27
src/NadekoBot/Db/Models/btnrole/ButtonRole.cs
Normal file
27
src/NadekoBot/Db/Models/btnrole/ButtonRole.cs
Normal file
@@ -0,0 +1,27 @@
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
|
||||
namespace NadekoBot.Db.Models;
|
||||
|
||||
public sealed class ButtonRole
|
||||
{
|
||||
[Key]
|
||||
public int Id { get; set; }
|
||||
|
||||
[MaxLength(200)]
|
||||
public string ButtonId { get; set; } = string.Empty;
|
||||
|
||||
public ulong GuildId { get; set; }
|
||||
public ulong ChannelId { get; set; }
|
||||
public ulong MessageId { get; set; }
|
||||
|
||||
public int Position { get; set; }
|
||||
public ulong RoleId { get; set; }
|
||||
|
||||
[MaxLength(100)]
|
||||
public string Emote { get; set; } = string.Empty;
|
||||
|
||||
[MaxLength(50)]
|
||||
public string Label { get; set; } = string.Empty;
|
||||
|
||||
public bool Exclusive { get; set; }
|
||||
}
|
@@ -3,6 +3,7 @@ namespace NadekoBot.Db.Models;
|
||||
|
||||
public class WarningPunishment : DbEntity
|
||||
{
|
||||
public ulong GuildId { get; set; }
|
||||
public int Count { get; set; }
|
||||
public PunishmentAction Punishment { get; set; }
|
||||
public int Time { get; set; }
|
||||
|
@@ -1,11 +1,24 @@
|
||||
#nullable disable
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
|
||||
namespace NadekoBot.Db.Models;
|
||||
|
||||
public class SelfAssignedRole : DbEntity
|
||||
public sealed class Sar
|
||||
{
|
||||
[Key]
|
||||
public int Id { get; set; }
|
||||
|
||||
public ulong GuildId { get; set; }
|
||||
public ulong RoleId { get; set; }
|
||||
|
||||
public int Group { get; set; }
|
||||
public int LevelRequirement { get; set; }
|
||||
public int SarGroupId { get; set; }
|
||||
public int LevelReq { get; set; }
|
||||
}
|
||||
|
||||
public sealed class SarAutoDelete
|
||||
{
|
||||
[Key]
|
||||
public int Id { get; set; }
|
||||
|
||||
public ulong GuildId { get; set; }
|
||||
public bool IsEnabled { get; set; } = false;
|
||||
}
|
@@ -1,8 +1,12 @@
|
||||
#nullable disable
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
|
||||
namespace NadekoBot.Db.Models;
|
||||
|
||||
public class PatronUser
|
||||
{
|
||||
// [Key]
|
||||
// public int Id { get; set; }
|
||||
public string UniquePlatformUserId { get; set; }
|
||||
public ulong UserId { get; set; }
|
||||
public int AmountCents { get; set; }
|
||||
|
@@ -2,6 +2,7 @@
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using NadekoBot.Db.Models;
|
||||
using NadekoBot.Modules.Administration.Services;
|
||||
|
||||
// ReSharper disable UnusedAutoPropertyAccessor.Global
|
||||
|
||||
@@ -14,7 +15,6 @@ public abstract class NadekoContext : DbContext
|
||||
|
||||
public DbSet<Quote> Quotes { get; set; }
|
||||
public DbSet<Reminder> Reminders { get; set; }
|
||||
public DbSet<SelfAssignedRole> SelfAssignableRoles { get; set; }
|
||||
public DbSet<MusicPlaylist> MusicPlaylists { get; set; }
|
||||
public DbSet<NadekoExpression> Expressions { get; set; }
|
||||
public DbSet<CurrencyTransaction> CurrencyTransactions { get; set; }
|
||||
@@ -62,7 +62,7 @@ public abstract class NadekoContext : DbContext
|
||||
public DbSet<ArchivedTodoListModel> TodosArchive { get; set; }
|
||||
public DbSet<HoneypotChannel> HoneyPotChannels { get; set; }
|
||||
|
||||
// todo add guild colors
|
||||
|
||||
// public DbSet<GuildColors> GuildColors { get; set; }
|
||||
|
||||
|
||||
@@ -74,6 +74,99 @@ public abstract class NadekoContext : DbContext
|
||||
|
||||
protected override void OnModelCreating(ModelBuilder modelBuilder)
|
||||
{
|
||||
#region GuildColors
|
||||
|
||||
modelBuilder.Entity<GuildColors>()
|
||||
.HasIndex(x => x.GuildId)
|
||||
.IsUnique(true);
|
||||
|
||||
#endregion
|
||||
|
||||
#region Button Roles
|
||||
|
||||
modelBuilder.Entity<ButtonRole>(br =>
|
||||
{
|
||||
br.HasIndex(x => x.GuildId)
|
||||
.IsUnique(false);
|
||||
|
||||
br.HasAlternateKey(x => new
|
||||
{
|
||||
x.RoleId,
|
||||
x.MessageId,
|
||||
});
|
||||
});
|
||||
|
||||
#endregion
|
||||
|
||||
#region New Sar
|
||||
|
||||
modelBuilder.Entity<SarGroup>(sg =>
|
||||
{
|
||||
sg.HasAlternateKey(x => new
|
||||
{
|
||||
x.GuildId,
|
||||
x.GroupNumber
|
||||
});
|
||||
|
||||
sg.HasMany(x => x.Roles)
|
||||
.WithOne()
|
||||
.OnDelete(DeleteBehavior.Cascade);
|
||||
});
|
||||
|
||||
modelBuilder.Entity<Sar>()
|
||||
.HasAlternateKey(x => new
|
||||
{
|
||||
x.GuildId,
|
||||
x.RoleId
|
||||
});
|
||||
|
||||
modelBuilder.Entity<SarAutoDelete>()
|
||||
.HasIndex(x => x.GuildId)
|
||||
.IsUnique();
|
||||
|
||||
#endregion
|
||||
|
||||
#region Rakeback
|
||||
|
||||
modelBuilder.Entity<Rakeback>()
|
||||
.HasKey(x => x.UserId);
|
||||
|
||||
#endregion
|
||||
|
||||
#region UserBetStats
|
||||
|
||||
modelBuilder.Entity<UserBetStats>()
|
||||
.HasIndex(x => new
|
||||
{
|
||||
x.UserId,
|
||||
x.Game
|
||||
})
|
||||
.IsUnique();
|
||||
|
||||
#endregion
|
||||
|
||||
#region Flag Translate
|
||||
|
||||
modelBuilder.Entity<FlagTranslateChannel>()
|
||||
.HasIndex(x => new
|
||||
{
|
||||
x.GuildId,
|
||||
x.ChannelId
|
||||
})
|
||||
.IsUnique();
|
||||
|
||||
#endregion
|
||||
|
||||
#region NCanvas
|
||||
|
||||
modelBuilder.Entity<NCPixel>()
|
||||
.HasAlternateKey(x => x.Position);
|
||||
|
||||
modelBuilder.Entity<NCPixel>()
|
||||
.HasIndex(x => x.OwnerId);
|
||||
|
||||
#endregion
|
||||
|
||||
#region QUOTES
|
||||
|
||||
var quoteEntity = modelBuilder.Entity<Quote>();
|
||||
@@ -195,11 +288,6 @@ public abstract class NadekoContext : DbContext
|
||||
.WithOne()
|
||||
.OnDelete(DeleteBehavior.Cascade);
|
||||
|
||||
modelBuilder.Entity<GuildConfig>()
|
||||
.HasMany(x => x.WarnPunishments)
|
||||
.WithOne()
|
||||
.OnDelete(DeleteBehavior.Cascade);
|
||||
|
||||
modelBuilder.Entity<GuildConfig>()
|
||||
.HasMany(x => x.SlowmodeIgnoredRoles)
|
||||
.WithOne()
|
||||
@@ -257,11 +345,6 @@ public abstract class NadekoContext : DbContext
|
||||
.HasForeignKey(x => x.GuildConfigId)
|
||||
.OnDelete(DeleteBehavior.Cascade);
|
||||
|
||||
modelBuilder.Entity<GuildConfig>()
|
||||
.HasMany(x => x.SelfAssignableRoleGroupNames)
|
||||
.WithOne()
|
||||
.OnDelete(DeleteBehavior.Cascade);
|
||||
|
||||
modelBuilder.Entity<FeedSub>()
|
||||
.HasAlternateKey(x => new
|
||||
{
|
||||
@@ -277,19 +360,16 @@ public abstract class NadekoContext : DbContext
|
||||
|
||||
#endregion
|
||||
|
||||
#region WarningPunishments
|
||||
|
||||
#region Self Assignable Roles
|
||||
|
||||
var selfassignableRolesEntity = modelBuilder.Entity<SelfAssignedRole>();
|
||||
|
||||
selfassignableRolesEntity.HasIndex(s => new
|
||||
{
|
||||
s.GuildId,
|
||||
s.RoleId
|
||||
})
|
||||
.IsUnique();
|
||||
|
||||
selfassignableRolesEntity.Property(x => x.Group).HasDefaultValue(0);
|
||||
var warnpunishmentEntity = modelBuilder.Entity<WarningPunishment>(b =>
|
||||
{
|
||||
b.HasAlternateKey(x => new
|
||||
{
|
||||
x.GuildId,
|
||||
x.Count
|
||||
});
|
||||
});
|
||||
|
||||
#endregion
|
||||
|
||||
@@ -339,6 +419,7 @@ public abstract class NadekoContext : DbContext
|
||||
du.HasIndex(x => x.TotalXp);
|
||||
du.HasIndex(x => x.CurrencyAmount);
|
||||
du.HasIndex(x => x.UserId);
|
||||
du.HasIndex(x => x.Username);
|
||||
});
|
||||
|
||||
#endregion
|
||||
@@ -474,23 +555,6 @@ public abstract class NadekoContext : DbContext
|
||||
|
||||
#endregion
|
||||
|
||||
#region GroupName
|
||||
|
||||
modelBuilder.Entity<GroupName>()
|
||||
.HasIndex(x => new
|
||||
{
|
||||
x.GuildConfigId,
|
||||
x.Number
|
||||
})
|
||||
.IsUnique();
|
||||
|
||||
modelBuilder.Entity<GroupName>()
|
||||
.HasOne(x => x.GuildConfig)
|
||||
.WithMany(x => x.SelfAssignableRoleGroupNames)
|
||||
.IsRequired();
|
||||
|
||||
#endregion
|
||||
|
||||
#region BanTemplate
|
||||
|
||||
modelBuilder.Entity<BanTemplate>().HasIndex(x => x.GuildId).IsUnique();
|
||||
@@ -695,7 +759,7 @@ public abstract class NadekoContext : DbContext
|
||||
gs
|
||||
.Property(x => x.IsEnabled)
|
||||
.HasDefaultValue(false);
|
||||
|
||||
|
||||
gs
|
||||
.Property(x => x.AutoDeleteTimer)
|
||||
.HasDefaultValue(0);
|
||||
|
@@ -5,6 +5,41 @@ namespace NadekoBot.Migrations;
|
||||
|
||||
public static class MigrationQueries
|
||||
{
|
||||
public static void MigrateSar(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.Sql("""
|
||||
INSERT INTO GroupName (Number, GuildConfigId)
|
||||
SELECT DISTINCT "Group", GC.Id
|
||||
FROM SelfAssignableRoles as SAR
|
||||
INNER JOIN GuildConfigs as GC
|
||||
ON SAR.GuildId = GC.GuildId
|
||||
WHERE SAR.GuildId not in (SELECT GuildConfigs.GuildId from GroupName LEFT JOIN GuildConfigs ON GroupName.GuildConfigId = GuildConfigs.Id);
|
||||
|
||||
INSERT INTO SarGroup (Id, GroupNumber, Name, IsExclusive, GuildId)
|
||||
SELECT GN.Id, GN.Number, GN.Name, GC.ExclusiveSelfAssignedRoles, GC.GuildId
|
||||
FROM GroupName as GN
|
||||
INNER JOIN GuildConfigs as GC ON GN.GuildConfigId = GC.Id;
|
||||
|
||||
INSERT INTO Sar (GuildId, RoleId, SarGroupId, LevelReq)
|
||||
SELECT SAR.GuildId, SAR.RoleId, (SELECT Id FROM SarGroup WHERE SG.Number = SarGroup.GroupNumber AND SG.GuildId = SarGroup.GuildId), MIN(SAR.LevelRequirement)
|
||||
FROM SelfAssignableRoles as SAR
|
||||
INNER JOIN (SELECT GuildId, gn.Number FROM GroupName as gn
|
||||
INNER JOIN GuildConfigs as gc ON gn.GuildConfigId =gc.Id
|
||||
) as SG
|
||||
ON SG.GuildId = SAR.GuildId
|
||||
WHERE SG.Number IN (SELECT GroupNumber FROM SarGroup WHERE Sar.GuildId = SarGroup.GuildId)
|
||||
GROUP BY SAR.GuildId, SAR.RoleId;
|
||||
|
||||
INSERT INTO SarAutoDelete (GuildId, IsEnabled)
|
||||
SELECT GuildId, AutoDeleteSelfAssignedRoleMessages FROM GuildConfigs WHERE AutoDeleteSelfAssignedRoleMessages = TRUE;
|
||||
""");
|
||||
}
|
||||
|
||||
public static void UpdateUsernames(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.Sql("UPDATE DiscordUser SET Username = '??' || Username WHERE Discriminator = '????';");
|
||||
}
|
||||
|
||||
public static void MigrateRero(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
if (migrationBuilder.IsSqlite())
|
||||
@@ -38,6 +73,7 @@ left join guildconfigs on reactionrolemessage.guildconfigid = guildconfigs.id;")
|
||||
DELETE FROM "DelMsgOnCmdChannel" WHERE "GuildConfigId" is NULL;
|
||||
DELETE FROM "WarningPunishment" WHERE "GuildConfigId" NOT IN (SELECT "Id" from "GuildConfigs");
|
||||
DELETE FROM "StreamRoleBlacklistedUser" WHERE "StreamRoleSettingsId" is NULL;
|
||||
DELETE FROM "Permissions" WHERE "GuildConfigId" NOT IN (SELECT "Id" from "GuildConfigs");
|
||||
""");
|
||||
}
|
||||
|
||||
@@ -65,4 +101,20 @@ left join guildconfigs on reactionrolemessage.guildconfigid = guildconfigs.id;")
|
||||
WHERE SendBoostMessage = TRUE;
|
||||
""");
|
||||
}
|
||||
|
||||
public static void AddGuildIdsToWarningPunishment(MigrationBuilder builder)
|
||||
{
|
||||
builder.Sql("""
|
||||
DELETE FROM WarningPunishment WHERE GuildConfigId IS NULL OR GuildConfigId NOT IN (SELECT Id FROM GuildConfigs);
|
||||
UPDATE WarningPunishment
|
||||
SET GuildId = (SELECT GuildId FROM GuildConfigs WHERE Id = GuildConfigId);
|
||||
|
||||
DELETE FROM WarningPunishment as wp
|
||||
WHERE (wp.Count, wp.GuildConfigId) in (
|
||||
SELECT wp2.Count, wp2.GuildConfigId FROM WarningPunishment as wp2
|
||||
GROUP BY wp2.Count, wp2.GuildConfigId
|
||||
HAVING COUNT(id) > 1
|
||||
);
|
||||
""");
|
||||
}
|
||||
}
|
3778
src/NadekoBot/Migrations/PostgreSql/20241018004623_warn-split.Designer.cs
generated
Normal file
3778
src/NadekoBot/Migrations/PostgreSql/20241018004623_warn-split.Designer.cs
generated
Normal file
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,71 @@
|
||||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
|
||||
#nullable disable
|
||||
|
||||
namespace NadekoBot.Migrations.PostgreSql
|
||||
{
|
||||
/// <inheritdoc />
|
||||
public partial class warnsplit : Migration
|
||||
{
|
||||
/// <inheritdoc />
|
||||
protected override void Up(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.AddColumn<decimal>(
|
||||
name: "guildid",
|
||||
table: "warningpunishment",
|
||||
type: "numeric(20,0)",
|
||||
nullable: false,
|
||||
defaultValue: 0m);
|
||||
|
||||
MigrationQueries.AddGuildIdsToWarningPunishment(migrationBuilder);
|
||||
|
||||
migrationBuilder.DropForeignKey(
|
||||
name: "fk_warningpunishment_guildconfigs_guildconfigid",
|
||||
table: "warningpunishment");
|
||||
|
||||
migrationBuilder.DropIndex(
|
||||
name: "ix_warningpunishment_guildconfigid",
|
||||
table: "warningpunishment");
|
||||
|
||||
migrationBuilder.DropColumn(
|
||||
name: "guildconfigid",
|
||||
table: "warningpunishment");
|
||||
|
||||
migrationBuilder.AddUniqueConstraint(
|
||||
name: "ak_warningpunishment_guildid_count",
|
||||
table: "warningpunishment",
|
||||
columns: new[] { "guildid", "count" });
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override void Down(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.DropUniqueConstraint(
|
||||
name: "ak_warningpunishment_guildid_count",
|
||||
table: "warningpunishment");
|
||||
|
||||
migrationBuilder.DropColumn(
|
||||
name: "guildid",
|
||||
table: "warningpunishment");
|
||||
|
||||
migrationBuilder.AddColumn<int>(
|
||||
name: "guildconfigid",
|
||||
table: "warningpunishment",
|
||||
type: "integer",
|
||||
nullable: true);
|
||||
|
||||
migrationBuilder.CreateIndex(
|
||||
name: "ix_warningpunishment_guildconfigid",
|
||||
table: "warningpunishment",
|
||||
column: "guildconfigid");
|
||||
|
||||
migrationBuilder.AddForeignKey(
|
||||
name: "fk_warningpunishment_guildconfigs_guildconfigid",
|
||||
table: "warningpunishment",
|
||||
column: "guildconfigid",
|
||||
principalTable: "guildconfigs",
|
||||
principalColumn: "id",
|
||||
onDelete: ReferentialAction.Cascade);
|
||||
}
|
||||
}
|
||||
}
|
3824
src/NadekoBot/Migrations/PostgreSql/20241028033704_ncanvas.Designer.cs
generated
Normal file
3824
src/NadekoBot/Migrations/PostgreSql/20241028033704_ncanvas.Designer.cs
generated
Normal file
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,54 @@
|
||||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata;
|
||||
|
||||
#nullable disable
|
||||
|
||||
namespace NadekoBot.Migrations.PostgreSql
|
||||
{
|
||||
/// <inheritdoc />
|
||||
public partial class ncanvas : Migration
|
||||
{
|
||||
/// <inheritdoc />
|
||||
protected override void Up(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.CreateTable(
|
||||
name: "ncpixel",
|
||||
columns: table => new
|
||||
{
|
||||
id = table.Column<int>(type: "integer", nullable: false)
|
||||
.Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn),
|
||||
position = table.Column<int>(type: "integer", nullable: false),
|
||||
price = table.Column<long>(type: "bigint", nullable: false),
|
||||
ownerid = table.Column<decimal>(type: "numeric(20,0)", nullable: false),
|
||||
color = table.Column<long>(type: "bigint", nullable: false),
|
||||
text = table.Column<string>(type: "character varying(256)", maxLength: 256, nullable: false)
|
||||
},
|
||||
constraints: table =>
|
||||
{
|
||||
table.PrimaryKey("pk_ncpixel", x => x.id);
|
||||
table.UniqueConstraint("ak_ncpixel_position", x => x.position);
|
||||
});
|
||||
|
||||
migrationBuilder.CreateIndex(
|
||||
name: "ix_discorduser_username",
|
||||
table: "discorduser",
|
||||
column: "username");
|
||||
|
||||
migrationBuilder.CreateIndex(
|
||||
name: "ix_ncpixel_ownerid",
|
||||
table: "ncpixel",
|
||||
column: "ownerid");
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override void Down(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.DropTable(
|
||||
name: "ncpixel");
|
||||
|
||||
migrationBuilder.DropIndex(
|
||||
name: "ix_discorduser_username",
|
||||
table: "discorduser");
|
||||
}
|
||||
}
|
||||
}
|
3851
src/NadekoBot/Migrations/PostgreSql/20241102022956_no-discrim-and-flag-translate.Designer.cs
generated
Normal file
3851
src/NadekoBot/Migrations/PostgreSql/20241102022956_no-discrim-and-flag-translate.Designer.cs
generated
Normal file
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,54 @@
|
||||
using System;
|
||||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata;
|
||||
|
||||
#nullable disable
|
||||
|
||||
namespace NadekoBot.Migrations.PostgreSql
|
||||
{
|
||||
/// <inheritdoc />
|
||||
public partial class nodiscrimandflagtranslate : Migration
|
||||
{
|
||||
/// <inheritdoc />
|
||||
protected override void Up(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.DropColumn(
|
||||
name: "discriminator",
|
||||
table: "discorduser");
|
||||
|
||||
migrationBuilder.CreateTable(
|
||||
name: "flagtranslatechannel",
|
||||
columns: table => new
|
||||
{
|
||||
id = table.Column<int>(type: "integer", nullable: false)
|
||||
.Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn),
|
||||
guildid = table.Column<decimal>(type: "numeric(20,0)", nullable: false),
|
||||
channelid = table.Column<decimal>(type: "numeric(20,0)", nullable: false),
|
||||
dateadded = table.Column<DateTime>(type: "timestamp without time zone", nullable: true)
|
||||
},
|
||||
constraints: table =>
|
||||
{
|
||||
table.PrimaryKey("pk_flagtranslatechannel", x => x.id);
|
||||
});
|
||||
|
||||
migrationBuilder.CreateIndex(
|
||||
name: "ix_flagtranslatechannel_guildid_channelid",
|
||||
table: "flagtranslatechannel",
|
||||
columns: new[] { "guildid", "channelid" },
|
||||
unique: true);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override void Down(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.DropTable(
|
||||
name: "flagtranslatechannel");
|
||||
|
||||
migrationBuilder.AddColumn<string>(
|
||||
name: "discriminator",
|
||||
table: "discorduser",
|
||||
type: "text",
|
||||
nullable: true);
|
||||
}
|
||||
}
|
||||
}
|
3902
src/NadekoBot/Migrations/PostgreSql/20241104094232_betstats.Designer.cs
generated
Normal file
3902
src/NadekoBot/Migrations/PostgreSql/20241104094232_betstats.Designer.cs
generated
Normal file
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,48 @@
|
||||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata;
|
||||
|
||||
#nullable disable
|
||||
|
||||
namespace NadekoBot.Migrations.PostgreSql
|
||||
{
|
||||
/// <inheritdoc />
|
||||
public partial class betstats : Migration
|
||||
{
|
||||
/// <inheritdoc />
|
||||
protected override void Up(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.CreateTable(
|
||||
name: "userbetstats",
|
||||
columns: table => new
|
||||
{
|
||||
id = table.Column<int>(type: "integer", nullable: false)
|
||||
.Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn),
|
||||
userid = table.Column<decimal>(type: "numeric(20,0)", nullable: false),
|
||||
game = table.Column<int>(type: "integer", nullable: false),
|
||||
wincount = table.Column<long>(type: "bigint", nullable: false),
|
||||
losecount = table.Column<long>(type: "bigint", nullable: false),
|
||||
totalbet = table.Column<decimal>(type: "numeric", nullable: false),
|
||||
paidout = table.Column<decimal>(type: "numeric", nullable: false),
|
||||
maxwin = table.Column<long>(type: "bigint", nullable: false),
|
||||
maxbet = table.Column<long>(type: "bigint", nullable: false)
|
||||
},
|
||||
constraints: table =>
|
||||
{
|
||||
table.PrimaryKey("pk_userbetstats", x => x.id);
|
||||
});
|
||||
|
||||
migrationBuilder.CreateIndex(
|
||||
name: "ix_userbetstats_userid_game",
|
||||
table: "userbetstats",
|
||||
columns: new[] { "userid", "game" },
|
||||
unique: true);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override void Down(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.DropTable(
|
||||
name: "userbetstats");
|
||||
}
|
||||
}
|
||||
}
|
3919
src/NadekoBot/Migrations/PostgreSql/20241105073004_rakeback.Designer.cs
generated
Normal file
3919
src/NadekoBot/Migrations/PostgreSql/20241105073004_rakeback.Designer.cs
generated
Normal file
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,33 @@
|
||||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
|
||||
#nullable disable
|
||||
|
||||
namespace NadekoBot.Migrations.PostgreSql
|
||||
{
|
||||
/// <inheritdoc />
|
||||
public partial class rakeback : Migration
|
||||
{
|
||||
/// <inheritdoc />
|
||||
protected override void Up(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.CreateTable(
|
||||
name: "rakeback",
|
||||
columns: table => new
|
||||
{
|
||||
userid = table.Column<decimal>(type: "numeric(20,0)", nullable: false),
|
||||
amount = table.Column<decimal>(type: "numeric", nullable: false)
|
||||
},
|
||||
constraints: table =>
|
||||
{
|
||||
table.PrimaryKey("pk_rakeback", x => x.userid);
|
||||
});
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override void Down(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.DropTable(
|
||||
name: "rakeback");
|
||||
}
|
||||
}
|
||||
}
|
3947
src/NadekoBot/Migrations/PostgreSql/20241115171647_sar-rework.Designer.cs
generated
Normal file
3947
src/NadekoBot/Migrations/PostgreSql/20241115171647_sar-rework.Designer.cs
generated
Normal file
File diff suppressed because it is too large
Load Diff
170
src/NadekoBot/Migrations/PostgreSql/20241115171647_sar-rework.cs
Normal file
170
src/NadekoBot/Migrations/PostgreSql/20241115171647_sar-rework.cs
Normal file
@@ -0,0 +1,170 @@
|
||||
using System;
|
||||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata;
|
||||
|
||||
#nullable disable
|
||||
|
||||
namespace NadekoBot.Migrations.PostgreSql
|
||||
{
|
||||
/// <inheritdoc />
|
||||
public partial class sarrework : Migration
|
||||
{
|
||||
/// <inheritdoc />
|
||||
protected override void Up(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
|
||||
migrationBuilder.CreateTable(
|
||||
name: "sarautodelete",
|
||||
columns: table => new
|
||||
{
|
||||
id = table.Column<int>(type: "integer", nullable: false)
|
||||
.Annotation("Npgsql:ValueGenerationStrategy",
|
||||
NpgsqlValueGenerationStrategy.IdentityByDefaultColumn),
|
||||
guildid = table.Column<decimal>(type: "numeric(20,0)", nullable: false),
|
||||
isenabled = table.Column<bool>(type: "boolean", nullable: false)
|
||||
},
|
||||
constraints: table =>
|
||||
{
|
||||
table.PrimaryKey("pk_sarautodelete", x => x.id);
|
||||
});
|
||||
|
||||
migrationBuilder.CreateTable(
|
||||
name: "sargroup",
|
||||
columns: table => new
|
||||
{
|
||||
id = table.Column<int>(type: "integer", nullable: false)
|
||||
.Annotation("Npgsql:ValueGenerationStrategy",
|
||||
NpgsqlValueGenerationStrategy.IdentityByDefaultColumn),
|
||||
groupnumber = table.Column<int>(type: "integer", nullable: false),
|
||||
guildid = table.Column<decimal>(type: "numeric(20,0)", nullable: false),
|
||||
rolereq = table.Column<decimal>(type: "numeric(20,0)", nullable: true),
|
||||
isexclusive = table.Column<bool>(type: "boolean", nullable: false),
|
||||
name = table.Column<string>(type: "character varying(100)", maxLength: 100, nullable: true)
|
||||
},
|
||||
constraints: table =>
|
||||
{
|
||||
table.PrimaryKey("pk_sargroup", x => x.id);
|
||||
table.UniqueConstraint("ak_sargroup_guildid_groupnumber",
|
||||
x => new
|
||||
{
|
||||
x.guildid,
|
||||
x.groupnumber
|
||||
});
|
||||
});
|
||||
|
||||
migrationBuilder.CreateTable(
|
||||
name: "sar",
|
||||
columns: table => new
|
||||
{
|
||||
id = table.Column<int>(type: "integer", nullable: false)
|
||||
.Annotation("Npgsql:ValueGenerationStrategy",
|
||||
NpgsqlValueGenerationStrategy.IdentityByDefaultColumn),
|
||||
guildid = table.Column<decimal>(type: "numeric(20,0)", nullable: false),
|
||||
roleid = table.Column<decimal>(type: "numeric(20,0)", nullable: false),
|
||||
sargroupid = table.Column<int>(type: "integer", nullable: false),
|
||||
levelreq = table.Column<int>(type: "integer", nullable: false)
|
||||
},
|
||||
constraints: table =>
|
||||
{
|
||||
table.PrimaryKey("pk_sar", x => x.id);
|
||||
table.UniqueConstraint("ak_sar_guildid_roleid",
|
||||
x => new
|
||||
{
|
||||
x.guildid,
|
||||
x.roleid
|
||||
});
|
||||
table.ForeignKey(
|
||||
name: "fk_sar_sargroup_sargroupid",
|
||||
column: x => x.sargroupid,
|
||||
principalTable: "sargroup",
|
||||
principalColumn: "id",
|
||||
onDelete: ReferentialAction.Cascade);
|
||||
});
|
||||
|
||||
migrationBuilder.CreateIndex(
|
||||
name: "ix_sar_sargroupid",
|
||||
table: "sar",
|
||||
column: "sargroupid");
|
||||
|
||||
migrationBuilder.CreateIndex(
|
||||
name: "ix_sarautodelete_guildid",
|
||||
table: "sarautodelete",
|
||||
column: "guildid",
|
||||
unique: true);
|
||||
|
||||
MigrationQueries.MigrateSar(migrationBuilder);
|
||||
|
||||
migrationBuilder.DropTable(
|
||||
name: "groupname");
|
||||
|
||||
migrationBuilder.DropTable(
|
||||
name: "selfassignableroles");
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override void Down(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.DropTable(
|
||||
name: "sar");
|
||||
|
||||
migrationBuilder.DropTable(
|
||||
name: "sarautodelete");
|
||||
|
||||
migrationBuilder.DropTable(
|
||||
name: "sargroup");
|
||||
|
||||
migrationBuilder.CreateTable(
|
||||
name: "groupname",
|
||||
columns: table => new
|
||||
{
|
||||
id = table.Column<int>(type: "integer", nullable: false)
|
||||
.Annotation("Npgsql:ValueGenerationStrategy",
|
||||
NpgsqlValueGenerationStrategy.IdentityByDefaultColumn),
|
||||
guildconfigid = table.Column<int>(type: "integer", nullable: false),
|
||||
dateadded = table.Column<DateTime>(type: "timestamp without time zone", nullable: true),
|
||||
name = table.Column<string>(type: "text", nullable: true),
|
||||
number = table.Column<int>(type: "integer", nullable: false)
|
||||
},
|
||||
constraints: table =>
|
||||
{
|
||||
table.PrimaryKey("pk_groupname", x => x.id);
|
||||
table.ForeignKey(
|
||||
name: "fk_groupname_guildconfigs_guildconfigid",
|
||||
column: x => x.guildconfigid,
|
||||
principalTable: "guildconfigs",
|
||||
principalColumn: "id",
|
||||
onDelete: ReferentialAction.Cascade);
|
||||
});
|
||||
|
||||
migrationBuilder.CreateTable(
|
||||
name: "selfassignableroles",
|
||||
columns: table => new
|
||||
{
|
||||
id = table.Column<int>(type: "integer", nullable: false)
|
||||
.Annotation("Npgsql:ValueGenerationStrategy",
|
||||
NpgsqlValueGenerationStrategy.IdentityByDefaultColumn),
|
||||
dateadded = table.Column<DateTime>(type: "timestamp without time zone", nullable: true),
|
||||
group = table.Column<int>(type: "integer", nullable: false, defaultValue: 0),
|
||||
guildid = table.Column<decimal>(type: "numeric(20,0)", nullable: false),
|
||||
levelrequirement = table.Column<int>(type: "integer", nullable: false),
|
||||
roleid = table.Column<decimal>(type: "numeric(20,0)", nullable: false)
|
||||
},
|
||||
constraints: table =>
|
||||
{
|
||||
table.PrimaryKey("pk_selfassignableroles", x => x.id);
|
||||
});
|
||||
|
||||
migrationBuilder.CreateIndex(
|
||||
name: "ix_groupname_guildconfigid_number",
|
||||
table: "groupname",
|
||||
columns: new[] { "guildconfigid", "number" },
|
||||
unique: true);
|
||||
|
||||
migrationBuilder.CreateIndex(
|
||||
name: "ix_selfassignableroles_guildid_roleid",
|
||||
table: "selfassignableroles",
|
||||
columns: new[] { "guildid", "roleid" },
|
||||
unique: true);
|
||||
}
|
||||
}
|
||||
}
|
4048
src/NadekoBot/Migrations/PostgreSql/20241126033634_btnroles_guildcolors.Designer.cs
generated
Normal file
4048
src/NadekoBot/Migrations/PostgreSql/20241126033634_btnroles_guildcolors.Designer.cs
generated
Normal file
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,74 @@
|
||||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata;
|
||||
|
||||
#nullable disable
|
||||
|
||||
namespace NadekoBot.Migrations.PostgreSql
|
||||
{
|
||||
/// <inheritdoc />
|
||||
public partial class btnroles_guildcolors : Migration
|
||||
{
|
||||
/// <inheritdoc />
|
||||
protected override void Up(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.CreateTable(
|
||||
name: "buttonrole",
|
||||
columns: table => new
|
||||
{
|
||||
id = table.Column<int>(type: "integer", nullable: false)
|
||||
.Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn),
|
||||
buttonid = table.Column<string>(type: "character varying(200)", maxLength: 200, nullable: false),
|
||||
guildid = table.Column<decimal>(type: "numeric(20,0)", nullable: false),
|
||||
channelid = table.Column<decimal>(type: "numeric(20,0)", nullable: false),
|
||||
messageid = table.Column<decimal>(type: "numeric(20,0)", nullable: false),
|
||||
position = table.Column<int>(type: "integer", nullable: false),
|
||||
roleid = table.Column<decimal>(type: "numeric(20,0)", nullable: false),
|
||||
emote = table.Column<string>(type: "character varying(100)", maxLength: 100, nullable: false),
|
||||
label = table.Column<string>(type: "character varying(50)", maxLength: 50, nullable: false),
|
||||
exclusive = table.Column<bool>(type: "boolean", nullable: false)
|
||||
},
|
||||
constraints: table =>
|
||||
{
|
||||
table.PrimaryKey("pk_buttonrole", x => x.id);
|
||||
table.UniqueConstraint("ak_buttonrole_roleid_messageid", x => new { x.roleid, x.messageid });
|
||||
});
|
||||
|
||||
migrationBuilder.CreateTable(
|
||||
name: "guildcolors",
|
||||
columns: table => new
|
||||
{
|
||||
id = table.Column<int>(type: "integer", nullable: false)
|
||||
.Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn),
|
||||
guildid = table.Column<decimal>(type: "numeric(20,0)", nullable: false),
|
||||
okcolor = table.Column<string>(type: "character varying(9)", maxLength: 9, nullable: true),
|
||||
errorcolor = table.Column<string>(type: "character varying(9)", maxLength: 9, nullable: true),
|
||||
pendingcolor = table.Column<string>(type: "character varying(9)", maxLength: 9, nullable: true)
|
||||
},
|
||||
constraints: table =>
|
||||
{
|
||||
table.PrimaryKey("pk_guildcolors", x => x.id);
|
||||
});
|
||||
|
||||
migrationBuilder.CreateIndex(
|
||||
name: "ix_buttonrole_guildid",
|
||||
table: "buttonrole",
|
||||
column: "guildid");
|
||||
|
||||
migrationBuilder.CreateIndex(
|
||||
name: "ix_guildcolors_guildid",
|
||||
table: "guildcolors",
|
||||
column: "guildid",
|
||||
unique: true);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override void Down(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.DropTable(
|
||||
name: "buttonrole");
|
||||
|
||||
migrationBuilder.DropTable(
|
||||
name: "guildcolors");
|
||||
}
|
||||
}
|
||||
}
|
@@ -451,6 +451,69 @@ namespace NadekoBot.Migrations.PostgreSql
|
||||
b.ToTable("blacklist", (string)null);
|
||||
});
|
||||
|
||||
modelBuilder.Entity("NadekoBot.Db.Models.ButtonRole", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("integer")
|
||||
.HasColumnName("id");
|
||||
|
||||
NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id"));
|
||||
|
||||
b.Property<string>("ButtonId")
|
||||
.IsRequired()
|
||||
.HasMaxLength(200)
|
||||
.HasColumnType("character varying(200)")
|
||||
.HasColumnName("buttonid");
|
||||
|
||||
b.Property<decimal>("ChannelId")
|
||||
.HasColumnType("numeric(20,0)")
|
||||
.HasColumnName("channelid");
|
||||
|
||||
b.Property<string>("Emote")
|
||||
.IsRequired()
|
||||
.HasMaxLength(100)
|
||||
.HasColumnType("character varying(100)")
|
||||
.HasColumnName("emote");
|
||||
|
||||
b.Property<bool>("Exclusive")
|
||||
.HasColumnType("boolean")
|
||||
.HasColumnName("exclusive");
|
||||
|
||||
b.Property<decimal>("GuildId")
|
||||
.HasColumnType("numeric(20,0)")
|
||||
.HasColumnName("guildid");
|
||||
|
||||
b.Property<string>("Label")
|
||||
.IsRequired()
|
||||
.HasMaxLength(50)
|
||||
.HasColumnType("character varying(50)")
|
||||
.HasColumnName("label");
|
||||
|
||||
b.Property<decimal>("MessageId")
|
||||
.HasColumnType("numeric(20,0)")
|
||||
.HasColumnName("messageid");
|
||||
|
||||
b.Property<int>("Position")
|
||||
.HasColumnType("integer")
|
||||
.HasColumnName("position");
|
||||
|
||||
b.Property<decimal>("RoleId")
|
||||
.HasColumnType("numeric(20,0)")
|
||||
.HasColumnName("roleid");
|
||||
|
||||
b.HasKey("Id")
|
||||
.HasName("pk_buttonrole");
|
||||
|
||||
b.HasAlternateKey("RoleId", "MessageId")
|
||||
.HasName("ak_buttonrole_roleid_messageid");
|
||||
|
||||
b.HasIndex("GuildId")
|
||||
.HasDatabaseName("ix_buttonrole_guildid");
|
||||
|
||||
b.ToTable("buttonrole", (string)null);
|
||||
});
|
||||
|
||||
modelBuilder.Entity("NadekoBot.Db.Models.ClubApplicants", b =>
|
||||
{
|
||||
b.Property<int>("ClubId")
|
||||
@@ -751,10 +814,6 @@ namespace NadekoBot.Migrations.PostgreSql
|
||||
.HasColumnType("timestamp without time zone")
|
||||
.HasColumnName("dateadded");
|
||||
|
||||
b.Property<string>("Discriminator")
|
||||
.HasColumnType("text")
|
||||
.HasColumnName("discriminator");
|
||||
|
||||
b.Property<bool>("IsClubAdmin")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("boolean")
|
||||
@@ -799,6 +858,9 @@ namespace NadekoBot.Migrations.PostgreSql
|
||||
b.HasIndex("UserId")
|
||||
.HasDatabaseName("ix_discorduser_userid");
|
||||
|
||||
b.HasIndex("Username")
|
||||
.HasDatabaseName("ix_discorduser_username");
|
||||
|
||||
b.ToTable("discorduser", (string)null);
|
||||
});
|
||||
|
||||
@@ -995,6 +1057,37 @@ namespace NadekoBot.Migrations.PostgreSql
|
||||
b.ToTable("filteredword", (string)null);
|
||||
});
|
||||
|
||||
modelBuilder.Entity("NadekoBot.Db.Models.FlagTranslateChannel", 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_flagtranslatechannel");
|
||||
|
||||
b.HasIndex("GuildId", "ChannelId")
|
||||
.IsUnique()
|
||||
.HasDatabaseName("ix_flagtranslatechannel_guildid_channelid");
|
||||
|
||||
b.ToTable("flagtranslatechannel", (string)null);
|
||||
});
|
||||
|
||||
modelBuilder.Entity("NadekoBot.Db.Models.FollowedStream", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
@@ -1172,7 +1265,7 @@ namespace NadekoBot.Migrations.PostgreSql
|
||||
b.ToTable("giveawayuser", (string)null);
|
||||
});
|
||||
|
||||
modelBuilder.Entity("NadekoBot.Db.Models.GroupName", b =>
|
||||
modelBuilder.Entity("NadekoBot.Db.Models.GuildColors", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
@@ -1181,30 +1274,33 @@ namespace NadekoBot.Migrations.PostgreSql
|
||||
|
||||
NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id"));
|
||||
|
||||
b.Property<DateTime?>("DateAdded")
|
||||
.HasColumnType("timestamp without time zone")
|
||||
.HasColumnName("dateadded");
|
||||
b.Property<string>("ErrorColor")
|
||||
.HasMaxLength(9)
|
||||
.HasColumnType("character varying(9)")
|
||||
.HasColumnName("errorcolor");
|
||||
|
||||
b.Property<int>("GuildConfigId")
|
||||
.HasColumnType("integer")
|
||||
.HasColumnName("guildconfigid");
|
||||
b.Property<decimal>("GuildId")
|
||||
.HasColumnType("numeric(20,0)")
|
||||
.HasColumnName("guildid");
|
||||
|
||||
b.Property<string>("Name")
|
||||
.HasColumnType("text")
|
||||
.HasColumnName("name");
|
||||
b.Property<string>("OkColor")
|
||||
.HasMaxLength(9)
|
||||
.HasColumnType("character varying(9)")
|
||||
.HasColumnName("okcolor");
|
||||
|
||||
b.Property<int>("Number")
|
||||
.HasColumnType("integer")
|
||||
.HasColumnName("number");
|
||||
b.Property<string>("PendingColor")
|
||||
.HasMaxLength(9)
|
||||
.HasColumnType("character varying(9)")
|
||||
.HasColumnName("pendingcolor");
|
||||
|
||||
b.HasKey("Id")
|
||||
.HasName("pk_groupname");
|
||||
.HasName("pk_guildcolors");
|
||||
|
||||
b.HasIndex("GuildConfigId", "Number")
|
||||
b.HasIndex("GuildId")
|
||||
.IsUnique()
|
||||
.HasDatabaseName("ix_groupname_guildconfigid_number");
|
||||
.HasDatabaseName("ix_guildcolors_guildid");
|
||||
|
||||
b.ToTable("groupname", (string)null);
|
||||
b.ToTable("guildcolors", (string)null);
|
||||
});
|
||||
|
||||
modelBuilder.Entity("NadekoBot.Db.Models.GuildConfig", b =>
|
||||
@@ -1627,6 +1723,49 @@ namespace NadekoBot.Migrations.PostgreSql
|
||||
b.ToTable("muteduserid", (string)null);
|
||||
});
|
||||
|
||||
modelBuilder.Entity("NadekoBot.Db.Models.NCPixel", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("integer")
|
||||
.HasColumnName("id");
|
||||
|
||||
NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id"));
|
||||
|
||||
b.Property<long>("Color")
|
||||
.HasColumnType("bigint")
|
||||
.HasColumnName("color");
|
||||
|
||||
b.Property<decimal>("OwnerId")
|
||||
.HasColumnType("numeric(20,0)")
|
||||
.HasColumnName("ownerid");
|
||||
|
||||
b.Property<int>("Position")
|
||||
.HasColumnType("integer")
|
||||
.HasColumnName("position");
|
||||
|
||||
b.Property<long>("Price")
|
||||
.HasColumnType("bigint")
|
||||
.HasColumnName("price");
|
||||
|
||||
b.Property<string>("Text")
|
||||
.IsRequired()
|
||||
.HasMaxLength(256)
|
||||
.HasColumnType("character varying(256)")
|
||||
.HasColumnName("text");
|
||||
|
||||
b.HasKey("Id")
|
||||
.HasName("pk_ncpixel");
|
||||
|
||||
b.HasAlternateKey("Position")
|
||||
.HasName("ak_ncpixel_position");
|
||||
|
||||
b.HasIndex("OwnerId")
|
||||
.HasDatabaseName("ix_ncpixel_ownerid");
|
||||
|
||||
b.ToTable("ncpixel", (string)null);
|
||||
});
|
||||
|
||||
modelBuilder.Entity("NadekoBot.Db.Models.NadekoExpression", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
@@ -2127,7 +2266,7 @@ namespace NadekoBot.Migrations.PostgreSql
|
||||
b.ToTable("rotatingstatus", (string)null);
|
||||
});
|
||||
|
||||
modelBuilder.Entity("NadekoBot.Db.Models.SelfAssignedRole", b =>
|
||||
modelBuilder.Entity("NadekoBot.Db.Models.Sar", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
@@ -2136,36 +2275,98 @@ namespace NadekoBot.Migrations.PostgreSql
|
||||
|
||||
NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id"));
|
||||
|
||||
b.Property<DateTime?>("DateAdded")
|
||||
.HasColumnType("timestamp without time zone")
|
||||
.HasColumnName("dateadded");
|
||||
|
||||
b.Property<int>("Group")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("integer")
|
||||
.HasDefaultValue(0)
|
||||
.HasColumnName("group");
|
||||
|
||||
b.Property<decimal>("GuildId")
|
||||
.HasColumnType("numeric(20,0)")
|
||||
.HasColumnName("guildid");
|
||||
|
||||
b.Property<int>("LevelRequirement")
|
||||
b.Property<int>("LevelReq")
|
||||
.HasColumnType("integer")
|
||||
.HasColumnName("levelrequirement");
|
||||
.HasColumnName("levelreq");
|
||||
|
||||
b.Property<decimal>("RoleId")
|
||||
.HasColumnType("numeric(20,0)")
|
||||
.HasColumnName("roleid");
|
||||
|
||||
b.Property<int>("SarGroupId")
|
||||
.HasColumnType("integer")
|
||||
.HasColumnName("sargroupid");
|
||||
|
||||
b.HasKey("Id")
|
||||
.HasName("pk_selfassignableroles");
|
||||
.HasName("pk_sar");
|
||||
|
||||
b.HasIndex("GuildId", "RoleId")
|
||||
b.HasAlternateKey("GuildId", "RoleId")
|
||||
.HasName("ak_sar_guildid_roleid");
|
||||
|
||||
b.HasIndex("SarGroupId")
|
||||
.HasDatabaseName("ix_sar_sargroupid");
|
||||
|
||||
b.ToTable("sar", (string)null);
|
||||
});
|
||||
|
||||
modelBuilder.Entity("NadekoBot.Db.Models.SarAutoDelete", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("integer")
|
||||
.HasColumnName("id");
|
||||
|
||||
NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id"));
|
||||
|
||||
b.Property<decimal>("GuildId")
|
||||
.HasColumnType("numeric(20,0)")
|
||||
.HasColumnName("guildid");
|
||||
|
||||
b.Property<bool>("IsEnabled")
|
||||
.HasColumnType("boolean")
|
||||
.HasColumnName("isenabled");
|
||||
|
||||
b.HasKey("Id")
|
||||
.HasName("pk_sarautodelete");
|
||||
|
||||
b.HasIndex("GuildId")
|
||||
.IsUnique()
|
||||
.HasDatabaseName("ix_selfassignableroles_guildid_roleid");
|
||||
.HasDatabaseName("ix_sarautodelete_guildid");
|
||||
|
||||
b.ToTable("selfassignableroles", (string)null);
|
||||
b.ToTable("sarautodelete", (string)null);
|
||||
});
|
||||
|
||||
modelBuilder.Entity("NadekoBot.Db.Models.SarGroup", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("integer")
|
||||
.HasColumnName("id");
|
||||
|
||||
NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id"));
|
||||
|
||||
b.Property<int>("GroupNumber")
|
||||
.HasColumnType("integer")
|
||||
.HasColumnName("groupnumber");
|
||||
|
||||
b.Property<decimal>("GuildId")
|
||||
.HasColumnType("numeric(20,0)")
|
||||
.HasColumnName("guildid");
|
||||
|
||||
b.Property<bool>("IsExclusive")
|
||||
.HasColumnType("boolean")
|
||||
.HasColumnName("isexclusive");
|
||||
|
||||
b.Property<string>("Name")
|
||||
.HasMaxLength(100)
|
||||
.HasColumnType("character varying(100)")
|
||||
.HasColumnName("name");
|
||||
|
||||
b.Property<decimal?>("RoleReq")
|
||||
.HasColumnType("numeric(20,0)")
|
||||
.HasColumnName("rolereq");
|
||||
|
||||
b.HasKey("Id")
|
||||
.HasName("pk_sargroup");
|
||||
|
||||
b.HasAlternateKey("GuildId", "GroupNumber")
|
||||
.HasName("ak_sargroup_guildid_groupnumber");
|
||||
|
||||
b.ToTable("sargroup", (string)null);
|
||||
});
|
||||
|
||||
modelBuilder.Entity("NadekoBot.Db.Models.ShopEntry", b =>
|
||||
@@ -2938,9 +3139,9 @@ namespace NadekoBot.Migrations.PostgreSql
|
||||
.HasColumnType("timestamp without time zone")
|
||||
.HasColumnName("dateadded");
|
||||
|
||||
b.Property<int?>("GuildConfigId")
|
||||
.HasColumnType("integer")
|
||||
.HasColumnName("guildconfigid");
|
||||
b.Property<decimal>("GuildId")
|
||||
.HasColumnType("numeric(20,0)")
|
||||
.HasColumnName("guildid");
|
||||
|
||||
b.Property<int>("Punishment")
|
||||
.HasColumnType("integer")
|
||||
@@ -2957,8 +3158,8 @@ namespace NadekoBot.Migrations.PostgreSql
|
||||
b.HasKey("Id")
|
||||
.HasName("pk_warningpunishment");
|
||||
|
||||
b.HasIndex("GuildConfigId")
|
||||
.HasDatabaseName("ix_warningpunishment_guildconfigid");
|
||||
b.HasAlternateKey("GuildId", "Count")
|
||||
.HasName("ak_warningpunishment_guildid_count");
|
||||
|
||||
b.ToTable("warningpunishment", (string)null);
|
||||
});
|
||||
@@ -3154,6 +3355,74 @@ namespace NadekoBot.Migrations.PostgreSql
|
||||
b.ToTable("greetsettings", (string)null);
|
||||
});
|
||||
|
||||
modelBuilder.Entity("NadekoBot.Services.Rakeback", b =>
|
||||
{
|
||||
b.Property<decimal>("UserId")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("numeric(20,0)")
|
||||
.HasColumnName("userid");
|
||||
|
||||
b.Property<decimal>("Amount")
|
||||
.HasColumnType("numeric")
|
||||
.HasColumnName("amount");
|
||||
|
||||
b.HasKey("UserId")
|
||||
.HasName("pk_rakeback");
|
||||
|
||||
b.ToTable("rakeback", (string)null);
|
||||
});
|
||||
|
||||
modelBuilder.Entity("NadekoBot.Services.UserBetStats", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("integer")
|
||||
.HasColumnName("id");
|
||||
|
||||
NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id"));
|
||||
|
||||
b.Property<int>("Game")
|
||||
.HasColumnType("integer")
|
||||
.HasColumnName("game");
|
||||
|
||||
b.Property<long>("LoseCount")
|
||||
.HasColumnType("bigint")
|
||||
.HasColumnName("losecount");
|
||||
|
||||
b.Property<long>("MaxBet")
|
||||
.HasColumnType("bigint")
|
||||
.HasColumnName("maxbet");
|
||||
|
||||
b.Property<long>("MaxWin")
|
||||
.HasColumnType("bigint")
|
||||
.HasColumnName("maxwin");
|
||||
|
||||
b.Property<decimal>("PaidOut")
|
||||
.HasColumnType("numeric")
|
||||
.HasColumnName("paidout");
|
||||
|
||||
b.Property<decimal>("TotalBet")
|
||||
.HasColumnType("numeric")
|
||||
.HasColumnName("totalbet");
|
||||
|
||||
b.Property<decimal>("UserId")
|
||||
.HasColumnType("numeric(20,0)")
|
||||
.HasColumnName("userid");
|
||||
|
||||
b.Property<long>("WinCount")
|
||||
.HasColumnType("bigint")
|
||||
.HasColumnName("wincount");
|
||||
|
||||
b.HasKey("Id")
|
||||
.HasName("pk_userbetstats");
|
||||
|
||||
b.HasIndex("UserId", "Game")
|
||||
.IsUnique()
|
||||
.HasDatabaseName("ix_userbetstats_userid_game");
|
||||
|
||||
b.ToTable("userbetstats", (string)null);
|
||||
});
|
||||
|
||||
modelBuilder.Entity("NadekoBot.Db.Models.AntiAltSetting", b =>
|
||||
{
|
||||
b.HasOne("NadekoBot.Db.Models.GuildConfig", null)
|
||||
@@ -3386,18 +3655,6 @@ namespace NadekoBot.Migrations.PostgreSql
|
||||
.HasConstraintName("fk_giveawayuser_giveawaymodel_giveawayid");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("NadekoBot.Db.Models.GroupName", b =>
|
||||
{
|
||||
b.HasOne("NadekoBot.Db.Models.GuildConfig", "GuildConfig")
|
||||
.WithMany("SelfAssignableRoleGroupNames")
|
||||
.HasForeignKey("GuildConfigId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired()
|
||||
.HasConstraintName("fk_groupname_guildconfigs_guildconfigid");
|
||||
|
||||
b.Navigation("GuildConfig");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("NadekoBot.Db.Models.IgnoredLogItem", b =>
|
||||
{
|
||||
b.HasOne("NadekoBot.Db.Models.LogSetting", "LogSetting")
|
||||
@@ -3437,6 +3694,16 @@ namespace NadekoBot.Migrations.PostgreSql
|
||||
.HasConstraintName("fk_playlistsong_musicplaylists_musicplaylistid");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("NadekoBot.Db.Models.Sar", b =>
|
||||
{
|
||||
b.HasOne("NadekoBot.Db.Models.SarGroup", null)
|
||||
.WithMany("Roles")
|
||||
.HasForeignKey("SarGroupId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired()
|
||||
.HasConstraintName("fk_sar_sargroup_sargroupid");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("NadekoBot.Db.Models.ShopEntry", b =>
|
||||
{
|
||||
b.HasOne("NadekoBot.Db.Models.GuildConfig", null)
|
||||
@@ -3616,15 +3883,6 @@ namespace NadekoBot.Migrations.PostgreSql
|
||||
b.Navigation("User");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("NadekoBot.Db.Models.WarningPunishment", b =>
|
||||
{
|
||||
b.HasOne("NadekoBot.Db.Models.GuildConfig", null)
|
||||
.WithMany("WarnPunishments")
|
||||
.HasForeignKey("GuildConfigId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.HasConstraintName("fk_warningpunishment_guildconfigs_guildconfigid");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("NadekoBot.Db.Models.XpCurrencyReward", b =>
|
||||
{
|
||||
b.HasOne("NadekoBot.Db.Models.XpSettings", "XpSettings")
|
||||
@@ -3722,8 +3980,6 @@ namespace NadekoBot.Migrations.PostgreSql
|
||||
|
||||
b.Navigation("Permissions");
|
||||
|
||||
b.Navigation("SelfAssignableRoleGroupNames");
|
||||
|
||||
b.Navigation("ShopEntries");
|
||||
|
||||
b.Navigation("SlowmodeIgnoredRoles");
|
||||
@@ -3740,8 +3996,6 @@ namespace NadekoBot.Migrations.PostgreSql
|
||||
|
||||
b.Navigation("VcRoleInfos");
|
||||
|
||||
b.Navigation("WarnPunishments");
|
||||
|
||||
b.Navigation("XpSettings");
|
||||
});
|
||||
|
||||
@@ -3755,6 +4009,11 @@ namespace NadekoBot.Migrations.PostgreSql
|
||||
b.Navigation("Songs");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("NadekoBot.Db.Models.SarGroup", b =>
|
||||
{
|
||||
b.Navigation("Roles");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("NadekoBot.Db.Models.ShopEntry", b =>
|
||||
{
|
||||
b.Navigation("Items");
|
||||
|
2919
src/NadekoBot/Migrations/Sqlite/20241018004612_warn-split.Designer.cs
generated
Normal file
2919
src/NadekoBot/Migrations/Sqlite/20241018004612_warn-split.Designer.cs
generated
Normal file
File diff suppressed because it is too large
Load Diff
72
src/NadekoBot/Migrations/Sqlite/20241018004612_warn-split.cs
Normal file
72
src/NadekoBot/Migrations/Sqlite/20241018004612_warn-split.cs
Normal file
@@ -0,0 +1,72 @@
|
||||
using Microsoft.EntityFrameworkCore.Metadata.Internal;
|
||||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
|
||||
#nullable disable
|
||||
|
||||
namespace NadekoBot.Migrations
|
||||
{
|
||||
/// <inheritdoc />
|
||||
public partial class warnsplit : Migration
|
||||
{
|
||||
/// <inheritdoc />
|
||||
protected override void Up(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.AddColumn<ulong>(
|
||||
name: "GuildId",
|
||||
table: "WarningPunishment",
|
||||
type: "INTEGER",
|
||||
nullable: false,
|
||||
defaultValue: 0ul);
|
||||
|
||||
MigrationQueries.AddGuildIdsToWarningPunishment(migrationBuilder);
|
||||
|
||||
migrationBuilder.DropForeignKey(
|
||||
name: "FK_WarningPunishment_GuildConfigs_GuildConfigId",
|
||||
table: "WarningPunishment");
|
||||
|
||||
migrationBuilder.DropIndex(
|
||||
name: "IX_WarningPunishment_GuildConfigId",
|
||||
table: "WarningPunishment");
|
||||
|
||||
migrationBuilder.DropColumn(
|
||||
name: "GuildConfigId",
|
||||
table: "WarningPunishment");
|
||||
|
||||
migrationBuilder.AddUniqueConstraint(
|
||||
name: "AK_WarningPunishment_GuildId_Count",
|
||||
table: "WarningPunishment",
|
||||
columns: new[] { "GuildId", "Count" });
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override void Down(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.DropUniqueConstraint(
|
||||
name: "AK_WarningPunishment_GuildId_Count",
|
||||
table: "WarningPunishment");
|
||||
|
||||
migrationBuilder.DropColumn(
|
||||
name: "GuildId",
|
||||
table: "WarningPunishment");
|
||||
|
||||
migrationBuilder.AddColumn<int>(
|
||||
name: "GuildConfigId",
|
||||
table: "WarningPunishment",
|
||||
type: "INTEGER",
|
||||
nullable: true);
|
||||
|
||||
migrationBuilder.CreateIndex(
|
||||
name: "IX_WarningPunishment_GuildConfigId",
|
||||
table: "WarningPunishment",
|
||||
column: "GuildConfigId");
|
||||
|
||||
migrationBuilder.AddForeignKey(
|
||||
name: "FK_WarningPunishment_GuildConfigs_GuildConfigId",
|
||||
table: "WarningPunishment",
|
||||
column: "GuildConfigId",
|
||||
principalTable: "GuildConfigs",
|
||||
principalColumn: "Id",
|
||||
onDelete: ReferentialAction.Cascade);
|
||||
}
|
||||
}
|
||||
}
|
2953
src/NadekoBot/Migrations/Sqlite/20241028033656_ncanvas.Designer.cs
generated
Normal file
2953
src/NadekoBot/Migrations/Sqlite/20241028033656_ncanvas.Designer.cs
generated
Normal file
File diff suppressed because it is too large
Load Diff
53
src/NadekoBot/Migrations/Sqlite/20241028033656_ncanvas.cs
Normal file
53
src/NadekoBot/Migrations/Sqlite/20241028033656_ncanvas.cs
Normal file
@@ -0,0 +1,53 @@
|
||||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
|
||||
#nullable disable
|
||||
|
||||
namespace NadekoBot.Migrations
|
||||
{
|
||||
/// <inheritdoc />
|
||||
public partial class ncanvas : Migration
|
||||
{
|
||||
/// <inheritdoc />
|
||||
protected override void Up(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.CreateTable(
|
||||
name: "NCPixel",
|
||||
columns: table => new
|
||||
{
|
||||
Id = table.Column<int>(type: "INTEGER", nullable: false)
|
||||
.Annotation("Sqlite:Autoincrement", true),
|
||||
Position = table.Column<int>(type: "INTEGER", nullable: false),
|
||||
Price = table.Column<long>(type: "INTEGER", nullable: false),
|
||||
OwnerId = table.Column<ulong>(type: "INTEGER", nullable: false),
|
||||
Color = table.Column<uint>(type: "INTEGER", nullable: false),
|
||||
Text = table.Column<string>(type: "TEXT", maxLength: 256, nullable: false)
|
||||
},
|
||||
constraints: table =>
|
||||
{
|
||||
table.PrimaryKey("PK_NCPixel", x => x.Id);
|
||||
table.UniqueConstraint("AK_NCPixel_Position", x => x.Position);
|
||||
});
|
||||
|
||||
migrationBuilder.CreateIndex(
|
||||
name: "IX_DiscordUser_Username",
|
||||
table: "DiscordUser",
|
||||
column: "Username");
|
||||
|
||||
migrationBuilder.CreateIndex(
|
||||
name: "IX_NCPixel_OwnerId",
|
||||
table: "NCPixel",
|
||||
column: "OwnerId");
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override void Down(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.DropTable(
|
||||
name: "NCPixel");
|
||||
|
||||
migrationBuilder.DropIndex(
|
||||
name: "IX_DiscordUser_Username",
|
||||
table: "DiscordUser");
|
||||
}
|
||||
}
|
||||
}
|
2973
src/NadekoBot/Migrations/Sqlite/20241102022949_no-discrim-and-flag-translate.Designer.cs
generated
Normal file
2973
src/NadekoBot/Migrations/Sqlite/20241102022949_no-discrim-and-flag-translate.Designer.cs
generated
Normal file
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,53 @@
|
||||
using System;
|
||||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
|
||||
#nullable disable
|
||||
|
||||
namespace NadekoBot.Migrations
|
||||
{
|
||||
/// <inheritdoc />
|
||||
public partial class nodiscrimandflagtranslate : Migration
|
||||
{
|
||||
/// <inheritdoc />
|
||||
protected override void Up(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.DropColumn(
|
||||
name: "Discriminator",
|
||||
table: "DiscordUser");
|
||||
|
||||
migrationBuilder.CreateTable(
|
||||
name: "FlagTranslateChannel",
|
||||
columns: table => new
|
||||
{
|
||||
Id = table.Column<int>(type: "INTEGER", nullable: false)
|
||||
.Annotation("Sqlite:Autoincrement", true),
|
||||
GuildId = table.Column<ulong>(type: "INTEGER", nullable: false),
|
||||
ChannelId = table.Column<ulong>(type: "INTEGER", nullable: false),
|
||||
DateAdded = table.Column<DateTime>(type: "TEXT", nullable: true)
|
||||
},
|
||||
constraints: table =>
|
||||
{
|
||||
table.PrimaryKey("PK_FlagTranslateChannel", x => x.Id);
|
||||
});
|
||||
|
||||
migrationBuilder.CreateIndex(
|
||||
name: "IX_FlagTranslateChannel_GuildId_ChannelId",
|
||||
table: "FlagTranslateChannel",
|
||||
columns: new[] { "GuildId", "ChannelId" },
|
||||
unique: true);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override void Down(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.DropTable(
|
||||
name: "FlagTranslateChannel");
|
||||
|
||||
migrationBuilder.AddColumn<string>(
|
||||
name: "Discriminator",
|
||||
table: "DiscordUser",
|
||||
type: "TEXT",
|
||||
nullable: true);
|
||||
}
|
||||
}
|
||||
}
|
3011
src/NadekoBot/Migrations/Sqlite/20241104094222_betstats.Designer.cs
generated
Normal file
3011
src/NadekoBot/Migrations/Sqlite/20241104094222_betstats.Designer.cs
generated
Normal file
File diff suppressed because it is too large
Load Diff
47
src/NadekoBot/Migrations/Sqlite/20241104094222_betstats.cs
Normal file
47
src/NadekoBot/Migrations/Sqlite/20241104094222_betstats.cs
Normal file
@@ -0,0 +1,47 @@
|
||||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
|
||||
#nullable disable
|
||||
|
||||
namespace NadekoBot.Migrations
|
||||
{
|
||||
/// <inheritdoc />
|
||||
public partial class betstats : Migration
|
||||
{
|
||||
/// <inheritdoc />
|
||||
protected override void Up(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.CreateTable(
|
||||
name: "UserBetStats",
|
||||
columns: table => new
|
||||
{
|
||||
Id = table.Column<int>(type: "INTEGER", nullable: false)
|
||||
.Annotation("Sqlite:Autoincrement", true),
|
||||
UserId = table.Column<ulong>(type: "INTEGER", nullable: false),
|
||||
Game = table.Column<int>(type: "INTEGER", nullable: false),
|
||||
WinCount = table.Column<long>(type: "INTEGER", nullable: false),
|
||||
LoseCount = table.Column<long>(type: "INTEGER", nullable: false),
|
||||
TotalBet = table.Column<decimal>(type: "TEXT", nullable: false),
|
||||
PaidOut = table.Column<decimal>(type: "TEXT", nullable: false),
|
||||
MaxWin = table.Column<long>(type: "INTEGER", nullable: false),
|
||||
MaxBet = table.Column<long>(type: "INTEGER", nullable: false)
|
||||
},
|
||||
constraints: table =>
|
||||
{
|
||||
table.PrimaryKey("PK_UserBetStats", x => x.Id);
|
||||
});
|
||||
|
||||
migrationBuilder.CreateIndex(
|
||||
name: "IX_UserBetStats_UserId_Game",
|
||||
table: "UserBetStats",
|
||||
columns: new[] { "UserId", "Game" },
|
||||
unique: true);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override void Down(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.DropTable(
|
||||
name: "UserBetStats");
|
||||
}
|
||||
}
|
||||
}
|
3025
src/NadekoBot/Migrations/Sqlite/20241105072953_rakeback.Designer.cs
generated
Normal file
3025
src/NadekoBot/Migrations/Sqlite/20241105072953_rakeback.Designer.cs
generated
Normal file
File diff suppressed because it is too large
Load Diff
34
src/NadekoBot/Migrations/Sqlite/20241105072953_rakeback.cs
Normal file
34
src/NadekoBot/Migrations/Sqlite/20241105072953_rakeback.cs
Normal file
@@ -0,0 +1,34 @@
|
||||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
|
||||
#nullable disable
|
||||
|
||||
namespace NadekoBot.Migrations
|
||||
{
|
||||
/// <inheritdoc />
|
||||
public partial class rakeback : Migration
|
||||
{
|
||||
/// <inheritdoc />
|
||||
protected override void Up(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.CreateTable(
|
||||
name: "Rakeback",
|
||||
columns: table => new
|
||||
{
|
||||
UserId = table.Column<ulong>(type: "INTEGER", nullable: false)
|
||||
.Annotation("Sqlite:Autoincrement", true),
|
||||
Amount = table.Column<decimal>(type: "TEXT", nullable: false)
|
||||
},
|
||||
constraints: table =>
|
||||
{
|
||||
table.PrimaryKey("PK_Rakeback", x => x.UserId);
|
||||
});
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override void Down(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.DropTable(
|
||||
name: "Rakeback");
|
||||
}
|
||||
}
|
||||
}
|
3045
src/NadekoBot/Migrations/Sqlite/20241115171638_sar-rework.Designer.cs
generated
Normal file
3045
src/NadekoBot/Migrations/Sqlite/20241115171638_sar-rework.Designer.cs
generated
Normal file
File diff suppressed because it is too large
Load Diff
163
src/NadekoBot/Migrations/Sqlite/20241115171638_sar-rework.cs
Normal file
163
src/NadekoBot/Migrations/Sqlite/20241115171638_sar-rework.cs
Normal file
@@ -0,0 +1,163 @@
|
||||
using System;
|
||||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
|
||||
#nullable disable
|
||||
|
||||
namespace NadekoBot.Migrations
|
||||
{
|
||||
/// <inheritdoc />
|
||||
public partial class sarrework : Migration
|
||||
{
|
||||
/// <inheritdoc />
|
||||
protected override void Up(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.CreateTable(
|
||||
name: "SarAutoDelete",
|
||||
columns: table => new
|
||||
{
|
||||
Id = table.Column<int>(type: "INTEGER", nullable: false)
|
||||
.Annotation("Sqlite:Autoincrement", true),
|
||||
GuildId = table.Column<ulong>(type: "INTEGER", nullable: false),
|
||||
IsEnabled = table.Column<bool>(type: "INTEGER", nullable: false)
|
||||
},
|
||||
constraints: table =>
|
||||
{
|
||||
table.PrimaryKey("PK_SarAutoDelete", x => x.Id);
|
||||
});
|
||||
|
||||
migrationBuilder.CreateTable(
|
||||
name: "SarGroup",
|
||||
columns: table => new
|
||||
{
|
||||
Id = table.Column<int>(type: "INTEGER", nullable: false)
|
||||
.Annotation("Sqlite:Autoincrement", true),
|
||||
GroupNumber = table.Column<int>(type: "INTEGER", nullable: false),
|
||||
GuildId = table.Column<ulong>(type: "INTEGER", nullable: false),
|
||||
RoleReq = table.Column<ulong>(type: "INTEGER", nullable: true),
|
||||
IsExclusive = table.Column<bool>(type: "INTEGER", nullable: false),
|
||||
Name = table.Column<string>(type: "TEXT", maxLength: 100, nullable: true)
|
||||
},
|
||||
constraints: table =>
|
||||
{
|
||||
table.PrimaryKey("PK_SarGroup", x => x.Id);
|
||||
table.UniqueConstraint("AK_SarGroup_GuildId_GroupNumber",
|
||||
x => new
|
||||
{
|
||||
x.GuildId,
|
||||
x.GroupNumber
|
||||
});
|
||||
});
|
||||
|
||||
migrationBuilder.CreateTable(
|
||||
name: "Sar",
|
||||
columns: table => new
|
||||
{
|
||||
Id = table.Column<int>(type: "INTEGER", nullable: false)
|
||||
.Annotation("Sqlite:Autoincrement", true),
|
||||
GuildId = table.Column<ulong>(type: "INTEGER", nullable: false),
|
||||
RoleId = table.Column<ulong>(type: "INTEGER", nullable: false),
|
||||
SarGroupId = table.Column<int>(type: "INTEGER", nullable: false),
|
||||
LevelReq = table.Column<int>(type: "INTEGER", nullable: false)
|
||||
},
|
||||
constraints: table =>
|
||||
{
|
||||
table.PrimaryKey("PK_Sar", x => x.Id);
|
||||
table.UniqueConstraint("AK_Sar_GuildId_RoleId",
|
||||
x => new
|
||||
{
|
||||
x.GuildId,
|
||||
x.RoleId
|
||||
});
|
||||
table.ForeignKey(
|
||||
name: "FK_Sar_SarGroup_SarGroupId",
|
||||
column: x => x.SarGroupId,
|
||||
principalTable: "SarGroup",
|
||||
principalColumn: "Id",
|
||||
onDelete: ReferentialAction.Cascade);
|
||||
});
|
||||
|
||||
migrationBuilder.CreateIndex(
|
||||
name: "IX_Sar_SarGroupId",
|
||||
table: "Sar",
|
||||
column: "SarGroupId");
|
||||
|
||||
migrationBuilder.CreateIndex(
|
||||
name: "IX_SarAutoDelete_GuildId",
|
||||
table: "SarAutoDelete",
|
||||
column: "GuildId",
|
||||
unique: true);
|
||||
|
||||
MigrationQueries.MigrateSar(migrationBuilder);
|
||||
|
||||
migrationBuilder.DropTable(
|
||||
name: "GroupName");
|
||||
|
||||
migrationBuilder.DropTable(
|
||||
name: "SelfAssignableRoles");
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override void Down(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.DropTable(
|
||||
name: "Sar");
|
||||
|
||||
migrationBuilder.DropTable(
|
||||
name: "SarAutoDelete");
|
||||
|
||||
migrationBuilder.DropTable(
|
||||
name: "SarGroup");
|
||||
|
||||
migrationBuilder.CreateTable(
|
||||
name: "GroupName",
|
||||
columns: table => new
|
||||
{
|
||||
Id = table.Column<int>(type: "INTEGER", nullable: false)
|
||||
.Annotation("Sqlite:Autoincrement", true),
|
||||
GuildConfigId = table.Column<int>(type: "INTEGER", nullable: false),
|
||||
DateAdded = table.Column<DateTime>(type: "TEXT", nullable: true),
|
||||
Name = table.Column<string>(type: "TEXT", nullable: true),
|
||||
Number = table.Column<int>(type: "INTEGER", nullable: false)
|
||||
},
|
||||
constraints: table =>
|
||||
{
|
||||
table.PrimaryKey("PK_GroupName", x => x.Id);
|
||||
table.ForeignKey(
|
||||
name: "FK_GroupName_GuildConfigs_GuildConfigId",
|
||||
column: x => x.GuildConfigId,
|
||||
principalTable: "GuildConfigs",
|
||||
principalColumn: "Id",
|
||||
onDelete: ReferentialAction.Cascade);
|
||||
});
|
||||
|
||||
migrationBuilder.CreateTable(
|
||||
name: "SelfAssignableRoles",
|
||||
columns: table => new
|
||||
{
|
||||
Id = table.Column<int>(type: "INTEGER", nullable: false)
|
||||
.Annotation("Sqlite:Autoincrement", true),
|
||||
DateAdded = table.Column<DateTime>(type: "TEXT", nullable: true),
|
||||
Group = table.Column<int>(type: "INTEGER", nullable: false, defaultValue: 0),
|
||||
GuildId = table.Column<ulong>(type: "INTEGER", nullable: false),
|
||||
LevelRequirement = table.Column<int>(type: "INTEGER", nullable: false),
|
||||
RoleId = table.Column<ulong>(type: "INTEGER", nullable: false)
|
||||
},
|
||||
constraints: table =>
|
||||
{
|
||||
table.PrimaryKey("PK_SelfAssignableRoles", x => x.Id);
|
||||
});
|
||||
|
||||
migrationBuilder.CreateIndex(
|
||||
name: "IX_GroupName_GuildConfigId_Number",
|
||||
table: "GroupName",
|
||||
columns: new[] { "GuildConfigId", "Number" },
|
||||
unique: true);
|
||||
|
||||
migrationBuilder.CreateIndex(
|
||||
name: "IX_SelfAssignableRoles_GuildId_RoleId",
|
||||
table: "SelfAssignableRoles",
|
||||
columns: new[] { "GuildId", "RoleId" },
|
||||
unique: true);
|
||||
}
|
||||
}
|
||||
}
|
3122
src/NadekoBot/Migrations/Sqlite/20241126033626_btnroles_guildcolors.Designer.cs
generated
Normal file
3122
src/NadekoBot/Migrations/Sqlite/20241126033626_btnroles_guildcolors.Designer.cs
generated
Normal file
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,73 @@
|
||||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
|
||||
#nullable disable
|
||||
|
||||
namespace NadekoBot.Migrations
|
||||
{
|
||||
/// <inheritdoc />
|
||||
public partial class btnroles_guildcolors : Migration
|
||||
{
|
||||
/// <inheritdoc />
|
||||
protected override void Up(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.CreateTable(
|
||||
name: "ButtonRole",
|
||||
columns: table => new
|
||||
{
|
||||
Id = table.Column<int>(type: "INTEGER", nullable: false)
|
||||
.Annotation("Sqlite:Autoincrement", true),
|
||||
ButtonId = table.Column<string>(type: "TEXT", maxLength: 200, nullable: false),
|
||||
GuildId = table.Column<ulong>(type: "INTEGER", nullable: false),
|
||||
ChannelId = table.Column<ulong>(type: "INTEGER", nullable: false),
|
||||
MessageId = table.Column<ulong>(type: "INTEGER", nullable: false),
|
||||
Position = table.Column<int>(type: "INTEGER", nullable: false),
|
||||
RoleId = table.Column<ulong>(type: "INTEGER", nullable: false),
|
||||
Emote = table.Column<string>(type: "TEXT", maxLength: 100, nullable: false),
|
||||
Label = table.Column<string>(type: "TEXT", maxLength: 50, nullable: false),
|
||||
Exclusive = table.Column<bool>(type: "INTEGER", nullable: false)
|
||||
},
|
||||
constraints: table =>
|
||||
{
|
||||
table.PrimaryKey("PK_ButtonRole", x => x.Id);
|
||||
table.UniqueConstraint("AK_ButtonRole_RoleId_MessageId", x => new { x.RoleId, x.MessageId });
|
||||
});
|
||||
|
||||
migrationBuilder.CreateTable(
|
||||
name: "GuildColors",
|
||||
columns: table => new
|
||||
{
|
||||
Id = table.Column<int>(type: "INTEGER", nullable: false)
|
||||
.Annotation("Sqlite:Autoincrement", true),
|
||||
GuildId = table.Column<ulong>(type: "INTEGER", nullable: false),
|
||||
OkColor = table.Column<string>(type: "TEXT", maxLength: 9, nullable: true),
|
||||
ErrorColor = table.Column<string>(type: "TEXT", maxLength: 9, nullable: true),
|
||||
PendingColor = table.Column<string>(type: "TEXT", maxLength: 9, nullable: true)
|
||||
},
|
||||
constraints: table =>
|
||||
{
|
||||
table.PrimaryKey("PK_GuildColors", x => x.Id);
|
||||
});
|
||||
|
||||
migrationBuilder.CreateIndex(
|
||||
name: "IX_ButtonRole_GuildId",
|
||||
table: "ButtonRole",
|
||||
column: "GuildId");
|
||||
|
||||
migrationBuilder.CreateIndex(
|
||||
name: "IX_GuildColors_GuildId",
|
||||
table: "GuildColors",
|
||||
column: "GuildId",
|
||||
unique: true);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override void Down(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.DropTable(
|
||||
name: "ButtonRole");
|
||||
|
||||
migrationBuilder.DropTable(
|
||||
name: "GuildColors");
|
||||
}
|
||||
}
|
||||
}
|
@@ -335,6 +335,54 @@ namespace NadekoBot.Migrations
|
||||
b.ToTable("Blacklist");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("NadekoBot.Db.Models.ButtonRole", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<string>("ButtonId")
|
||||
.IsRequired()
|
||||
.HasMaxLength(200)
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<ulong>("ChannelId")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<string>("Emote")
|
||||
.IsRequired()
|
||||
.HasMaxLength(100)
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<bool>("Exclusive")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<ulong>("GuildId")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<string>("Label")
|
||||
.IsRequired()
|
||||
.HasMaxLength(50)
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<ulong>("MessageId")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<int>("Position")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<ulong>("RoleId")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasAlternateKey("RoleId", "MessageId");
|
||||
|
||||
b.HasIndex("GuildId");
|
||||
|
||||
b.ToTable("ButtonRole");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("NadekoBot.Db.Models.ClubApplicants", b =>
|
||||
{
|
||||
b.Property<int>("ClubId")
|
||||
@@ -560,9 +608,6 @@ namespace NadekoBot.Migrations
|
||||
b.Property<DateTime?>("DateAdded")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("Discriminator")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<bool>("IsClubAdmin")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("INTEGER")
|
||||
@@ -596,6 +641,8 @@ namespace NadekoBot.Migrations
|
||||
|
||||
b.HasIndex("UserId");
|
||||
|
||||
b.HasIndex("Username");
|
||||
|
||||
b.ToTable("DiscordUser");
|
||||
});
|
||||
|
||||
@@ -741,6 +788,29 @@ namespace NadekoBot.Migrations
|
||||
b.ToTable("FilteredWord");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("NadekoBot.Db.Models.FlagTranslateChannel", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<ulong>("ChannelId")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<DateTime?>("DateAdded")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<ulong>("GuildId")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("GuildId", "ChannelId")
|
||||
.IsUnique();
|
||||
|
||||
b.ToTable("FlagTranslateChannel");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("NadekoBot.Db.Models.FollowedStream", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
@@ -872,30 +942,33 @@ namespace NadekoBot.Migrations
|
||||
b.ToTable("GiveawayUser");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("NadekoBot.Db.Models.GroupName", b =>
|
||||
modelBuilder.Entity("NadekoBot.Db.Models.GuildColors", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<DateTime?>("DateAdded")
|
||||
b.Property<string>("ErrorColor")
|
||||
.HasMaxLength(9)
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<int>("GuildConfigId")
|
||||
b.Property<ulong>("GuildId")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<string>("Name")
|
||||
b.Property<string>("OkColor")
|
||||
.HasMaxLength(9)
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<int>("Number")
|
||||
.HasColumnType("INTEGER");
|
||||
b.Property<string>("PendingColor")
|
||||
.HasMaxLength(9)
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("GuildConfigId", "Number")
|
||||
b.HasIndex("GuildId")
|
||||
.IsUnique();
|
||||
|
||||
b.ToTable("GroupName");
|
||||
b.ToTable("GuildColors");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("NadekoBot.Db.Models.GuildConfig", b =>
|
||||
@@ -1213,6 +1286,38 @@ namespace NadekoBot.Migrations
|
||||
b.ToTable("MutedUserId");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("NadekoBot.Db.Models.NCPixel", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<uint>("Color")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<ulong>("OwnerId")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<int>("Position")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<long>("Price")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<string>("Text")
|
||||
.IsRequired()
|
||||
.HasMaxLength(256)
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasAlternateKey("Position");
|
||||
|
||||
b.HasIndex("OwnerId");
|
||||
|
||||
b.ToTable("NCPixel");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("NadekoBot.Db.Models.NadekoExpression", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
@@ -1586,35 +1691,80 @@ namespace NadekoBot.Migrations
|
||||
b.ToTable("RotatingStatus");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("NadekoBot.Db.Models.SelfAssignedRole", b =>
|
||||
modelBuilder.Entity("NadekoBot.Db.Models.Sar", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<DateTime?>("DateAdded")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<int>("Group")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("INTEGER")
|
||||
.HasDefaultValue(0);
|
||||
|
||||
b.Property<ulong>("GuildId")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<int>("LevelRequirement")
|
||||
b.Property<int>("LevelReq")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<ulong>("RoleId")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<int>("SarGroupId")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("GuildId", "RoleId")
|
||||
b.HasAlternateKey("GuildId", "RoleId");
|
||||
|
||||
b.HasIndex("SarGroupId");
|
||||
|
||||
b.ToTable("Sar");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("NadekoBot.Db.Models.SarAutoDelete", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<ulong>("GuildId")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<bool>("IsEnabled")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("GuildId")
|
||||
.IsUnique();
|
||||
|
||||
b.ToTable("SelfAssignableRoles");
|
||||
b.ToTable("SarAutoDelete");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("NadekoBot.Db.Models.SarGroup", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<int>("GroupNumber")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<ulong>("GuildId")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<bool>("IsExclusive")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<string>("Name")
|
||||
.HasMaxLength(100)
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<ulong?>("RoleReq")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasAlternateKey("GuildId", "GroupNumber");
|
||||
|
||||
b.ToTable("SarGroup");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("NadekoBot.Db.Models.ShopEntry", b =>
|
||||
@@ -2183,7 +2333,7 @@ namespace NadekoBot.Migrations
|
||||
b.Property<DateTime?>("DateAdded")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<int?>("GuildConfigId")
|
||||
b.Property<ulong>("GuildId")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<int>("Punishment")
|
||||
@@ -2197,7 +2347,7 @@ namespace NadekoBot.Migrations
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("GuildConfigId");
|
||||
b.HasAlternateKey("GuildId", "Count");
|
||||
|
||||
b.ToTable("WarningPunishment");
|
||||
});
|
||||
@@ -2345,6 +2495,58 @@ namespace NadekoBot.Migrations
|
||||
b.ToTable("GreetSettings");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("NadekoBot.Services.Rakeback", b =>
|
||||
{
|
||||
b.Property<ulong>("UserId")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<decimal>("Amount")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.HasKey("UserId");
|
||||
|
||||
b.ToTable("Rakeback");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("NadekoBot.Services.UserBetStats", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<int>("Game")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<long>("LoseCount")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<long>("MaxBet")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<long>("MaxWin")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<decimal>("PaidOut")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<decimal>("TotalBet")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<ulong>("UserId")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<long>("WinCount")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("UserId", "Game")
|
||||
.IsUnique();
|
||||
|
||||
b.ToTable("UserBetStats");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("NadekoBot.Db.Models.AntiAltSetting", b =>
|
||||
{
|
||||
b.HasOne("NadekoBot.Db.Models.GuildConfig", null)
|
||||
@@ -2554,17 +2756,6 @@ namespace NadekoBot.Migrations
|
||||
.IsRequired();
|
||||
});
|
||||
|
||||
modelBuilder.Entity("NadekoBot.Db.Models.GroupName", b =>
|
||||
{
|
||||
b.HasOne("NadekoBot.Db.Models.GuildConfig", "GuildConfig")
|
||||
.WithMany("SelfAssignableRoleGroupNames")
|
||||
.HasForeignKey("GuildConfigId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
|
||||
b.Navigation("GuildConfig");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("NadekoBot.Db.Models.IgnoredLogItem", b =>
|
||||
{
|
||||
b.HasOne("NadekoBot.Db.Models.LogSetting", "LogSetting")
|
||||
@@ -2600,6 +2791,15 @@ namespace NadekoBot.Migrations
|
||||
.OnDelete(DeleteBehavior.Cascade);
|
||||
});
|
||||
|
||||
modelBuilder.Entity("NadekoBot.Db.Models.Sar", b =>
|
||||
{
|
||||
b.HasOne("NadekoBot.Db.Models.SarGroup", null)
|
||||
.WithMany("Roles")
|
||||
.HasForeignKey("SarGroupId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
});
|
||||
|
||||
modelBuilder.Entity("NadekoBot.Db.Models.ShopEntry", b =>
|
||||
{
|
||||
b.HasOne("NadekoBot.Db.Models.GuildConfig", null)
|
||||
@@ -2760,14 +2960,6 @@ namespace NadekoBot.Migrations
|
||||
b.Navigation("User");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("NadekoBot.Db.Models.WarningPunishment", b =>
|
||||
{
|
||||
b.HasOne("NadekoBot.Db.Models.GuildConfig", null)
|
||||
.WithMany("WarnPunishments")
|
||||
.HasForeignKey("GuildConfigId")
|
||||
.OnDelete(DeleteBehavior.Cascade);
|
||||
});
|
||||
|
||||
modelBuilder.Entity("NadekoBot.Db.Models.XpCurrencyReward", b =>
|
||||
{
|
||||
b.HasOne("NadekoBot.Db.Models.XpSettings", "XpSettings")
|
||||
@@ -2862,8 +3054,6 @@ namespace NadekoBot.Migrations
|
||||
|
||||
b.Navigation("Permissions");
|
||||
|
||||
b.Navigation("SelfAssignableRoleGroupNames");
|
||||
|
||||
b.Navigation("ShopEntries");
|
||||
|
||||
b.Navigation("SlowmodeIgnoredRoles");
|
||||
@@ -2880,8 +3070,6 @@ namespace NadekoBot.Migrations
|
||||
|
||||
b.Navigation("VcRoleInfos");
|
||||
|
||||
b.Navigation("WarnPunishments");
|
||||
|
||||
b.Navigation("XpSettings");
|
||||
});
|
||||
|
||||
@@ -2895,6 +3083,11 @@ namespace NadekoBot.Migrations
|
||||
b.Navigation("Songs");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("NadekoBot.Db.Models.SarGroup", b =>
|
||||
{
|
||||
b.Navigation("Roles");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("NadekoBot.Db.Models.ShopEntry", b =>
|
||||
{
|
||||
b.Navigation("Items");
|
||||
|
@@ -96,7 +96,7 @@ public partial class Administration : NadekoModule<AdministrationService>
|
||||
var guild = (SocketGuild)ctx.Guild;
|
||||
var (enabled, channels) = _service.GetDelMsgOnCmdData(ctx.Guild.Id);
|
||||
|
||||
var embed = _sender.CreateEmbed()
|
||||
var embed = CreateEmbed()
|
||||
.WithOkColor()
|
||||
.WithTitle(GetText(strs.server_delmsgoncmd))
|
||||
.WithDescription(enabled ? "✅" : "❌");
|
||||
|
@@ -3,7 +3,7 @@ using Microsoft.EntityFrameworkCore;
|
||||
using NadekoBot.Db.Models;
|
||||
using NadekoBot.Modules.Administration._common.results;
|
||||
|
||||
namespace NadekoBot.Modules.Administration.Services;
|
||||
namespace NadekoBot.Modules.Administration;
|
||||
|
||||
public class AdministrationService : INService
|
||||
{
|
||||
|
@@ -24,6 +24,13 @@ public partial class Administration
|
||||
await Response().Error(strs.hierarchy).SendAsync();
|
||||
return;
|
||||
}
|
||||
|
||||
// the user can't aar the role which is greater or equal to the bot's highest role
|
||||
if (role.Position >= ((SocketGuild)ctx.Guild).CurrentUser.GetRoles().Max(x => x.Position))
|
||||
{
|
||||
await Response().Error(strs.hierarchy).SendAsync();
|
||||
return;
|
||||
}
|
||||
|
||||
var roles = await _service.ToggleAarAsync(ctx.Guild.Id, role.Id);
|
||||
if (roles.Count == 0)
|
||||
|
@@ -1,4 +1,3 @@
|
||||
#nullable disable
|
||||
using LinqToDB;
|
||||
using LinqToDB.EntityFrameworkCore;
|
||||
using NadekoBot.Common.ModuleBehaviors;
|
||||
@@ -11,53 +10,63 @@ public class AutoPublishService : IExecNoCommand, IReadyExecutor, INService
|
||||
private readonly DbService _db;
|
||||
private readonly DiscordSocketClient _client;
|
||||
private readonly IBotCredsProvider _creds;
|
||||
private ConcurrentDictionary<ulong, ulong> _enabled;
|
||||
private ConcurrentDictionary<ulong, ulong> _enabled = new();
|
||||
|
||||
public AutoPublishService(DbService db, DiscordSocketClient client, IBotCredsProvider creds)
|
||||
{
|
||||
_db = db;
|
||||
_client = client;
|
||||
_creds = creds;
|
||||
}
|
||||
|
||||
public async Task ExecOnNoCommandAsync(IGuild guild, IUserMessage msg)
|
||||
}
|
||||
|
||||
public async Task ExecOnNoCommandAsync(IGuild? guild, IUserMessage msg)
|
||||
{
|
||||
if (guild is null)
|
||||
return;
|
||||
|
||||
|
||||
if (msg.Channel.GetChannelType() != ChannelType.News)
|
||||
return;
|
||||
|
||||
if (!_enabled.TryGetValue(guild.Id, out var cid) || cid != msg.Channel.Id)
|
||||
return;
|
||||
|
||||
|
||||
await msg.CrosspostAsync(new RequestOptions()
|
||||
{
|
||||
RetryMode = RetryMode.AlwaysFail
|
||||
});
|
||||
}
|
||||
|
||||
// todo GUILDS
|
||||
|
||||
public async Task OnReadyAsync()
|
||||
{
|
||||
var creds = _creds.GetCreds();
|
||||
|
||||
|
||||
await using var ctx = _db.GetDbContext();
|
||||
var items = await ctx.GetTable<AutoPublishChannel>()
|
||||
.Where(x => Linq2DbExpressions.GuildOnShard(x.GuildId, creds.TotalShards, _client.ShardId))
|
||||
.ToListAsyncLinqToDB();
|
||||
.Where(x => Linq2DbExpressions.GuildOnShard(x.GuildId, creds.TotalShards, _client.ShardId))
|
||||
.ToListAsyncLinqToDB();
|
||||
|
||||
_enabled = items
|
||||
.ToDictionary(x => x.GuildId, x => x.ChannelId)
|
||||
.ToConcurrent();
|
||||
.ToDictionary(x => x.GuildId, x => x.ChannelId)
|
||||
.ToConcurrent();
|
||||
|
||||
_client.LeftGuild += ClientOnLeftGuild;
|
||||
}
|
||||
|
||||
|
||||
private async Task ClientOnLeftGuild(SocketGuild guild)
|
||||
{
|
||||
await using var ctx = _db.GetDbContext();
|
||||
_enabled.TryRemove(guild.Id, out _);
|
||||
|
||||
await ctx.GetTable<AutoPublishChannel>()
|
||||
.Where(x => x.GuildId == guild.Id)
|
||||
.DeleteAsync();
|
||||
}
|
||||
|
||||
public async Task<bool> ToggleAutoPublish(ulong guildId, ulong channelId)
|
||||
{
|
||||
await using var ctx = _db.GetDbContext();
|
||||
var deleted = await ctx.GetTable<AutoPublishChannel>()
|
||||
.DeleteAsync(x => x.GuildId == guildId && x.ChannelId == channelId);
|
||||
.DeleteAsync(x => x.GuildId == guildId && x.ChannelId == channelId);
|
||||
|
||||
if (deleted != 0)
|
||||
{
|
||||
@@ -66,22 +75,22 @@ public class AutoPublishService : IExecNoCommand, IReadyExecutor, INService
|
||||
}
|
||||
|
||||
await ctx.GetTable<AutoPublishChannel>()
|
||||
.InsertOrUpdateAsync(() => new()
|
||||
{
|
||||
GuildId = guildId,
|
||||
ChannelId = channelId,
|
||||
DateAdded = DateTime.UtcNow,
|
||||
},
|
||||
old => new()
|
||||
{
|
||||
ChannelId = channelId,
|
||||
DateAdded = DateTime.UtcNow,
|
||||
},
|
||||
() => new()
|
||||
{
|
||||
GuildId = guildId
|
||||
});
|
||||
|
||||
.InsertOrUpdateAsync(() => new()
|
||||
{
|
||||
GuildId = guildId,
|
||||
ChannelId = channelId,
|
||||
DateAdded = DateTime.UtcNow,
|
||||
},
|
||||
old => new()
|
||||
{
|
||||
ChannelId = channelId,
|
||||
DateAdded = DateTime.UtcNow,
|
||||
},
|
||||
() => new()
|
||||
{
|
||||
GuildId = guildId
|
||||
});
|
||||
|
||||
_enabled[guildId] = channelId;
|
||||
|
||||
return true;
|
||||
|
@@ -136,7 +136,7 @@ public sealed class CleanupService : ICleanupService, IReadyExecutor, INService
|
||||
await using var linqCtx = ctx.CreateLinqToDBContext();
|
||||
await using var tempTable = linqCtx.CreateTempTable<CleanupId>();
|
||||
|
||||
foreach (var chunk in allIds.Chunk(20000))
|
||||
foreach (var chunk in allIds.Chunk(10000))
|
||||
{
|
||||
await tempTable.BulkCopyAsync(chunk.Select(x => new CleanupId()
|
||||
{
|
||||
@@ -187,13 +187,6 @@ public sealed class CleanupService : ICleanupService, IReadyExecutor, INService
|
||||
.Contains(x.GuildId))
|
||||
.DeleteAsync();
|
||||
|
||||
// delete ignored users
|
||||
await ctx.GetTable<DiscordPermOverride>()
|
||||
.Where(x => x.GuildId != null
|
||||
&& !tempTable.Select(x => x.GuildId)
|
||||
.Contains(x.GuildId.Value))
|
||||
.DeleteAsync();
|
||||
|
||||
// delete perm overrides
|
||||
await ctx.GetTable<DiscordPermOverride>()
|
||||
.Where(x => x.GuildId != null
|
||||
@@ -206,7 +199,67 @@ public sealed class CleanupService : ICleanupService, IReadyExecutor, INService
|
||||
.Where(x => !tempTable.Select(x => x.GuildId)
|
||||
.Contains(x.GuildId))
|
||||
.DeleteAsync();
|
||||
|
||||
|
||||
// delete autopublish channels
|
||||
await ctx.GetTable<AutoPublishChannel>()
|
||||
.Where(x => !tempTable.Select(x => x.GuildId)
|
||||
.Contains(x.GuildId))
|
||||
.DeleteAsync();
|
||||
|
||||
// delete greet settings
|
||||
await ctx.GetTable<GreetSettings>()
|
||||
.Where(x => !tempTable.Select(x => x.GuildId)
|
||||
.Contains(x.GuildId))
|
||||
.DeleteAsync();
|
||||
|
||||
// delete sar
|
||||
await ctx.GetTable<SarGroup>()
|
||||
.Where(x => !tempTable.Select(x => x.GuildId)
|
||||
.Contains(x.GuildId))
|
||||
.DeleteAsync();
|
||||
|
||||
// delete warnings
|
||||
await ctx.GetTable<Warning>()
|
||||
.Where(x => !tempTable.Select(x => x.GuildId)
|
||||
.Contains(x.GuildId))
|
||||
.DeleteAsync();
|
||||
|
||||
// delete warn punishments
|
||||
await ctx.GetTable<WarningPunishment>()
|
||||
.Where(x => !tempTable.Select(x => x.GuildId)
|
||||
.Contains(x.GuildId))
|
||||
.DeleteAsync();
|
||||
|
||||
// delete sticky roles
|
||||
await ctx.GetTable<StickyRole>()
|
||||
.Where(x => !tempTable.Select(x => x.GuildId)
|
||||
.Contains(x.GuildId))
|
||||
.DeleteAsync();
|
||||
|
||||
// delete at channels
|
||||
await ctx.GetTable<AutoTranslateChannel>()
|
||||
.Where(x => !tempTable.Select(x => x.GuildId)
|
||||
.Contains(x.GuildId))
|
||||
.DeleteAsync();
|
||||
|
||||
// delete ban templates
|
||||
await ctx.GetTable<BanTemplate>()
|
||||
.Where(x => !tempTable.Select(x => x.GuildId)
|
||||
.Contains(x.GuildId))
|
||||
.DeleteAsync();
|
||||
|
||||
// delete reminders
|
||||
await ctx.GetTable<Reminder>()
|
||||
.Where(x => !tempTable.Select(x => x.GuildId)
|
||||
.Contains(x.ServerId))
|
||||
.DeleteAsync();
|
||||
|
||||
// delete button roles
|
||||
await ctx.GetTable<ButtonRole>()
|
||||
.Where(x => !tempTable.Select(x => x.GuildId)
|
||||
.Contains(x.GuildId))
|
||||
.DeleteAsync();
|
||||
|
||||
return new()
|
||||
{
|
||||
GuildCount = guildIds.Keys.Count,
|
||||
|
@@ -42,9 +42,9 @@ public partial class Administration
|
||||
.Page((items, _) =>
|
||||
{
|
||||
if (!items.Any())
|
||||
return _sender.CreateEmbed().WithErrorColor().WithFooter(sql).WithDescription("-");
|
||||
return CreateEmbed().WithErrorColor().WithFooter(sql).WithDescription("-");
|
||||
|
||||
return _sender.CreateEmbed()
|
||||
return CreateEmbed()
|
||||
.WithOkColor()
|
||||
.WithFooter(sql)
|
||||
.WithTitle(string.Join(" ║ ", result.ColumnNames))
|
||||
@@ -99,7 +99,7 @@ public partial class Administration
|
||||
{
|
||||
try
|
||||
{
|
||||
var embed = _sender.CreateEmbed()
|
||||
var embed = CreateEmbed()
|
||||
.WithTitle(GetText(strs.sql_confirm_exec))
|
||||
.WithDescription(Format.Code(sql));
|
||||
|
||||
@@ -119,7 +119,7 @@ public partial class Administration
|
||||
[OwnerOnly]
|
||||
public async Task PurgeUser(ulong userId)
|
||||
{
|
||||
var embed = _sender.CreateEmbed()
|
||||
var embed = CreateEmbed()
|
||||
.WithDescription(GetText(strs.purge_user_confirm(Format.Bold(userId.ToString()))));
|
||||
|
||||
if (!await PromptUserConfirmAsync(embed))
|
||||
@@ -138,8 +138,7 @@ public partial class Administration
|
||||
[OwnerOnly]
|
||||
public Task DeleteXp()
|
||||
=> ConfirmActionInternalAsync("Delete Xp", () => _xcs.DeleteXp());
|
||||
|
||||
|
||||
|
||||
[Cmd]
|
||||
[OwnerOnly]
|
||||
public Task DeleteWaifus()
|
||||
|
@@ -200,27 +200,48 @@ public partial class Administration
|
||||
|
||||
if (!isEnabled)
|
||||
{
|
||||
var cmdName = type switch
|
||||
{
|
||||
GreetType.Greet => "greet",
|
||||
GreetType.Bye => "bye",
|
||||
GreetType.Boost => "boost",
|
||||
GreetType.GreetDm => "greetdm",
|
||||
_ => "unknown_command"
|
||||
};
|
||||
|
||||
await Response().Pending(strs.boostmsg_enable($"`{prefix}{cmdName}`")).SendAsync();
|
||||
await SendGreetEnableHint(type);
|
||||
}
|
||||
}
|
||||
|
||||
private static string GetCmdName(GreetType type)
|
||||
{
|
||||
var cmdName = type switch
|
||||
{
|
||||
GreetType.Greet => "greet",
|
||||
GreetType.Bye => "bye",
|
||||
GreetType.Boost => "boost",
|
||||
GreetType.GreetDm => "greetdm",
|
||||
_ => "unknown_command"
|
||||
};
|
||||
return cmdName;
|
||||
}
|
||||
|
||||
public async Task Test(GreetType type, IGuildUser? user = null)
|
||||
{
|
||||
user ??= (IGuildUser)ctx.User;
|
||||
|
||||
await _service.Test(ctx.Guild.Id, type, (ITextChannel)ctx.Channel, user);
|
||||
var conf = await _service.GetGreetSettingsAsync(ctx.Guild.Id, type);
|
||||
|
||||
if (conf?.IsEnabled is not true)
|
||||
await Response().Pending(strs.boostmsg_enable($"`{prefix}boost`")).SendAsync();
|
||||
await SendGreetEnableHint(type);
|
||||
}
|
||||
|
||||
private async Task SendGreetEnableHint(GreetType type)
|
||||
{
|
||||
var cmd = $"`{prefix}{GetCmdName(type)}`";
|
||||
|
||||
var str = type switch
|
||||
{
|
||||
GreetType.Greet => strs.greetmsg_enable(cmd),
|
||||
GreetType.Bye => strs.byemsg_enable(cmd),
|
||||
GreetType.Boost => strs.boostmsg_enable(cmd),
|
||||
GreetType.GreetDm => strs.greetdmmsg_enable(cmd),
|
||||
_ => strs.error
|
||||
};
|
||||
|
||||
await Response().Pending(str).SendAsync();
|
||||
}
|
||||
}
|
||||
}
|
@@ -75,16 +75,27 @@ public class GreetService : INService, IReadyExecutor
|
||||
|
||||
_client.GuildMemberUpdated += ClientOnGuildMemberUpdated;
|
||||
|
||||
var timer = new PeriodicTimer(TimeSpan.FromSeconds(2));
|
||||
while (await timer.WaitForNextTickAsync())
|
||||
while (true)
|
||||
{
|
||||
var (conf, user, ch) = await _greetQueue.Reader.ReadAsync();
|
||||
await GreetUsers(conf, ch, user);
|
||||
try
|
||||
{
|
||||
var (conf, user, ch) = await _greetQueue.Reader.ReadAsync();
|
||||
await GreetUsers(conf, ch, user);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Log.Error(ex, "Greet Loop almost crashed. Please report this!");
|
||||
}
|
||||
|
||||
await Task.Delay(2016);
|
||||
}
|
||||
}
|
||||
|
||||
private Task ClientOnGuildMemberUpdated(Cacheable<SocketGuildUser, ulong> optOldUser, SocketGuildUser newUser)
|
||||
{
|
||||
if (!_enabled[GreetType.Boost].Contains(newUser.Guild.Id))
|
||||
return Task.CompletedTask;
|
||||
|
||||
// if user is a new booster
|
||||
// or boosted again the same server
|
||||
if ((optOldUser.Value is { PremiumSince: null } && newUser is { PremiumSince: not null })
|
||||
@@ -126,21 +137,63 @@ public class GreetService : INService, IReadyExecutor
|
||||
.DeleteAsync();
|
||||
}
|
||||
|
||||
private Task OnUserLeft(SocketGuild guild, SocketUser user)
|
||||
private Task OnUserJoined(IGuildUser user)
|
||||
{
|
||||
_ = Task.Run(async () =>
|
||||
{
|
||||
try
|
||||
{
|
||||
if (_enabled[GreetType.Greet].Contains(user.GuildId))
|
||||
{
|
||||
var conf = await GetGreetSettingsAsync(user.GuildId, GreetType.Greet);
|
||||
if (conf?.ChannelId is ulong cid)
|
||||
{
|
||||
var channel = await user.Guild.GetTextChannelAsync(cid);
|
||||
if (channel is not null)
|
||||
{
|
||||
await _greetQueue.Writer.WriteAsync((conf, user, channel));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (_enabled[GreetType.GreetDm].Contains(user.GuildId))
|
||||
{
|
||||
var confDm = await GetGreetSettingsAsync(user.GuildId, GreetType.GreetDm);
|
||||
if (confDm is not null)
|
||||
{
|
||||
await _greetQueue.Writer.WriteAsync((confDm, user, null));
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Log.Error(ex, "Error in GreetService.OnUserJoined. This should not happen. Please report it");
|
||||
}
|
||||
});
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
private Task OnUserLeft(SocketGuild guild, SocketUser user)
|
||||
{
|
||||
_ = Task.Run(async () =>
|
||||
{
|
||||
if (!_enabled[GreetType.Bye].Contains(guild.Id))
|
||||
return;
|
||||
|
||||
try
|
||||
{
|
||||
var conf = await GetGreetSettingsAsync(guild.Id, GreetType.Bye);
|
||||
|
||||
if (conf is null)
|
||||
if (conf?.ChannelId is not { } cid)
|
||||
return;
|
||||
|
||||
var channel = guild.TextChannels.FirstOrDefault(c => c.Id == conf.ChannelId);
|
||||
|
||||
var channel = guild.GetChannel(cid) as ITextChannel;
|
||||
if (channel is null) //maybe warn the server owner that the channel is missing
|
||||
{
|
||||
Log.Warning("Channel {ChannelId} in {GuildId} was not found. Bye message will be disabled",
|
||||
conf.ChannelId,
|
||||
conf.GuildId);
|
||||
await SetGreet(guild.Id, null, GreetType.Bye, false);
|
||||
return;
|
||||
}
|
||||
@@ -155,10 +208,11 @@ public class GreetService : INService, IReadyExecutor
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
private readonly TypedKey<GreetSettings?> _greetSettingsKey = new("greet_settings");
|
||||
private TypedKey<GreetSettings?> GreetSettingsKey(ulong gid, GreetType type)
|
||||
=> new($"greet_settings:{gid}:{type}");
|
||||
|
||||
public async Task<GreetSettings?> GetGreetSettingsAsync(ulong gid, GreetType type)
|
||||
=> await _cache.GetOrAddAsync<GreetSettings?>(_greetSettingsKey,
|
||||
=> await _cache.GetOrAddAsync<GreetSettings?>(GreetSettingsKey(gid, type),
|
||||
() => InternalGetGreetSettingsAsync(gid, type),
|
||||
TimeSpan.FromSeconds(3));
|
||||
|
||||
@@ -207,9 +261,10 @@ public class GreetService : INService, IReadyExecutor
|
||||
or DiscordErrorCode.UnknownChannel)
|
||||
{
|
||||
Log.Warning(ex,
|
||||
"Missing permissions to send a bye message, the greet message will be disabled on server: {GuildId}",
|
||||
"Missing permissions to send a {GreetType} message, it will be disabled on server: {GuildId}",
|
||||
conf.GreetType,
|
||||
channel.GuildId);
|
||||
await SetGreet(channel.GuildId, channel.Id, GreetType.Greet, false);
|
||||
await SetGreet(channel.GuildId, channel.Id, conf.GreetType, false);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
@@ -217,14 +272,6 @@ public class GreetService : INService, IReadyExecutor
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private async Task<bool> GreetDmUser(GreetSettings conf, IGuildUser user)
|
||||
{
|
||||
var completionSource = new TaskCompletionSource<bool>(TaskCreationOptions.RunContinuationsAsynchronously);
|
||||
await _greetQueue.Writer.WriteAsync((conf, user, null));
|
||||
return await completionSource.Task;
|
||||
}
|
||||
|
||||
private async Task<bool> GreetDmUserInternal(GreetSettings conf, IGuildUser user)
|
||||
{
|
||||
try
|
||||
@@ -290,8 +337,9 @@ public class GreetService : INService, IReadyExecutor
|
||||
|
||||
await _sender.Response(user).Text(smartText).Sanitize(false).SendAsync();
|
||||
}
|
||||
catch
|
||||
catch (Exception ex)
|
||||
{
|
||||
Log.Warning(ex, "Unable to send Greet DM. Probably the user has closed DMs");
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -305,36 +353,6 @@ public class GreetService : INService, IReadyExecutor
|
||||
IconUrl = user.Guild.IconUrl
|
||||
};
|
||||
|
||||
private Task OnUserJoined(IGuildUser user)
|
||||
{
|
||||
_ = Task.Run(async () =>
|
||||
{
|
||||
try
|
||||
{
|
||||
var conf = await GetGreetSettingsAsync(user.GuildId, GreetType.Greet);
|
||||
|
||||
if (conf is not null && conf.IsEnabled && conf.ChannelId is { } channelId)
|
||||
{
|
||||
var channel = await user.Guild.GetTextChannelAsync(channelId);
|
||||
if (channel is not null)
|
||||
{
|
||||
await _greetQueue.Writer.WriteAsync((conf, user, channel));
|
||||
}
|
||||
}
|
||||
|
||||
var confDm = await GetGreetSettingsAsync(user.GuildId, GreetType.GreetDm);
|
||||
|
||||
if (confDm?.IsEnabled ?? false)
|
||||
await GreetDmUser(confDm, user);
|
||||
}
|
||||
catch
|
||||
{
|
||||
// ignored
|
||||
}
|
||||
});
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
|
||||
public static string GetDefaultGreet(GreetType greetType)
|
||||
=> greetType switch
|
||||
@@ -354,8 +372,8 @@ public class GreetService : INService, IReadyExecutor
|
||||
{
|
||||
await using var uow = _db.GetDbContext();
|
||||
var q = uow.GetTable<GreetSettings>();
|
||||
|
||||
if(value is null)
|
||||
|
||||
if (value is null)
|
||||
value = !_enabled[greetType].Contains(guildId);
|
||||
|
||||
if (value is { } v)
|
||||
@@ -457,7 +475,17 @@ public class GreetService : INService, IReadyExecutor
|
||||
{
|
||||
var conf = await GetGreetSettingsAsync(guildId, type);
|
||||
if (conf is null)
|
||||
return false;
|
||||
{
|
||||
conf = new GreetSettings()
|
||||
{
|
||||
ChannelId = channel.Id,
|
||||
GreetType = type,
|
||||
IsEnabled = false,
|
||||
GuildId = guildId,
|
||||
AutoDeleteTimer = 30,
|
||||
MessageText = GetDefaultGreet(type)
|
||||
};
|
||||
}
|
||||
|
||||
await SendMessage(conf, channel, user);
|
||||
return true;
|
||||
@@ -467,8 +495,8 @@ public class GreetService : INService, IReadyExecutor
|
||||
{
|
||||
if (conf.GreetType == GreetType.GreetDm)
|
||||
{
|
||||
await _greetQueue.Writer.WriteAsync((conf, user, channel as ITextChannel));
|
||||
return await GreetDmUser(conf, user);
|
||||
await _greetQueue.Writer.WriteAsync((conf, user, null));
|
||||
return true;
|
||||
}
|
||||
|
||||
if (channel is not ITextChannel ch)
|
||||
|
@@ -123,7 +123,7 @@ public partial class Administration
|
||||
|
||||
[Cmd]
|
||||
public async Task LanguagesList()
|
||||
=> await Response().Embed(_sender.CreateEmbed()
|
||||
=> await Response().Embed(CreateEmbed()
|
||||
.WithOkColor()
|
||||
.WithTitle(GetText(strs.lang_list))
|
||||
.WithDescription(string.Join("\n",
|
||||
|
@@ -122,7 +122,7 @@ public class MuteService : INService
|
||||
return;
|
||||
|
||||
_ = Task.Run(() => _sender.Response(user)
|
||||
.Embed(_sender.CreateEmbed()
|
||||
.Embed(_sender.CreateEmbed(user?.GuildId)
|
||||
.WithDescription($"You've been muted in {user.Guild} server")
|
||||
.AddField("Mute Type", type.ToString())
|
||||
.AddField("Moderator", mod.ToString())
|
||||
@@ -140,7 +140,7 @@ public class MuteService : INService
|
||||
return;
|
||||
|
||||
_ = Task.Run(() => _sender.Response(user)
|
||||
.Embed(_sender.CreateEmbed()
|
||||
.Embed(_sender.CreateEmbed(user.GuildId)
|
||||
.WithDescription($"You've been unmuted in {user.Guild} server")
|
||||
.AddField("Unmute Type", type.ToString())
|
||||
.AddField("Moderator", mod.ToString())
|
||||
|
@@ -36,7 +36,7 @@ public partial class Administration
|
||||
[UserPerm(GuildPerm.Administrator)]
|
||||
public async Task DiscordPermOverrideReset()
|
||||
{
|
||||
var result = await PromptUserConfirmAsync(_sender.CreateEmbed()
|
||||
var result = await PromptUserConfirmAsync(CreateEmbed()
|
||||
.WithOkColor()
|
||||
.WithDescription(GetText(strs.perm_override_all_confirm)));
|
||||
|
||||
@@ -65,7 +65,7 @@ public partial class Administration
|
||||
.CurrentPage(page)
|
||||
.Page((items, _) =>
|
||||
{
|
||||
var eb = _sender.CreateEmbed().WithTitle(GetText(strs.perm_overrides)).WithOkColor();
|
||||
var eb = CreateEmbed().WithTitle(GetText(strs.perm_overrides)).WithOkColor();
|
||||
|
||||
if (items.Count == 0)
|
||||
eb.WithDescription(GetText(strs.perm_override_page_none));
|
||||
|
@@ -9,7 +9,9 @@ public sealed class PlayingRotateService : INService, IReadyExecutor
|
||||
{
|
||||
private readonly BotConfigService _bss;
|
||||
private readonly SelfService _selfService;
|
||||
|
||||
private readonly IReplacementService _repService;
|
||||
|
||||
// private readonly Replacer _rep;
|
||||
private readonly DbService _db;
|
||||
private readonly DiscordSocketClient _client;
|
||||
@@ -27,14 +29,13 @@ public sealed class PlayingRotateService : INService, IReadyExecutor
|
||||
_selfService = selfService;
|
||||
_repService = repService;
|
||||
_client = client;
|
||||
|
||||
}
|
||||
|
||||
public async Task OnReadyAsync()
|
||||
{
|
||||
if (_client.ShardId != 0)
|
||||
return;
|
||||
|
||||
|
||||
using var timer = new PeriodicTimer(TimeSpan.FromMinutes(1));
|
||||
var index = 0;
|
||||
while (await timer.WaitForNextTickAsync())
|
||||
@@ -57,7 +58,7 @@ public sealed class PlayingRotateService : INService, IReadyExecutor
|
||||
? rotatingStatuses[index = 0]
|
||||
: rotatingStatuses[index++];
|
||||
|
||||
var statusText = await _repService.ReplaceAsync(playingStatus.Status, new (client: _client));
|
||||
var statusText = await _repService.ReplaceAsync(playingStatus.Status, new(client: _client));
|
||||
await _selfService.SetActivityAsync(statusText, (ActivityType)playingStatus.Type);
|
||||
}
|
||||
catch (Exception ex)
|
||||
@@ -72,7 +73,11 @@ public sealed class PlayingRotateService : INService, IReadyExecutor
|
||||
ArgumentOutOfRangeException.ThrowIfNegative(index);
|
||||
|
||||
await using var uow = _db.GetDbContext();
|
||||
var toRemove = await uow.Set<RotatingPlayingStatus>().AsQueryable().AsNoTracking().Skip(index).FirstOrDefaultAsync();
|
||||
var toRemove = await uow.Set<RotatingPlayingStatus>()
|
||||
.AsQueryable()
|
||||
.AsNoTracking()
|
||||
.Skip(index)
|
||||
.FirstOrDefaultAsync();
|
||||
|
||||
if (toRemove is null)
|
||||
return null;
|
||||
@@ -94,6 +99,11 @@ public sealed class PlayingRotateService : INService, IReadyExecutor
|
||||
await uow.SaveChangesAsync();
|
||||
}
|
||||
|
||||
public void DisableRotatePlaying()
|
||||
{
|
||||
_bss.ModifyConfig(bs => { bs.RotateStatuses = false; });
|
||||
}
|
||||
|
||||
public bool ToggleRotatePlaying()
|
||||
{
|
||||
var enabled = false;
|
||||
|
@@ -241,7 +241,7 @@ public partial class Administration
|
||||
return;
|
||||
}
|
||||
|
||||
var embed = _sender.CreateEmbed().WithOkColor().WithTitle(GetText(strs.prot_active));
|
||||
var embed = CreateEmbed().WithOkColor().WithTitle(GetText(strs.prot_active));
|
||||
|
||||
if (spam is not null)
|
||||
embed.AddField("Anti-Spam", GetAntiSpamString(spam).TrimTo(1024), true);
|
||||
|
@@ -113,7 +113,7 @@ public partial class Administration
|
||||
{
|
||||
await progressMsg.ModifyAsync(props =>
|
||||
{
|
||||
props.Embed = _sender.CreateEmbed()
|
||||
props.Embed = CreateEmbed()
|
||||
.WithPendingColor()
|
||||
.WithDescription(GetText(strs.prune_progress(deleted, total)))
|
||||
.Build();
|
||||
|
302
src/NadekoBot/Modules/Administration/Role/ButtonRolesCommands.cs
Normal file
302
src/NadekoBot/Modules/Administration/Role/ButtonRolesCommands.cs
Normal file
@@ -0,0 +1,302 @@
|
||||
using NadekoBot.Common.TypeReaders.Models;
|
||||
using NadekoBot.Db.Models;
|
||||
using NadekoBot.Modules.Administration.Services;
|
||||
using System.Text;
|
||||
using ContextType = Discord.Commands.ContextType;
|
||||
|
||||
namespace NadekoBot.Modules.Administration;
|
||||
|
||||
public partial class Administration
|
||||
{
|
||||
[Group("btr")]
|
||||
public partial class ButtonRoleCommands : NadekoModule<ButtonRolesService>
|
||||
{
|
||||
private List<ActionRowBuilder> GetActionRows(IReadOnlyList<ButtonRole> roles)
|
||||
{
|
||||
var rows = roles.Select((x, i) => (Index: i, ButtonRole: x))
|
||||
.GroupBy(x => x.Index / 5)
|
||||
.Select(x => x.Select(y => y.ButtonRole))
|
||||
.Select(x =>
|
||||
{
|
||||
var ab = new ActionRowBuilder()
|
||||
.WithComponents(x.Select(y =>
|
||||
{
|
||||
var curRole = ctx.Guild.GetRole(y.RoleId);
|
||||
var label = string.IsNullOrWhiteSpace(y.Label)
|
||||
? curRole?.ToString() ?? "?missing " + y.RoleId
|
||||
: y.Label;
|
||||
|
||||
var btnEmote = EmoteTypeReader.TryParse(y.Emote, out var e)
|
||||
? e
|
||||
: null;
|
||||
|
||||
return new ButtonBuilder()
|
||||
.WithCustomId(y.ButtonId)
|
||||
.WithEmote(btnEmote)
|
||||
.WithLabel(label)
|
||||
.WithStyle(ButtonStyle.Secondary)
|
||||
.Build() as IMessageComponent;
|
||||
})
|
||||
.ToList());
|
||||
|
||||
return ab;
|
||||
})
|
||||
.ToList();
|
||||
return rows;
|
||||
}
|
||||
|
||||
private async Task<MessageLink?> CreateMessageLinkAsync(ulong messageId)
|
||||
{
|
||||
var msg = await ctx.Channel.GetMessageAsync(messageId);
|
||||
if (msg is null)
|
||||
return null;
|
||||
|
||||
return new MessageLink(ctx.Guild, ctx.Channel, msg);
|
||||
}
|
||||
|
||||
[Cmd]
|
||||
[RequireContext(ContextType.Guild)]
|
||||
[BotPerm(GuildPerm.ManageRoles)]
|
||||
[RequireUserPermission(GuildPerm.ManageRoles)]
|
||||
public async Task BtnRoleAdd(ulong messageId, IEmote emote, [Leftover] IRole role)
|
||||
{
|
||||
var link = await CreateMessageLinkAsync(messageId);
|
||||
|
||||
if (link is null)
|
||||
{
|
||||
await Response().Error(strs.invalid_message_id).SendAsync();
|
||||
return;
|
||||
}
|
||||
|
||||
await BtnRoleAdd(link, emote, role);
|
||||
}
|
||||
|
||||
|
||||
[Cmd]
|
||||
[RequireContext(ContextType.Guild)]
|
||||
[BotPerm(GuildPerm.ManageRoles)]
|
||||
[RequireUserPermission(GuildPerm.ManageRoles)]
|
||||
public async Task BtnRoleAdd(MessageLink link, IEmote emote, [Leftover] IRole role)
|
||||
{
|
||||
if (link.Message is not IUserMessage msg || !msg.IsAuthor(ctx.Client))
|
||||
{
|
||||
await Response().Error(strs.invalid_message_link).SendAsync();
|
||||
return;
|
||||
}
|
||||
|
||||
if (!await CheckRoleHierarchy(role))
|
||||
{
|
||||
await Response().Error(strs.hierarchy).SendAsync();
|
||||
return;
|
||||
}
|
||||
|
||||
var success = await _service.AddButtonRole(ctx.Guild.Id, link.Channel.Id, role.Id, link.Message.Id, emote);
|
||||
if (!success)
|
||||
{
|
||||
await Response().Error(strs.btnrole_message_max).SendAsync();
|
||||
return;
|
||||
}
|
||||
|
||||
var roles = await _service.GetButtonRoles(ctx.Guild.Id, link.Message.Id);
|
||||
|
||||
var rows = GetActionRows(roles);
|
||||
|
||||
await msg.ModifyAsync(x => x.Components = new(new ComponentBuilder().WithRows(rows).Build()));
|
||||
await ctx.OkAsync();
|
||||
}
|
||||
|
||||
[Cmd]
|
||||
[RequireContext(ContextType.Guild)]
|
||||
[BotPerm(GuildPerm.ManageRoles)]
|
||||
[RequireUserPermission(GuildPerm.ManageRoles)]
|
||||
public Task BtnRoleRemove(ulong messageId, IRole role)
|
||||
=> BtnRoleRemove(messageId, role.Id);
|
||||
|
||||
[Cmd]
|
||||
[RequireContext(ContextType.Guild)]
|
||||
[BotPerm(GuildPerm.ManageRoles)]
|
||||
[RequireUserPermission(GuildPerm.ManageRoles)]
|
||||
public Task BtnRoleRemove(MessageLink link, IRole role)
|
||||
=> BtnRoleRemove(link.Message.Id, role.Id);
|
||||
|
||||
[Cmd]
|
||||
[RequireContext(ContextType.Guild)]
|
||||
[BotPerm(GuildPerm.ManageRoles)]
|
||||
[RequireUserPermission(GuildPerm.ManageRoles)]
|
||||
public Task BtnRoleRemove(MessageLink link, ulong roleId)
|
||||
=> BtnRoleRemove(link.Message.Id, roleId);
|
||||
|
||||
[Cmd]
|
||||
[RequireContext(ContextType.Guild)]
|
||||
[BotPerm(GuildPerm.ManageRoles)]
|
||||
[RequireUserPermission(GuildPerm.ManageRoles)]
|
||||
public async Task BtnRoleRemove(ulong messageId, ulong roleId)
|
||||
{
|
||||
var removed = await _service.RemoveButtonRole(ctx.Guild.Id, messageId, roleId);
|
||||
if (removed is null)
|
||||
{
|
||||
await Response().Error(strs.btnrole_not_found).SendAsync();
|
||||
return;
|
||||
}
|
||||
|
||||
var roles = await _service.GetButtonRoles(ctx.Guild.Id, messageId);
|
||||
|
||||
var ch = await ctx.Guild.GetTextChannelAsync(removed.ChannelId);
|
||||
|
||||
if (ch is null)
|
||||
{
|
||||
await Response().Error(strs.btnrole_removeall_not_found).SendAsync();
|
||||
return;
|
||||
}
|
||||
|
||||
var msg = await ch.GetMessageAsync(removed.MessageId) as IUserMessage;
|
||||
|
||||
if (msg is null)
|
||||
{
|
||||
await Response().Error(strs.btnrole_removeall_not_found).SendAsync();
|
||||
return;
|
||||
}
|
||||
|
||||
var rows = GetActionRows(roles);
|
||||
await msg.ModifyAsync(x => x.Components = new(new ComponentBuilder().WithRows(rows).Build()));
|
||||
await Response().Confirm(strs.btnrole_removed).SendAsync();
|
||||
}
|
||||
|
||||
[Cmd]
|
||||
[RequireContext(ContextType.Guild)]
|
||||
[BotPerm(GuildPerm.ManageRoles)]
|
||||
[RequireUserPermission(GuildPerm.ManageRoles)]
|
||||
public Task BtnRoleRemoveAll(MessageLink link)
|
||||
=> BtnRoleRemoveAll(link.Message.Id);
|
||||
|
||||
[Cmd]
|
||||
[RequireContext(ContextType.Guild)]
|
||||
[BotPerm(GuildPerm.ManageRoles)]
|
||||
[RequireUserPermission(GuildPerm.ManageRoles)]
|
||||
public async Task BtnRoleRemoveAll(ulong messageId)
|
||||
{
|
||||
var succ = await _service.RemoveButtonRoles(ctx.Guild.Id, messageId);
|
||||
|
||||
if (succ.Count == 0)
|
||||
{
|
||||
await Response().Error(strs.btnrole_not_found).SendAsync();
|
||||
return;
|
||||
}
|
||||
|
||||
var info = succ[0];
|
||||
|
||||
var ch = await ctx.Guild.GetTextChannelAsync(info.ChannelId);
|
||||
if (ch is null)
|
||||
{
|
||||
await Response().Pending(strs.btnrole_removeall_not_found).SendAsync();
|
||||
return;
|
||||
}
|
||||
|
||||
var msg = await ch.GetMessageAsync(info.MessageId) as IUserMessage;
|
||||
if (msg is null)
|
||||
{
|
||||
await Response().Pending(strs.btnrole_removeall_not_found).SendAsync();
|
||||
return;
|
||||
}
|
||||
|
||||
await msg.ModifyAsync(x => x.Components = new(new ComponentBuilder().Build()));
|
||||
await ctx.OkAsync();
|
||||
}
|
||||
|
||||
[Cmd]
|
||||
[RequireContext(ContextType.Guild)]
|
||||
[BotPerm(GuildPerm.ManageRoles)]
|
||||
[RequireUserPermission(GuildPerm.ManageRoles)]
|
||||
public async Task BtnRoleList()
|
||||
{
|
||||
var btnRoles = await _service.GetButtonRoles(ctx.Guild.Id, null);
|
||||
|
||||
var groups = btnRoles
|
||||
.GroupBy(x => (x.ChannelId, x.MessageId))
|
||||
.ToList();
|
||||
|
||||
await Response()
|
||||
.Paginated()
|
||||
.Items(groups)
|
||||
.PageSize(1)
|
||||
.AddFooter(false)
|
||||
.Page(async (items, page) =>
|
||||
{
|
||||
var eb = CreateEmbed()
|
||||
.WithOkColor();
|
||||
|
||||
var item = items.FirstOrDefault();
|
||||
if (item == default)
|
||||
{
|
||||
eb.WithPendingColor()
|
||||
.WithDescription(GetText(strs.btnrole_none));
|
||||
|
||||
return eb;
|
||||
}
|
||||
|
||||
var (cid, msgId) = item.Key;
|
||||
|
||||
var str = new StringBuilder();
|
||||
|
||||
var ch = await ctx.Client.GetChannelAsync(cid) as IMessageChannel;
|
||||
|
||||
str.AppendLine($"Channel: {ch?.ToString() ?? cid.ToString()}");
|
||||
str.AppendLine($"Message: {msgId}");
|
||||
|
||||
if (ch is not null)
|
||||
{
|
||||
var msg = await ch.GetMessageAsync(msgId);
|
||||
if (msg is not null)
|
||||
{
|
||||
str.AppendLine(new MessageLink(ctx.Guild, ch, msg).ToString());
|
||||
}
|
||||
}
|
||||
|
||||
str.AppendLine("---");
|
||||
|
||||
foreach (var x in item.AsEnumerable())
|
||||
{
|
||||
var role = ctx.Guild.GetRole(x.RoleId);
|
||||
|
||||
str.AppendLine($"{x.Emote} {(role?.ToString() ?? x.RoleId.ToString())}");
|
||||
}
|
||||
|
||||
eb.WithDescription(str.ToString());
|
||||
|
||||
return eb;
|
||||
})
|
||||
.SendAsync();
|
||||
}
|
||||
|
||||
[Cmd]
|
||||
[RequireContext(ContextType.Guild)]
|
||||
[BotPerm(GuildPerm.ManageRoles)]
|
||||
[RequireUserPermission(GuildPerm.ManageRoles)]
|
||||
public Task BtnRoleExclusive(MessageLink link, PermissionAction exclusive)
|
||||
=> BtnRoleExclusive(link.Message.Id, exclusive);
|
||||
|
||||
[Cmd]
|
||||
[RequireContext(ContextType.Guild)]
|
||||
[BotPerm(GuildPerm.ManageRoles)]
|
||||
[RequireUserPermission(GuildPerm.ManageRoles)]
|
||||
public async Task BtnRoleExclusive(ulong messageId, PermissionAction exclusive)
|
||||
{
|
||||
var res = await _service.SetExclusiveButtonRoles(ctx.Guild.Id, messageId, exclusive.Value);
|
||||
|
||||
if (!res)
|
||||
{
|
||||
await Response().Error(strs.btnrole_not_found).SendAsync();
|
||||
return;
|
||||
}
|
||||
|
||||
if (exclusive.Value)
|
||||
{
|
||||
await Response().Confirm(strs.btnrole_exclusive).SendAsync();
|
||||
}
|
||||
else
|
||||
{
|
||||
await Response().Confirm(strs.btnrole_multiple).SendAsync();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
187
src/NadekoBot/Modules/Administration/Role/ButtonRolesService.cs
Normal file
187
src/NadekoBot/Modules/Administration/Role/ButtonRolesService.cs
Normal file
@@ -0,0 +1,187 @@
|
||||
using LinqToDB;
|
||||
using LinqToDB.EntityFrameworkCore;
|
||||
using LinqToDB.SqlQuery;
|
||||
using NadekoBot.Common.ModuleBehaviors;
|
||||
using NadekoBot.Db.Models;
|
||||
using NCalc;
|
||||
|
||||
namespace NadekoBot.Modules.Administration.Services;
|
||||
|
||||
public sealed class ButtonRolesService : INService, IReadyExecutor
|
||||
{
|
||||
private const string BTN_PREFIX = "n:btnrole:";
|
||||
|
||||
private readonly DbService _db;
|
||||
private readonly DiscordSocketClient _client;
|
||||
private readonly IBotCreds _creds;
|
||||
|
||||
public ButtonRolesService(IBotCreds creds, DiscordSocketClient client, DbService db)
|
||||
{
|
||||
_creds = creds;
|
||||
_client = client;
|
||||
_db = db;
|
||||
}
|
||||
|
||||
|
||||
public Task OnReadyAsync()
|
||||
{
|
||||
_client.InteractionCreated += OnInteraction;
|
||||
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
private async Task OnInteraction(SocketInteraction inter)
|
||||
{
|
||||
if (inter is not SocketMessageComponent smc)
|
||||
return;
|
||||
|
||||
if (!smc.Data.CustomId.StartsWith(BTN_PREFIX))
|
||||
return;
|
||||
|
||||
await inter.DeferAsync();
|
||||
|
||||
_ = Task.Run(async () =>
|
||||
{
|
||||
try
|
||||
{
|
||||
await using var uow = _db.GetDbContext();
|
||||
var buttonRole = await uow.GetTable<ButtonRole>()
|
||||
.Where(x => x.ButtonId == smc.Data.CustomId && x.MessageId == smc.Message.Id)
|
||||
.FirstOrDefaultAsyncLinqToDB();
|
||||
|
||||
if (buttonRole is null)
|
||||
return;
|
||||
|
||||
var guild = _client.GetGuild(buttonRole.GuildId);
|
||||
if (guild is null)
|
||||
return;
|
||||
|
||||
var role = guild.GetRole(buttonRole.RoleId);
|
||||
if (role is null)
|
||||
return;
|
||||
|
||||
if (smc.User is not IGuildUser user)
|
||||
return;
|
||||
|
||||
if (user.GetRoles().Any(x => x.Id == role.Id))
|
||||
{
|
||||
await user.RemoveRoleAsync(role.Id);
|
||||
return;
|
||||
}
|
||||
|
||||
if (buttonRole.Exclusive)
|
||||
{
|
||||
var otherRoles = await uow.GetTable<ButtonRole>()
|
||||
.Where(x => x.GuildId == smc.GuildId && x.MessageId == smc.Message.Id)
|
||||
.Select(x => x.RoleId)
|
||||
.ToListAsyncLinqToDB();
|
||||
|
||||
await user.RemoveRolesAsync(otherRoles);
|
||||
}
|
||||
|
||||
await user.AddRoleAsync(role.Id);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Log.Warning(ex, "Unable to handle button role interaction for user {UserId}", inter.User.Id);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public async Task<bool> AddButtonRole(
|
||||
ulong guildId,
|
||||
ulong channelId,
|
||||
ulong roleId,
|
||||
ulong messageId,
|
||||
IEmote emote
|
||||
)
|
||||
{
|
||||
await using var uow = _db.GetDbContext();
|
||||
|
||||
// up to 25 per message
|
||||
if (await uow.GetTable<ButtonRole>()
|
||||
.Where(x => x.MessageId == messageId)
|
||||
.CountAsyncLinqToDB()
|
||||
>= 25)
|
||||
return false;
|
||||
|
||||
|
||||
var emoteStr = emote.ToString()!;
|
||||
var guid = Guid.NewGuid();
|
||||
await uow.GetTable<ButtonRole>()
|
||||
.InsertOrUpdateAsync(() => new ButtonRole()
|
||||
{
|
||||
GuildId = guildId,
|
||||
ChannelId = channelId,
|
||||
RoleId = roleId,
|
||||
MessageId = messageId,
|
||||
Position =
|
||||
uow
|
||||
.GetTable<ButtonRole>()
|
||||
.Any(x => x.MessageId == messageId)
|
||||
? uow.GetTable<ButtonRole>()
|
||||
.Where(x => x.MessageId == messageId)
|
||||
.Max(x => x.Position)
|
||||
: 1,
|
||||
Emote = emoteStr,
|
||||
Label = string.Empty,
|
||||
ButtonId = $"{BTN_PREFIX}:{guildId}:{guid}",
|
||||
Exclusive = uow.GetTable<ButtonRole>()
|
||||
.Any(x => x.GuildId == guildId && x.MessageId == messageId)
|
||||
&& uow.GetTable<ButtonRole>()
|
||||
.Where(x => x.GuildId == guildId && x.MessageId == messageId)
|
||||
.All(x => x.Exclusive)
|
||||
},
|
||||
_ => new()
|
||||
{
|
||||
Emote = emoteStr,
|
||||
Label = string.Empty,
|
||||
ButtonId = $"{BTN_PREFIX}:{guildId}:{guid}"
|
||||
},
|
||||
() => new()
|
||||
{
|
||||
RoleId = roleId,
|
||||
MessageId = messageId,
|
||||
});
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public async Task<IReadOnlyList<ButtonRole>> RemoveButtonRoles(ulong guildId, ulong messageId)
|
||||
{
|
||||
await using var uow = _db.GetDbContext();
|
||||
return await uow.GetTable<ButtonRole>()
|
||||
.Where(x => x.GuildId == guildId && x.MessageId == messageId)
|
||||
.DeleteWithOutputAsync();
|
||||
}
|
||||
|
||||
public async Task<ButtonRole?> RemoveButtonRole(ulong guildId, ulong messageId, ulong roleId)
|
||||
{
|
||||
await using var uow = _db.GetDbContext();
|
||||
var deleted = await uow.GetTable<ButtonRole>()
|
||||
.Where(x => x.GuildId == guildId && x.MessageId == messageId && x.RoleId == roleId)
|
||||
.DeleteWithOutputAsync();
|
||||
|
||||
return deleted.FirstOrDefault();
|
||||
}
|
||||
|
||||
public async Task<IReadOnlyList<ButtonRole>> GetButtonRoles(ulong guildId, ulong? messageId)
|
||||
{
|
||||
await using var uow = _db.GetDbContext();
|
||||
return await uow.GetTable<ButtonRole>()
|
||||
.Where(x => x.GuildId == guildId && (messageId == null || x.MessageId == messageId))
|
||||
.OrderBy(x => x.Id)
|
||||
.ToListAsyncLinqToDB();
|
||||
}
|
||||
|
||||
public async Task<bool> SetExclusiveButtonRoles(ulong guildId, ulong messageId, bool exclusive)
|
||||
{
|
||||
await using var uow = _db.GetDbContext();
|
||||
return await uow.GetTable<ButtonRole>()
|
||||
.Where(x => x.GuildId == guildId && x.MessageId == messageId)
|
||||
.UpdateAsync((_) => new()
|
||||
{
|
||||
Exclusive = exclusive
|
||||
}) > 0;
|
||||
}
|
||||
}
|
@@ -80,7 +80,7 @@ public partial class Administration
|
||||
.CurrentPage(page)
|
||||
.Page((items, _) =>
|
||||
{
|
||||
var embed = _sender.CreateEmbed()
|
||||
var embed = CreateEmbed()
|
||||
.WithOkColor();
|
||||
|
||||
var content = string.Empty;
|
||||
|
@@ -1,8 +1,6 @@
|
||||
#nullable disable
|
||||
using LinqToDB;
|
||||
using LinqToDB;
|
||||
using LinqToDB.EntityFrameworkCore;
|
||||
using NadekoBot.Common.ModuleBehaviors;
|
||||
using NadekoBot.Modules.Patronage;
|
||||
using NadekoBot.Db.Models;
|
||||
using OneOf.Types;
|
||||
using OneOf;
|
||||
@@ -13,23 +11,20 @@ public sealed class ReactionRolesService : IReadyExecutor, INService, IReactionR
|
||||
{
|
||||
private readonly DbService _db;
|
||||
private readonly DiscordSocketClient _client;
|
||||
private readonly IBotCredentials _creds;
|
||||
private readonly IBotCreds _creds;
|
||||
|
||||
private ConcurrentDictionary<ulong, List<ReactionRoleV2>> _cache;
|
||||
private readonly object _cacheLock = new();
|
||||
private readonly SemaphoreSlim _assignementLock = new(1, 1);
|
||||
private readonly IPatronageService _ps;
|
||||
|
||||
public ReactionRolesService(
|
||||
DiscordSocketClient client,
|
||||
IPatronageService ps,
|
||||
DbService db,
|
||||
IBotCredentials creds)
|
||||
IBotCreds creds)
|
||||
{
|
||||
_db = db;
|
||||
_client = client;
|
||||
_creds = creds;
|
||||
_ps = ps;
|
||||
_cache = new();
|
||||
}
|
||||
|
||||
@@ -57,7 +52,7 @@ public sealed class ReactionRolesService : IReadyExecutor, INService, IReactionR
|
||||
var guild = _client.GetGuild(rero.GuildId);
|
||||
var role = guild?.GetRole(rero.RoleId);
|
||||
|
||||
if (role is null)
|
||||
if (guild is null || role is null)
|
||||
return default;
|
||||
|
||||
var user = guild.GetUser(userId) as IGuildUser
|
||||
@@ -80,8 +75,8 @@ public sealed class ReactionRolesService : IReadyExecutor, INService, IReactionR
|
||||
_ = Task.Run(async () =>
|
||||
{
|
||||
var emote = await GetFixedEmoteAsync(cmsg, r.Emote);
|
||||
|
||||
var rero = reros.FirstOrDefault(x => x.Emote == emote.Name
|
||||
|
||||
var rero = reros.FirstOrDefault(x => x.Emote == emote.Name
|
||||
|| x.Emote == emote.ToString());
|
||||
if (rero is null)
|
||||
return;
|
||||
@@ -96,10 +91,11 @@ public sealed class ReactionRolesService : IReadyExecutor, INService, IReactionR
|
||||
{
|
||||
if (user.RoleIds.Contains(role.Id))
|
||||
{
|
||||
await user.RemoveRoleAsync(role.Id, new RequestOptions()
|
||||
{
|
||||
AuditLogReason = $"Reaction role"
|
||||
});
|
||||
await user.RemoveRoleAsync(role.Id,
|
||||
new RequestOptions()
|
||||
{
|
||||
AuditLogReason = $"Reaction role"
|
||||
});
|
||||
}
|
||||
}
|
||||
finally
|
||||
@@ -111,7 +107,7 @@ public sealed class ReactionRolesService : IReadyExecutor, INService, IReactionR
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
|
||||
|
||||
// had to add this because for some reason, reactionremoved event's reaction doesn't have IsAnimated set,
|
||||
// causing the .ToString() to be wrong on animated custom emotes
|
||||
private async Task<IEmote> GetFixedEmoteAsync(
|
||||
@@ -210,10 +206,11 @@ public sealed class ReactionRolesService : IReadyExecutor, INService, IReactionR
|
||||
}
|
||||
}
|
||||
|
||||
await user.AddRoleAsync(role.Id, new()
|
||||
{
|
||||
AuditLogReason = "Reaction role"
|
||||
});
|
||||
await user.AddRoleAsync(role.Id,
|
||||
new()
|
||||
{
|
||||
AuditLogReason = "Reaction role"
|
||||
});
|
||||
}
|
||||
}
|
||||
finally
|
||||
@@ -244,23 +241,10 @@ public sealed class ReactionRolesService : IReadyExecutor, INService, IReactionR
|
||||
int levelReq = 0)
|
||||
{
|
||||
ArgumentOutOfRangeException.ThrowIfNegative(group);
|
||||
|
||||
ArgumentOutOfRangeException.ThrowIfNegative(levelReq);
|
||||
|
||||
await using var ctx = _db.GetDbContext();
|
||||
|
||||
await using var tran = await ctx.Database.BeginTransactionAsync();
|
||||
var activeReactionRoles = await ctx.GetTable<ReactionRoleV2>()
|
||||
.Where(x => x.GuildId == guild.Id)
|
||||
.CountAsync();
|
||||
|
||||
var limit = await _ps.GetUserLimit(LimitedFeatureName.ReactionRole, guild.OwnerId);
|
||||
|
||||
if (!_creds.IsOwner(guild.OwnerId) && (activeReactionRoles >= limit.Quota && limit.Quota >= 0))
|
||||
{
|
||||
return new Error();
|
||||
}
|
||||
|
||||
await ctx.GetTable<ReactionRoleV2>()
|
||||
.InsertOrUpdateAsync(() => new()
|
||||
{
|
||||
@@ -286,8 +270,6 @@ public sealed class ReactionRolesService : IReadyExecutor, INService, IReactionR
|
||||
Emote = emote,
|
||||
});
|
||||
|
||||
await tran.CommitAsync();
|
||||
|
||||
var obj = new ReactionRoleV2()
|
||||
{
|
||||
GuildId = guild.Id,
|
||||
|
@@ -174,12 +174,11 @@ public partial class Administration
|
||||
[UserPerm(GuildPerm.ManageRoles)]
|
||||
[BotPerm(GuildPerm.ManageRoles)]
|
||||
[Priority(0)]
|
||||
public async Task RoleColor(Color color, [Leftover] IRole role)
|
||||
public async Task RoleColor(Rgba32 color, [Leftover] IRole role)
|
||||
{
|
||||
try
|
||||
{
|
||||
var rgba32 = color.ToPixel<Rgba32>();
|
||||
await role.ModifyAsync(r => r.Color = new Discord.Color(rgba32.R, rgba32.G, rgba32.B));
|
||||
await role.ModifyAsync(r => r.Color = new Discord.Color(color.R, color.G, color.B));
|
||||
await Response().Confirm(strs.rc(Format.Bold(role.Name))).SendAsync();
|
||||
}
|
||||
catch (Exception)
|
||||
|
@@ -9,13 +9,13 @@ namespace NadekoBot.Modules.Administration;
|
||||
public sealed class StickyRolesService : INService, IReadyExecutor
|
||||
{
|
||||
private readonly DiscordSocketClient _client;
|
||||
private readonly IBotCredentials _creds;
|
||||
private readonly IBotCreds _creds;
|
||||
private readonly DbService _db;
|
||||
private HashSet<ulong> _stickyRoles = new();
|
||||
|
||||
public StickyRolesService(
|
||||
DiscordSocketClient client,
|
||||
IBotCredentials creds,
|
||||
IBotCreds creds,
|
||||
DbService db)
|
||||
{
|
||||
_client = client;
|
||||
|
@@ -62,7 +62,7 @@ public partial class Administration
|
||||
var (added, updated) = await _service.RefreshUsersAsync(users);
|
||||
|
||||
await message.ModifyAsync(x =>
|
||||
x.Embed = _sender.CreateEmbed()
|
||||
x.Embed = CreateEmbed()
|
||||
.WithDescription(GetText(strs.cache_users_done(added, updated)))
|
||||
.WithOkColor()
|
||||
.Build()
|
||||
@@ -115,7 +115,7 @@ public partial class Administration
|
||||
_service.AddNewAutoCommand(cmd);
|
||||
|
||||
await Response()
|
||||
.Embed(_sender.CreateEmbed()
|
||||
.Embed(CreateEmbed()
|
||||
.WithOkColor()
|
||||
.WithTitle(GetText(strs.scadd))
|
||||
.AddField(GetText(strs.server),
|
||||
@@ -343,7 +343,7 @@ public partial class Administration
|
||||
if (string.IsNullOrWhiteSpace(str))
|
||||
str = GetText(strs.no_shards_on_page);
|
||||
|
||||
return _sender.CreateEmbed().WithOkColor().WithDescription($"{status}\n\n{str}");
|
||||
return CreateEmbed().WithOkColor().WithDescription($"{status}\n\n{str}");
|
||||
})
|
||||
.SendAsync();
|
||||
}
|
||||
|
@@ -15,7 +15,7 @@ public sealed class SelfService : IExecNoCommand, IReadyExecutor, INService
|
||||
private readonly IBotStrings _strings;
|
||||
private readonly DiscordSocketClient _client;
|
||||
|
||||
private readonly IBotCredentials _creds;
|
||||
private readonly IBotCreds _creds;
|
||||
|
||||
private ImmutableDictionary<ulong, IDMChannel> ownerChannels =
|
||||
new Dictionary<ulong, IDMChannel>().ToImmutableDictionary();
|
||||
@@ -36,7 +36,7 @@ public sealed class SelfService : IExecNoCommand, IReadyExecutor, INService
|
||||
CommandHandler cmdHandler,
|
||||
DbService db,
|
||||
IBotStrings strings,
|
||||
IBotCredentials creds,
|
||||
IBotCreds creds,
|
||||
IHttpClientFactory factory,
|
||||
BotConfigService bss,
|
||||
IPubSub pubSub,
|
||||
@@ -71,7 +71,6 @@ public sealed class SelfService : IExecNoCommand, IReadyExecutor, INService
|
||||
if (server.OwnerId != _client.CurrentUser.Id)
|
||||
{
|
||||
await server.LeaveAsync();
|
||||
Log.Information("Left server {Name} [{Id}]", server.Name, server.Id);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -453,7 +452,6 @@ public sealed class SelfService : IExecNoCommand, IReadyExecutor, INService
|
||||
{
|
||||
x.UserId,
|
||||
x.Username,
|
||||
x.Discriminator
|
||||
})
|
||||
.Where(x => users.Select(y => y.Id).Contains(x.UserId))
|
||||
.ToArrayAsyncEF();
|
||||
@@ -465,12 +463,11 @@ public sealed class SelfService : IExecNoCommand, IReadyExecutor, INService
|
||||
UserId = x.Id,
|
||||
AvatarId = x.AvatarId,
|
||||
Username = x.Username,
|
||||
Discriminator = x.Discriminator
|
||||
});
|
||||
|
||||
var added = (await ctx.BulkCopyAsync(usersToAdd)).RowsCopied;
|
||||
var toUpdateUserIds = presentDbUsers
|
||||
.Where(x => x.Username == "Unknown" && x.Discriminator == "????")
|
||||
.Where(x => x.Username.StartsWith("??"))
|
||||
.Select(x => x.UserId)
|
||||
.ToArray();
|
||||
|
||||
@@ -481,7 +478,6 @@ public sealed class SelfService : IExecNoCommand, IReadyExecutor, INService
|
||||
.UpdateAsync(x => new DiscordUser()
|
||||
{
|
||||
Username = user.Username,
|
||||
Discriminator = user.Discriminator,
|
||||
|
||||
// .award tends to set AvatarId and DateAdded to NULL, so account for that.
|
||||
AvatarId = user.AvatarId,
|
||||
|
@@ -6,16 +6,136 @@ namespace NadekoBot.Modules.Administration;
|
||||
|
||||
public partial class Administration
|
||||
{
|
||||
[Group]
|
||||
public partial class SelfAssignedRolesHelpers : NadekoModule<SelfAssignedRolesService>
|
||||
{
|
||||
private readonly SarAssignerService _sas;
|
||||
|
||||
public SelfAssignedRolesHelpers(SarAssignerService sas)
|
||||
{
|
||||
_sas = sas;
|
||||
}
|
||||
|
||||
[Cmd]
|
||||
[RequireContext(ContextType.Guild)]
|
||||
public async Task Iam([Leftover] IRole role)
|
||||
{
|
||||
var guildUser = (IGuildUser)ctx.User;
|
||||
|
||||
var group = await _service.GetRoleGroup(ctx.Guild.Id, role.Id);
|
||||
|
||||
IUserMessage msg = null;
|
||||
try
|
||||
{
|
||||
if (group is null)
|
||||
{
|
||||
msg = await Response().Error(strs.self_assign_not).SendAsync();
|
||||
return;
|
||||
}
|
||||
|
||||
var tcs = new TaskCompletionSource<SarAssignResult>(TaskCreationOptions.RunContinuationsAsynchronously);
|
||||
await _sas.Add(new()
|
||||
{
|
||||
Group = group,
|
||||
RoleId = role.Id,
|
||||
User = guildUser,
|
||||
CompletionTask = tcs
|
||||
});
|
||||
|
||||
var res = await tcs.Task;
|
||||
|
||||
if (res.TryPickT0(out _, out var error))
|
||||
{
|
||||
msg = await Response()
|
||||
.Confirm(strs.self_assign_success(Format.Bold(role.Name)))
|
||||
.SendAsync();
|
||||
}
|
||||
else
|
||||
{
|
||||
var resStr = error.Match(
|
||||
_ => strs.error_occured,
|
||||
lvlReq => strs.self_assign_not_level(Format.Bold(lvlReq.Level.ToString())),
|
||||
roleRq => strs.self_assign_role_req(Format.Bold(ctx.Guild.GetRole(roleRq.RoleId).ToString()
|
||||
?? "missing role " + roleRq.RoleId),
|
||||
group.Name),
|
||||
_ => strs.self_assign_already(Format.Bold(role.Name)),
|
||||
_ => strs.self_assign_perms);
|
||||
|
||||
msg = await Response().Error(resStr).SendAsync();
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
var ad = _service.GetAutoDelete(ctx.Guild.Id);
|
||||
|
||||
if (ad)
|
||||
{
|
||||
msg?.DeleteAfter(3);
|
||||
ctx.Message.DeleteAfter(3);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[Cmd]
|
||||
[RequireContext(ContextType.Guild)]
|
||||
public async Task Iamnot([Leftover] IRole role)
|
||||
{
|
||||
var guildUser = (IGuildUser)ctx.User;
|
||||
|
||||
IUserMessage msg = null;
|
||||
try
|
||||
{
|
||||
if (!guildUser.RoleIds.Contains(role.Id))
|
||||
{
|
||||
msg = await Response().Error(strs.self_assign_not_have(Format.Bold(role.Name))).SendAsync();
|
||||
return;
|
||||
}
|
||||
|
||||
var group = await _service.GetRoleGroup(ctx.Guild.Id, role.Id);
|
||||
|
||||
if (group is null || group.Roles.All(x => x.RoleId != role.Id))
|
||||
{
|
||||
msg = await Response().Error(strs.self_assign_not).SendAsync();
|
||||
return;
|
||||
}
|
||||
|
||||
if (role.Position >= ((SocketGuild)ctx.Guild).CurrentUser.Roles.Max(x => x.Position))
|
||||
{
|
||||
msg = await Response().Error(strs.self_assign_perms).SendAsync();
|
||||
return;
|
||||
}
|
||||
|
||||
await guildUser.RemoveRoleAsync(role);
|
||||
msg = await Response().Confirm(strs.self_assign_remove(Format.Bold(role.Name))).SendAsync();
|
||||
}
|
||||
finally
|
||||
{
|
||||
var ad = _service.GetAutoDelete(ctx.Guild.Id);
|
||||
if (ad)
|
||||
{
|
||||
msg?.DeleteAfter(3);
|
||||
ctx.Message.DeleteAfter(3);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[Group("sar")]
|
||||
public partial class SelfAssignedRolesCommands : NadekoModule<SelfAssignedRolesService>
|
||||
{
|
||||
private readonly SarAssignerService _sas;
|
||||
|
||||
public SelfAssignedRolesCommands(SarAssignerService sas)
|
||||
{
|
||||
_sas = sas;
|
||||
}
|
||||
|
||||
[Cmd]
|
||||
[RequireContext(ContextType.Guild)]
|
||||
[UserPerm(GuildPerm.ManageMessages)]
|
||||
[BotPerm(GuildPerm.ManageMessages)]
|
||||
public async Task AdSarm()
|
||||
public async Task SarAutoDelete()
|
||||
{
|
||||
var newVal = _service.ToggleAdSarm(ctx.Guild.Id);
|
||||
var newVal = await _service.ToggleAutoDelete(ctx.Guild.Id);
|
||||
|
||||
if (newVal)
|
||||
await Response().Confirm(strs.adsarm_enable(prefix)).SendAsync();
|
||||
@@ -28,30 +148,24 @@ public partial class Administration
|
||||
[UserPerm(GuildPerm.ManageRoles)]
|
||||
[BotPerm(GuildPerm.ManageRoles)]
|
||||
[Priority(1)]
|
||||
public Task Asar([Leftover] IRole role)
|
||||
=> Asar(0, role);
|
||||
public Task SarAdd([Leftover] IRole role)
|
||||
=> SarAdd(0, role);
|
||||
|
||||
[Cmd]
|
||||
[RequireContext(ContextType.Guild)]
|
||||
[UserPerm(GuildPerm.ManageRoles)]
|
||||
[BotPerm(GuildPerm.ManageRoles)]
|
||||
[Priority(0)]
|
||||
public async Task Asar(int group, [Leftover] IRole role)
|
||||
public async Task SarAdd(int group, [Leftover] IRole role)
|
||||
{
|
||||
var guser = (IGuildUser)ctx.User;
|
||||
if (ctx.User.Id != guser.Guild.OwnerId && guser.GetRoles().Max(x => x.Position) <= role.Position)
|
||||
if (!await CheckRoleHierarchy(role))
|
||||
return;
|
||||
|
||||
var succ = _service.AddNew(ctx.Guild.Id, role, group);
|
||||
await _service.AddAsync(ctx.Guild.Id, role.Id, group);
|
||||
|
||||
if (succ)
|
||||
{
|
||||
await Response()
|
||||
.Confirm(strs.role_added(Format.Bold(role.Name), Format.Bold(group.ToString())))
|
||||
.SendAsync();
|
||||
}
|
||||
else
|
||||
await Response().Error(strs.role_in_list(Format.Bold(role.Name))).SendAsync();
|
||||
await Response()
|
||||
.Confirm(strs.role_added(Format.Bold(role.Name), Format.Bold(group.ToString())))
|
||||
.SendAsync();
|
||||
}
|
||||
|
||||
[Cmd]
|
||||
@@ -59,9 +173,9 @@ public partial class Administration
|
||||
[UserPerm(GuildPerm.ManageRoles)]
|
||||
[BotPerm(GuildPerm.ManageRoles)]
|
||||
[Priority(0)]
|
||||
public async Task Sargn(int group, [Leftover] string name = null)
|
||||
public async Task SarGroupName(int group, [Leftover] string name = null)
|
||||
{
|
||||
var set = await _service.SetNameAsync(ctx.Guild.Id, group, name);
|
||||
var set = await _service.SetGroupNameAsync(ctx.Guild.Id, group, name);
|
||||
|
||||
if (set)
|
||||
{
|
||||
@@ -70,19 +184,19 @@ public partial class Administration
|
||||
.SendAsync();
|
||||
}
|
||||
else
|
||||
{
|
||||
await Response().Confirm(strs.group_name_removed(Format.Bold(group.ToString()))).SendAsync();
|
||||
}
|
||||
}
|
||||
|
||||
[Cmd]
|
||||
[RequireContext(ContextType.Guild)]
|
||||
[UserPerm(GuildPerm.ManageRoles)]
|
||||
public async Task Rsar([Leftover] IRole role)
|
||||
public async Task SarRemove([Leftover] IRole role)
|
||||
{
|
||||
var guser = (IGuildUser)ctx.User;
|
||||
if (ctx.User.Id != guser.Guild.OwnerId && guser.GetRoles().Max(x => x.Position) <= role.Position)
|
||||
return;
|
||||
|
||||
var success = _service.RemoveSar(role.Guild.Id, role.Id);
|
||||
var success = await _service.RemoveAsync(role.Guild.Id, role.Id);
|
||||
if (!success)
|
||||
await Response().Error(strs.self_assign_not).SendAsync();
|
||||
else
|
||||
@@ -91,59 +205,81 @@ public partial class Administration
|
||||
|
||||
[Cmd]
|
||||
[RequireContext(ContextType.Guild)]
|
||||
public async Task Lsar(int page = 1)
|
||||
public async Task SarList(int page = 1)
|
||||
{
|
||||
if (--page < 0)
|
||||
return;
|
||||
|
||||
var (exclusive, roles, groups) = _service.GetRoles(ctx.Guild);
|
||||
var groups = await _service.GetSarsAsync(ctx.Guild.Id);
|
||||
|
||||
var gDict = groups.ToDictionary(x => x.Id, x => x);
|
||||
|
||||
await Response()
|
||||
.Paginated()
|
||||
.Items(roles.OrderBy(x => x.Model.Group).ToList())
|
||||
.Items(groups.SelectMany(x => x.Roles).ToList())
|
||||
.PageSize(20)
|
||||
.CurrentPage(page)
|
||||
.Page((items, _) =>
|
||||
.Page(async (items, _) =>
|
||||
{
|
||||
var rolesStr = new StringBuilder();
|
||||
var roleGroups = items
|
||||
.GroupBy(x => x.Model.Group)
|
||||
.GroupBy(x => x.SarGroupId)
|
||||
.OrderBy(x => x.Key);
|
||||
|
||||
var eb = CreateEmbed()
|
||||
.WithOkColor()
|
||||
.WithTitle(GetText(strs.self_assign_list(groups.Sum(x => x.Roles.Count))));
|
||||
|
||||
foreach (var kvp in roleGroups)
|
||||
{
|
||||
string groupNameText;
|
||||
if (!groups.TryGetValue(kvp.Key, out var name))
|
||||
groupNameText = Format.Bold(GetText(strs.self_assign_group(kvp.Key)));
|
||||
else
|
||||
groupNameText = Format.Bold($"{kvp.Key} - {name.TrimTo(25, true)}");
|
||||
var group = gDict[kvp.Key];
|
||||
|
||||
rolesStr.AppendLine("\t\t\t\t ⟪" + groupNameText + "⟫");
|
||||
foreach (var (model, role) in kvp.AsEnumerable())
|
||||
var groupNameText = "";
|
||||
|
||||
if (!string.IsNullOrWhiteSpace(group.Name))
|
||||
groupNameText += $" **{group.Name}**";
|
||||
|
||||
groupNameText = $"`{group.GroupNumber}` {groupNameText}";
|
||||
|
||||
var rolesStr = new StringBuilder();
|
||||
|
||||
if (group.IsExclusive)
|
||||
{
|
||||
if (role is null)
|
||||
rolesStr.AppendLine(Format.Italics(GetText(strs.choose_one)));
|
||||
}
|
||||
|
||||
if (group.RoleReq is ulong rrId)
|
||||
{
|
||||
var rr = ctx.Guild.GetRole(rrId);
|
||||
|
||||
if (rr is null)
|
||||
{
|
||||
await _service.SetGroupRoleReq(group.GuildId, group.GroupNumber, null);
|
||||
}
|
||||
else
|
||||
{
|
||||
// first character is invisible space
|
||||
if (model.LevelRequirement == 0)
|
||||
rolesStr.AppendLine(" " + role.Name);
|
||||
else
|
||||
rolesStr.AppendLine(" " + role.Name + $" (lvl {model.LevelRequirement}+)");
|
||||
rolesStr.AppendLine(
|
||||
Format.Italics(GetText(strs.requires_role(Format.Bold(rr.Name)))));
|
||||
}
|
||||
}
|
||||
|
||||
rolesStr.AppendLine();
|
||||
foreach (var sar in kvp)
|
||||
{
|
||||
var roleName = (ctx.Guild.GetRole(sar.RoleId)?.Name ?? (sar.RoleId + " (deleted)"));
|
||||
rolesStr.Append("- " + Format.Code(roleName));
|
||||
|
||||
if (sar.LevelReq > 0)
|
||||
{
|
||||
rolesStr.Append($" *[lvl {sar.LevelReq}+]*");
|
||||
}
|
||||
|
||||
rolesStr.AppendLine();
|
||||
}
|
||||
|
||||
|
||||
eb.AddField(groupNameText, rolesStr, false);
|
||||
}
|
||||
|
||||
return _sender.CreateEmbed()
|
||||
.WithOkColor()
|
||||
.WithTitle(Format.Bold(GetText(strs.self_assign_list(roles.Count()))))
|
||||
.WithDescription(rolesStr.ToString())
|
||||
.WithFooter(exclusive
|
||||
? GetText(strs.self_assign_are_exclusive)
|
||||
: GetText(strs.self_assign_are_not_exclusive));
|
||||
return eb;
|
||||
})
|
||||
.SendAsync();
|
||||
}
|
||||
@@ -152,25 +288,36 @@ public partial class Administration
|
||||
[RequireContext(ContextType.Guild)]
|
||||
[UserPerm(GuildPerm.ManageRoles)]
|
||||
[BotPerm(GuildPerm.ManageRoles)]
|
||||
public async Task Togglexclsar()
|
||||
public async Task SarExclusive(int groupNumber)
|
||||
{
|
||||
var areExclusive = _service.ToggleEsar(ctx.Guild.Id);
|
||||
if (areExclusive)
|
||||
var areExclusive = await _service.SetGroupExclusivityAsync(ctx.Guild.Id, groupNumber);
|
||||
|
||||
if (areExclusive is null)
|
||||
{
|
||||
await Response().Error(strs.sar_group_not_found).SendAsync();
|
||||
return;
|
||||
}
|
||||
|
||||
if (areExclusive is true)
|
||||
{
|
||||
await Response().Confirm(strs.self_assign_excl).SendAsync();
|
||||
}
|
||||
else
|
||||
{
|
||||
await Response().Confirm(strs.self_assign_no_excl).SendAsync();
|
||||
}
|
||||
}
|
||||
|
||||
[Cmd]
|
||||
[RequireContext(ContextType.Guild)]
|
||||
[UserPerm(GuildPerm.ManageRoles)]
|
||||
[BotPerm(GuildPerm.ManageRoles)]
|
||||
public async Task RoleLevelReq(int level, [Leftover] IRole role)
|
||||
public async Task SarRoleLevelReq(int level, [Leftover] IRole role)
|
||||
{
|
||||
if (level < 0)
|
||||
return;
|
||||
|
||||
var succ = _service.SetLevelReq(ctx.Guild.Id, role, level);
|
||||
var succ = await _service.SetRoleLevelReq(ctx.Guild.Id, role.Id, level);
|
||||
|
||||
if (!succ)
|
||||
{
|
||||
@@ -186,54 +333,35 @@ public partial class Administration
|
||||
|
||||
[Cmd]
|
||||
[RequireContext(ContextType.Guild)]
|
||||
public async Task Iam([Leftover] IRole role)
|
||||
[UserPerm(GuildPerm.ManageRoles)]
|
||||
[BotPerm(GuildPerm.ManageRoles)]
|
||||
public async Task SarGroupRoleReq(int groupNumber, [Leftover] IRole role)
|
||||
{
|
||||
var guildUser = (IGuildUser)ctx.User;
|
||||
var succ = await _service.SetGroupRoleReq(ctx.Guild.Id, groupNumber, role.Id);
|
||||
|
||||
var (result, autoDelete, extra) = await _service.Assign(guildUser, role);
|
||||
|
||||
IUserMessage msg;
|
||||
if (result == SelfAssignedRolesService.AssignResult.ErrNotAssignable)
|
||||
msg = await Response().Error(strs.self_assign_not).SendAsync();
|
||||
else if (result == SelfAssignedRolesService.AssignResult.ErrLvlReq)
|
||||
msg = await Response().Error(strs.self_assign_not_level(Format.Bold(extra.ToString()))).SendAsync();
|
||||
else if (result == SelfAssignedRolesService.AssignResult.ErrAlreadyHave)
|
||||
msg = await Response().Error(strs.self_assign_already(Format.Bold(role.Name))).SendAsync();
|
||||
else if (result == SelfAssignedRolesService.AssignResult.ErrNotPerms)
|
||||
msg = await Response().Error(strs.self_assign_perms).SendAsync();
|
||||
else
|
||||
msg = await Response().Confirm(strs.self_assign_success(Format.Bold(role.Name))).SendAsync();
|
||||
|
||||
if (autoDelete)
|
||||
if (!succ)
|
||||
{
|
||||
msg.DeleteAfter(3);
|
||||
ctx.Message.DeleteAfter(3);
|
||||
await Response().Error(strs.sar_group_not_found).SendAsync();
|
||||
return;
|
||||
}
|
||||
|
||||
await Response()
|
||||
.Confirm(strs.self_assign_group_role_req(
|
||||
Format.Bold(groupNumber.ToString()),
|
||||
Format.Bold(role.Name)))
|
||||
.SendAsync();
|
||||
}
|
||||
|
||||
[Cmd]
|
||||
[RequireContext(ContextType.Guild)]
|
||||
public async Task Iamnot([Leftover] IRole role)
|
||||
[UserPerm(GuildPerm.ManageRoles)]
|
||||
public async Task SarGroupDelete(int groupNumber)
|
||||
{
|
||||
var guildUser = (IGuildUser)ctx.User;
|
||||
|
||||
var (result, autoDelete) = await _service.Remove(guildUser, role);
|
||||
|
||||
IUserMessage msg;
|
||||
if (result == SelfAssignedRolesService.RemoveResult.ErrNotAssignable)
|
||||
msg = await Response().Error(strs.self_assign_not).SendAsync();
|
||||
else if (result == SelfAssignedRolesService.RemoveResult.ErrNotHave)
|
||||
msg = await Response().Error(strs.self_assign_not_have(Format.Bold(role.Name))).SendAsync();
|
||||
else if (result == SelfAssignedRolesService.RemoveResult.ErrNotPerms)
|
||||
msg = await Response().Error(strs.self_assign_perms).SendAsync();
|
||||
var succ = await _service.DeleteRoleGroup(ctx.Guild.Id, groupNumber);
|
||||
if (succ)
|
||||
await Response().Confirm(strs.sar_group_deleted(Format.Bold(groupNumber.ToString()))).SendAsync();
|
||||
else
|
||||
msg = await Response().Confirm(strs.self_assign_remove(Format.Bold(role.Name))).SendAsync();
|
||||
|
||||
if (autoDelete)
|
||||
{
|
||||
msg.DeleteAfter(3);
|
||||
ctx.Message.DeleteAfter(3);
|
||||
}
|
||||
await Response().Error(strs.sar_group_not_found).SendAsync();
|
||||
}
|
||||
}
|
||||
}
|
@@ -1,233 +1,326 @@
|
||||
#nullable disable
|
||||
using LinqToDB;
|
||||
using LinqToDB.EntityFrameworkCore;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using NadekoBot.Common.ModuleBehaviors;
|
||||
using NadekoBot.Db.Models;
|
||||
using NadekoBot.Modules.Xp.Services;
|
||||
using OneOf;
|
||||
using OneOf.Types;
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using System.Threading.Channels;
|
||||
|
||||
namespace NadekoBot.Modules.Administration.Services;
|
||||
|
||||
public class SelfAssignedRolesService : INService
|
||||
public class SelfAssignedRolesService : INService, IReadyExecutor
|
||||
{
|
||||
public enum AssignResult
|
||||
private readonly DbService _db;
|
||||
private readonly DiscordSocketClient _client;
|
||||
private readonly IBotCreds _creds;
|
||||
|
||||
private ConcurrentHashSet<ulong> _sarAds = new();
|
||||
|
||||
public SelfAssignedRolesService(DbService db, DiscordSocketClient client, IBotCreds creds)
|
||||
{
|
||||
Assigned, // successfully removed
|
||||
ErrNotAssignable, // not assignable (error)
|
||||
ErrAlreadyHave, // you already have that role (error)
|
||||
ErrNotPerms, // bot doesn't have perms (error)
|
||||
ErrLvlReq // you are not required level (error)
|
||||
_db = db;
|
||||
_client = client;
|
||||
_creds = creds;
|
||||
}
|
||||
|
||||
public enum RemoveResult
|
||||
public async Task AddAsync(ulong guildId, ulong roleId, int groupNumber)
|
||||
{
|
||||
Removed, // successfully removed
|
||||
ErrNotAssignable, // not assignable (error)
|
||||
ErrNotHave, // you don't have a role you want to remove (error)
|
||||
ErrNotPerms // bot doesn't have perms (error)
|
||||
await using var ctx = _db.GetDbContext();
|
||||
|
||||
await ctx.GetTable<SarGroup>()
|
||||
.InsertOrUpdateAsync(() => new()
|
||||
{
|
||||
GuildId = guildId,
|
||||
GroupNumber = groupNumber,
|
||||
IsExclusive = false
|
||||
},
|
||||
_ => new()
|
||||
{
|
||||
},
|
||||
() => new()
|
||||
{
|
||||
GuildId = guildId,
|
||||
GroupNumber = groupNumber
|
||||
});
|
||||
|
||||
await ctx.GetTable<Sar>()
|
||||
.InsertOrUpdateAsync(() => new()
|
||||
{
|
||||
RoleId = roleId,
|
||||
LevelReq = 0,
|
||||
GuildId = guildId,
|
||||
SarGroupId = ctx.GetTable<SarGroup>()
|
||||
.Where(x => x.GuildId == guildId && x.GroupNumber == groupNumber)
|
||||
.Select(x => x.Id)
|
||||
.First()
|
||||
},
|
||||
_ => new()
|
||||
{
|
||||
},
|
||||
() => new()
|
||||
{
|
||||
RoleId = roleId,
|
||||
});
|
||||
}
|
||||
|
||||
public async Task<bool> RemoveAsync(ulong guildId, ulong roleId)
|
||||
{
|
||||
await using var ctx = _db.GetDbContext();
|
||||
|
||||
var deleted = await ctx.GetTable<Sar>()
|
||||
.Where(x => x.RoleId == roleId && x.GuildId == guildId)
|
||||
.DeleteAsync();
|
||||
|
||||
return deleted > 0;
|
||||
}
|
||||
|
||||
public async Task<bool> SetGroupNameAsync(ulong guildId, int groupNumber, string? name)
|
||||
{
|
||||
await using var ctx = _db.GetDbContext();
|
||||
|
||||
var changes = await ctx.GetTable<SarGroup>()
|
||||
.Where(x => x.GuildId == guildId && x.GroupNumber == groupNumber)
|
||||
.UpdateAsync(x => new()
|
||||
{
|
||||
Name = name
|
||||
});
|
||||
|
||||
return changes > 0;
|
||||
}
|
||||
|
||||
public async Task<IReadOnlyCollection<SarGroup>> GetSarsAsync(ulong guildId)
|
||||
{
|
||||
await using var ctx = _db.GetDbContext();
|
||||
|
||||
var sgs = await ctx.GetTable<SarGroup>()
|
||||
.Where(x => x.GuildId == guildId)
|
||||
.LoadWith(x => x.Roles)
|
||||
.ToListAsyncLinqToDB();
|
||||
|
||||
return sgs;
|
||||
}
|
||||
|
||||
public async Task<bool> SetRoleLevelReq(ulong guildId, ulong roleId, int levelReq)
|
||||
{
|
||||
await using var ctx = _db.GetDbContext();
|
||||
var changes = await ctx.GetTable<Sar>()
|
||||
.Where(x => x.GuildId == guildId && x.RoleId == roleId)
|
||||
.UpdateAsync(_ => new()
|
||||
{
|
||||
LevelReq = levelReq,
|
||||
});
|
||||
|
||||
return changes > 0;
|
||||
}
|
||||
|
||||
public async Task<bool> SetGroupRoleReq(ulong guildId, int groupNumber, ulong? roleId)
|
||||
{
|
||||
await using var ctx = _db.GetDbContext();
|
||||
var changes = await ctx.GetTable<SarGroup>()
|
||||
.Where(x => x.GuildId == guildId && x.GroupNumber == groupNumber)
|
||||
.UpdateAsync(_ => new()
|
||||
{
|
||||
RoleReq = roleId
|
||||
});
|
||||
|
||||
return changes > 0;
|
||||
}
|
||||
|
||||
public async Task<bool?> SetGroupExclusivityAsync(ulong guildId, int groupNumber)
|
||||
{
|
||||
await using var ctx = _db.GetDbContext();
|
||||
var changes = await ctx.GetTable<SarGroup>()
|
||||
.Where(x => x.GuildId == guildId && x.GroupNumber == groupNumber)
|
||||
.UpdateWithOutputAsync(old => new()
|
||||
{
|
||||
IsExclusive = !old.IsExclusive
|
||||
},
|
||||
(o, n) => n.IsExclusive);
|
||||
|
||||
if (changes.Length == 0)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
return changes[0];
|
||||
}
|
||||
|
||||
public async Task<SarGroup?> GetRoleGroup(ulong guildId, ulong roleId)
|
||||
{
|
||||
await using var ctx = _db.GetDbContext();
|
||||
|
||||
var group = await ctx.GetTable<SarGroup>()
|
||||
.Where(x => x.GuildId == guildId && x.Roles.Any(x => x.RoleId == roleId))
|
||||
.LoadWith(x => x.Roles)
|
||||
.FirstOrDefaultAsyncLinqToDB();
|
||||
|
||||
|
||||
return group;
|
||||
}
|
||||
|
||||
public async Task<bool> DeleteRoleGroup(ulong guildId, int groupNumber)
|
||||
{
|
||||
await using var ctx = _db.GetDbContext();
|
||||
|
||||
var deleted = await ctx.GetTable<SarGroup>()
|
||||
.Where(x => x.GuildId == guildId && x.GroupNumber == groupNumber)
|
||||
.DeleteAsync();
|
||||
|
||||
return deleted > 0;
|
||||
}
|
||||
|
||||
public async Task<bool> ToggleAutoDelete(ulong guildId)
|
||||
{
|
||||
await using var ctx = _db.GetDbContext();
|
||||
|
||||
var delted = await ctx.GetTable<SarAutoDelete>()
|
||||
.DeleteAsync(x => x.GuildId == guildId);
|
||||
|
||||
if (delted > 0)
|
||||
{
|
||||
_sarAds.TryRemove(guildId);
|
||||
return false;
|
||||
}
|
||||
|
||||
await ctx.GetTable<SarAutoDelete>()
|
||||
.InsertOrUpdateAsync(() => new()
|
||||
{
|
||||
IsEnabled = true,
|
||||
GuildId = guildId,
|
||||
},
|
||||
(_) => new()
|
||||
{
|
||||
IsEnabled = true
|
||||
},
|
||||
() => new()
|
||||
{
|
||||
GuildId = guildId
|
||||
});
|
||||
|
||||
_sarAds.Add(guildId);
|
||||
return true;
|
||||
}
|
||||
|
||||
public bool GetAutoDelete(ulong guildId)
|
||||
=> _sarAds.Contains(guildId);
|
||||
|
||||
public async Task OnReadyAsync()
|
||||
{
|
||||
await using var uow = _db.GetDbContext();
|
||||
var guilds = await uow.GetTable<SarAutoDelete>()
|
||||
.Where(x => x.IsEnabled && Linq2DbExpressions.GuildOnShard(x.GuildId, _creds.TotalShards, _client.ShardId))
|
||||
.Select(x => x.GuildId)
|
||||
.ToListAsyncLinqToDB();
|
||||
|
||||
_sarAds = new(guilds);
|
||||
}
|
||||
}
|
||||
|
||||
public sealed class SarAssignerService : INService, IReadyExecutor
|
||||
{
|
||||
private readonly XpService _xp;
|
||||
private readonly DbService _db;
|
||||
|
||||
public SelfAssignedRolesService(DbService db)
|
||||
=> _db = db;
|
||||
private readonly Channel<SarAssignerDataItem> _channel =
|
||||
Channel.CreateBounded<SarAssignerDataItem>(100);
|
||||
|
||||
public bool AddNew(ulong guildId, IRole role, int group)
|
||||
|
||||
public SarAssignerService(XpService xp, DbService db)
|
||||
{
|
||||
using var uow = _db.GetDbContext();
|
||||
var roles = uow.Set<SelfAssignedRole>().GetFromGuild(guildId);
|
||||
if (roles.Any(s => s.RoleId == role.Id && s.GuildId == role.Guild.Id))
|
||||
return false;
|
||||
|
||||
uow.Set<SelfAssignedRole>().Add(new()
|
||||
{
|
||||
Group = group,
|
||||
RoleId = role.Id,
|
||||
GuildId = role.Guild.Id
|
||||
});
|
||||
uow.SaveChanges();
|
||||
return true;
|
||||
_xp = xp;
|
||||
_db = db;
|
||||
}
|
||||
|
||||
public bool ToggleAdSarm(ulong guildId)
|
||||
public async Task OnReadyAsync()
|
||||
{
|
||||
bool newval;
|
||||
using var uow = _db.GetDbContext();
|
||||
var config = uow.GuildConfigsForId(guildId, set => set);
|
||||
newval = config.AutoDeleteSelfAssignedRoleMessages = !config.AutoDeleteSelfAssignedRoleMessages;
|
||||
uow.SaveChanges();
|
||||
return newval;
|
||||
}
|
||||
|
||||
public async Task<(AssignResult Result, bool AutoDelete, object extra)> Assign(IGuildUser guildUser, IRole role)
|
||||
{
|
||||
LevelStats userLevelData;
|
||||
await using (var uow = _db.GetDbContext())
|
||||
var reader = _channel.Reader;
|
||||
while (true)
|
||||
{
|
||||
var stats = uow.GetOrCreateUserXpStats(guildUser.Guild.Id, guildUser.Id);
|
||||
userLevelData = new(stats.Xp + stats.AwardedXp);
|
||||
}
|
||||
var item = await reader.ReadAsync();
|
||||
|
||||
var (autoDelete, exclusive, roles) = GetAdAndRoles(guildUser.Guild.Id);
|
||||
|
||||
var theRoleYouWant = roles.FirstOrDefault(r => r.RoleId == role.Id);
|
||||
if (theRoleYouWant is null)
|
||||
return (AssignResult.ErrNotAssignable, autoDelete, null);
|
||||
if (theRoleYouWant.LevelRequirement > userLevelData.Level)
|
||||
return (AssignResult.ErrLvlReq, autoDelete, theRoleYouWant.LevelRequirement);
|
||||
if (guildUser.RoleIds.Contains(role.Id))
|
||||
return (AssignResult.ErrAlreadyHave, autoDelete, null);
|
||||
|
||||
var roleIds = roles.Where(x => x.Group == theRoleYouWant.Group).Select(x => x.RoleId).ToArray();
|
||||
if (exclusive)
|
||||
{
|
||||
var sameRoles = guildUser.RoleIds.Where(r => roleIds.Contains(r));
|
||||
|
||||
foreach (var roleId in sameRoles)
|
||||
try
|
||||
{
|
||||
var sameRole = guildUser.Guild.GetRole(roleId);
|
||||
if (sameRole is not null)
|
||||
var sar = item.Group.Roles.First(x => x.RoleId == item.RoleId);
|
||||
|
||||
if (item.User.RoleIds.Contains(item.RoleId))
|
||||
{
|
||||
try
|
||||
{
|
||||
await guildUser.RemoveRoleAsync(sameRole);
|
||||
await Task.Delay(300);
|
||||
}
|
||||
catch
|
||||
{
|
||||
// ignored
|
||||
}
|
||||
item.CompletionTask.TrySetResult(new SarAlreadyHasRole());
|
||||
continue;
|
||||
}
|
||||
|
||||
if (item.Group.RoleReq is { } rid)
|
||||
{
|
||||
if (!item.User.RoleIds.Contains(rid))
|
||||
{
|
||||
item.CompletionTask.TrySetResult(new SarRoleRequirement(rid));
|
||||
continue;
|
||||
}
|
||||
|
||||
// passed
|
||||
}
|
||||
|
||||
// check level requirement
|
||||
if (sar.LevelReq > 0)
|
||||
{
|
||||
await using var ctx = _db.GetDbContext();
|
||||
var xpStats = await ctx.GetTable<UserXpStats>().GetGuildUserXp(sar.GuildId, item.User.Id);
|
||||
var lvlData = new LevelStats(xpStats?.Xp ?? 0);
|
||||
|
||||
if (lvlData.Level < sar.LevelReq)
|
||||
{
|
||||
item.CompletionTask.TrySetResult(new SarLevelRequirement(sar.LevelReq));
|
||||
continue;
|
||||
}
|
||||
|
||||
// passed
|
||||
}
|
||||
|
||||
if (item.Group.IsExclusive)
|
||||
{
|
||||
var rolesToRemove = item.Group.Roles.Select(x => x.RoleId);
|
||||
await item.User.RemoveRolesAsync(rolesToRemove);
|
||||
}
|
||||
|
||||
await item.User.AddRoleAsync(item.RoleId);
|
||||
|
||||
item.CompletionTask.TrySetResult(new Success());
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Log.Error(ex, "Unknown error ocurred in SAR runner: {Error}", ex.Message);
|
||||
item.CompletionTask.TrySetResult(new Error());
|
||||
}
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
await guildUser.AddRoleAsync(role);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
return (AssignResult.ErrNotPerms, autoDelete, ex);
|
||||
}
|
||||
|
||||
return (AssignResult.Assigned, autoDelete, null);
|
||||
}
|
||||
|
||||
public async Task<bool> SetNameAsync(ulong guildId, int group, string name)
|
||||
public async Task Add(SarAssignerDataItem item)
|
||||
{
|
||||
var set = false;
|
||||
await using var uow = _db.GetDbContext();
|
||||
var gc = uow.GuildConfigsForId(guildId, y => y.Include(x => x.SelfAssignableRoleGroupNames));
|
||||
var toUpdate = gc.SelfAssignableRoleGroupNames.FirstOrDefault(x => x.Number == group);
|
||||
|
||||
if (string.IsNullOrWhiteSpace(name))
|
||||
{
|
||||
if (toUpdate is not null)
|
||||
gc.SelfAssignableRoleGroupNames.Remove(toUpdate);
|
||||
}
|
||||
else if (toUpdate is null)
|
||||
{
|
||||
gc.SelfAssignableRoleGroupNames.Add(new()
|
||||
{
|
||||
Name = name,
|
||||
Number = group
|
||||
});
|
||||
set = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
toUpdate.Name = name;
|
||||
set = true;
|
||||
}
|
||||
|
||||
await uow.SaveChangesAsync();
|
||||
|
||||
return set;
|
||||
await _channel.Writer.WriteAsync(item);
|
||||
}
|
||||
|
||||
public async Task<(RemoveResult Result, bool AutoDelete)> Remove(IGuildUser guildUser, IRole role)
|
||||
{
|
||||
var (autoDelete, _, roles) = GetAdAndRoles(guildUser.Guild.Id);
|
||||
}
|
||||
|
||||
if (roles.FirstOrDefault(r => r.RoleId == role.Id) is null)
|
||||
return (RemoveResult.ErrNotAssignable, autoDelete);
|
||||
if (!guildUser.RoleIds.Contains(role.Id))
|
||||
return (RemoveResult.ErrNotHave, autoDelete);
|
||||
try
|
||||
{
|
||||
await guildUser.RemoveRoleAsync(role);
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
return (RemoveResult.ErrNotPerms, autoDelete);
|
||||
}
|
||||
public sealed class SarAssignerDataItem
|
||||
{
|
||||
public required SarGroup Group { get; init; }
|
||||
public required IGuildUser User { get; init; }
|
||||
public required ulong RoleId { get; init; }
|
||||
public required TaskCompletionSource<SarAssignResult> CompletionTask { get; init; }
|
||||
}
|
||||
|
||||
return (RemoveResult.Removed, autoDelete);
|
||||
}
|
||||
[GenerateOneOf]
|
||||
public sealed partial class SarAssignResult
|
||||
: OneOfBase<Success, Error, SarLevelRequirement, SarRoleRequirement, SarAlreadyHasRole, SarInsuffPerms>
|
||||
{
|
||||
}
|
||||
|
||||
public bool RemoveSar(ulong guildId, ulong roleId)
|
||||
{
|
||||
bool success;
|
||||
using var uow = _db.GetDbContext();
|
||||
success = uow.Set<SelfAssignedRole>().DeleteByGuildAndRoleId(guildId, roleId);
|
||||
uow.SaveChanges();
|
||||
return success;
|
||||
}
|
||||
public record class SarLevelRequirement(int Level);
|
||||
|
||||
public (bool AutoDelete, bool Exclusive, IReadOnlyCollection<SelfAssignedRole>) GetAdAndRoles(ulong guildId)
|
||||
{
|
||||
using var uow = _db.GetDbContext();
|
||||
var gc = uow.GuildConfigsForId(guildId, set => set);
|
||||
var autoDelete = gc.AutoDeleteSelfAssignedRoleMessages;
|
||||
var exclusive = gc.ExclusiveSelfAssignedRoles;
|
||||
var roles = uow.Set<SelfAssignedRole>().GetFromGuild(guildId);
|
||||
public record class SarRoleRequirement(ulong RoleId);
|
||||
|
||||
return (autoDelete, exclusive, roles);
|
||||
}
|
||||
public record class SarAlreadyHasRole();
|
||||
|
||||
public bool SetLevelReq(ulong guildId, IRole role, int level)
|
||||
{
|
||||
using var uow = _db.GetDbContext();
|
||||
var roles = uow.Set<SelfAssignedRole>().GetFromGuild(guildId);
|
||||
var sar = roles.FirstOrDefault(x => x.RoleId == role.Id);
|
||||
if (sar is not null)
|
||||
{
|
||||
sar.LevelRequirement = level;
|
||||
uow.SaveChanges();
|
||||
}
|
||||
else
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public bool ToggleEsar(ulong guildId)
|
||||
{
|
||||
bool areExclusive;
|
||||
using var uow = _db.GetDbContext();
|
||||
var config = uow.GuildConfigsForId(guildId, set => set);
|
||||
|
||||
areExclusive = config.ExclusiveSelfAssignedRoles = !config.ExclusiveSelfAssignedRoles;
|
||||
uow.SaveChanges();
|
||||
return areExclusive;
|
||||
}
|
||||
|
||||
public (bool Exclusive, IReadOnlyCollection<(SelfAssignedRole Model, IRole Role)> Roles, IDictionary<int, string>
|
||||
GroupNames
|
||||
) GetRoles(IGuild guild)
|
||||
{
|
||||
var exclusive = false;
|
||||
|
||||
IReadOnlyCollection<(SelfAssignedRole Model, IRole Role)> roles;
|
||||
IDictionary<int, string> groupNames;
|
||||
using (var uow = _db.GetDbContext())
|
||||
{
|
||||
var gc = uow.GuildConfigsForId(guild.Id, set => set.Include(x => x.SelfAssignableRoleGroupNames));
|
||||
exclusive = gc.ExclusiveSelfAssignedRoles;
|
||||
groupNames = gc.SelfAssignableRoleGroupNames.ToDictionary(x => x.Number, x => x.Name);
|
||||
var roleModels = uow.Set<SelfAssignedRole>().GetFromGuild(guild.Id);
|
||||
roles = roleModels.Select(x => (Model: x, Role: guild.GetRole(x.RoleId)))
|
||||
.ToList();
|
||||
uow.Set<SelfAssignedRole>().RemoveRange(roles.Where(x => x.Role is null).Select(x => x.Model).ToArray());
|
||||
uow.SaveChanges();
|
||||
}
|
||||
|
||||
return (exclusive, roles.Where(x => x.Role is not null).ToList(), groupNames);
|
||||
}
|
||||
}
|
||||
public record class SarInsuffPerms();
|
@@ -35,7 +35,7 @@ public partial class Administration
|
||||
var usrs = settings?.LogIgnores.Where(x => x.ItemType == IgnoredItemType.User).ToList()
|
||||
?? new List<IgnoredLogItem>();
|
||||
|
||||
var eb = _sender.CreateEmbed()
|
||||
var eb = CreateEmbed()
|
||||
.WithOkColor()
|
||||
.AddField(GetText(strs.log_ignored_channels),
|
||||
chs.Count == 0
|
||||
|
@@ -42,7 +42,7 @@ public partial class Administration
|
||||
.Items(timezoneStrings)
|
||||
.PageSize(timezonesPerPage)
|
||||
.CurrentPage(page)
|
||||
.Page((items, _) => _sender.CreateEmbed()
|
||||
.Page((items, _) => CreateEmbed()
|
||||
.WithOkColor()
|
||||
.WithTitle(GetText(strs.timezones_available))
|
||||
.WithDescription(string.Join("\n", items)))
|
||||
|
@@ -23,27 +23,6 @@ public partial class Administration
|
||||
_mute = mute;
|
||||
}
|
||||
|
||||
private async Task<bool> CheckRoleHierarchy(IGuildUser target)
|
||||
{
|
||||
var curUser = ((SocketGuild)ctx.Guild).CurrentUser;
|
||||
var ownerId = ctx.Guild.OwnerId;
|
||||
var modMaxRole = ((IGuildUser)ctx.User).GetRoles().Max(r => r.Position);
|
||||
var targetMaxRole = target.GetRoles().Max(r => r.Position);
|
||||
var botMaxRole = curUser.GetRoles().Max(r => r.Position);
|
||||
// bot can't punish a user who is higher in the hierarchy. Discord will return 403
|
||||
// moderator can be owner, in which case role hierarchy doesn't matter
|
||||
// otherwise, moderator has to have a higher role
|
||||
if (botMaxRole <= targetMaxRole
|
||||
|| (ctx.User.Id != ownerId && targetMaxRole >= modMaxRole)
|
||||
|| target.Id == ownerId)
|
||||
{
|
||||
await Response().Error(strs.hierarchy).SendAsync();
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
[Cmd]
|
||||
[RequireContext(ContextType.Guild)]
|
||||
[UserPerm(GuildPerm.BanMembers)]
|
||||
@@ -65,11 +44,11 @@ public partial class Administration
|
||||
try
|
||||
{
|
||||
await _sender.Response(user)
|
||||
.Embed(_sender.CreateEmbed()
|
||||
.WithErrorColor()
|
||||
.WithDescription(GetText(strs.warned_on(ctx.Guild.ToString())))
|
||||
.AddField(GetText(strs.moderator), ctx.User.ToString())
|
||||
.AddField(GetText(strs.reason), reason ?? "-"))
|
||||
.Embed(CreateEmbed()
|
||||
.WithErrorColor()
|
||||
.WithDescription(GetText(strs.warned_on(ctx.Guild.ToString())))
|
||||
.AddField(GetText(strs.moderator), ctx.User.ToString())
|
||||
.AddField(GetText(strs.reason), reason ?? "-"))
|
||||
.SendAsync();
|
||||
}
|
||||
catch
|
||||
@@ -85,8 +64,9 @@ public partial class Administration
|
||||
catch (Exception ex)
|
||||
{
|
||||
Log.Warning(ex, "Exception occured while warning a user");
|
||||
var errorEmbed = _sender.CreateEmbed().WithErrorColor()
|
||||
.WithDescription(GetText(strs.cant_apply_punishment));
|
||||
var errorEmbed = CreateEmbed()
|
||||
.WithErrorColor()
|
||||
.WithDescription(GetText(strs.cant_apply_punishment));
|
||||
|
||||
if (dmFailed)
|
||||
errorEmbed.WithFooter("⚠️ " + GetText(strs.unable_to_dm_user));
|
||||
@@ -95,7 +75,7 @@ public partial class Administration
|
||||
return;
|
||||
}
|
||||
|
||||
var embed = _sender.CreateEmbed().WithOkColor();
|
||||
var embed = CreateEmbed().WithOkColor();
|
||||
if (punishment is null)
|
||||
embed.WithDescription(GetText(strs.user_warned(Format.Bold(user.ToString()))));
|
||||
else
|
||||
@@ -117,7 +97,7 @@ public partial class Administration
|
||||
[Priority(1)]
|
||||
public async Task WarnExpire()
|
||||
{
|
||||
var expireDays = await _service.GetWarnExpire(ctx.Guild.Id);
|
||||
var (expireDays, _) = await _service.GetWarnExpire(ctx.Guild.Id);
|
||||
|
||||
if (expireDays == 0)
|
||||
await Response().Confirm(strs.warns_dont_expire).SendAsync();
|
||||
@@ -204,7 +184,7 @@ public partial class Administration
|
||||
.Page((warnings, page) =>
|
||||
{
|
||||
var user = (ctx.Guild as SocketGuild)?.GetUser(userId)?.ToString() ?? userId.ToString();
|
||||
var embed = _sender.CreateEmbed().WithOkColor().WithTitle(GetText(strs.warnlog_for(user)));
|
||||
var embed = CreateEmbed().WithOkColor().WithTitle(GetText(strs.warnlog_for(user)));
|
||||
|
||||
if (!warnings.Any())
|
||||
embed.WithDescription(GetText(strs.warnings_none));
|
||||
@@ -265,10 +245,10 @@ public partial class Administration
|
||||
+ $" | {total} ({all} - {forgiven})";
|
||||
});
|
||||
|
||||
return _sender.CreateEmbed()
|
||||
.WithOkColor()
|
||||
.WithTitle(GetText(strs.warnings_list))
|
||||
.WithDescription(string.Join("\n", ws));
|
||||
return CreateEmbed()
|
||||
.WithOkColor()
|
||||
.WithTitle(GetText(strs.warnings_list))
|
||||
.WithDescription(string.Join("\n", ws));
|
||||
})
|
||||
.SendAsync();
|
||||
}
|
||||
@@ -278,7 +258,7 @@ public partial class Administration
|
||||
[UserPerm(GuildPerm.Administrator)]
|
||||
public Task WarnDelete(IGuildUser user, int index)
|
||||
=> WarnDelete(user.Id, index);
|
||||
|
||||
|
||||
[Cmd]
|
||||
[RequireContext(ContextType.Guild)]
|
||||
[UserPerm(GuildPerm.Administrator)]
|
||||
@@ -286,15 +266,15 @@ public partial class Administration
|
||||
{
|
||||
if (--index < 0)
|
||||
return;
|
||||
|
||||
var warn = await _service.WarnDelete(userId, index);
|
||||
|
||||
var warn = await _service.WarnDelete(ctx.Guild.Id, userId, index);
|
||||
|
||||
if (warn is null)
|
||||
{
|
||||
await Response().Error(strs.warning_not_found).SendAsync();
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
await Response().Confirm(strs.warning_deleted(Format.Bold(index.ToString()))).SendAsync();
|
||||
}
|
||||
|
||||
@@ -311,7 +291,7 @@ public partial class Administration
|
||||
{
|
||||
if (index < 0)
|
||||
return;
|
||||
|
||||
|
||||
var success = await _service.WarnClearAsync(ctx.Guild.Id, userId, index, ctx.User.ToString());
|
||||
var userStr = Format.Bold((ctx.Guild as SocketGuild)?.GetUser(userId)?.ToString() ?? userId.ToString());
|
||||
if (index == 0)
|
||||
@@ -344,7 +324,7 @@ public partial class Administration
|
||||
return;
|
||||
}
|
||||
|
||||
var success = _service.WarnPunish(ctx.Guild.Id, number, punish, time, role);
|
||||
var success = await _service.WarnPunish(ctx.Guild.Id, number, punish, time, role);
|
||||
|
||||
if (!success)
|
||||
return;
|
||||
@@ -380,7 +360,7 @@ public partial class Administration
|
||||
if (punish is PunishmentAction.TimeOut && time is null)
|
||||
return;
|
||||
|
||||
var success = _service.WarnPunish(ctx.Guild.Id, number, punish, time);
|
||||
var success = await _service.WarnPunish(ctx.Guild.Id, number, punish, time);
|
||||
|
||||
if (!success)
|
||||
return;
|
||||
@@ -407,7 +387,7 @@ public partial class Administration
|
||||
[UserPerm(GuildPerm.BanMembers)]
|
||||
public async Task WarnPunish(int number)
|
||||
{
|
||||
if (!_service.WarnPunishRemove(ctx.Guild.Id, number))
|
||||
if (!await _service.WarnPunishRemove(ctx.Guild.Id, number))
|
||||
return;
|
||||
|
||||
await Response().Confirm(strs.warn_punish_rem(Format.Bold(number.ToString()))).SendAsync();
|
||||
@@ -417,7 +397,7 @@ public partial class Administration
|
||||
[RequireContext(ContextType.Guild)]
|
||||
public async Task WarnPunishList()
|
||||
{
|
||||
var ps = _service.WarnPunishList(ctx.Guild.Id);
|
||||
var ps = await _service.WarnPunishList(ctx.Guild.Id);
|
||||
|
||||
string list;
|
||||
if (ps.Any())
|
||||
@@ -477,14 +457,14 @@ public partial class Administration
|
||||
var user = await ctx.Client.GetUserAsync(userId);
|
||||
var banPrune = await _service.GetBanPruneAsync(ctx.Guild.Id) ?? 7;
|
||||
await _mute.TimedBan(ctx.Guild, userId, time.Time, (ctx.User + " | " + msg).TrimTo(512), banPrune);
|
||||
var toSend = _sender.CreateEmbed()
|
||||
.WithOkColor()
|
||||
.WithTitle("⛔️ " + GetText(strs.banned_user))
|
||||
.AddField(GetText(strs.username), user?.ToString() ?? userId.ToString(), true)
|
||||
.AddField("ID", userId.ToString(), true)
|
||||
.AddField(GetText(strs.duration),
|
||||
time.Time.ToPrettyStringHm(),
|
||||
true);
|
||||
var toSend = CreateEmbed()
|
||||
.WithOkColor()
|
||||
.WithTitle("⛔️ " + GetText(strs.banned_user))
|
||||
.AddField(GetText(strs.username), user?.ToString() ?? userId.ToString(), true)
|
||||
.AddField("ID", userId.ToString(), true)
|
||||
.AddField(GetText(strs.duration),
|
||||
time.Time.ToPrettyStringHm(),
|
||||
true);
|
||||
|
||||
if (dmFailed)
|
||||
toSend.WithFooter("⚠️ " + GetText(strs.unable_to_dm_user));
|
||||
@@ -505,11 +485,12 @@ public partial class Administration
|
||||
var banPrune = await _service.GetBanPruneAsync(ctx.Guild.Id) ?? 7;
|
||||
await ctx.Guild.AddBanAsync(userId, banPrune, (ctx.User + " | " + msg).TrimTo(512));
|
||||
|
||||
await Response().Embed(_sender.CreateEmbed()
|
||||
.WithOkColor()
|
||||
.WithTitle("⛔️ " + GetText(strs.banned_user))
|
||||
.AddField("ID", userId.ToString(), true))
|
||||
.SendAsync();
|
||||
await Response()
|
||||
.Embed(CreateEmbed()
|
||||
.WithOkColor()
|
||||
.WithTitle("⛔️ " + GetText(strs.banned_user))
|
||||
.AddField("ID", userId.ToString(), true))
|
||||
.SendAsync();
|
||||
}
|
||||
else
|
||||
await Ban(user, msg);
|
||||
@@ -542,11 +523,11 @@ public partial class Administration
|
||||
var banPrune = await _service.GetBanPruneAsync(ctx.Guild.Id) ?? 7;
|
||||
await ctx.Guild.AddBanAsync(user, banPrune, (ctx.User + " | " + msg).TrimTo(512));
|
||||
|
||||
var toSend = _sender.CreateEmbed()
|
||||
.WithOkColor()
|
||||
.WithTitle("⛔️ " + GetText(strs.banned_user))
|
||||
.AddField(GetText(strs.username), user.ToString(), true)
|
||||
.AddField("ID", user.Id.ToString(), true);
|
||||
var toSend = CreateEmbed()
|
||||
.WithOkColor()
|
||||
.WithTitle("⛔️ " + GetText(strs.banned_user))
|
||||
.AddField(GetText(strs.username), user.ToString(), true)
|
||||
.AddField("ID", user.Id.ToString(), true);
|
||||
|
||||
if (dmFailed)
|
||||
toSend.WithFooter("⚠️ " + GetText(strs.unable_to_dm_user));
|
||||
@@ -737,11 +718,11 @@ public partial class Administration
|
||||
try { await ctx.Guild.RemoveBanAsync(user); }
|
||||
catch { await ctx.Guild.RemoveBanAsync(user); }
|
||||
|
||||
var toSend = _sender.CreateEmbed()
|
||||
.WithOkColor()
|
||||
.WithTitle("☣ " + GetText(strs.sb_user))
|
||||
.AddField(GetText(strs.username), user.ToString(), true)
|
||||
.AddField("ID", user.Id.ToString(), true);
|
||||
var toSend = CreateEmbed()
|
||||
.WithOkColor()
|
||||
.WithTitle("☣ " + GetText(strs.sb_user))
|
||||
.AddField(GetText(strs.username), user.ToString(), true)
|
||||
.AddField("ID", user.Id.ToString(), true);
|
||||
|
||||
if (dmFailed)
|
||||
toSend.WithFooter("⚠️ " + GetText(strs.unable_to_dm_user));
|
||||
@@ -792,11 +773,11 @@ public partial class Administration
|
||||
|
||||
await user.KickAsync((ctx.User + " | " + msg).TrimTo(512));
|
||||
|
||||
var toSend = _sender.CreateEmbed()
|
||||
.WithOkColor()
|
||||
.WithTitle(GetText(strs.kicked_user))
|
||||
.AddField(GetText(strs.username), user.ToString(), true)
|
||||
.AddField("ID", user.Id.ToString(), true);
|
||||
var toSend = CreateEmbed()
|
||||
.WithOkColor()
|
||||
.WithTitle(GetText(strs.kicked_user))
|
||||
.AddField(GetText(strs.username), user.ToString(), true)
|
||||
.AddField("ID", user.Id.ToString(), true);
|
||||
|
||||
if (dmFailed)
|
||||
toSend.WithFooter("⚠️ " + GetText(strs.unable_to_dm_user));
|
||||
@@ -825,9 +806,9 @@ public partial class Administration
|
||||
{
|
||||
var dmMessage = GetText(strs.timeoutdm(Format.Bold(ctx.Guild.Name), msg));
|
||||
await _sender.Response(user)
|
||||
.Embed(_sender.CreateEmbed()
|
||||
.WithPendingColor()
|
||||
.WithDescription(dmMessage))
|
||||
.Embed(CreateEmbed()
|
||||
.WithPendingColor()
|
||||
.WithDescription(dmMessage))
|
||||
.SendAsync();
|
||||
}
|
||||
catch
|
||||
@@ -837,11 +818,11 @@ public partial class Administration
|
||||
|
||||
await user.SetTimeOutAsync(time.Time);
|
||||
|
||||
var toSend = _sender.CreateEmbed()
|
||||
.WithOkColor()
|
||||
.WithTitle("⏳ " + GetText(strs.timedout_user))
|
||||
.AddField(GetText(strs.username), user.ToString(), true)
|
||||
.AddField("ID", user.Id.ToString(), true);
|
||||
var toSend = CreateEmbed()
|
||||
.WithOkColor()
|
||||
.WithTitle("⏳ " + GetText(strs.timedout_user))
|
||||
.AddField(GetText(strs.username), user.ToString(), true)
|
||||
.AddField("ID", user.Id.ToString(), true);
|
||||
|
||||
if (dmFailed)
|
||||
toSend.WithFooter("⚠️ " + GetText(strs.unable_to_dm_user));
|
||||
@@ -898,10 +879,10 @@ public partial class Administration
|
||||
if (string.IsNullOrWhiteSpace(missStr))
|
||||
missStr = "-";
|
||||
|
||||
var toSend = _sender.CreateEmbed()
|
||||
.WithDescription(GetText(strs.mass_ban_in_progress(banning.Count)))
|
||||
.AddField(GetText(strs.invalid(missing.Count)), missStr)
|
||||
.WithPendingColor();
|
||||
var toSend = CreateEmbed()
|
||||
.WithDescription(GetText(strs.mass_ban_in_progress(banning.Count)))
|
||||
.AddField(GetText(strs.invalid(missing.Count)), missStr)
|
||||
.WithPendingColor();
|
||||
|
||||
var banningMessage = await Response().Embed(toSend).SendAsync();
|
||||
|
||||
@@ -918,12 +899,14 @@ public partial class Administration
|
||||
}
|
||||
}
|
||||
|
||||
await banningMessage.ModifyAsync(x => x.Embed = _sender.CreateEmbed()
|
||||
.WithDescription(
|
||||
GetText(strs.mass_ban_completed(banning.Count())))
|
||||
.AddField(GetText(strs.invalid(missing.Count)), missStr)
|
||||
.WithOkColor()
|
||||
.Build());
|
||||
await banningMessage.ModifyAsync(x => x.Embed = CreateEmbed()
|
||||
.WithDescription(
|
||||
GetText(strs.mass_ban_completed(
|
||||
banning.Count())))
|
||||
.AddField(GetText(strs.invalid(missing.Count)),
|
||||
missStr)
|
||||
.WithOkColor()
|
||||
.Build());
|
||||
}
|
||||
|
||||
[Cmd]
|
||||
@@ -944,11 +927,11 @@ public partial class Administration
|
||||
|
||||
//send a message but don't wait for it
|
||||
var banningMessageTask = Response()
|
||||
.Embed(_sender.CreateEmbed()
|
||||
.WithDescription(
|
||||
GetText(strs.mass_kill_in_progress(bans.Count())))
|
||||
.AddField(GetText(strs.invalid(missing)), missStr)
|
||||
.WithPendingColor())
|
||||
.Embed(CreateEmbed()
|
||||
.WithDescription(
|
||||
GetText(strs.mass_kill_in_progress(bans.Count())))
|
||||
.AddField(GetText(strs.invalid(missing)), missStr)
|
||||
.WithPendingColor())
|
||||
.SendAsync();
|
||||
|
||||
var banPrune = await _service.GetBanPruneAsync(ctx.Guild.Id) ?? 7;
|
||||
@@ -965,12 +948,12 @@ public partial class Administration
|
||||
//wait for the message and edit it
|
||||
var banningMessage = await banningMessageTask;
|
||||
|
||||
await banningMessage.ModifyAsync(x => x.Embed = _sender.CreateEmbed()
|
||||
.WithDescription(
|
||||
GetText(strs.mass_kill_completed(bans.Count())))
|
||||
.AddField(GetText(strs.invalid(missing)), missStr)
|
||||
.WithOkColor()
|
||||
.Build());
|
||||
await banningMessage.ModifyAsync(x => x.Embed = CreateEmbed()
|
||||
.WithDescription(
|
||||
GetText(strs.mass_kill_completed(bans.Count())))
|
||||
.AddField(GetText(strs.invalid(missing)), missStr)
|
||||
.WithOkColor()
|
||||
.Build());
|
||||
}
|
||||
|
||||
public class WarnExpireOptions : INadekoCommandOptions
|
||||
|
@@ -1,9 +1,7 @@
|
||||
#nullable disable
|
||||
using LinqToDB;
|
||||
using LinqToDB.EntityFrameworkCore;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using NadekoBot.Common.ModuleBehaviors;
|
||||
using NadekoBot.Common.TypeReaders.Models;
|
||||
using NadekoBot.Modules.Permissions.Services;
|
||||
using NadekoBot.Db.Models;
|
||||
using Newtonsoft.Json;
|
||||
@@ -83,17 +81,24 @@ public class UserPunishService : INService, IReadyExecutor
|
||||
};
|
||||
|
||||
long previousCount;
|
||||
List<WarningPunishment> ps;
|
||||
var ps = await WarnPunishList(guildId);
|
||||
await using (var uow = _db.GetDbContext())
|
||||
{
|
||||
ps = uow.GuildConfigsForId(guildId, set => set.Include(x => x.WarnPunishments)).WarnPunishments;
|
||||
|
||||
previousCount = uow.Set<Warning>()
|
||||
.ForId(guildId, userId)
|
||||
.Where(w => !w.Forgiven && w.UserId == userId)
|
||||
previousCount = uow.GetTable<Warning>()
|
||||
.Where(w => w.GuildId == guildId && w.UserId == userId && !w.Forgiven)
|
||||
.Sum(x => x.Weight);
|
||||
|
||||
uow.Set<Warning>().Add(warn);
|
||||
await uow.GetTable<Warning>()
|
||||
.InsertAsync(() => new()
|
||||
{
|
||||
UserId = userId,
|
||||
GuildId = guildId,
|
||||
Forgiven = false,
|
||||
Reason = reason,
|
||||
Moderator = modName,
|
||||
Weight = weight,
|
||||
DateAdded = DateTime.UtcNow,
|
||||
});
|
||||
|
||||
await uow.SaveChangesAsync();
|
||||
}
|
||||
@@ -260,12 +265,12 @@ public class UserPunishService : INService, IReadyExecutor
|
||||
.ToListAsyncLinqToDB();
|
||||
|
||||
var cleared = await uow.GetTable<Warning>()
|
||||
.Where(x => toClear.Contains(x.Id))
|
||||
.UpdateAsync(_ => new()
|
||||
{
|
||||
Forgiven = true,
|
||||
ForgivenBy = "expiry"
|
||||
});
|
||||
.Where(x => toClear.Contains(x.Id))
|
||||
.UpdateAsync(_ => new()
|
||||
{
|
||||
Forgiven = true,
|
||||
ForgivenBy = "expiry"
|
||||
});
|
||||
|
||||
var toDelete = await uow.GetTable<Warning>()
|
||||
.Where(x => uow.GetTable<GuildConfig>()
|
||||
@@ -282,8 +287,8 @@ public class UserPunishService : INService, IReadyExecutor
|
||||
.ToListAsyncLinqToDB();
|
||||
|
||||
var deleted = await uow.GetTable<Warning>()
|
||||
.Where(x => toDelete.Contains(x.Id))
|
||||
.DeleteAsync();
|
||||
.Where(x => toDelete.Contains(x.Id))
|
||||
.DeleteAsync();
|
||||
|
||||
if (cleared > 0 || deleted > 0)
|
||||
{
|
||||
@@ -324,11 +329,11 @@ public class UserPunishService : INService, IReadyExecutor
|
||||
await uow.SaveChangesAsync();
|
||||
}
|
||||
|
||||
public Task<int> GetWarnExpire(ulong guildId)
|
||||
public Task<(int, bool)> GetWarnExpire(ulong guildId)
|
||||
{
|
||||
using var uow = _db.GetDbContext();
|
||||
var config = uow.GuildConfigsForId(guildId, set => set);
|
||||
return Task.FromResult(config.WarnExpireHours / 24);
|
||||
return Task.FromResult((config.WarnExpireHours / 24, config.WarnExpireAction == WarnExpireAction.Delete));
|
||||
}
|
||||
|
||||
public async Task WarnExpireAsync(ulong guildId, int days, bool delete)
|
||||
@@ -377,18 +382,19 @@ public class UserPunishService : INService, IReadyExecutor
|
||||
return toReturn;
|
||||
}
|
||||
|
||||
public bool WarnPunish(
|
||||
public async Task<bool> WarnPunish(
|
||||
ulong guildId,
|
||||
int number,
|
||||
PunishmentAction punish,
|
||||
StoopidTime time,
|
||||
TimeSpan? time,
|
||||
IRole role = null)
|
||||
{
|
||||
// these 3 don't make sense with time
|
||||
if (punish is PunishmentAction.Softban or PunishmentAction.Kick or PunishmentAction.RemoveRoles
|
||||
&& time is not null)
|
||||
return false;
|
||||
if (number <= 0 || (time is not null && time.Time > TimeSpan.FromDays(49)))
|
||||
|
||||
if (number <= 0 || (time is not null && time > TimeSpan.FromDays(59)))
|
||||
return false;
|
||||
|
||||
if (punish is PunishmentAction.AddRole && role is null)
|
||||
@@ -397,47 +403,51 @@ public class UserPunishService : INService, IReadyExecutor
|
||||
if (punish is PunishmentAction.TimeOut && time is null)
|
||||
return false;
|
||||
|
||||
using var uow = _db.GetDbContext();
|
||||
var ps = uow.GuildConfigsForId(guildId, set => set.Include(x => x.WarnPunishments)).WarnPunishments;
|
||||
var toDelete = ps.Where(x => x.Count == number);
|
||||
|
||||
uow.RemoveRange(toDelete);
|
||||
|
||||
ps.Add(new()
|
||||
{
|
||||
Count = number,
|
||||
Punishment = punish,
|
||||
Time = (int?)time?.Time.TotalMinutes ?? 0,
|
||||
RoleId = punish == PunishmentAction.AddRole ? role!.Id : default(ulong?)
|
||||
});
|
||||
uow.SaveChanges();
|
||||
var timeMinutes = (int?)time?.TotalMinutes ?? 0;
|
||||
var roleId = punish == PunishmentAction.AddRole ? role!.Id : default(ulong?);
|
||||
await using var uow = _db.GetDbContext();
|
||||
await uow.GetTable<WarningPunishment>()
|
||||
.InsertOrUpdateAsync(() => new()
|
||||
{
|
||||
GuildId = guildId,
|
||||
Count = number,
|
||||
Punishment = punish,
|
||||
Time = timeMinutes,
|
||||
RoleId = roleId
|
||||
},
|
||||
_ => new()
|
||||
{
|
||||
Punishment = punish,
|
||||
Time = timeMinutes,
|
||||
RoleId = roleId
|
||||
},
|
||||
() => new()
|
||||
{
|
||||
GuildId = guildId,
|
||||
Count = number
|
||||
});
|
||||
return true;
|
||||
}
|
||||
|
||||
public bool WarnPunishRemove(ulong guildId, int number)
|
||||
public async Task<bool> WarnPunishRemove(ulong guildId, int count)
|
||||
{
|
||||
if (number <= 0)
|
||||
return false;
|
||||
await using var uow = _db.GetDbContext();
|
||||
var numDeleted = await uow.GetTable<WarningPunishment>()
|
||||
.DeleteAsync(x => x.GuildId == guildId && x.Count == count);
|
||||
|
||||
using var uow = _db.GetDbContext();
|
||||
var ps = uow.GuildConfigsForId(guildId, set => set.Include(x => x.WarnPunishments)).WarnPunishments;
|
||||
var p = ps.FirstOrDefault(x => x.Count == number);
|
||||
|
||||
if (p is not null)
|
||||
{
|
||||
uow.Remove(p);
|
||||
uow.SaveChanges();
|
||||
}
|
||||
|
||||
return true;
|
||||
return numDeleted > 0;
|
||||
}
|
||||
|
||||
public WarningPunishment[] WarnPunishList(ulong guildId)
|
||||
|
||||
public async Task<WarningPunishment[]> WarnPunishList(ulong guildId)
|
||||
{
|
||||
using var uow = _db.GetDbContext();
|
||||
return uow.GuildConfigsForId(guildId, gc => gc.Include(x => x.WarnPunishments))
|
||||
.WarnPunishments.OrderBy(x => x.Count)
|
||||
.ToArray();
|
||||
await using var uow = _db.GetDbContext();
|
||||
|
||||
var wps = uow.GetTable<WarningPunishment>()
|
||||
.Where(x => x.GuildId == guildId)
|
||||
.OrderBy(x => x.Count)
|
||||
.ToArray();
|
||||
return wps;
|
||||
}
|
||||
|
||||
public (IReadOnlyCollection<(string Original, ulong? Id, string Reason)> Bans, int Missing) MassKill(
|
||||
@@ -607,12 +617,12 @@ public class UserPunishService : INService, IReadyExecutor
|
||||
return await _repSvc.ReplaceAsync(output, repCtx);
|
||||
}
|
||||
|
||||
public async Task<Warning> WarnDelete(ulong userId, int index)
|
||||
public async Task<Warning> WarnDelete(ulong guildId, ulong userId, int index)
|
||||
{
|
||||
await using var uow = _db.GetDbContext();
|
||||
|
||||
var warn = await uow.GetTable<Warning>()
|
||||
.Where(x => x.UserId == userId)
|
||||
.Where(x => x.GuildId == guildId && x.UserId == userId)
|
||||
.OrderByDescending(x => x.DateAdded)
|
||||
.Skip(index)
|
||||
.FirstOrDefaultAsyncLinqToDB();
|
||||
@@ -626,4 +636,73 @@ public class UserPunishService : INService, IReadyExecutor
|
||||
|
||||
return warn;
|
||||
}
|
||||
|
||||
public async Task<bool> WarnDelete(ulong guildId, int id)
|
||||
{
|
||||
await using var uow = _db.GetDbContext();
|
||||
|
||||
var numDeleted = await uow.GetTable<Warning>()
|
||||
.Where(x => x.GuildId == guildId && x.Id == id)
|
||||
.DeleteAsync();
|
||||
|
||||
return numDeleted > 0;
|
||||
}
|
||||
|
||||
public async Task<(IReadOnlyCollection<Warning> latest, int totalCount)> GetLatestWarnings(
|
||||
ulong guildId,
|
||||
int page = 1)
|
||||
{
|
||||
ArgumentOutOfRangeException.ThrowIfNegativeOrZero(page);
|
||||
|
||||
await using var uow = _db.GetDbContext();
|
||||
var latest = await uow.GetTable<Warning>()
|
||||
.Where(x => x.GuildId == guildId)
|
||||
.OrderByDescending(x => x.DateAdded)
|
||||
.Skip(10 * (page - 1))
|
||||
.Take(10)
|
||||
.ToListAsyncLinqToDB();
|
||||
|
||||
var totalCount = await uow.GetTable<Warning>()
|
||||
.Where(x => x.GuildId == guildId)
|
||||
.CountAsyncLinqToDB();
|
||||
|
||||
return (latest, totalCount);
|
||||
}
|
||||
|
||||
public async Task<bool> ForgiveWarning(ulong requestGuildId, int warnId, string modName)
|
||||
{
|
||||
await using var uow = _db.GetDbContext();
|
||||
var success = await uow.GetTable<Warning>()
|
||||
.Where(x => x.GuildId == requestGuildId && x.Id == warnId)
|
||||
.UpdateAsync(_ => new()
|
||||
{
|
||||
Forgiven = true,
|
||||
ForgivenBy = modName,
|
||||
})
|
||||
== 1;
|
||||
|
||||
return success;
|
||||
}
|
||||
|
||||
public async Task<(IReadOnlyCollection<Warning> latest, int totalCount)> GetUserWarnings(
|
||||
ulong guildId,
|
||||
ulong userId,
|
||||
int page)
|
||||
{
|
||||
ArgumentOutOfRangeException.ThrowIfNegativeOrZero(page);
|
||||
|
||||
await using var uow = _db.GetDbContext();
|
||||
var latest = await uow.GetTable<Warning>()
|
||||
.Where(x => x.GuildId == guildId && x.UserId == userId)
|
||||
.OrderByDescending(x => x.DateAdded)
|
||||
.Skip(10 * (page - 1))
|
||||
.Take(10)
|
||||
.ToListAsyncLinqToDB();
|
||||
|
||||
var totalCount = await uow.GetTable<Warning>()
|
||||
.Where(x => x.GuildId == guildId && x.UserId == userId)
|
||||
.CountAsyncLinqToDB();
|
||||
|
||||
return (latest, totalCount);
|
||||
}
|
||||
}
|
@@ -68,7 +68,7 @@ public partial class Administration
|
||||
else
|
||||
text = GetText(strs.no_vcroles);
|
||||
|
||||
await Response().Embed(_sender.CreateEmbed()
|
||||
await Response().Embed(CreateEmbed()
|
||||
.WithOkColor()
|
||||
.WithTitle(GetText(strs.vc_role_list))
|
||||
.WithDescription(text)).SendAsync();
|
||||
|
@@ -6,48 +6,7 @@ namespace NadekoBot.Modules.NadekoExpressions;
|
||||
|
||||
public static class NadekoExpressionExtensions
|
||||
{
|
||||
private static string ResolveTriggerString(this string str, DiscordSocketClient client)
|
||||
=> str.Replace("%bot.mention%", client.CurrentUser.Mention, StringComparison.Ordinal);
|
||||
|
||||
public static async Task<IUserMessage> Send(
|
||||
this NadekoExpression cr,
|
||||
IUserMessage ctx,
|
||||
IReplacementService repSvc,
|
||||
DiscordSocketClient client,
|
||||
IMessageSenderService sender)
|
||||
{
|
||||
var channel = cr.DmResponse ? await ctx.Author.CreateDMChannelAsync() : ctx.Channel;
|
||||
|
||||
var trigger = cr.Trigger.ResolveTriggerString(client);
|
||||
var substringIndex = trigger.Length;
|
||||
if (cr.ContainsAnywhere)
|
||||
{
|
||||
var pos = ctx.Content.AsSpan().GetWordPosition(trigger);
|
||||
if (pos == WordPosition.Start)
|
||||
substringIndex += 1;
|
||||
else if (pos == WordPosition.End)
|
||||
substringIndex = ctx.Content.Length;
|
||||
else if (pos == WordPosition.Middle)
|
||||
substringIndex += ctx.Content.IndexOf(trigger, StringComparison.InvariantCulture);
|
||||
}
|
||||
|
||||
var canMentionEveryone = (ctx.Author as IGuildUser)?.GuildPermissions.MentionEveryone ?? true;
|
||||
|
||||
var repCtx = new ReplacementContext(client: client,
|
||||
guild: (ctx.Channel as ITextChannel)?.Guild as SocketGuild,
|
||||
channel: ctx.Channel,
|
||||
user: ctx.Author
|
||||
)
|
||||
.WithOverride("%target%",
|
||||
() => canMentionEveryone
|
||||
? ctx.Content[substringIndex..].Trim()
|
||||
: ctx.Content[substringIndex..].Trim().SanitizeMentions(true));
|
||||
|
||||
var text = SmartText.CreateFrom(cr.Response);
|
||||
text = await repSvc.ReplaceAsync(text, repCtx);
|
||||
|
||||
return await sender.Response(channel).Text(text).Sanitize(false).SendAsync();
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static WordPosition GetWordPosition(this ReadOnlySpan<char> str, in ReadOnlySpan<char> word)
|
||||
|
@@ -12,10 +12,10 @@ public partial class NadekoExpressions : NadekoModule<NadekoExpressionsService>
|
||||
All
|
||||
}
|
||||
|
||||
private readonly IBotCredentials _creds;
|
||||
private readonly IBotCreds _creds;
|
||||
private readonly IHttpClientFactory _clientFactory;
|
||||
|
||||
public NadekoExpressions(IBotCredentials creds, IHttpClientFactory clientFactory)
|
||||
public NadekoExpressions(IBotCreds creds, IHttpClientFactory clientFactory)
|
||||
{
|
||||
_creds = creds;
|
||||
_clientFactory = clientFactory;
|
||||
@@ -35,7 +35,7 @@ public partial class NadekoExpressions : NadekoModule<NadekoExpressionsService>
|
||||
var ex = await _service.AddAsync(ctx.Guild?.Id, key, message);
|
||||
|
||||
await Response()
|
||||
.Embed(_sender.CreateEmbed()
|
||||
.Embed(CreateEmbed()
|
||||
.WithOkColor()
|
||||
.WithTitle(GetText(strs.expr_new))
|
||||
.WithDescription($"#{new kwum(ex.Id)}")
|
||||
@@ -105,7 +105,7 @@ public partial class NadekoExpressions : NadekoModule<NadekoExpressionsService>
|
||||
if (ex is not null)
|
||||
{
|
||||
await Response()
|
||||
.Embed(_sender.CreateEmbed()
|
||||
.Embed(CreateEmbed()
|
||||
.WithOkColor()
|
||||
.WithTitle(GetText(strs.expr_edited))
|
||||
.WithDescription($"#{id}")
|
||||
@@ -160,7 +160,7 @@ public partial class NadekoExpressions : NadekoModule<NadekoExpressionsService>
|
||||
: " // " + string.Join(" ", ex.GetReactions())))
|
||||
.Join('\n');
|
||||
|
||||
return _sender.CreateEmbed().WithOkColor().WithTitle(GetText(strs.expressions)).WithDescription(desc);
|
||||
return CreateEmbed().WithOkColor().WithTitle(GetText(strs.expressions)).WithDescription(desc);
|
||||
})
|
||||
.SendAsync();
|
||||
}
|
||||
@@ -180,7 +180,7 @@ public partial class NadekoExpressions : NadekoModule<NadekoExpressionsService>
|
||||
|
||||
await Response()
|
||||
.Interaction(IsValidExprEditor() ? inter : null)
|
||||
.Embed(_sender.CreateEmbed()
|
||||
.Embed(CreateEmbed()
|
||||
.WithOkColor()
|
||||
.WithDescription($"#{id}")
|
||||
.AddField(GetText(strs.trigger), found.Trigger.TrimTo(1024))
|
||||
@@ -225,7 +225,7 @@ public partial class NadekoExpressions : NadekoModule<NadekoExpressionsService>
|
||||
if (ex is not null)
|
||||
{
|
||||
await Response()
|
||||
.Embed(_sender.CreateEmbed()
|
||||
.Embed(CreateEmbed()
|
||||
.WithOkColor()
|
||||
.WithTitle(GetText(strs.expr_deleted))
|
||||
.WithDescription($"#{id}")
|
||||
@@ -376,7 +376,7 @@ public partial class NadekoExpressions : NadekoModule<NadekoExpressionsService>
|
||||
[UserPerm(GuildPerm.Administrator)]
|
||||
public async Task ExprClear()
|
||||
{
|
||||
if (await PromptUserConfirmAsync(_sender.CreateEmbed()
|
||||
if (await PromptUserConfirmAsync(CreateEmbed()
|
||||
.WithTitle("Expression clear")
|
||||
.WithDescription("This will delete all expressions on this server.")))
|
||||
{
|
||||
|
@@ -67,7 +67,6 @@ public sealed class NadekoExpressionsService : IExecOnMessage, IReadyExecutor
|
||||
// private readonly GlobalPermissionService _gperm;
|
||||
// private readonly CmdCdService _cmdCds;
|
||||
private readonly IPermissionChecker _permChecker;
|
||||
private readonly ICommandHandler _cmd;
|
||||
private readonly IBotStrings _strings;
|
||||
private readonly IBot _bot;
|
||||
private readonly IPubSub _pubSub;
|
||||
@@ -84,7 +83,6 @@ public sealed class NadekoExpressionsService : IExecOnMessage, IReadyExecutor
|
||||
IBotStrings strings,
|
||||
IBot bot,
|
||||
DiscordSocketClient client,
|
||||
ICommandHandler cmd,
|
||||
IPubSub pubSub,
|
||||
IMessageSenderService sender,
|
||||
IReplacementService repSvc,
|
||||
@@ -93,7 +91,6 @@ public sealed class NadekoExpressionsService : IExecOnMessage, IReadyExecutor
|
||||
{
|
||||
_db = db;
|
||||
_client = client;
|
||||
_cmd = cmd;
|
||||
_strings = strings;
|
||||
_bot = bot;
|
||||
_pubSub = pubSub;
|
||||
@@ -249,46 +246,54 @@ public sealed class NadekoExpressionsService : IExecOnMessage, IReadyExecutor
|
||||
|
||||
try
|
||||
{
|
||||
if (guild is SocketGuild sg)
|
||||
if (guild is not SocketGuild sg)
|
||||
return false;
|
||||
|
||||
var result = await _permChecker.CheckPermsAsync(
|
||||
guild,
|
||||
msg.Channel,
|
||||
msg.Author,
|
||||
"ACTUALEXPRESSIONS",
|
||||
expr.Trigger
|
||||
);
|
||||
|
||||
if (!result.IsAllowed)
|
||||
{
|
||||
var result = await _permChecker.CheckPermsAsync(
|
||||
guild,
|
||||
msg.Channel,
|
||||
msg.Author,
|
||||
"ACTUALEXPRESSIONS",
|
||||
expr.Trigger
|
||||
);
|
||||
|
||||
if (!result.IsAllowed)
|
||||
var cache = _pc.GetCacheFor(guild.Id);
|
||||
if (cache.Verbose)
|
||||
{
|
||||
var cache = _pc.GetCacheFor(guild.Id);
|
||||
if (cache.Verbose)
|
||||
if (result.TryPickT3(out var disallowed, out _))
|
||||
{
|
||||
if (result.TryPickT3(out var disallowed, out _))
|
||||
var permissionMessage = _strings.GetText(strs.perm_prevent(disallowed.PermIndex + 1,
|
||||
Format.Bold(disallowed.PermText)),
|
||||
sg.Id);
|
||||
|
||||
try
|
||||
{
|
||||
await _sender.Response(msg.Channel)
|
||||
.Error(permissionMessage)
|
||||
.SendAsync();
|
||||
}
|
||||
catch
|
||||
{
|
||||
var permissionMessage = _strings.GetText(strs.perm_prevent(disallowed.PermIndex + 1,
|
||||
Format.Bold(disallowed.PermText)),
|
||||
sg.Id);
|
||||
|
||||
try
|
||||
{
|
||||
await _sender.Response(msg.Channel)
|
||||
.Error(permissionMessage)
|
||||
.SendAsync();
|
||||
}
|
||||
catch
|
||||
{
|
||||
}
|
||||
|
||||
Log.Information("{PermissionMessage}", permissionMessage);
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
Log.Information("{PermissionMessage}", permissionMessage);
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
var sentMsg = await expr.Send(msg, _repSvc, _client, _sender);
|
||||
var cu = sg.CurrentUser;
|
||||
|
||||
var channel = expr.DmResponse ? await msg.Author.CreateDMChannelAsync() : msg.Channel;
|
||||
|
||||
// have no perms to speak in that channel
|
||||
if (channel is ITextChannel tc && !cu.GetPermissions(tc).SendMessages)
|
||||
return false;
|
||||
|
||||
var sentMsg = await Send(expr, msg, channel);
|
||||
|
||||
var reactions = expr.GetReactions();
|
||||
foreach (var reaction in reactions)
|
||||
@@ -336,6 +341,47 @@ public sealed class NadekoExpressionsService : IExecOnMessage, IReadyExecutor
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
public string ResolveTriggerString(string str)
|
||||
=> str.Replace("%bot.mention%", _client.CurrentUser.Mention, StringComparison.Ordinal);
|
||||
|
||||
public async Task<IUserMessage> Send(
|
||||
NadekoExpression cr,
|
||||
IUserMessage ctx,
|
||||
IMessageChannel channel
|
||||
)
|
||||
{
|
||||
var trigger = ResolveTriggerString(cr.Trigger);
|
||||
var substringIndex = trigger.Length;
|
||||
if (cr.ContainsAnywhere)
|
||||
{
|
||||
var pos = ctx.Content.AsSpan().GetWordPosition(trigger);
|
||||
if (pos == WordPosition.Start)
|
||||
substringIndex += 1;
|
||||
else if (pos == WordPosition.End)
|
||||
substringIndex = ctx.Content.Length;
|
||||
else if (pos == WordPosition.Middle)
|
||||
substringIndex += ctx.Content.IndexOf(trigger, StringComparison.InvariantCulture);
|
||||
}
|
||||
|
||||
var canMentionEveryone = (ctx.Author as IGuildUser)?.GuildPermissions.MentionEveryone ?? true;
|
||||
|
||||
var repCtx = new ReplacementContext(client: _client,
|
||||
guild: (ctx.Channel as ITextChannel)?.Guild as SocketGuild,
|
||||
channel: ctx.Channel,
|
||||
user: ctx.Author
|
||||
)
|
||||
.WithOverride("%target%",
|
||||
() => canMentionEveryone
|
||||
? ctx.Content[substringIndex..].Trim()
|
||||
: ctx.Content[substringIndex..].Trim().SanitizeMentions(true));
|
||||
|
||||
var text = SmartText.CreateFrom(cr.Response);
|
||||
text = await _repSvc.ReplaceAsync(text, repCtx);
|
||||
|
||||
return await _sender.Response(channel).Text(text).Sanitize(false).SendAsync();
|
||||
}
|
||||
|
||||
public async Task ResetExprReactions(ulong? maybeGuildId, int id)
|
||||
{
|
||||
NadekoExpression expr;
|
||||
@@ -789,7 +835,7 @@ public sealed class NadekoExpressionsService : IExecOnMessage, IReadyExecutor
|
||||
|
||||
if (newguildExpressions.TryGetValue(guildId, out var exprs))
|
||||
{
|
||||
return (exprs.Where(x => x.Trigger.Contains(query))
|
||||
return (exprs.Where(x => x.Trigger.Contains(query) || x.Response.Contains(query))
|
||||
.Skip(page * 9)
|
||||
.Take(9)
|
||||
.ToArray(), exprs.Length);
|
||||
|
@@ -6,6 +6,10 @@ namespace NadekoBot.Modules.Gambling.Common.AnimalRacing;
|
||||
|
||||
public sealed class AnimalRace : IDisposable
|
||||
{
|
||||
public const double BASE_MULTIPLIER = 0.87;
|
||||
public const double MAX_MULTIPLIER = 0.94;
|
||||
public const double MULTI_PER_USER = 0.005;
|
||||
|
||||
public enum Phase
|
||||
{
|
||||
WaitingForPlayers,
|
||||
@@ -100,7 +104,7 @@ public sealed class AnimalRace : IDisposable
|
||||
foreach (var user in _users)
|
||||
{
|
||||
if (user.Bet > 0)
|
||||
await _currency.AddAsync(user.UserId, user.Bet, new("animalrace", "refund"));
|
||||
await _currency.AddAsync(user.UserId, (long)(user.Bet * BASE_MULTIPLIER), new("animalrace", "refund"));
|
||||
}
|
||||
|
||||
_ = OnStartingFailed?.Invoke(this);
|
||||
@@ -116,7 +120,7 @@ public sealed class AnimalRace : IDisposable
|
||||
{
|
||||
foreach (var user in _users)
|
||||
{
|
||||
user.Progress += rng.Next(1, 11);
|
||||
user.Progress += rng.Next(1, 10);
|
||||
if (user.Progress >= 60)
|
||||
user.Progress = 60;
|
||||
}
|
||||
@@ -126,13 +130,15 @@ public sealed class AnimalRace : IDisposable
|
||||
FinishedUsers.AddRange(finished);
|
||||
|
||||
_ = OnStateUpdate?.Invoke(this);
|
||||
await Task.Delay(2500);
|
||||
await Task.Delay(1750);
|
||||
}
|
||||
|
||||
if (FinishedUsers[0].Bet > 0)
|
||||
{
|
||||
Multi = FinishedUsers.Count
|
||||
* Math.Min(MAX_MULTIPLIER, BASE_MULTIPLIER + (MULTI_PER_USER * FinishedUsers.Count));
|
||||
await _currency.AddAsync(FinishedUsers[0].UserId,
|
||||
FinishedUsers[0].Bet * (_users.Count - 1),
|
||||
(long)(FinishedUsers[0].Bet * Multi),
|
||||
new("animalrace", "win"));
|
||||
}
|
||||
|
||||
@@ -140,6 +146,8 @@ public sealed class AnimalRace : IDisposable
|
||||
});
|
||||
}
|
||||
|
||||
public double Multi { get; set; } = BASE_MULTIPLIER;
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
CurrentPhase = Phase.Ended;
|
||||
|
@@ -12,7 +12,7 @@ namespace NadekoBot.Modules.Gambling;
|
||||
public partial class Gambling
|
||||
{
|
||||
[Group]
|
||||
public partial class AnimalRacingCommands : GamblingSubmodule<AnimalRaceService>
|
||||
public partial class AnimalRacingCommands : GamblingModule<AnimalRaceService>
|
||||
{
|
||||
private readonly ICurrencyService _cs;
|
||||
private readonly DiscordSocketClient _client;
|
||||
@@ -74,10 +74,14 @@ public partial class Gambling
|
||||
if (race.FinishedUsers[0].Bet > 0)
|
||||
{
|
||||
return Response()
|
||||
.Confirm(GetText(strs.animal_race),
|
||||
GetText(strs.animal_race_won_money(Format.Bold(winner.Username),
|
||||
winner.Animal.Icon,
|
||||
(race.FinishedUsers[0].Bet * (race.Users.Count - 1)) + CurrencySign)))
|
||||
.Embed(CreateEmbed()
|
||||
.WithOkColor()
|
||||
.WithTitle(GetText(strs.animal_race))
|
||||
.WithDescription(GetText(strs.animal_race_won_money(
|
||||
Format.Bold(winner.Username),
|
||||
winner.Animal.Icon,
|
||||
N(race.FinishedUsers[0].Bet * race.Multi))))
|
||||
.WithFooter($"x{race.Multi:F2}"))
|
||||
.SendAsync();
|
||||
}
|
||||
|
||||
@@ -113,14 +117,14 @@ public partial class Gambling
|
||||
|
||||
private async Task Ar_OnStateUpdate(AnimalRace race)
|
||||
{
|
||||
var text = $@"|🏁🏁🏁🏁🏁🏁🏁🏁🏁🏁🏁🏁🏁🏁🏁🔚|
|
||||
var text = $@"|🏁 🏁 🏁 🏁 🏁 🏁 🏁 🏁 🏁 🏁 🏁 🏁 🏁 🏁 🏁🔚|
|
||||
{string.Join("\n", race.Users.Select(p =>
|
||||
{
|
||||
var index = race.FinishedUsers.IndexOf(p);
|
||||
var extra = index == -1 ? "" : $"#{index + 1} {(index == 0 ? "🏆" : "")}";
|
||||
return $"{(int)(p.Progress / 60f * 100),-2}%|{new string('‣', p.Progress) + p.Animal.Icon + extra}";
|
||||
}))}
|
||||
|🏁🏁🏁🏁🏁🏁🏁🏁🏁🏁🏁🏁🏁🏁🏁🔚|";
|
||||
|🏁 🏁 🏁 🏁 🏁 🏁 🏁 🏁 🏁 🏁 🏁 🏁 🏁 🏁 🏁 🔚|";
|
||||
|
||||
var msg = raceMessage;
|
||||
|
||||
@@ -128,11 +132,11 @@ public partial class Gambling
|
||||
raceMessage = await Response().Confirm(text).SendAsync();
|
||||
else
|
||||
{
|
||||
await msg.ModifyAsync(x => x.Embed = _sender.CreateEmbed()
|
||||
.WithTitle(GetText(strs.animal_race))
|
||||
.WithDescription(text)
|
||||
.WithOkColor()
|
||||
.Build());
|
||||
await msg.ModifyAsync(x => x.Embed = CreateEmbed()
|
||||
.WithTitle(GetText(strs.animal_race))
|
||||
.WithDescription(text)
|
||||
.WithOkColor()
|
||||
.Build());
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -59,7 +59,7 @@ public partial class Gambling
|
||||
{
|
||||
var bal = await _bank.GetBalanceAsync(ctx.User.Id);
|
||||
|
||||
var eb = _sender.CreateEmbed()
|
||||
var eb = CreateEmbed()
|
||||
.WithOkColor()
|
||||
.WithDescription(GetText(strs.bank_balance(N(bal))));
|
||||
|
||||
@@ -80,7 +80,7 @@ public partial class Gambling
|
||||
{
|
||||
var bal = await _bank.GetBalanceAsync(user.Id);
|
||||
|
||||
var eb = _sender.CreateEmbed()
|
||||
var eb = CreateEmbed()
|
||||
.WithOkColor()
|
||||
.WithDescription(GetText(strs.bank_balance_other(user.ToString(), N(bal))));
|
||||
|
||||
|
175
src/NadekoBot/Modules/Gambling/BetStatsCommands.cs
Normal file
175
src/NadekoBot/Modules/Gambling/BetStatsCommands.cs
Normal file
@@ -0,0 +1,175 @@
|
||||
#nullable disable
|
||||
using NadekoBot.Modules.Gambling.Common;
|
||||
using NadekoBot.Modules.Gambling.Services;
|
||||
|
||||
namespace NadekoBot.Modules.Gambling;
|
||||
|
||||
public partial class Gambling
|
||||
{
|
||||
[Group]
|
||||
public sealed class BetStatsCommands : GamblingModule<UserBetStatsService>
|
||||
{
|
||||
private readonly GamblingTxTracker _gamblingTxTracker;
|
||||
|
||||
public BetStatsCommands(
|
||||
GamblingTxTracker gamblingTxTracker,
|
||||
GamblingConfigService gcs)
|
||||
: base(gcs)
|
||||
{
|
||||
_gamblingTxTracker = gamblingTxTracker;
|
||||
}
|
||||
|
||||
[Cmd]
|
||||
public async Task BetStatsReset(GamblingGame? game = null)
|
||||
{
|
||||
var price = await _service.GetResetStatsPriceAsync(ctx.User.Id, game);
|
||||
|
||||
var result = await PromptUserConfirmAsync(CreateEmbed()
|
||||
.WithDescription(
|
||||
$"""
|
||||
Are you sure you want to reset your bet stats for **{GetGameName(game)}**?
|
||||
|
||||
It will cost you {N(price)}
|
||||
"""));
|
||||
|
||||
if (!result)
|
||||
return;
|
||||
|
||||
var success = await _service.ResetStatsAsync(ctx.User.Id, game);
|
||||
|
||||
if (success)
|
||||
{
|
||||
await ctx.OkAsync();
|
||||
}
|
||||
else
|
||||
{
|
||||
await Response()
|
||||
.Error(strs.not_enough(CurrencySign))
|
||||
.SendAsync();
|
||||
}
|
||||
}
|
||||
|
||||
private string GetGameName(GamblingGame? game)
|
||||
{
|
||||
if (game is null)
|
||||
return "all games";
|
||||
|
||||
return game.ToString();
|
||||
}
|
||||
|
||||
[Cmd]
|
||||
[Priority(3)]
|
||||
public async Task BetStats()
|
||||
=> await BetStats(ctx.User, null);
|
||||
|
||||
[Cmd]
|
||||
[Priority(2)]
|
||||
public async Task BetStats(GamblingGame game)
|
||||
=> await BetStats(ctx.User, game);
|
||||
|
||||
[Cmd]
|
||||
[Priority(1)]
|
||||
public async Task BetStats([Leftover] IUser user)
|
||||
=> await BetStats(user, null);
|
||||
|
||||
[Cmd]
|
||||
[Priority(0)]
|
||||
public async Task BetStats(IUser user, GamblingGame? game)
|
||||
{
|
||||
var stats = await _gamblingTxTracker.GetUserStatsAsync(user.Id, game);
|
||||
|
||||
if (stats.Count == 0)
|
||||
stats = new()
|
||||
{
|
||||
new()
|
||||
{
|
||||
TotalBet = 1
|
||||
}
|
||||
};
|
||||
|
||||
var eb = CreateEmbed()
|
||||
.WithOkColor()
|
||||
.WithAuthor(user)
|
||||
.AddField("Total Won", N(stats.Sum(x => x.PaidOut)), true)
|
||||
.AddField("Biggest Win", N(stats.Max(x => x.MaxWin)), true)
|
||||
.AddField("Biggest Bet", N(stats.Max(x => x.MaxBet)), true)
|
||||
.AddField("# Bets", stats.Sum(x => x.WinCount + x.LoseCount), true)
|
||||
.AddField("Payout",
|
||||
(stats.Sum(x => x.PaidOut) / stats.Sum(x => x.TotalBet)).ToString("P2", Culture),
|
||||
true);
|
||||
if (game == null)
|
||||
{
|
||||
var favGame = stats.MaxBy(x => x.WinCount + x.LoseCount);
|
||||
eb.AddField("Favorite Game",
|
||||
favGame.Game + "\n" + Format.Italics((favGame.WinCount + favGame.LoseCount) + " plays"),
|
||||
true);
|
||||
}
|
||||
else
|
||||
{
|
||||
eb.WithDescription(game.ToString())
|
||||
.AddField("# Wins", stats.Sum(x => x.WinCount), true);
|
||||
}
|
||||
|
||||
await Response()
|
||||
.Embed(eb)
|
||||
.SendAsync();
|
||||
}
|
||||
|
||||
[Cmd]
|
||||
public async Task GambleStats()
|
||||
{
|
||||
var stats = await _gamblingTxTracker.GetAllAsync();
|
||||
|
||||
var eb = CreateEmbed()
|
||||
.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 Response().Embed(eb).SendAsync();
|
||||
}
|
||||
|
||||
[Cmd]
|
||||
[OwnerOnly]
|
||||
public async Task GambleStatsReset()
|
||||
{
|
||||
if (!await PromptUserConfirmAsync(CreateEmbed()
|
||||
.WithDescription(
|
||||
"""
|
||||
Are you sure?
|
||||
This will completely reset Gambling Stats.
|
||||
|
||||
This action is irreversible.
|
||||
""")))
|
||||
return;
|
||||
|
||||
await GambleStats();
|
||||
await _service.ResetGamblingStatsAsync();
|
||||
|
||||
await ctx.OkAsync();
|
||||
}
|
||||
}
|
||||
}
|
@@ -8,7 +8,7 @@ namespace NadekoBot.Modules.Gambling;
|
||||
|
||||
public partial class Gambling
|
||||
{
|
||||
public partial class BlackJackCommands : GamblingSubmodule<BlackJackService>
|
||||
public partial class BlackJackCommands : GamblingModule<BlackJackService>
|
||||
{
|
||||
public enum BjAction
|
||||
{
|
||||
@@ -95,7 +95,7 @@ public partial class Gambling
|
||||
|
||||
var cStr = string.Concat(c.Select(x => x[..^1] + " "));
|
||||
cStr += "\n" + string.Concat(c.Select(x => x.Last() + " "));
|
||||
var embed = _sender.CreateEmbed()
|
||||
var embed = CreateEmbed()
|
||||
.WithOkColor()
|
||||
.WithTitle("BlackJack")
|
||||
.AddField($"{dealerIcon} Dealer's Hand | Value: {bj.Dealer.GetHandValue()}", cStr);
|
||||
|
@@ -9,7 +9,7 @@ namespace NadekoBot.Modules.Gambling;
|
||||
public partial class Gambling
|
||||
{
|
||||
[Group]
|
||||
public partial class Connect4Commands : GamblingSubmodule<GamblingService>
|
||||
public partial class Connect4Commands : GamblingModule<GamblingService>
|
||||
{
|
||||
private static readonly string[] _numbers =
|
||||
[
|
||||
@@ -132,7 +132,7 @@ public partial class Gambling
|
||||
else
|
||||
title = GetText(strs.connect4_draw);
|
||||
|
||||
return msg.ModifyAsync(x => x.Embed = _sender.CreateEmbed()
|
||||
return msg.ModifyAsync(x => x.Embed = CreateEmbed()
|
||||
.WithTitle(title)
|
||||
.WithDescription(GetGameStateText(game))
|
||||
.WithOkColor()
|
||||
@@ -142,7 +142,7 @@ public partial class Gambling
|
||||
|
||||
private async Task Game_OnGameStateUpdated(Connect4Game game)
|
||||
{
|
||||
var embed = _sender.CreateEmbed()
|
||||
var embed = CreateEmbed()
|
||||
.WithTitle($"{game.CurrentPlayer.Username} vs {game.OtherPlayer.Username}")
|
||||
.WithDescription(GetGameStateText(game))
|
||||
.WithOkColor();
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user