mirror of
https://gitlab.com/Kwoth/nadekobot.git
synced 2025-09-10 17:28:27 -04:00
add: Added .notify and migrations, added levelup and protection events for notify, removed xpnotify completely
This commit is contained in:
@@ -357,3 +357,4 @@ resharper_arrange_redundant_parentheses_highlighting = hint
|
|||||||
# IDE0011: Add braces
|
# IDE0011: Add braces
|
||||||
dotnet_diagnostic.IDE0011.severity = warning
|
dotnet_diagnostic.IDE0011.severity = warning
|
||||||
|
|
||||||
|
resharper_arrange_type_member_modifiers_highlighting = hint
|
@@ -6,15 +6,17 @@ public class Notify
|
|||||||
{
|
{
|
||||||
[Key]
|
[Key]
|
||||||
public int Id { get; set; }
|
public int Id { get; set; }
|
||||||
|
|
||||||
public ulong GuildId { get; set; }
|
public ulong GuildId { get; set; }
|
||||||
public ulong ChannelId { get; set; }
|
public ulong ChannelId { get; set; }
|
||||||
public NotifyEvent Event { get; set; }
|
public NotifyType Type { get; set; }
|
||||||
|
|
||||||
[MaxLength(10_000)]
|
[MaxLength(10_000)]
|
||||||
public string Message { get; set; } = string.Empty;
|
public string Message { get; set; } = string.Empty;
|
||||||
}
|
}
|
||||||
|
|
||||||
public enum NotifyEvent
|
public enum NotifyType
|
||||||
{
|
{
|
||||||
UserLevelUp
|
LevelUp = 0,
|
||||||
|
Protection = 1, Prot = 1,
|
||||||
}
|
}
|
@@ -1,4 +1,4 @@
|
|||||||
namespace NadekoBot.Db.Models;
|
namespace NadekoBot.Db.Models;
|
||||||
|
|
||||||
public enum XpNotificationLocation
|
public enum XpNotificationLocation
|
||||||
{
|
{
|
||||||
|
@@ -81,7 +81,7 @@ public abstract class NadekoContext : DbContext
|
|||||||
e.HasAlternateKey(x => new
|
e.HasAlternateKey(x => new
|
||||||
{
|
{
|
||||||
x.GuildId,
|
x.GuildId,
|
||||||
x.Event
|
Event = x.Type
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@@ -12,8 +12,8 @@ using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata;
|
|||||||
namespace NadekoBot.Migrations.PostgreSql
|
namespace NadekoBot.Migrations.PostgreSql
|
||||||
{
|
{
|
||||||
[DbContext(typeof(PostgreSqlContext))]
|
[DbContext(typeof(PostgreSqlContext))]
|
||||||
[Migration("20241203093815_awarded-xp-and-notify-removed")]
|
[Migration("20241205052146_awardedxp-temprole-notify")]
|
||||||
partial class awardedxpandnotifyremoved
|
partial class awardedxptemprolenotify
|
||||||
{
|
{
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
protected override void BuildTargetModel(ModelBuilder modelBuilder)
|
protected override void BuildTargetModel(ModelBuilder modelBuilder)
|
||||||
@@ -1820,6 +1820,42 @@ namespace NadekoBot.Migrations.PostgreSql
|
|||||||
b.ToTable("expressions", (string)null);
|
b.ToTable("expressions", (string)null);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("NadekoBot.Db.Models.Notify", 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<decimal>("GuildId")
|
||||||
|
.HasColumnType("numeric(20,0)")
|
||||||
|
.HasColumnName("guildid");
|
||||||
|
|
||||||
|
b.Property<string>("Message")
|
||||||
|
.IsRequired()
|
||||||
|
.HasMaxLength(10000)
|
||||||
|
.HasColumnType("character varying(10000)")
|
||||||
|
.HasColumnName("message");
|
||||||
|
|
||||||
|
b.Property<int>("Type")
|
||||||
|
.HasColumnType("integer")
|
||||||
|
.HasColumnName("type");
|
||||||
|
|
||||||
|
b.HasKey("Id")
|
||||||
|
.HasName("pk_notify");
|
||||||
|
|
||||||
|
b.HasAlternateKey("GuildId", "Type")
|
||||||
|
.HasName("ak_notify_guildid_type");
|
||||||
|
|
||||||
|
b.ToTable("notify", (string)null);
|
||||||
|
});
|
||||||
|
|
||||||
modelBuilder.Entity("NadekoBot.Db.Models.PatronUser", b =>
|
modelBuilder.Entity("NadekoBot.Db.Models.PatronUser", b =>
|
||||||
{
|
{
|
||||||
b.Property<decimal>("UserId")
|
b.Property<decimal>("UserId")
|
||||||
@@ -2910,10 +2946,6 @@ namespace NadekoBot.Migrations.PostgreSql
|
|||||||
.HasColumnType("numeric(20,0)")
|
.HasColumnType("numeric(20,0)")
|
||||||
.HasColumnName("guildid");
|
.HasColumnName("guildid");
|
||||||
|
|
||||||
b.Property<int>("NotifyOnLevelUp")
|
|
||||||
.HasColumnType("integer")
|
|
||||||
.HasColumnName("notifyonlevelup");
|
|
||||||
|
|
||||||
b.Property<decimal>("UserId")
|
b.Property<decimal>("UserId")
|
||||||
.HasColumnType("numeric(20,0)")
|
.HasColumnType("numeric(20,0)")
|
||||||
.HasColumnName("userid");
|
.HasColumnName("userid");
|
@@ -7,7 +7,7 @@ using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata;
|
|||||||
namespace NadekoBot.Migrations.PostgreSql
|
namespace NadekoBot.Migrations.PostgreSql
|
||||||
{
|
{
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public partial class awardedxpandnotifyremoved : Migration
|
public partial class awardedxptemprolenotify : Migration
|
||||||
{
|
{
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
protected override void Up(MigrationBuilder migrationBuilder)
|
protected override void Up(MigrationBuilder migrationBuilder)
|
||||||
@@ -20,6 +20,27 @@ namespace NadekoBot.Migrations.PostgreSql
|
|||||||
name: "awardedxp",
|
name: "awardedxp",
|
||||||
table: "userxpstats");
|
table: "userxpstats");
|
||||||
|
|
||||||
|
migrationBuilder.DropColumn(
|
||||||
|
name: "notifyonlevelup",
|
||||||
|
table: "userxpstats");
|
||||||
|
|
||||||
|
migrationBuilder.CreateTable(
|
||||||
|
name: "notify",
|
||||||
|
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),
|
||||||
|
type = table.Column<int>(type: "integer", nullable: false),
|
||||||
|
message = table.Column<string>(type: "character varying(10000)", maxLength: 10000, nullable: false)
|
||||||
|
},
|
||||||
|
constraints: table =>
|
||||||
|
{
|
||||||
|
table.PrimaryKey("pk_notify", x => x.id);
|
||||||
|
table.UniqueConstraint("ak_notify_guildid_type", x => new { x.guildid, x.type });
|
||||||
|
});
|
||||||
|
|
||||||
migrationBuilder.CreateTable(
|
migrationBuilder.CreateTable(
|
||||||
name: "temprole",
|
name: "temprole",
|
||||||
columns: table => new
|
columns: table => new
|
||||||
@@ -47,6 +68,9 @@ namespace NadekoBot.Migrations.PostgreSql
|
|||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
protected override void Down(MigrationBuilder migrationBuilder)
|
protected override void Down(MigrationBuilder migrationBuilder)
|
||||||
{
|
{
|
||||||
|
migrationBuilder.DropTable(
|
||||||
|
name: "notify");
|
||||||
|
|
||||||
migrationBuilder.DropTable(
|
migrationBuilder.DropTable(
|
||||||
name: "temprole");
|
name: "temprole");
|
||||||
|
|
||||||
@@ -57,6 +81,13 @@ namespace NadekoBot.Migrations.PostgreSql
|
|||||||
nullable: false,
|
nullable: false,
|
||||||
defaultValue: 0L);
|
defaultValue: 0L);
|
||||||
|
|
||||||
|
migrationBuilder.AddColumn<int>(
|
||||||
|
name: "notifyonlevelup",
|
||||||
|
table: "userxpstats",
|
||||||
|
type: "integer",
|
||||||
|
nullable: false,
|
||||||
|
defaultValue: 0);
|
||||||
|
|
||||||
migrationBuilder.CreateIndex(
|
migrationBuilder.CreateIndex(
|
||||||
name: "ix_userxpstats_awardedxp",
|
name: "ix_userxpstats_awardedxp",
|
||||||
table: "userxpstats",
|
table: "userxpstats",
|
@@ -1817,6 +1817,42 @@ namespace NadekoBot.Migrations.PostgreSql
|
|||||||
b.ToTable("expressions", (string)null);
|
b.ToTable("expressions", (string)null);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("NadekoBot.Db.Models.Notify", 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<decimal>("GuildId")
|
||||||
|
.HasColumnType("numeric(20,0)")
|
||||||
|
.HasColumnName("guildid");
|
||||||
|
|
||||||
|
b.Property<string>("Message")
|
||||||
|
.IsRequired()
|
||||||
|
.HasMaxLength(10000)
|
||||||
|
.HasColumnType("character varying(10000)")
|
||||||
|
.HasColumnName("message");
|
||||||
|
|
||||||
|
b.Property<int>("Type")
|
||||||
|
.HasColumnType("integer")
|
||||||
|
.HasColumnName("type");
|
||||||
|
|
||||||
|
b.HasKey("Id")
|
||||||
|
.HasName("pk_notify");
|
||||||
|
|
||||||
|
b.HasAlternateKey("GuildId", "Type")
|
||||||
|
.HasName("ak_notify_guildid_type");
|
||||||
|
|
||||||
|
b.ToTable("notify", (string)null);
|
||||||
|
});
|
||||||
|
|
||||||
modelBuilder.Entity("NadekoBot.Db.Models.PatronUser", b =>
|
modelBuilder.Entity("NadekoBot.Db.Models.PatronUser", b =>
|
||||||
{
|
{
|
||||||
b.Property<decimal>("UserId")
|
b.Property<decimal>("UserId")
|
||||||
@@ -2907,10 +2943,6 @@ namespace NadekoBot.Migrations.PostgreSql
|
|||||||
.HasColumnType("numeric(20,0)")
|
.HasColumnType("numeric(20,0)")
|
||||||
.HasColumnName("guildid");
|
.HasColumnName("guildid");
|
||||||
|
|
||||||
b.Property<int>("NotifyOnLevelUp")
|
|
||||||
.HasColumnType("integer")
|
|
||||||
.HasColumnName("notifyonlevelup");
|
|
||||||
|
|
||||||
b.Property<decimal>("UserId")
|
b.Property<decimal>("UserId")
|
||||||
.HasColumnType("numeric(20,0)")
|
.HasColumnType("numeric(20,0)")
|
||||||
.HasColumnName("userid");
|
.HasColumnName("userid");
|
||||||
|
@@ -11,8 +11,8 @@ using NadekoBot.Db;
|
|||||||
namespace NadekoBot.Migrations
|
namespace NadekoBot.Migrations
|
||||||
{
|
{
|
||||||
[DbContext(typeof(SqliteContext))]
|
[DbContext(typeof(SqliteContext))]
|
||||||
[Migration("20241203093804_awarded-xp-and-notify-removed")]
|
[Migration("20241205052137_awardedxp-temprole-notify")]
|
||||||
partial class awardedxpandnotifyremoved
|
partial class awardedxptemprolenotify
|
||||||
{
|
{
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
protected override void BuildTargetModel(ModelBuilder modelBuilder)
|
protected override void BuildTargetModel(ModelBuilder modelBuilder)
|
||||||
@@ -1359,6 +1359,33 @@ namespace NadekoBot.Migrations
|
|||||||
b.ToTable("Expressions");
|
b.ToTable("Expressions");
|
||||||
});
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("NadekoBot.Db.Models.Notify", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<ulong>("ChannelId")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<ulong>("GuildId")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<string>("Message")
|
||||||
|
.IsRequired()
|
||||||
|
.HasMaxLength(10000)
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<int>("Type")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.HasAlternateKey("GuildId", "Type");
|
||||||
|
|
||||||
|
b.ToTable("Notify");
|
||||||
|
});
|
||||||
|
|
||||||
modelBuilder.Entity("NadekoBot.Db.Models.PatronUser", b =>
|
modelBuilder.Entity("NadekoBot.Db.Models.PatronUser", b =>
|
||||||
{
|
{
|
||||||
b.Property<ulong>("UserId")
|
b.Property<ulong>("UserId")
|
||||||
@@ -2166,9 +2193,6 @@ namespace NadekoBot.Migrations
|
|||||||
b.Property<ulong>("GuildId")
|
b.Property<ulong>("GuildId")
|
||||||
.HasColumnType("INTEGER");
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
b.Property<int>("NotifyOnLevelUp")
|
|
||||||
.HasColumnType("INTEGER");
|
|
||||||
|
|
||||||
b.Property<ulong>("UserId")
|
b.Property<ulong>("UserId")
|
||||||
.HasColumnType("INTEGER");
|
.HasColumnType("INTEGER");
|
||||||
|
|
@@ -6,7 +6,7 @@ using Microsoft.EntityFrameworkCore.Migrations;
|
|||||||
namespace NadekoBot.Migrations
|
namespace NadekoBot.Migrations
|
||||||
{
|
{
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public partial class awardedxpandnotifyremoved : Migration
|
public partial class awardedxptemprolenotify : Migration
|
||||||
{
|
{
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
protected override void Up(MigrationBuilder migrationBuilder)
|
protected override void Up(MigrationBuilder migrationBuilder)
|
||||||
@@ -19,6 +19,27 @@ namespace NadekoBot.Migrations
|
|||||||
name: "AwardedXp",
|
name: "AwardedXp",
|
||||||
table: "UserXpStats");
|
table: "UserXpStats");
|
||||||
|
|
||||||
|
migrationBuilder.DropColumn(
|
||||||
|
name: "NotifyOnLevelUp",
|
||||||
|
table: "UserXpStats");
|
||||||
|
|
||||||
|
migrationBuilder.CreateTable(
|
||||||
|
name: "Notify",
|
||||||
|
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),
|
||||||
|
Type = table.Column<int>(type: "INTEGER", nullable: false),
|
||||||
|
Message = table.Column<string>(type: "TEXT", maxLength: 10000, nullable: false)
|
||||||
|
},
|
||||||
|
constraints: table =>
|
||||||
|
{
|
||||||
|
table.PrimaryKey("PK_Notify", x => x.Id);
|
||||||
|
table.UniqueConstraint("AK_Notify_GuildId_Type", x => new { x.GuildId, x.Type });
|
||||||
|
});
|
||||||
|
|
||||||
migrationBuilder.CreateTable(
|
migrationBuilder.CreateTable(
|
||||||
name: "TempRole",
|
name: "TempRole",
|
||||||
columns: table => new
|
columns: table => new
|
||||||
@@ -46,6 +67,9 @@ namespace NadekoBot.Migrations
|
|||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
protected override void Down(MigrationBuilder migrationBuilder)
|
protected override void Down(MigrationBuilder migrationBuilder)
|
||||||
{
|
{
|
||||||
|
migrationBuilder.DropTable(
|
||||||
|
name: "Notify");
|
||||||
|
|
||||||
migrationBuilder.DropTable(
|
migrationBuilder.DropTable(
|
||||||
name: "TempRole");
|
name: "TempRole");
|
||||||
|
|
||||||
@@ -56,6 +80,13 @@ namespace NadekoBot.Migrations
|
|||||||
nullable: false,
|
nullable: false,
|
||||||
defaultValue: 0L);
|
defaultValue: 0L);
|
||||||
|
|
||||||
|
migrationBuilder.AddColumn<int>(
|
||||||
|
name: "NotifyOnLevelUp",
|
||||||
|
table: "UserXpStats",
|
||||||
|
type: "INTEGER",
|
||||||
|
nullable: false,
|
||||||
|
defaultValue: 0);
|
||||||
|
|
||||||
migrationBuilder.CreateIndex(
|
migrationBuilder.CreateIndex(
|
||||||
name: "IX_UserXpStats_AwardedXp",
|
name: "IX_UserXpStats_AwardedXp",
|
||||||
table: "UserXpStats",
|
table: "UserXpStats",
|
@@ -1356,6 +1356,33 @@ namespace NadekoBot.Migrations
|
|||||||
b.ToTable("Expressions");
|
b.ToTable("Expressions");
|
||||||
});
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("NadekoBot.Db.Models.Notify", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<ulong>("ChannelId")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<ulong>("GuildId")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<string>("Message")
|
||||||
|
.IsRequired()
|
||||||
|
.HasMaxLength(10000)
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<int>("Type")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.HasAlternateKey("GuildId", "Type");
|
||||||
|
|
||||||
|
b.ToTable("Notify");
|
||||||
|
});
|
||||||
|
|
||||||
modelBuilder.Entity("NadekoBot.Db.Models.PatronUser", b =>
|
modelBuilder.Entity("NadekoBot.Db.Models.PatronUser", b =>
|
||||||
{
|
{
|
||||||
b.Property<ulong>("UserId")
|
b.Property<ulong>("UserId")
|
||||||
@@ -2163,9 +2190,6 @@ namespace NadekoBot.Migrations
|
|||||||
b.Property<ulong>("GuildId")
|
b.Property<ulong>("GuildId")
|
||||||
.HasColumnType("INTEGER");
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
b.Property<int>("NotifyOnLevelUp")
|
|
||||||
.HasColumnType("INTEGER");
|
|
||||||
|
|
||||||
b.Property<ulong>("UserId")
|
b.Property<ulong>("UserId")
|
||||||
.HasColumnType("INTEGER");
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
23
src/NadekoBot/Modules/Administration/Notify/INotifyModel.cs
Normal file
23
src/NadekoBot/Modules/Administration/Notify/INotifyModel.cs
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
using NadekoBot.Db.Models;
|
||||||
|
using System.Collections;
|
||||||
|
|
||||||
|
namespace NadekoBot.Modules.Administration;
|
||||||
|
|
||||||
|
public interface INotifyModel
|
||||||
|
{
|
||||||
|
static abstract string KeyName { get; }
|
||||||
|
static abstract NotifyType NotifyType { get; }
|
||||||
|
IReadOnlyDictionary<string, Func<SocketGuild, string>> GetReplacements();
|
||||||
|
|
||||||
|
public virtual bool TryGetGuildId(out ulong guildId)
|
||||||
|
{
|
||||||
|
guildId = 0;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public virtual bool TryGetUserId(out ulong userId)
|
||||||
|
{
|
||||||
|
userId = 0;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
@@ -0,0 +1,7 @@
|
|||||||
|
namespace NadekoBot.Modules.Administration;
|
||||||
|
|
||||||
|
public interface INotifySubscriber
|
||||||
|
{
|
||||||
|
Task NotifyAsync<T>(T data, bool isShardLocal = false)
|
||||||
|
where T : struct, INotifyModel;
|
||||||
|
}
|
@@ -0,0 +1,44 @@
|
|||||||
|
using NadekoBot.Db.Models;
|
||||||
|
|
||||||
|
namespace NadekoBot.Modules.Administration;
|
||||||
|
|
||||||
|
public record struct LevelUpNotifyModel(
|
||||||
|
ulong GuildId,
|
||||||
|
ulong ChannelId,
|
||||||
|
ulong UserId,
|
||||||
|
long Level) : INotifyModel
|
||||||
|
{
|
||||||
|
public static string KeyName
|
||||||
|
=> "notify.levelup";
|
||||||
|
|
||||||
|
public static NotifyType NotifyType
|
||||||
|
=> NotifyType.LevelUp;
|
||||||
|
|
||||||
|
public IReadOnlyDictionary<string, Func<SocketGuild, string>> GetReplacements()
|
||||||
|
{
|
||||||
|
var data = this;
|
||||||
|
return new Dictionary<string, Func<SocketGuild, string>>()
|
||||||
|
{
|
||||||
|
{ "%event.level%", g => data.Level.ToString() },
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool TryGetGuildId(out ulong guildId)
|
||||||
|
{
|
||||||
|
guildId = GuildId;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool TryGetUserId(out ulong userId)
|
||||||
|
{
|
||||||
|
userId = UserId;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class INotifyModelExtensions
|
||||||
|
{
|
||||||
|
public static TypedKey<T> GetTypedKey<T>(this T model)
|
||||||
|
where T : struct, INotifyModel
|
||||||
|
=> new(T.KeyName);
|
||||||
|
}
|
@@ -1,92 +1,24 @@
|
|||||||
using LinqToDB;
|
using NadekoBot.Db.Models;
|
||||||
using LinqToDB.EntityFrameworkCore;
|
|
||||||
using NadekoBot.Common.ModuleBehaviors;
|
|
||||||
using NadekoBot.Db.Models;
|
|
||||||
|
|
||||||
namespace NadekoBot.Modules.Administration;
|
namespace NadekoBot.Modules.Administration;
|
||||||
|
|
||||||
public sealed class NotifyService : IReadyExecutor, INService
|
|
||||||
{
|
|
||||||
private readonly DbService _db;
|
|
||||||
private readonly IMessageSenderService _mss;
|
|
||||||
private readonly DiscordSocketClient _client;
|
|
||||||
private readonly IBotCreds _creds;
|
|
||||||
|
|
||||||
public NotifyService(
|
|
||||||
DbService db,
|
|
||||||
IMessageSenderService mss,
|
|
||||||
DiscordSocketClient client,
|
|
||||||
IBotCreds creds)
|
|
||||||
{
|
|
||||||
_db = db;
|
|
||||||
_mss = mss;
|
|
||||||
_client = client;
|
|
||||||
_creds = creds;
|
|
||||||
}
|
|
||||||
|
|
||||||
public async Task OnReadyAsync()
|
|
||||||
{
|
|
||||||
// .Where(x => Linq2DbExpressions.GuildOnShard(guildId,
|
|
||||||
// _creds.TotalShards,
|
|
||||||
// _client.ShardId))
|
|
||||||
}
|
|
||||||
|
|
||||||
public async Task EnableAsync(
|
|
||||||
ulong guildId,
|
|
||||||
ulong channelId,
|
|
||||||
NotifyEvent nEvent,
|
|
||||||
string message)
|
|
||||||
{
|
|
||||||
await using var uow = _db.GetDbContext();
|
|
||||||
await uow.GetTable<Notify>()
|
|
||||||
.InsertOrUpdateAsync(() => new()
|
|
||||||
{
|
|
||||||
GuildId = guildId,
|
|
||||||
ChannelId = channelId,
|
|
||||||
Event = nEvent,
|
|
||||||
Message = message,
|
|
||||||
},
|
|
||||||
(_) => new()
|
|
||||||
{
|
|
||||||
Message = message,
|
|
||||||
ChannelId = channelId
|
|
||||||
},
|
|
||||||
() => new()
|
|
||||||
{
|
|
||||||
GuildId = guildId,
|
|
||||||
Event = nEvent
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
public async Task DisableAsync(ulong guildId, NotifyEvent nEvent)
|
|
||||||
{
|
|
||||||
await using var uow = _db.GetDbContext();
|
|
||||||
var deleted = await uow.GetTable<Notify>()
|
|
||||||
.Where(x => x.GuildId == guildId && x.Event == nEvent)
|
|
||||||
.DeleteAsync();
|
|
||||||
|
|
||||||
if (deleted > 0)
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public partial class Administration
|
public partial class Administration
|
||||||
{
|
{
|
||||||
public class NotifyCommands : NadekoModule<NotifyService>
|
public class NotifyCommands : NadekoModule<NotifyService>
|
||||||
{
|
{
|
||||||
[Cmd]
|
[Cmd]
|
||||||
[OwnerOnly]
|
[OwnerOnly]
|
||||||
public async Task Notify(NotifyEvent nEvent, [Leftover] string message = null)
|
public async Task Notify(NotifyType nType, [Leftover] string? message = null)
|
||||||
{
|
{
|
||||||
if (string.IsNullOrWhiteSpace(message))
|
if (string.IsNullOrWhiteSpace(message))
|
||||||
{
|
{
|
||||||
await _service.DisableAsync(ctx.Guild.Id, nEvent);
|
await _service.DisableAsync(ctx.Guild.Id, nType);
|
||||||
await Response().Confirm(strs.notify_off(nEvent)).SendAsync();
|
await Response().Confirm(strs.notify_off(nType)).SendAsync();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
await _service.EnableAsync(ctx.Guild.Id, ctx.Channel.Id, nEvent, message);
|
await _service.EnableAsync(ctx.Guild.Id, ctx.Channel.Id, nType, message);
|
||||||
await Response().Confirm(strs.notify_on(nEvent.ToString())).SendAsync();
|
await Response().Confirm(strs.notify_on(nType.ToString())).SendAsync();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
@@ -0,0 +1,6 @@
|
|||||||
|
namespace NadekoBot.Modules.Administration;
|
||||||
|
|
||||||
|
public static class NotifyKeys
|
||||||
|
{
|
||||||
|
public static TypedKey<LevelUpNotifyModel> LevelUp { get; } = new("notify:levelup");
|
||||||
|
}
|
202
src/NadekoBot/Modules/Administration/Notify/NotifyService.cs
Normal file
202
src/NadekoBot/Modules/Administration/Notify/NotifyService.cs
Normal file
@@ -0,0 +1,202 @@
|
|||||||
|
using LinqToDB;
|
||||||
|
using LinqToDB.EntityFrameworkCore;
|
||||||
|
using NadekoBot.Common.ModuleBehaviors;
|
||||||
|
using NadekoBot.Db.Models;
|
||||||
|
|
||||||
|
namespace NadekoBot.Modules.Administration;
|
||||||
|
|
||||||
|
public sealed class NotifyService : IReadyExecutor, INotifySubscriber, INService
|
||||||
|
{
|
||||||
|
private readonly DbService _db;
|
||||||
|
private readonly IMessageSenderService _mss;
|
||||||
|
private readonly DiscordSocketClient _client;
|
||||||
|
private readonly IBotCreds _creds;
|
||||||
|
private readonly IReplacementService _repSvc;
|
||||||
|
private readonly IPubSub _pubSub;
|
||||||
|
private ConcurrentDictionary<NotifyType, ConcurrentDictionary<ulong, Notify>> _events = new();
|
||||||
|
|
||||||
|
public NotifyService(
|
||||||
|
DbService db,
|
||||||
|
IMessageSenderService mss,
|
||||||
|
DiscordSocketClient client,
|
||||||
|
IBotCreds creds,
|
||||||
|
IReplacementService repSvc,
|
||||||
|
IPubSub pubSub)
|
||||||
|
{
|
||||||
|
_db = db;
|
||||||
|
_mss = mss;
|
||||||
|
_client = client;
|
||||||
|
_creds = creds;
|
||||||
|
_repSvc = repSvc;
|
||||||
|
_pubSub = pubSub;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task OnReadyAsync()
|
||||||
|
{
|
||||||
|
await using var uow = _db.GetDbContext();
|
||||||
|
_events = (await uow.GetTable<Notify>()
|
||||||
|
.Where(x => Linq2DbExpressions.GuildOnShard(x.GuildId,
|
||||||
|
_creds.TotalShards,
|
||||||
|
_client.ShardId))
|
||||||
|
.ToListAsyncLinqToDB())
|
||||||
|
.GroupBy(x => x.Type)
|
||||||
|
.ToDictionary(x => x.Key, x => x.ToDictionary(x => x.GuildId).ToConcurrent())
|
||||||
|
.ToConcurrent();
|
||||||
|
|
||||||
|
|
||||||
|
await SubscribeToEvent<LevelUpNotifyModel>();
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task SubscribeToEvent<T>()
|
||||||
|
where T : struct, INotifyModel
|
||||||
|
{
|
||||||
|
await _pubSub.Sub(new TypedKey<T>(T.KeyName), async (model) => await OnEvent(model));
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task NotifyAsync<T>(T data, bool isShardLocal = false)
|
||||||
|
where T : struct, INotifyModel
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
if (isShardLocal)
|
||||||
|
{
|
||||||
|
await OnEvent(data);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
await _pubSub.Pub(data.GetTypedKey(), data);
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
Log.Warning(ex,
|
||||||
|
"Unknown error occurred while trying to triger {NotifyEvent} for {NotifyModel}",
|
||||||
|
T.KeyName,
|
||||||
|
data);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task OnEvent<T>(T model)
|
||||||
|
where T : struct, INotifyModel
|
||||||
|
{
|
||||||
|
if (_events.TryGetValue(T.NotifyType, out var subs))
|
||||||
|
{
|
||||||
|
if (model.TryGetGuildId(out var gid))
|
||||||
|
{
|
||||||
|
if (!subs.TryGetValue(gid, out var conf))
|
||||||
|
return;
|
||||||
|
|
||||||
|
await HandleNotifyEvent(conf, model);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach (var key in subs.Keys.ToArray())
|
||||||
|
{
|
||||||
|
if (subs.TryGetValue(key, out var notif))
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
await HandleNotifyEvent(notif, model);
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
Log.Error(ex,
|
||||||
|
"Error occured while sending notification {NotifyEvent} to guild {GuildId}: {ErrorMessage}",
|
||||||
|
T.NotifyType,
|
||||||
|
key,
|
||||||
|
ex.Message);
|
||||||
|
}
|
||||||
|
|
||||||
|
await Task.Delay(500);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task HandleNotifyEvent(Notify conf, INotifyModel model)
|
||||||
|
{
|
||||||
|
var guild = _client.GetGuild(conf.GuildId);
|
||||||
|
var channel = guild?.GetTextChannel(conf.ChannelId);
|
||||||
|
|
||||||
|
if (guild is null || channel is null)
|
||||||
|
return;
|
||||||
|
|
||||||
|
IUser? user = null;
|
||||||
|
if (model.TryGetUserId(out var userId))
|
||||||
|
{
|
||||||
|
user = guild.GetUser(userId) ?? _client.GetUser(userId);
|
||||||
|
}
|
||||||
|
|
||||||
|
var rctx = new ReplacementContext(guild: guild, channel: channel, user: user);
|
||||||
|
|
||||||
|
var st = SmartText.CreateFrom(conf.Message);
|
||||||
|
foreach (var modelRep in model.GetReplacements())
|
||||||
|
{
|
||||||
|
rctx.WithOverride(modelRep.Key, () => modelRep.Value(guild));
|
||||||
|
}
|
||||||
|
|
||||||
|
st = await _repSvc.ReplaceAsync(st, rctx);
|
||||||
|
if (st is SmartPlainText spt)
|
||||||
|
{
|
||||||
|
await _mss.Response(channel)
|
||||||
|
.Confirm(spt.Text)
|
||||||
|
.SendAsync();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
await _mss.Response(channel)
|
||||||
|
.Text(st)
|
||||||
|
.SendAsync();
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task EnableAsync(
|
||||||
|
ulong guildId,
|
||||||
|
ulong channelId,
|
||||||
|
NotifyType nType,
|
||||||
|
string message)
|
||||||
|
{
|
||||||
|
await using var uow = _db.GetDbContext();
|
||||||
|
await uow.GetTable<Notify>()
|
||||||
|
.InsertOrUpdateAsync(() => new()
|
||||||
|
{
|
||||||
|
GuildId = guildId,
|
||||||
|
ChannelId = channelId,
|
||||||
|
Type = nType,
|
||||||
|
Message = message,
|
||||||
|
},
|
||||||
|
(_) => new()
|
||||||
|
{
|
||||||
|
Message = message,
|
||||||
|
ChannelId = channelId
|
||||||
|
},
|
||||||
|
() => new()
|
||||||
|
{
|
||||||
|
GuildId = guildId,
|
||||||
|
Type = nType
|
||||||
|
});
|
||||||
|
|
||||||
|
var eventDict = _events.GetOrAdd(nType, _ => new());
|
||||||
|
eventDict[guildId] = new()
|
||||||
|
{
|
||||||
|
GuildId = guildId,
|
||||||
|
ChannelId = channelId,
|
||||||
|
Type = nType,
|
||||||
|
Message = message
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task DisableAsync(ulong guildId, NotifyType nType)
|
||||||
|
{
|
||||||
|
await using var uow = _db.GetDbContext();
|
||||||
|
var deleted = await uow.GetTable<Notify>()
|
||||||
|
.Where(x => x.GuildId == guildId && x.Type == nType)
|
||||||
|
.DeleteAsync();
|
||||||
|
|
||||||
|
if (deleted == 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (!_events.TryGetValue(nType, out var guildsDict))
|
||||||
|
return;
|
||||||
|
|
||||||
|
guildsDict.TryRemove(guildId, out _);
|
||||||
|
}
|
||||||
|
}
|
@@ -5,6 +5,36 @@ using System.Threading.Channels;
|
|||||||
|
|
||||||
namespace NadekoBot.Modules.Administration.Services;
|
namespace NadekoBot.Modules.Administration.Services;
|
||||||
|
|
||||||
|
public record struct ProtectionNotifyModel(ulong GuildId, ProtectionType ProtType, ulong UserId) : INotifyModel
|
||||||
|
{
|
||||||
|
public static string KeyName
|
||||||
|
=> "notify.protection";
|
||||||
|
|
||||||
|
public static NotifyType NotifyType
|
||||||
|
=> NotifyType.Protection;
|
||||||
|
|
||||||
|
public IReadOnlyDictionary<string, Func<SocketGuild, string>> GetReplacements()
|
||||||
|
{
|
||||||
|
var data = this;
|
||||||
|
return new Dictionary<string, Func<SocketGuild, string>>()
|
||||||
|
{
|
||||||
|
{ "%event.type%", g => data.ProtType.ToString() },
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool TryGetUserId(out ulong userId)
|
||||||
|
{
|
||||||
|
userId = UserId;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool TryGetGuildId(out ulong guildId)
|
||||||
|
{
|
||||||
|
guildId = GuildId;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public class ProtectionService : INService
|
public class ProtectionService : INService
|
||||||
{
|
{
|
||||||
public event Func<PunishmentAction, ProtectionType, IGuildUser[], Task> OnAntiProtectionTriggered = delegate
|
public event Func<PunishmentAction, ProtectionType, IGuildUser[], Task> OnAntiProtectionTriggered = delegate
|
||||||
@@ -22,6 +52,7 @@ public class ProtectionService : INService
|
|||||||
private readonly MuteService _mute;
|
private readonly MuteService _mute;
|
||||||
private readonly DbService _db;
|
private readonly DbService _db;
|
||||||
private readonly UserPunishService _punishService;
|
private readonly UserPunishService _punishService;
|
||||||
|
private readonly INotifySubscriber _notifySub;
|
||||||
|
|
||||||
private readonly Channel<PunishQueueItem> _punishUserQueue =
|
private readonly Channel<PunishQueueItem> _punishUserQueue =
|
||||||
Channel.CreateUnbounded<PunishQueueItem>(new()
|
Channel.CreateUnbounded<PunishQueueItem>(new()
|
||||||
@@ -35,12 +66,14 @@ public class ProtectionService : INService
|
|||||||
IBot bot,
|
IBot bot,
|
||||||
MuteService mute,
|
MuteService mute,
|
||||||
DbService db,
|
DbService db,
|
||||||
UserPunishService punishService)
|
UserPunishService punishService,
|
||||||
|
INotifySubscriber notifySub)
|
||||||
{
|
{
|
||||||
_client = client;
|
_client = client;
|
||||||
_mute = mute;
|
_mute = mute;
|
||||||
_db = db;
|
_db = db;
|
||||||
_punishService = punishService;
|
_punishService = punishService;
|
||||||
|
_notifySub = notifySub;
|
||||||
|
|
||||||
var ids = client.GetGuildIds();
|
var ids = client.GetGuildIds();
|
||||||
using (var uow = db.GetDbContext())
|
using (var uow = db.GetDbContext())
|
||||||
@@ -175,6 +208,9 @@ public class ProtectionService : INService
|
|||||||
alts.RoleId,
|
alts.RoleId,
|
||||||
user);
|
user);
|
||||||
|
|
||||||
|
await _notifySub.NotifyAsync(new ProtectionNotifyModel(user.Guild.Id,
|
||||||
|
ProtectionType.Alting,
|
||||||
|
user.Id));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -194,6 +230,8 @@ public class ProtectionService : INService
|
|||||||
var settings = stats.AntiRaidSettings;
|
var settings = stats.AntiRaidSettings;
|
||||||
|
|
||||||
await PunishUsers(settings.Action, ProtectionType.Raiding, settings.PunishDuration, null, users);
|
await PunishUsers(settings.Action, ProtectionType.Raiding, settings.PunishDuration, null, users);
|
||||||
|
await _notifySub.NotifyAsync(
|
||||||
|
new ProtectionNotifyModel(user.Guild.Id, ProtectionType.Raiding, users[0].Id));
|
||||||
}
|
}
|
||||||
|
|
||||||
await Task.Delay(1000 * stats.AntiRaidSettings.Seconds);
|
await Task.Delay(1000 * stats.AntiRaidSettings.Seconds);
|
||||||
@@ -246,6 +284,10 @@ public class ProtectionService : INService
|
|||||||
settings.MuteTime,
|
settings.MuteTime,
|
||||||
settings.RoleId,
|
settings.RoleId,
|
||||||
(IGuildUser)msg.Author);
|
(IGuildUser)msg.Author);
|
||||||
|
|
||||||
|
await _notifySub.NotifyAsync(new ProtectionNotifyModel(channel.GuildId,
|
||||||
|
ProtectionType.Spamming,
|
||||||
|
msg.Author.Id));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
11
src/NadekoBot/Modules/Xp/BuyResult.cs
Normal file
11
src/NadekoBot/Modules/Xp/BuyResult.cs
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
namespace NadekoBot.Modules.Xp.Services;
|
||||||
|
|
||||||
|
public enum BuyResult
|
||||||
|
{
|
||||||
|
Success,
|
||||||
|
XpShopDisabled,
|
||||||
|
AlreadyOwned,
|
||||||
|
InsufficientFunds,
|
||||||
|
UnknownItem,
|
||||||
|
InsufficientPatronTier,
|
||||||
|
}
|
@@ -51,26 +51,6 @@ public partial class Xp : NadekoModule<XpService>
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
[Cmd]
|
|
||||||
[RequireContext(ContextType.Guild)]
|
|
||||||
public async Task XpNotify()
|
|
||||||
{
|
|
||||||
var globalSetting = _service.GetNotificationType(ctx.User);
|
|
||||||
|
|
||||||
var embed = CreateEmbed()
|
|
||||||
.WithOkColor()
|
|
||||||
.AddField(GetText(strs.xpn_setting_global), GetNotifLocationString(globalSetting));
|
|
||||||
|
|
||||||
await Response().Embed(embed).SendAsync();
|
|
||||||
}
|
|
||||||
|
|
||||||
[Cmd]
|
|
||||||
public async Task XpNotify(XpNotificationLocation type)
|
|
||||||
{
|
|
||||||
await _service.ChangeNotificationType(ctx.User, type);
|
|
||||||
await ctx.OkAsync();
|
|
||||||
}
|
|
||||||
|
|
||||||
[Cmd]
|
[Cmd]
|
||||||
[RequireContext(ContextType.Guild)]
|
[RequireContext(ContextType.Guild)]
|
||||||
[UserPerm(GuildPerm.Administrator)]
|
[UserPerm(GuildPerm.Administrator)]
|
||||||
@@ -615,15 +595,4 @@ public partial class Xp : NadekoModule<XpService>
|
|||||||
await _service.UseShopItemAsync(ctx.User.Id, type, key);
|
await _service.UseShopItemAsync(ctx.User.Id, type, key);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private string GetNotifLocationString(XpNotificationLocation loc)
|
|
||||||
{
|
|
||||||
if (loc == XpNotificationLocation.Channel)
|
|
||||||
return GetText(strs.xpn_notif_channel);
|
|
||||||
|
|
||||||
if (loc == XpNotificationLocation.Dm)
|
|
||||||
return GetText(strs.xpn_notif_dm);
|
|
||||||
|
|
||||||
return GetText(strs.xpn_notif_disabled);
|
|
||||||
}
|
|
||||||
}
|
}
|
@@ -13,6 +13,7 @@ using SixLabors.ImageSharp.Processing;
|
|||||||
using System.Threading.Channels;
|
using System.Threading.Channels;
|
||||||
using LinqToDB.EntityFrameworkCore;
|
using LinqToDB.EntityFrameworkCore;
|
||||||
using LinqToDB.Tools;
|
using LinqToDB.Tools;
|
||||||
|
using NadekoBot.Modules.Administration;
|
||||||
using NadekoBot.Modules.Patronage;
|
using NadekoBot.Modules.Patronage;
|
||||||
using Color = SixLabors.ImageSharp.Color;
|
using Color = SixLabors.ImageSharp.Color;
|
||||||
using Exception = System.Exception;
|
using Exception = System.Exception;
|
||||||
@@ -20,31 +21,6 @@ using Image = SixLabors.ImageSharp.Image;
|
|||||||
|
|
||||||
namespace NadekoBot.Modules.Xp.Services;
|
namespace NadekoBot.Modules.Xp.Services;
|
||||||
|
|
||||||
public interface IUserService
|
|
||||||
{
|
|
||||||
Task<DiscordUser?> GetUserAsync(ulong userId);
|
|
||||||
}
|
|
||||||
|
|
||||||
public sealed class UserService : IUserService, INService
|
|
||||||
{
|
|
||||||
private readonly DbService _db;
|
|
||||||
|
|
||||||
public UserService(DbService db)
|
|
||||||
{
|
|
||||||
_db = db;
|
|
||||||
}
|
|
||||||
|
|
||||||
public async Task<DiscordUser> GetUserAsync(ulong userId)
|
|
||||||
{
|
|
||||||
await using var uow = _db.GetDbContext();
|
|
||||||
var user = await uow
|
|
||||||
.GetTable<DiscordUser>()
|
|
||||||
.FirstOrDefaultAsyncLinqToDB(u => u.UserId == userId);
|
|
||||||
|
|
||||||
return user;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public class XpService : INService, IReadyExecutor, IExecNoCommand
|
public class XpService : INService, IReadyExecutor, IExecNoCommand
|
||||||
{
|
{
|
||||||
private readonly DbService _db;
|
private readonly DbService _db;
|
||||||
@@ -72,6 +48,7 @@ public class XpService : INService, IReadyExecutor, IExecNoCommand
|
|||||||
private readonly QueueRunner _levelUpQueue = new QueueRunner(0, 50);
|
private readonly QueueRunner _levelUpQueue = new QueueRunner(0, 50);
|
||||||
private readonly Channel<UserXpGainData> _xpGainQueue = Channel.CreateUnbounded<UserXpGainData>();
|
private readonly Channel<UserXpGainData> _xpGainQueue = Channel.CreateUnbounded<UserXpGainData>();
|
||||||
private readonly IMessageSenderService _sender;
|
private readonly IMessageSenderService _sender;
|
||||||
|
private readonly INotifySubscriber _notifySub;
|
||||||
|
|
||||||
public XpService(
|
public XpService(
|
||||||
DiscordSocketClient client,
|
DiscordSocketClient client,
|
||||||
@@ -87,7 +64,8 @@ public class XpService : INService, IReadyExecutor, IExecNoCommand
|
|||||||
XpConfigService xpConfig,
|
XpConfigService xpConfig,
|
||||||
IPubSub pubSub,
|
IPubSub pubSub,
|
||||||
IPatronageService ps,
|
IPatronageService ps,
|
||||||
IMessageSenderService sender)
|
IMessageSenderService sender,
|
||||||
|
INotifySubscriber notifySub)
|
||||||
{
|
{
|
||||||
_db = db;
|
_db = db;
|
||||||
_images = images;
|
_images = images;
|
||||||
@@ -99,6 +77,7 @@ public class XpService : INService, IReadyExecutor, IExecNoCommand
|
|||||||
_xpConfig = xpConfig;
|
_xpConfig = xpConfig;
|
||||||
_pubSub = pubSub;
|
_pubSub = pubSub;
|
||||||
_sender = sender;
|
_sender = sender;
|
||||||
|
_notifySub = notifySub;
|
||||||
_excludedServers = new();
|
_excludedServers = new();
|
||||||
_excludedChannels = new();
|
_excludedChannels = new();
|
||||||
_client = client;
|
_client = client;
|
||||||
@@ -189,9 +168,9 @@ public class XpService : INService, IReadyExecutor, IExecNoCommand
|
|||||||
|
|
||||||
var dus = new List<DiscordUser>(globalToAdd.Count);
|
var dus = new List<DiscordUser>(globalToAdd.Count);
|
||||||
var gxps = new List<UserXpStats>(globalToAdd.Count);
|
var gxps = new List<UserXpStats>(globalToAdd.Count);
|
||||||
|
var conf = _xpConfig.Data;
|
||||||
await using (var ctx = _db.GetDbContext())
|
await using (var ctx = _db.GetDbContext())
|
||||||
{
|
{
|
||||||
var conf = _xpConfig.Data;
|
|
||||||
if (conf.CurrencyPerXp > 0)
|
if (conf.CurrencyPerXp > 0)
|
||||||
{
|
{
|
||||||
foreach (var user in globalToAdd)
|
foreach (var user in globalToAdd)
|
||||||
@@ -290,8 +269,7 @@ public class XpService : INService, IReadyExecutor, IExecNoCommand
|
|||||||
du.UserId,
|
du.UserId,
|
||||||
false,
|
false,
|
||||||
oldLevel.Level,
|
oldLevel.Level,
|
||||||
newLevel.Level,
|
newLevel.Level));
|
||||||
du.NotifyOnLevelUp));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -328,8 +306,7 @@ public class XpService : INService, IReadyExecutor, IExecNoCommand
|
|||||||
ulong userId,
|
ulong userId,
|
||||||
bool isServer,
|
bool isServer,
|
||||||
long oldLevel,
|
long oldLevel,
|
||||||
long newLevel,
|
long newLevel)
|
||||||
XpNotificationLocation notifyLoc = XpNotificationLocation.None)
|
|
||||||
=> async () =>
|
=> async () =>
|
||||||
{
|
{
|
||||||
if (isServer)
|
if (isServer)
|
||||||
@@ -337,7 +314,7 @@ public class XpService : INService, IReadyExecutor, IExecNoCommand
|
|||||||
await HandleRewardsInternalAsync(guildId, userId, oldLevel, newLevel);
|
await HandleRewardsInternalAsync(guildId, userId, oldLevel, newLevel);
|
||||||
}
|
}
|
||||||
|
|
||||||
await HandleNotifyInternalAsync(guildId, channelId, userId, isServer, newLevel, notifyLoc);
|
await HandleNotifyInternalAsync(guildId, channelId, userId, isServer, newLevel);
|
||||||
};
|
};
|
||||||
|
|
||||||
private async Task HandleRewardsInternalAsync(
|
private async Task HandleRewardsInternalAsync(
|
||||||
@@ -388,59 +365,25 @@ public class XpService : INService, IReadyExecutor, IExecNoCommand
|
|||||||
ulong channelId,
|
ulong channelId,
|
||||||
ulong userId,
|
ulong userId,
|
||||||
bool isServer,
|
bool isServer,
|
||||||
long newLevel,
|
long newLevel)
|
||||||
XpNotificationLocation notifyLoc)
|
|
||||||
{
|
{
|
||||||
if (notifyLoc == XpNotificationLocation.None)
|
|
||||||
return;
|
|
||||||
|
|
||||||
var guild = _client.GetGuild(guildId);
|
var guild = _client.GetGuild(guildId);
|
||||||
var user = guild?.GetUser(userId);
|
var user = guild?.GetUser(userId);
|
||||||
var ch = guild?.GetTextChannel(channelId);
|
|
||||||
|
|
||||||
if (guild is null || user is null)
|
if (guild is null || user is null)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (isServer)
|
if (isServer)
|
||||||
{
|
{
|
||||||
if (notifyLoc == XpNotificationLocation.Dm)
|
var model = new LevelUpNotifyModel()
|
||||||
{
|
{
|
||||||
await _sender.Response(user)
|
GuildId = guildId,
|
||||||
.Confirm(_strings.GetText(strs.level_up_dm(user.Mention,
|
UserId = userId,
|
||||||
Format.Bold(newLevel.ToString()),
|
ChannelId = channelId,
|
||||||
Format.Bold(guild.ToString() ?? "-")),
|
Level = newLevel
|
||||||
guild.Id))
|
|
||||||
.SendAsync();
|
|
||||||
}
|
|
||||||
else // channel
|
|
||||||
{
|
|
||||||
if (ch is not null)
|
|
||||||
{
|
|
||||||
await _sender.Response(ch)
|
|
||||||
.Confirm(_strings.GetText(strs.level_up_channel(user.Mention,
|
|
||||||
Format.Bold(newLevel.ToString())),
|
|
||||||
guild.Id))
|
|
||||||
.SendAsync();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else // global level
|
|
||||||
{
|
|
||||||
var chan = notifyLoc switch
|
|
||||||
{
|
|
||||||
XpNotificationLocation.Dm => (IMessageChannel)await user.CreateDMChannelAsync(),
|
|
||||||
XpNotificationLocation.Channel => ch,
|
|
||||||
_ => null
|
|
||||||
};
|
};
|
||||||
|
await _notifySub.NotifyAsync(model, true);
|
||||||
if (chan is null)
|
return;
|
||||||
return;
|
|
||||||
|
|
||||||
await _sender.Response(chan)
|
|
||||||
.Confirm(_strings.GetText(strs.level_up_global(user.Mention,
|
|
||||||
Format.Bold(newLevel.ToString())),
|
|
||||||
guild.Id))
|
|
||||||
.SendAsync();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -624,20 +567,6 @@ public class XpService : INService, IReadyExecutor, IExecNoCommand
|
|||||||
.ToArrayAsyncLinqToDB();
|
.ToArrayAsyncLinqToDB();
|
||||||
}
|
}
|
||||||
|
|
||||||
public XpNotificationLocation GetNotificationType(IUser user)
|
|
||||||
{
|
|
||||||
using var uow = _db.GetDbContext();
|
|
||||||
return uow.GetOrCreateUser(user).NotifyOnLevelUp;
|
|
||||||
}
|
|
||||||
|
|
||||||
public async Task ChangeNotificationType(IUser user, XpNotificationLocation type)
|
|
||||||
{
|
|
||||||
await using var uow = _db.GetDbContext();
|
|
||||||
var du = uow.GetOrCreateUser(user);
|
|
||||||
du.NotifyOnLevelUp = type;
|
|
||||||
await uow.SaveChangesAsync();
|
|
||||||
}
|
|
||||||
|
|
||||||
private Task Client_OnGuildAvailable(SocketGuild guild)
|
private Task Client_OnGuildAvailable(SocketGuild guild)
|
||||||
{
|
{
|
||||||
Task.Run(async () =>
|
Task.Run(async () =>
|
||||||
@@ -1639,28 +1568,20 @@ public class XpService : INService, IReadyExecutor, IExecNoCommand
|
|||||||
await using var ctx = _db.GetDbContext();
|
await using var ctx = _db.GetDbContext();
|
||||||
await ctx.GetTable<UserXpStats>()
|
await ctx.GetTable<UserXpStats>()
|
||||||
.InsertOrUpdateAsync(() => new()
|
.InsertOrUpdateAsync(() => new()
|
||||||
{
|
{
|
||||||
GuildId = guildId,
|
GuildId = guildId,
|
||||||
UserId = userId,
|
UserId = userId,
|
||||||
Xp = lvlStats.TotalXp,
|
Xp = lvlStats.TotalXp,
|
||||||
DateAdded = DateTime.UtcNow
|
DateAdded = DateTime.UtcNow
|
||||||
}, (old) => new()
|
},
|
||||||
{
|
(old) => new()
|
||||||
Xp = lvlStats.TotalXp
|
{
|
||||||
}, () => new()
|
Xp = lvlStats.TotalXp
|
||||||
{
|
},
|
||||||
GuildId = guildId,
|
() => new()
|
||||||
UserId = userId
|
{
|
||||||
});
|
GuildId = guildId,
|
||||||
|
UserId = userId
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public enum BuyResult
|
|
||||||
{
|
|
||||||
Success,
|
|
||||||
XpShopDisabled,
|
|
||||||
AlreadyOwned,
|
|
||||||
InsufficientFunds,
|
|
||||||
UnknownItem,
|
|
||||||
InsufficientPatronTier,
|
|
||||||
}
|
|
2
src/NadekoBot/NadekoBot.csproj.DotSettings
Normal file
2
src/NadekoBot/NadekoBot.csproj.DotSettings
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
<wpf:ResourceDictionary xml:space="preserve" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:s="clr-namespace:System;assembly=mscorlib" xmlns:ss="urn:shemas-jetbrains-com:settings-storage-xaml" xmlns:wpf="http://schemas.microsoft.com/winfx/2006/xaml/presentation">
|
||||||
|
<s:Boolean x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=modules_005Cadministration_005Cnotify_005Cmodels/@EntryIndexedValue">True</s:Boolean></wpf:ResourceDictionary>
|
8
src/NadekoBot/_common/Services/IUserService.cs
Normal file
8
src/NadekoBot/_common/Services/IUserService.cs
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
using NadekoBot.Db.Models;
|
||||||
|
|
||||||
|
namespace NadekoBot.Modules.Xp.Services;
|
||||||
|
|
||||||
|
public interface IUserService
|
||||||
|
{
|
||||||
|
Task<DiscordUser?> GetUserAsync(ulong userId);
|
||||||
|
}
|
24
src/NadekoBot/_common/Services/UserService.cs
Normal file
24
src/NadekoBot/_common/Services/UserService.cs
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
using LinqToDB.EntityFrameworkCore;
|
||||||
|
using NadekoBot.Db.Models;
|
||||||
|
|
||||||
|
namespace NadekoBot.Modules.Xp.Services;
|
||||||
|
|
||||||
|
public sealed class UserService : IUserService, INService
|
||||||
|
{
|
||||||
|
private readonly DbService _db;
|
||||||
|
|
||||||
|
public UserService(DbService db)
|
||||||
|
{
|
||||||
|
_db = db;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<DiscordUser> GetUserAsync(ulong userId)
|
||||||
|
{
|
||||||
|
await using var uow = _db.GetDbContext();
|
||||||
|
var user = await uow
|
||||||
|
.GetTable<DiscordUser>()
|
||||||
|
.FirstOrDefaultAsyncLinqToDB(u => u.UserId == userId);
|
||||||
|
|
||||||
|
return user;
|
||||||
|
}
|
||||||
|
}
|
@@ -1547,3 +1547,6 @@ minesweeper:
|
|||||||
- mw
|
- mw
|
||||||
temprole:
|
temprole:
|
||||||
- temprole
|
- temprole
|
||||||
|
notify:
|
||||||
|
- notify
|
||||||
|
- nfy
|
@@ -4854,3 +4854,13 @@ minesweeper:
|
|||||||
params:
|
params:
|
||||||
- mines:
|
- mines:
|
||||||
desc: "The number of mines to create."
|
desc: "The number of mines to create."
|
||||||
|
notify:
|
||||||
|
desc: |-
|
||||||
|
Sends a message to the current channel once the specified event occurs.
|
||||||
|
ex:
|
||||||
|
- 'levelup Congratulations to user %user.name% for reaching level %event.level%'
|
||||||
|
params:
|
||||||
|
- event:
|
||||||
|
desc: "The event to notify on."
|
||||||
|
- message:
|
||||||
|
desc: "The message to send."
|
Reference in New Issue
Block a user