forked from EllieBotDevs/elliebot
notify, minesweeper, migrations
renames, refactors remind optimized wait
This commit is contained in:
parent
204db02cd9
commit
6bc55cd97f
32 changed files with 8283 additions and 245 deletions
|
@ -74,6 +74,35 @@ public abstract class EllieContext : DbContext
|
||||||
|
|
||||||
protected override void OnModelCreating(ModelBuilder modelBuilder)
|
protected override void OnModelCreating(ModelBuilder modelBuilder)
|
||||||
{
|
{
|
||||||
|
#region Notify
|
||||||
|
|
||||||
|
modelBuilder.Entity<Notify>(e =>
|
||||||
|
{
|
||||||
|
e.HasAlternateKey(x => new
|
||||||
|
{
|
||||||
|
x.GuildId,
|
||||||
|
x.Event
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region TempRoles
|
||||||
|
|
||||||
|
modelBuilder.Entity<TempRole>(e =>
|
||||||
|
{
|
||||||
|
e.HasAlternateKey(x => new
|
||||||
|
{
|
||||||
|
x.GuildId,
|
||||||
|
x.UserId,
|
||||||
|
x.RoleId
|
||||||
|
});
|
||||||
|
|
||||||
|
e.HasIndex(x => x.ExpiresAt);
|
||||||
|
});
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
#region GuildColors
|
#region GuildColors
|
||||||
|
|
||||||
modelBuilder.Entity<GuildColors>()
|
modelBuilder.Entity<GuildColors>()
|
||||||
|
@ -449,7 +478,6 @@ public abstract class EllieContext : DbContext
|
||||||
xps.HasIndex(x => x.UserId);
|
xps.HasIndex(x => x.UserId);
|
||||||
xps.HasIndex(x => x.GuildId);
|
xps.HasIndex(x => x.GuildId);
|
||||||
xps.HasIndex(x => x.Xp);
|
xps.HasIndex(x => x.Xp);
|
||||||
xps.HasIndex(x => x.AwardedXp);
|
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
|
|
|
@ -20,7 +20,6 @@ public static class UserXpExtensions
|
||||||
{
|
{
|
||||||
Xp = 0,
|
Xp = 0,
|
||||||
UserId = userId,
|
UserId = userId,
|
||||||
NotifyOnLevelUp = XpNotificationLocation.None,
|
|
||||||
GuildId = guildId
|
GuildId = guildId
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
@ -36,29 +36,37 @@ public class GuildConfig : DbEntity
|
||||||
public HashSet<FilterChannelId> FilterInvitesChannelIds { get; set; } = new();
|
public HashSet<FilterChannelId> FilterInvitesChannelIds { get; set; } = new();
|
||||||
public HashSet<FilterLinksChannelId> FilterLinksChannelIds { get; set; } = new();
|
public HashSet<FilterLinksChannelId> FilterLinksChannelIds { get; set; } = new();
|
||||||
|
|
||||||
//public bool FilterLinks { get; set; }
|
|
||||||
//public HashSet<FilterLinksChannelId> FilterLinksChannels { get; set; } = new HashSet<FilterLinksChannelId>();
|
|
||||||
|
|
||||||
public bool FilterWords { get; set; }
|
public bool FilterWords { get; set; }
|
||||||
public HashSet<FilteredWord> FilteredWords { get; set; } = new();
|
public HashSet<FilteredWord> FilteredWords { get; set; } = new();
|
||||||
public HashSet<FilterWordsChannelId> FilterWordsChannelIds { get; set; } = new();
|
public HashSet<FilterWordsChannelId> FilterWordsChannelIds { get; set; } = new();
|
||||||
|
|
||||||
|
// mute
|
||||||
public HashSet<MutedUserId> MutedUsers { get; set; } = new();
|
public HashSet<MutedUserId> MutedUsers { get; set; } = new();
|
||||||
|
|
||||||
public string MuteRoleName { get; set; }
|
public string MuteRoleName { get; set; }
|
||||||
|
|
||||||
|
// chatterbot
|
||||||
public bool CleverbotEnabled { get; set; }
|
public bool CleverbotEnabled { get; set; }
|
||||||
|
|
||||||
|
// protection
|
||||||
public AntiRaidSetting AntiRaidSetting { get; set; }
|
public AntiRaidSetting AntiRaidSetting { get; set; }
|
||||||
public AntiSpamSetting AntiSpamSetting { get; set; }
|
public AntiSpamSetting AntiSpamSetting { get; set; }
|
||||||
public AntiAltSetting AntiAltSetting { get; set; }
|
public AntiAltSetting AntiAltSetting { get; set; }
|
||||||
|
|
||||||
|
// time
|
||||||
public string Locale { get; set; }
|
public string Locale { get; set; }
|
||||||
public string TimeZoneId { get; set; }
|
public string TimeZoneId { get; set; }
|
||||||
|
|
||||||
|
|
||||||
|
// timers
|
||||||
public HashSet<UnmuteTimer> UnmuteTimers { get; set; } = new();
|
public HashSet<UnmuteTimer> UnmuteTimers { get; set; } = new();
|
||||||
public HashSet<UnbanTimer> UnbanTimer { get; set; } = new();
|
public HashSet<UnbanTimer> UnbanTimer { get; set; } = new();
|
||||||
public HashSet<UnroleTimer> UnroleTimer { get; set; } = new();
|
public HashSet<UnroleTimer> UnroleTimer { get; set; } = new();
|
||||||
|
|
||||||
|
// vcrole
|
||||||
public HashSet<VcRoleInfo> VcRoleInfos { get; set; }
|
public HashSet<VcRoleInfo> VcRoleInfos { get; set; }
|
||||||
|
|
||||||
|
// aliases
|
||||||
public HashSet<CommandAlias> CommandAliases { get; set; } = new();
|
public HashSet<CommandAlias> CommandAliases { get; set; } = new();
|
||||||
public bool WarningsInitialized { get; set; }
|
public bool WarningsInitialized { get; set; }
|
||||||
public HashSet<SlowmodeIgnoredUser> SlowmodeIgnoredUsers { get; set; }
|
public HashSet<SlowmodeIgnoredUser> SlowmodeIgnoredUsers { get; set; }
|
||||||
|
|
20
src/EllieBot/Db/Models/Notify.cs
Normal file
20
src/EllieBot/Db/Models/Notify.cs
Normal file
|
@ -0,0 +1,20 @@
|
||||||
|
using System.ComponentModel.DataAnnotations;
|
||||||
|
|
||||||
|
namespace EllieBot.Db.Models;
|
||||||
|
|
||||||
|
public class Notify
|
||||||
|
{
|
||||||
|
[Key]
|
||||||
|
public int Id { get; set; }
|
||||||
|
public ulong GuildId { get; set; }
|
||||||
|
public ulong ChannelId { get; set; }
|
||||||
|
public NotifyEvent Event { get; set; }
|
||||||
|
|
||||||
|
[MaxLength(10_000)]
|
||||||
|
public string Message { get; set; } = string.Empty;
|
||||||
|
}
|
||||||
|
|
||||||
|
public enum NotifyEvent
|
||||||
|
{
|
||||||
|
UserLevelUp
|
||||||
|
}
|
12
src/EllieBot/Db/Models/roles/TempRole.cs
Normal file
12
src/EllieBot/Db/Models/roles/TempRole.cs
Normal file
|
@ -0,0 +1,12 @@
|
||||||
|
namespace EllieBot.Db.Models;
|
||||||
|
|
||||||
|
public class TempRole
|
||||||
|
{
|
||||||
|
public int Id { get; set; }
|
||||||
|
public ulong GuildId { get; set; }
|
||||||
|
public bool Remove { get; set; }
|
||||||
|
public ulong RoleId { get; set; }
|
||||||
|
public ulong UserId { get; set; }
|
||||||
|
|
||||||
|
public DateTime ExpiresAt { get; set; }
|
||||||
|
}
|
|
@ -6,6 +6,4 @@ public class UserXpStats : DbEntity
|
||||||
public ulong UserId { get; set; }
|
public ulong UserId { get; set; }
|
||||||
public ulong GuildId { get; set; }
|
public ulong GuildId { get; set; }
|
||||||
public long Xp { get; set; }
|
public long Xp { get; set; }
|
||||||
public long AwardedXp { get; set; }
|
|
||||||
public XpNotificationLocation NotifyOnLevelUp { get; set; }
|
|
||||||
}
|
}
|
4114
src/EllieBot/Migrations/PostgreSql/20241208035947_awarded-xp-and-notify-removed.Designer.cs
generated
Normal file
4114
src/EllieBot/Migrations/PostgreSql/20241208035947_awarded-xp-and-notify-removed.Designer.cs
generated
Normal file
File diff suppressed because it is too large
Load diff
|
@ -0,0 +1,107 @@
|
||||||
|
using System;
|
||||||
|
using Microsoft.EntityFrameworkCore.Migrations;
|
||||||
|
using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata;
|
||||||
|
|
||||||
|
#nullable disable
|
||||||
|
|
||||||
|
namespace EllieBot.Migrations.PostgreSql
|
||||||
|
{
|
||||||
|
/// <inheritdoc />
|
||||||
|
public partial class awardedxpandnotifyremoved : Migration
|
||||||
|
{
|
||||||
|
/// <inheritdoc />
|
||||||
|
protected override void Up(MigrationBuilder migrationBuilder)
|
||||||
|
{
|
||||||
|
migrationBuilder.DropIndex(
|
||||||
|
name: "ix_userxpstats_awardedxp",
|
||||||
|
table: "userxpstats");
|
||||||
|
|
||||||
|
migrationBuilder.DropColumn(
|
||||||
|
name: "awardedxp",
|
||||||
|
table: "userxpstats");
|
||||||
|
|
||||||
|
migrationBuilder.DropColumn(
|
||||||
|
name: "notifyonlevelup",
|
||||||
|
table: "userxpstats");
|
||||||
|
|
||||||
|
migrationBuilder.DropColumn(
|
||||||
|
name: "dateadded",
|
||||||
|
table: "sargroup");
|
||||||
|
|
||||||
|
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),
|
||||||
|
@event = table.Column<int>(name: "event", 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_event", x => new { x.guildid, x.@event });
|
||||||
|
});
|
||||||
|
|
||||||
|
migrationBuilder.CreateTable(
|
||||||
|
name: "temprole",
|
||||||
|
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),
|
||||||
|
remove = table.Column<bool>(type: "boolean", nullable: false),
|
||||||
|
roleid = table.Column<decimal>(type: "numeric(20,0)", nullable: false),
|
||||||
|
userid = table.Column<decimal>(type: "numeric(20,0)", nullable: false),
|
||||||
|
expiresat = table.Column<DateTime>(type: "timestamp without time zone", nullable: false)
|
||||||
|
},
|
||||||
|
constraints: table =>
|
||||||
|
{
|
||||||
|
table.PrimaryKey("pk_temprole", x => x.id);
|
||||||
|
table.UniqueConstraint("ak_temprole_guildid_userid_roleid", x => new { x.guildid, x.userid, x.roleid });
|
||||||
|
});
|
||||||
|
|
||||||
|
migrationBuilder.CreateIndex(
|
||||||
|
name: "ix_temprole_expiresat",
|
||||||
|
table: "temprole",
|
||||||
|
column: "expiresat");
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
protected override void Down(MigrationBuilder migrationBuilder)
|
||||||
|
{
|
||||||
|
migrationBuilder.DropTable(
|
||||||
|
name: "notify");
|
||||||
|
|
||||||
|
migrationBuilder.DropTable(
|
||||||
|
name: "temprole");
|
||||||
|
|
||||||
|
migrationBuilder.AddColumn<long>(
|
||||||
|
name: "awardedxp",
|
||||||
|
table: "userxpstats",
|
||||||
|
type: "bigint",
|
||||||
|
nullable: false,
|
||||||
|
defaultValue: 0L);
|
||||||
|
|
||||||
|
migrationBuilder.AddColumn<int>(
|
||||||
|
name: "notifyonlevelup",
|
||||||
|
table: "userxpstats",
|
||||||
|
type: "integer",
|
||||||
|
nullable: false,
|
||||||
|
defaultValue: 0);
|
||||||
|
|
||||||
|
migrationBuilder.AddColumn<DateTime>(
|
||||||
|
name: "dateadded",
|
||||||
|
table: "sargroup",
|
||||||
|
type: "timestamp without time zone",
|
||||||
|
nullable: true);
|
||||||
|
|
||||||
|
migrationBuilder.CreateIndex(
|
||||||
|
name: "ix_userxpstats_awardedxp",
|
||||||
|
table: "userxpstats",
|
||||||
|
column: "awardedxp");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -1817,6 +1817,42 @@ namespace EllieBot.Migrations.PostgreSql
|
||||||
b.ToTable("ncpixel", (string)null);
|
b.ToTable("ncpixel", (string)null);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("EllieBot.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<int>("Event")
|
||||||
|
.HasColumnType("integer")
|
||||||
|
.HasColumnName("event");
|
||||||
|
|
||||||
|
b.Property<decimal>("GuildId")
|
||||||
|
.HasColumnType("numeric(20,0)")
|
||||||
|
.HasColumnName("guildid");
|
||||||
|
|
||||||
|
b.Property<string>("Message")
|
||||||
|
.IsRequired()
|
||||||
|
.HasMaxLength(10000)
|
||||||
|
.HasColumnType("character varying(10000)")
|
||||||
|
.HasColumnName("message");
|
||||||
|
|
||||||
|
b.HasKey("Id")
|
||||||
|
.HasName("pk_notify");
|
||||||
|
|
||||||
|
b.HasAlternateKey("GuildId", "Event")
|
||||||
|
.HasName("ak_notify_guildid_event");
|
||||||
|
|
||||||
|
b.ToTable("notify", (string)null);
|
||||||
|
});
|
||||||
|
|
||||||
modelBuilder.Entity("EllieBot.Db.Models.PatronUser", b =>
|
modelBuilder.Entity("EllieBot.Db.Models.PatronUser", b =>
|
||||||
{
|
{
|
||||||
b.Property<decimal>("UserId")
|
b.Property<decimal>("UserId")
|
||||||
|
@ -2339,10 +2375,6 @@ namespace EllieBot.Migrations.PostgreSql
|
||||||
|
|
||||||
NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id"));
|
NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id"));
|
||||||
|
|
||||||
b.Property<DateTime?>("DateAdded")
|
|
||||||
.HasColumnType("timestamp without time zone")
|
|
||||||
.HasColumnName("dateadded");
|
|
||||||
|
|
||||||
b.Property<int>("GroupNumber")
|
b.Property<int>("GroupNumber")
|
||||||
.HasColumnType("integer")
|
.HasColumnType("integer")
|
||||||
.HasColumnName("groupnumber");
|
.HasColumnName("groupnumber");
|
||||||
|
@ -2706,6 +2738,47 @@ namespace EllieBot.Migrations.PostgreSql
|
||||||
b.ToTable("streamrolewhitelisteduser", (string)null);
|
b.ToTable("streamrolewhitelisteduser", (string)null);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("EllieBot.Db.Models.TempRole", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("integer")
|
||||||
|
.HasColumnName("id");
|
||||||
|
|
||||||
|
NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id"));
|
||||||
|
|
||||||
|
b.Property<DateTime>("ExpiresAt")
|
||||||
|
.HasColumnType("timestamp without time zone")
|
||||||
|
.HasColumnName("expiresat");
|
||||||
|
|
||||||
|
b.Property<decimal>("GuildId")
|
||||||
|
.HasColumnType("numeric(20,0)")
|
||||||
|
.HasColumnName("guildid");
|
||||||
|
|
||||||
|
b.Property<bool>("Remove")
|
||||||
|
.HasColumnType("boolean")
|
||||||
|
.HasColumnName("remove");
|
||||||
|
|
||||||
|
b.Property<decimal>("RoleId")
|
||||||
|
.HasColumnType("numeric(20,0)")
|
||||||
|
.HasColumnName("roleid");
|
||||||
|
|
||||||
|
b.Property<decimal>("UserId")
|
||||||
|
.HasColumnType("numeric(20,0)")
|
||||||
|
.HasColumnName("userid");
|
||||||
|
|
||||||
|
b.HasKey("Id")
|
||||||
|
.HasName("pk_temprole");
|
||||||
|
|
||||||
|
b.HasAlternateKey("GuildId", "UserId", "RoleId")
|
||||||
|
.HasName("ak_temprole_guildid_userid_roleid");
|
||||||
|
|
||||||
|
b.HasIndex("ExpiresAt")
|
||||||
|
.HasDatabaseName("ix_temprole_expiresat");
|
||||||
|
|
||||||
|
b.ToTable("temprole", (string)null);
|
||||||
|
});
|
||||||
|
|
||||||
modelBuilder.Entity("EllieBot.Db.Models.TodoModel", b =>
|
modelBuilder.Entity("EllieBot.Db.Models.TodoModel", b =>
|
||||||
{
|
{
|
||||||
b.Property<int>("Id")
|
b.Property<int>("Id")
|
||||||
|
@ -2862,10 +2935,6 @@ namespace EllieBot.Migrations.PostgreSql
|
||||||
|
|
||||||
NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id"));
|
NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id"));
|
||||||
|
|
||||||
b.Property<long>("AwardedXp")
|
|
||||||
.HasColumnType("bigint")
|
|
||||||
.HasColumnName("awardedxp");
|
|
||||||
|
|
||||||
b.Property<DateTime?>("DateAdded")
|
b.Property<DateTime?>("DateAdded")
|
||||||
.HasColumnType("timestamp without time zone")
|
.HasColumnType("timestamp without time zone")
|
||||||
.HasColumnName("dateadded");
|
.HasColumnName("dateadded");
|
||||||
|
@ -2874,10 +2943,6 @@ namespace EllieBot.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");
|
||||||
|
@ -2889,9 +2954,6 @@ namespace EllieBot.Migrations.PostgreSql
|
||||||
b.HasKey("Id")
|
b.HasKey("Id")
|
||||||
.HasName("pk_userxpstats");
|
.HasName("pk_userxpstats");
|
||||||
|
|
||||||
b.HasIndex("AwardedXp")
|
|
||||||
.HasDatabaseName("ix_userxpstats_awardedxp");
|
|
||||||
|
|
||||||
b.HasIndex("GuildId")
|
b.HasIndex("GuildId")
|
||||||
.HasDatabaseName("ix_userxpstats_guildid");
|
.HasDatabaseName("ix_userxpstats_guildid");
|
||||||
|
|
||||||
|
|
3171
src/EllieBot/Migrations/Sqlite/20241208035845_awarded-xp-and-notify-removed.Designer.cs
generated
Normal file
3171
src/EllieBot/Migrations/Sqlite/20241208035845_awarded-xp-and-notify-removed.Designer.cs
generated
Normal file
File diff suppressed because it is too large
Load diff
|
@ -0,0 +1,106 @@
|
||||||
|
using System;
|
||||||
|
using Microsoft.EntityFrameworkCore.Migrations;
|
||||||
|
|
||||||
|
#nullable disable
|
||||||
|
|
||||||
|
namespace EllieBot.Migrations
|
||||||
|
{
|
||||||
|
/// <inheritdoc />
|
||||||
|
public partial class awardedxpandnotifyremoved : Migration
|
||||||
|
{
|
||||||
|
/// <inheritdoc />
|
||||||
|
protected override void Up(MigrationBuilder migrationBuilder)
|
||||||
|
{
|
||||||
|
migrationBuilder.DropIndex(
|
||||||
|
name: "IX_UserXpStats_AwardedXp",
|
||||||
|
table: "UserXpStats");
|
||||||
|
|
||||||
|
migrationBuilder.DropColumn(
|
||||||
|
name: "AwardedXp",
|
||||||
|
table: "UserXpStats");
|
||||||
|
|
||||||
|
migrationBuilder.DropColumn(
|
||||||
|
name: "NotifyOnLevelUp",
|
||||||
|
table: "UserXpStats");
|
||||||
|
|
||||||
|
migrationBuilder.DropColumn(
|
||||||
|
name: "DateAdded",
|
||||||
|
table: "SarGroup");
|
||||||
|
|
||||||
|
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),
|
||||||
|
Event = 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_Event", x => new { x.GuildId, x.Event });
|
||||||
|
});
|
||||||
|
|
||||||
|
migrationBuilder.CreateTable(
|
||||||
|
name: "TempRole",
|
||||||
|
columns: table => new
|
||||||
|
{
|
||||||
|
Id = table.Column<int>(type: "INTEGER", nullable: false)
|
||||||
|
.Annotation("Sqlite:Autoincrement", true),
|
||||||
|
GuildId = table.Column<ulong>(type: "INTEGER", nullable: false),
|
||||||
|
Remove = table.Column<bool>(type: "INTEGER", nullable: false),
|
||||||
|
RoleId = table.Column<ulong>(type: "INTEGER", nullable: false),
|
||||||
|
UserId = table.Column<ulong>(type: "INTEGER", nullable: false),
|
||||||
|
ExpiresAt = table.Column<DateTime>(type: "TEXT", nullable: false)
|
||||||
|
},
|
||||||
|
constraints: table =>
|
||||||
|
{
|
||||||
|
table.PrimaryKey("PK_TempRole", x => x.Id);
|
||||||
|
table.UniqueConstraint("AK_TempRole_GuildId_UserId_RoleId", x => new { x.GuildId, x.UserId, x.RoleId });
|
||||||
|
});
|
||||||
|
|
||||||
|
migrationBuilder.CreateIndex(
|
||||||
|
name: "IX_TempRole_ExpiresAt",
|
||||||
|
table: "TempRole",
|
||||||
|
column: "ExpiresAt");
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
protected override void Down(MigrationBuilder migrationBuilder)
|
||||||
|
{
|
||||||
|
migrationBuilder.DropTable(
|
||||||
|
name: "Notify");
|
||||||
|
|
||||||
|
migrationBuilder.DropTable(
|
||||||
|
name: "TempRole");
|
||||||
|
|
||||||
|
migrationBuilder.AddColumn<long>(
|
||||||
|
name: "AwardedXp",
|
||||||
|
table: "UserXpStats",
|
||||||
|
type: "INTEGER",
|
||||||
|
nullable: false,
|
||||||
|
defaultValue: 0L);
|
||||||
|
|
||||||
|
migrationBuilder.AddColumn<int>(
|
||||||
|
name: "NotifyOnLevelUp",
|
||||||
|
table: "UserXpStats",
|
||||||
|
type: "INTEGER",
|
||||||
|
nullable: false,
|
||||||
|
defaultValue: 0);
|
||||||
|
|
||||||
|
migrationBuilder.AddColumn<DateTime>(
|
||||||
|
name: "DateAdded",
|
||||||
|
table: "SarGroup",
|
||||||
|
type: "TEXT",
|
||||||
|
nullable: true);
|
||||||
|
|
||||||
|
migrationBuilder.CreateIndex(
|
||||||
|
name: "IX_UserXpStats_AwardedXp",
|
||||||
|
table: "UserXpStats",
|
||||||
|
column: "AwardedXp");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -1356,6 +1356,33 @@ namespace EllieBot.Migrations
|
||||||
b.ToTable("NCPixel");
|
b.ToTable("NCPixel");
|
||||||
});
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("EllieBot.Db.Models.Notify", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<ulong>("ChannelId")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<int>("Event")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<ulong>("GuildId")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<string>("Message")
|
||||||
|
.IsRequired()
|
||||||
|
.HasMaxLength(10000)
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.HasAlternateKey("GuildId", "Event");
|
||||||
|
|
||||||
|
b.ToTable("Notify");
|
||||||
|
});
|
||||||
|
|
||||||
modelBuilder.Entity("EllieBot.Db.Models.PatronUser", b =>
|
modelBuilder.Entity("EllieBot.Db.Models.PatronUser", b =>
|
||||||
{
|
{
|
||||||
b.Property<ulong>("UserId")
|
b.Property<ulong>("UserId")
|
||||||
|
@ -1744,9 +1771,6 @@ namespace EllieBot.Migrations
|
||||||
.ValueGeneratedOnAdd()
|
.ValueGeneratedOnAdd()
|
||||||
.HasColumnType("INTEGER");
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
b.Property<DateTime?>("DateAdded")
|
|
||||||
.HasColumnType("TEXT");
|
|
||||||
|
|
||||||
b.Property<int>("GroupNumber")
|
b.Property<int>("GroupNumber")
|
||||||
.HasColumnType("INTEGER");
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
@ -2016,6 +2040,36 @@ namespace EllieBot.Migrations
|
||||||
b.ToTable("StreamRoleWhitelistedUser");
|
b.ToTable("StreamRoleWhitelistedUser");
|
||||||
});
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("EllieBot.Db.Models.TempRole", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<DateTime>("ExpiresAt")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<ulong>("GuildId")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<bool>("Remove")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<ulong>("RoleId")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<ulong>("UserId")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.HasAlternateKey("GuildId", "UserId", "RoleId");
|
||||||
|
|
||||||
|
b.HasIndex("ExpiresAt");
|
||||||
|
|
||||||
|
b.ToTable("TempRole");
|
||||||
|
});
|
||||||
|
|
||||||
modelBuilder.Entity("EllieBot.Db.Models.TodoModel", b =>
|
modelBuilder.Entity("EllieBot.Db.Models.TodoModel", b =>
|
||||||
{
|
{
|
||||||
b.Property<int>("Id")
|
b.Property<int>("Id")
|
||||||
|
@ -2130,18 +2184,12 @@ namespace EllieBot.Migrations
|
||||||
.ValueGeneratedOnAdd()
|
.ValueGeneratedOnAdd()
|
||||||
.HasColumnType("INTEGER");
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
b.Property<long>("AwardedXp")
|
|
||||||
.HasColumnType("INTEGER");
|
|
||||||
|
|
||||||
b.Property<DateTime?>("DateAdded")
|
b.Property<DateTime?>("DateAdded")
|
||||||
.HasColumnType("TEXT");
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
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");
|
||||||
|
|
||||||
|
@ -2150,8 +2198,6 @@ namespace EllieBot.Migrations
|
||||||
|
|
||||||
b.HasKey("Id");
|
b.HasKey("Id");
|
||||||
|
|
||||||
b.HasIndex("AwardedXp");
|
|
||||||
|
|
||||||
b.HasIndex("GuildId");
|
b.HasIndex("GuildId");
|
||||||
|
|
||||||
b.HasIndex("UserId");
|
b.HasIndex("UserId");
|
||||||
|
|
|
@ -46,7 +46,7 @@ public partial class Administration : EllieModule<AdministrationService>
|
||||||
[RequireContext(ContextType.Guild)]
|
[RequireContext(ContextType.Guild)]
|
||||||
[UserPerm(GuildPerm.Administrator)]
|
[UserPerm(GuildPerm.Administrator)]
|
||||||
[BotPerm(GuildPerm.ManageGuild)]
|
[BotPerm(GuildPerm.ManageGuild)]
|
||||||
public async Task ImageOnlyChannel(StoopidTime time = null)
|
public async Task ImageOnlyChannel(ParsedTimespan timespan = null)
|
||||||
{
|
{
|
||||||
var newValue = await _somethingOnly.ToggleImageOnlyChannelAsync(ctx.Guild.Id, ctx.Channel.Id);
|
var newValue = await _somethingOnly.ToggleImageOnlyChannelAsync(ctx.Guild.Id, ctx.Channel.Id);
|
||||||
if (newValue)
|
if (newValue)
|
||||||
|
@ -54,12 +54,12 @@ public partial class Administration : EllieModule<AdministrationService>
|
||||||
else
|
else
|
||||||
await Response().Pending(strs.imageonly_disable).SendAsync();
|
await Response().Pending(strs.imageonly_disable).SendAsync();
|
||||||
}
|
}
|
||||||
|
|
||||||
[Cmd]
|
[Cmd]
|
||||||
[RequireContext(ContextType.Guild)]
|
[RequireContext(ContextType.Guild)]
|
||||||
[UserPerm(GuildPerm.Administrator)]
|
[UserPerm(GuildPerm.Administrator)]
|
||||||
[BotPerm(GuildPerm.ManageGuild)]
|
[BotPerm(GuildPerm.ManageGuild)]
|
||||||
public async Task LinkOnlyChannel(StoopidTime time = null)
|
public async Task LinkOnlyChannel(ParsedTimespan timespan = null)
|
||||||
{
|
{
|
||||||
var newValue = await _somethingOnly.ToggleLinkOnlyChannelAsync(ctx.Guild.Id, ctx.Channel.Id);
|
var newValue = await _somethingOnly.ToggleLinkOnlyChannelAsync(ctx.Guild.Id, ctx.Channel.Id);
|
||||||
if (newValue)
|
if (newValue)
|
||||||
|
@ -72,10 +72,10 @@ public partial class Administration : EllieModule<AdministrationService>
|
||||||
[RequireContext(ContextType.Guild)]
|
[RequireContext(ContextType.Guild)]
|
||||||
[UserPerm(ChannelPerm.ManageChannels)]
|
[UserPerm(ChannelPerm.ManageChannels)]
|
||||||
[BotPerm(ChannelPerm.ManageChannels)]
|
[BotPerm(ChannelPerm.ManageChannels)]
|
||||||
public async Task Slowmode(StoopidTime time = null)
|
public async Task Slowmode(ParsedTimespan timespan = null)
|
||||||
{
|
{
|
||||||
var seconds = (int?)time?.Time.TotalSeconds ?? 0;
|
var seconds = (int?)timespan?.Time.TotalSeconds ?? 0;
|
||||||
if (time is not null && (time.Time < TimeSpan.FromSeconds(0) || time.Time > TimeSpan.FromHours(6)))
|
if (timespan is not null && (timespan.Time < TimeSpan.FromSeconds(0) || timespan.Time > TimeSpan.FromHours(6)))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
await ((ITextChannel)ctx.Channel).ModifyAsync(tcp =>
|
await ((ITextChannel)ctx.Channel).ModifyAsync(tcp =>
|
||||||
|
@ -221,7 +221,7 @@ public partial class Administration : EllieModule<AdministrationService>
|
||||||
[BotPerm(GuildPerm.ManageChannels)]
|
[BotPerm(GuildPerm.ManageChannels)]
|
||||||
public async Task CreaTxtChanl([Leftover] string channelName)
|
public async Task CreaTxtChanl([Leftover] string channelName)
|
||||||
{
|
{
|
||||||
var txtCh = await ctx.Guild.CreateTextChannelAsync(channelName);
|
var txtCh = await ctx.Guild.CreateTextChannelAsync(channelName);
|
||||||
await Response().Confirm(strs.createtextchan(Format.Bold(txtCh.Name))).SendAsync();
|
await Response().Confirm(strs.createtextchan(Format.Bold(txtCh.Name))).SendAsync();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -298,18 +298,18 @@ public partial class Administration : EllieModule<AdministrationService>
|
||||||
[RequireContext(ContextType.Guild)]
|
[RequireContext(ContextType.Guild)]
|
||||||
[UserPerm(ChannelPerm.ManageMessages)]
|
[UserPerm(ChannelPerm.ManageMessages)]
|
||||||
[BotPerm(ChannelPerm.ManageMessages)]
|
[BotPerm(ChannelPerm.ManageMessages)]
|
||||||
public Task Delete(ulong messageId, StoopidTime time = null)
|
public Task Delete(ulong messageId, ParsedTimespan timespan = null)
|
||||||
=> Delete((ITextChannel)ctx.Channel, messageId, time);
|
=> Delete((ITextChannel)ctx.Channel, messageId, timespan);
|
||||||
|
|
||||||
[Cmd]
|
[Cmd]
|
||||||
[RequireContext(ContextType.Guild)]
|
[RequireContext(ContextType.Guild)]
|
||||||
public async Task Delete(ITextChannel channel, ulong messageId, StoopidTime time = null)
|
public async Task Delete(ITextChannel channel, ulong messageId, ParsedTimespan timespan = null)
|
||||||
=> await InternalMessageAction(channel, messageId, time, msg => msg.DeleteAsync());
|
=> await InternalMessageAction(channel, messageId, timespan, msg => msg.DeleteAsync());
|
||||||
|
|
||||||
private async Task InternalMessageAction(
|
private async Task InternalMessageAction(
|
||||||
ITextChannel channel,
|
ITextChannel channel,
|
||||||
ulong messageId,
|
ulong messageId,
|
||||||
StoopidTime time,
|
ParsedTimespan timespan,
|
||||||
Func<IMessage, Task> func)
|
Func<IMessage, Task> func)
|
||||||
{
|
{
|
||||||
var userPerms = ((SocketGuildUser)ctx.User).GetPermissions(channel);
|
var userPerms = ((SocketGuildUser)ctx.User).GetPermissions(channel);
|
||||||
|
@ -334,13 +334,13 @@ public partial class Administration : EllieModule<AdministrationService>
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (time is null)
|
if (timespan is null)
|
||||||
await msg.DeleteAsync();
|
await msg.DeleteAsync();
|
||||||
else if (time.Time <= TimeSpan.FromDays(7))
|
else if (timespan.Time <= TimeSpan.FromDays(7))
|
||||||
{
|
{
|
||||||
_ = Task.Run(async () =>
|
_ = Task.Run(async () =>
|
||||||
{
|
{
|
||||||
await Task.Delay(time.Time);
|
await Task.Delay(timespan.Time);
|
||||||
await msg.DeleteAsync();
|
await msg.DeleteAsync();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -360,11 +360,11 @@ public partial class Administration : EllieModule<AdministrationService>
|
||||||
{
|
{
|
||||||
if (ctx.Channel is not SocketTextChannel stc)
|
if (ctx.Channel is not SocketTextChannel stc)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
await stc.CreateThreadAsync(name, message: ctx.Message.ReferencedMessage);
|
await stc.CreateThreadAsync(name, message: ctx.Message.ReferencedMessage);
|
||||||
await ctx.OkAsync();
|
await ctx.OkAsync();
|
||||||
}
|
}
|
||||||
|
|
||||||
[Cmd]
|
[Cmd]
|
||||||
[BotPerm(ChannelPermission.ManageThreads)]
|
[BotPerm(ChannelPermission.ManageThreads)]
|
||||||
[UserPerm(ChannelPermission.ManageThreads)]
|
[UserPerm(ChannelPermission.ManageThreads)]
|
||||||
|
@ -380,7 +380,7 @@ public partial class Administration : EllieModule<AdministrationService>
|
||||||
await Response().Error(strs.not_found).SendAsync();
|
await Response().Error(strs.not_found).SendAsync();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
await t.DeleteAsync();
|
await t.DeleteAsync();
|
||||||
await ctx.OkAsync();
|
await ctx.OkAsync();
|
||||||
}
|
}
|
||||||
|
@ -406,7 +406,7 @@ public partial class Administration : EllieModule<AdministrationService>
|
||||||
await Response().Confirm(strs.autopublish_disable).SendAsync();
|
await Response().Confirm(strs.autopublish_disable).SendAsync();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
[Cmd]
|
[Cmd]
|
||||||
[UserPerm(GuildPerm.ManageNicknames)]
|
[UserPerm(GuildPerm.ManageNicknames)]
|
||||||
[BotPerm(GuildPerm.ChangeNickname)]
|
[BotPerm(GuildPerm.ChangeNickname)]
|
||||||
|
@ -450,8 +450,9 @@ public partial class Administration : EllieModule<AdministrationService>
|
||||||
public async Task SetServerBanner([Leftover] string img = null)
|
public async Task SetServerBanner([Leftover] string img = null)
|
||||||
{
|
{
|
||||||
// Tier2 or higher is required to set a banner.
|
// Tier2 or higher is required to set a banner.
|
||||||
if (ctx.Guild.PremiumTier is PremiumTier.Tier1 or PremiumTier.None) return;
|
if (ctx.Guild.PremiumTier is PremiumTier.Tier1 or PremiumTier.None)
|
||||||
|
return;
|
||||||
|
|
||||||
var result = await _service.SetServerBannerAsync(ctx.Guild, img);
|
var result = await _service.SetServerBannerAsync(ctx.Guild, img);
|
||||||
|
|
||||||
switch (result)
|
switch (result)
|
||||||
|
@ -472,7 +473,7 @@ public partial class Administration : EllieModule<AdministrationService>
|
||||||
throw new ArgumentOutOfRangeException();
|
throw new ArgumentOutOfRangeException();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
[Cmd]
|
[Cmd]
|
||||||
[RequireContext(ContextType.Guild)]
|
[RequireContext(ContextType.Guild)]
|
||||||
[UserPerm(GuildPermission.ManageGuild)]
|
[UserPerm(GuildPermission.ManageGuild)]
|
||||||
|
|
|
@ -72,18 +72,18 @@ public partial class Administration
|
||||||
[RequireContext(ContextType.Guild)]
|
[RequireContext(ContextType.Guild)]
|
||||||
[UserPerm(GuildPerm.ManageRoles | GuildPerm.MuteMembers)]
|
[UserPerm(GuildPerm.ManageRoles | GuildPerm.MuteMembers)]
|
||||||
[Priority(1)]
|
[Priority(1)]
|
||||||
public async Task Mute(StoopidTime time, IGuildUser user, [Leftover] string reason = "")
|
public async Task Mute(ParsedTimespan timespan, IGuildUser user, [Leftover] string reason = "")
|
||||||
{
|
{
|
||||||
if (time.Time < TimeSpan.FromMinutes(1) || time.Time > TimeSpan.FromDays(49))
|
if (timespan.Time < TimeSpan.FromMinutes(1) || timespan.Time > TimeSpan.FromDays(49))
|
||||||
return;
|
return;
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
if (!await VerifyMutePermissions((IGuildUser)ctx.User, user))
|
if (!await VerifyMutePermissions((IGuildUser)ctx.User, user))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
await _service.TimedMute(user, ctx.User, time.Time, reason: reason);
|
await _service.TimedMute(user, ctx.User, timespan.Time, reason: reason);
|
||||||
await Response().Confirm(strs.user_muted_time(Format.Bold(user.ToString()),
|
await Response().Confirm(strs.user_muted_time(Format.Bold(user.ToString()),
|
||||||
(int)time.Time.TotalMinutes)).SendAsync();
|
(int)timespan.Time.TotalMinutes)).SendAsync();
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
|
@ -133,18 +133,18 @@ public partial class Administration
|
||||||
[RequireContext(ContextType.Guild)]
|
[RequireContext(ContextType.Guild)]
|
||||||
[UserPerm(GuildPerm.ManageRoles)]
|
[UserPerm(GuildPerm.ManageRoles)]
|
||||||
[Priority(1)]
|
[Priority(1)]
|
||||||
public async Task ChatMute(StoopidTime time, IGuildUser user, [Leftover] string reason = "")
|
public async Task ChatMute(ParsedTimespan timespan, IGuildUser user, [Leftover] string reason = "")
|
||||||
{
|
{
|
||||||
if (time.Time < TimeSpan.FromMinutes(1) || time.Time > TimeSpan.FromDays(49))
|
if (timespan.Time < TimeSpan.FromMinutes(1) || timespan.Time > TimeSpan.FromDays(49))
|
||||||
return;
|
return;
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
if (!await VerifyMutePermissions((IGuildUser)ctx.User, user))
|
if (!await VerifyMutePermissions((IGuildUser)ctx.User, user))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
await _service.TimedMute(user, ctx.User, time.Time, MuteType.Chat, reason);
|
await _service.TimedMute(user, ctx.User, timespan.Time, MuteType.Chat, reason);
|
||||||
await Response().Confirm(strs.user_chat_mute_time(Format.Bold(user.ToString()),
|
await Response().Confirm(strs.user_chat_mute_time(Format.Bold(user.ToString()),
|
||||||
(int)time.Time.TotalMinutes)).SendAsync();
|
(int)timespan.Time.TotalMinutes)).SendAsync();
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
|
@ -193,18 +193,18 @@ public partial class Administration
|
||||||
[RequireContext(ContextType.Guild)]
|
[RequireContext(ContextType.Guild)]
|
||||||
[UserPerm(GuildPerm.MuteMembers)]
|
[UserPerm(GuildPerm.MuteMembers)]
|
||||||
[Priority(1)]
|
[Priority(1)]
|
||||||
public async Task VoiceMute(StoopidTime time, IGuildUser user, [Leftover] string reason = "")
|
public async Task VoiceMute(ParsedTimespan timespan, IGuildUser user, [Leftover] string reason = "")
|
||||||
{
|
{
|
||||||
if (time.Time < TimeSpan.FromMinutes(1) || time.Time > TimeSpan.FromDays(49))
|
if (timespan.Time < TimeSpan.FromMinutes(1) || timespan.Time > TimeSpan.FromDays(49))
|
||||||
return;
|
return;
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
if (!await VerifyMutePermissions((IGuildUser)ctx.User, user))
|
if (!await VerifyMutePermissions((IGuildUser)ctx.User, user))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
await _service.TimedMute(user, ctx.User, time.Time, MuteType.Voice, reason);
|
await _service.TimedMute(user, ctx.User, timespan.Time, MuteType.Voice, reason);
|
||||||
await Response().Confirm(strs.user_voice_mute_time(Format.Bold(user.ToString()),
|
await Response().Confirm(strs.user_voice_mute_time(Format.Bold(user.ToString()),
|
||||||
(int)time.Time.TotalMinutes)).SendAsync();
|
(int)timespan.Time.TotalMinutes)).SendAsync();
|
||||||
}
|
}
|
||||||
catch
|
catch
|
||||||
{
|
{
|
||||||
|
|
92
src/EllieBot/Modules/Administration/Notify/NotifyCommands.cs
Normal file
92
src/EllieBot/Modules/Administration/Notify/NotifyCommands.cs
Normal file
|
@ -0,0 +1,92 @@
|
||||||
|
using LinqToDB;
|
||||||
|
using LinqToDB.EntityFrameworkCore;
|
||||||
|
using EllieBot.Common.ModuleBehaviors;
|
||||||
|
using EllieBot.Db.Models;
|
||||||
|
|
||||||
|
namespace EllieBot.Modules.Administration;
|
||||||
|
|
||||||
|
public sealed class NotifyService : IReadyExecutor, IEService
|
||||||
|
{
|
||||||
|
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 class NotifyCommands : EllieModule<NotifyService>
|
||||||
|
{
|
||||||
|
[Cmd]
|
||||||
|
[OwnerOnly]
|
||||||
|
public async Task Notify(NotifyEvent nEvent, [Leftover] string message = null)
|
||||||
|
{
|
||||||
|
if (string.IsNullOrWhiteSpace(message))
|
||||||
|
{
|
||||||
|
await _service.DisableAsync(ctx.Guild.Id, nEvent);
|
||||||
|
await Response().Confirm(strs.notify_off(nEvent)).SendAsync();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
await _service.EnableAsync(ctx.Guild.Id, ctx.Channel.Id, nEvent, message);
|
||||||
|
await Response().Confirm(strs.notify_on(nEvent.ToString())).SendAsync();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -28,17 +28,17 @@ public partial class Administration
|
||||||
[RequireContext(ContextType.Guild)]
|
[RequireContext(ContextType.Guild)]
|
||||||
[UserPerm(GuildPerm.Administrator)]
|
[UserPerm(GuildPerm.Administrator)]
|
||||||
public async Task AntiAlt(
|
public async Task AntiAlt(
|
||||||
StoopidTime minAge,
|
ParsedTimespan minAge,
|
||||||
PunishmentAction action,
|
PunishmentAction action,
|
||||||
[Leftover] StoopidTime punishTime = null)
|
[Leftover] ParsedTimespan punishTimespan = null)
|
||||||
{
|
{
|
||||||
var minAgeMinutes = (int)minAge.Time.TotalMinutes;
|
var minAgeMinutes = (int)minAge.Time.TotalMinutes;
|
||||||
var punishTimeMinutes = (int?)punishTime?.Time.TotalMinutes ?? 0;
|
var punishTimeMinutes = (int?)punishTimespan?.Time.TotalMinutes ?? 0;
|
||||||
|
|
||||||
if (minAgeMinutes < 1 || punishTimeMinutes < 0)
|
if (minAgeMinutes < 1 || punishTimeMinutes < 0)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
var minutes = (int?)punishTime?.Time.TotalMinutes ?? 0;
|
var minutes = (int?)punishTimespan?.Time.TotalMinutes ?? 0;
|
||||||
if (action is PunishmentAction.TimeOut && minutes < 1)
|
if (action is PunishmentAction.TimeOut && minutes < 1)
|
||||||
minutes = 1;
|
minutes = 1;
|
||||||
|
|
||||||
|
@ -53,7 +53,7 @@ public partial class Administration
|
||||||
[Cmd]
|
[Cmd]
|
||||||
[RequireContext(ContextType.Guild)]
|
[RequireContext(ContextType.Guild)]
|
||||||
[UserPerm(GuildPerm.Administrator)]
|
[UserPerm(GuildPerm.Administrator)]
|
||||||
public async Task AntiAlt(StoopidTime minAge, PunishmentAction action, [Leftover] IRole role)
|
public async Task AntiAlt(ParsedTimespan minAge, PunishmentAction action, [Leftover] IRole role)
|
||||||
{
|
{
|
||||||
var minAgeMinutes = (int)minAge.Time.TotalMinutes;
|
var minAgeMinutes = (int)minAge.Time.TotalMinutes;
|
||||||
|
|
||||||
|
@ -86,8 +86,8 @@ public partial class Administration
|
||||||
int userThreshold,
|
int userThreshold,
|
||||||
int seconds,
|
int seconds,
|
||||||
PunishmentAction action,
|
PunishmentAction action,
|
||||||
[Leftover] StoopidTime punishTime)
|
[Leftover] ParsedTimespan punishTimespan)
|
||||||
=> InternalAntiRaid(userThreshold, seconds, action, punishTime);
|
=> InternalAntiRaid(userThreshold, seconds, action, punishTimespan);
|
||||||
|
|
||||||
[Cmd]
|
[Cmd]
|
||||||
[RequireContext(ContextType.Guild)]
|
[RequireContext(ContextType.Guild)]
|
||||||
|
@ -100,7 +100,7 @@ public partial class Administration
|
||||||
int userThreshold,
|
int userThreshold,
|
||||||
int seconds = 10,
|
int seconds = 10,
|
||||||
PunishmentAction action = PunishmentAction.Mute,
|
PunishmentAction action = PunishmentAction.Mute,
|
||||||
StoopidTime punishTime = null)
|
ParsedTimespan punishTimespan = null)
|
||||||
{
|
{
|
||||||
if (action == PunishmentAction.AddRole)
|
if (action == PunishmentAction.AddRole)
|
||||||
{
|
{
|
||||||
|
@ -120,13 +120,13 @@ public partial class Administration
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (punishTime is not null)
|
if (punishTimespan is not null)
|
||||||
{
|
{
|
||||||
if (!_service.IsDurationAllowed(action))
|
if (!_service.IsDurationAllowed(action))
|
||||||
await Response().Error(strs.prot_cant_use_time).SendAsync();
|
await Response().Error(strs.prot_cant_use_time).SendAsync();
|
||||||
}
|
}
|
||||||
|
|
||||||
var time = (int?)punishTime?.Time.TotalMinutes ?? 0;
|
var time = (int?)punishTimespan?.Time.TotalMinutes ?? 0;
|
||||||
if (time is < 0 or > 60 * 24)
|
if (time is < 0 or > 60 * 24)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
@ -170,8 +170,8 @@ public partial class Administration
|
||||||
[RequireContext(ContextType.Guild)]
|
[RequireContext(ContextType.Guild)]
|
||||||
[UserPerm(GuildPerm.Administrator)]
|
[UserPerm(GuildPerm.Administrator)]
|
||||||
[Priority(1)]
|
[Priority(1)]
|
||||||
public Task AntiSpam(int messageCount, PunishmentAction action, [Leftover] StoopidTime punishTime)
|
public Task AntiSpam(int messageCount, PunishmentAction action, [Leftover] ParsedTimespan punishTimespan)
|
||||||
=> InternalAntiSpam(messageCount, action, punishTime);
|
=> InternalAntiSpam(messageCount, action, punishTimespan);
|
||||||
|
|
||||||
[Cmd]
|
[Cmd]
|
||||||
[RequireContext(ContextType.Guild)]
|
[RequireContext(ContextType.Guild)]
|
||||||
|
@ -183,19 +183,19 @@ public partial class Administration
|
||||||
private async Task InternalAntiSpam(
|
private async Task InternalAntiSpam(
|
||||||
int messageCount,
|
int messageCount,
|
||||||
PunishmentAction action,
|
PunishmentAction action,
|
||||||
StoopidTime timeData = null,
|
ParsedTimespan timespanData = null,
|
||||||
IRole role = null)
|
IRole role = null)
|
||||||
{
|
{
|
||||||
if (messageCount is < 2 or > 10)
|
if (messageCount is < 2 or > 10)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (timeData is not null)
|
if (timespanData is not null)
|
||||||
{
|
{
|
||||||
if (!_service.IsDurationAllowed(action))
|
if (!_service.IsDurationAllowed(action))
|
||||||
await Response().Error(strs.prot_cant_use_time).SendAsync();
|
await Response().Error(strs.prot_cant_use_time).SendAsync();
|
||||||
}
|
}
|
||||||
|
|
||||||
var time = (int?)timeData?.Time.TotalMinutes ?? 0;
|
var time = (int?)timespanData?.Time.TotalMinutes ?? 0;
|
||||||
if (time is < 0 or > 60 * 24)
|
if (time is < 0 or > 60 * 24)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,6 @@
|
||||||
#nullable disable
|
#nullable disable
|
||||||
|
using Google.Protobuf.WellKnownTypes;
|
||||||
|
using EllieBot.Common.TypeReaders.Models;
|
||||||
using SixLabors.ImageSharp.PixelFormats;
|
using SixLabors.ImageSharp.PixelFormats;
|
||||||
using Color = SixLabors.ImageSharp.Color;
|
using Color = SixLabors.ImageSharp.Color;
|
||||||
|
|
||||||
|
@ -13,13 +15,18 @@ public partial class Administration
|
||||||
Excl
|
Excl
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private readonly TempRoleService _tempRoleService;
|
||||||
private readonly IServiceProvider _services;
|
private readonly IServiceProvider _services;
|
||||||
private StickyRolesService _stickyRoleSvc;
|
private StickyRolesService _stickyRoleSvc;
|
||||||
|
|
||||||
public RoleCommands(IServiceProvider services, StickyRolesService stickyRoleSvc)
|
public RoleCommands(
|
||||||
|
IServiceProvider services,
|
||||||
|
StickyRolesService stickyRoleSvc,
|
||||||
|
TempRoleService tempRoleService)
|
||||||
{
|
{
|
||||||
_services = services;
|
_services = services;
|
||||||
_stickyRoleSvc = stickyRoleSvc;
|
_stickyRoleSvc = stickyRoleSvc;
|
||||||
|
_tempRoleService = tempRoleService;
|
||||||
}
|
}
|
||||||
|
|
||||||
[Cmd]
|
[Cmd]
|
||||||
|
@ -34,13 +41,16 @@ public partial class Administration
|
||||||
return;
|
return;
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
await targetUser.AddRoleAsync(roleToAdd, new RequestOptions()
|
await targetUser.AddRoleAsync(roleToAdd,
|
||||||
{
|
new RequestOptions()
|
||||||
AuditLogReason = $"Added by [{ctx.User.Username}]"
|
{
|
||||||
});
|
AuditLogReason = $"Added by [{ctx.User.Username}]"
|
||||||
|
});
|
||||||
|
|
||||||
await Response().Confirm(strs.setrole(Format.Bold(roleToAdd.Name),
|
await Response()
|
||||||
Format.Bold(targetUser.ToString()))).SendAsync();
|
.Confirm(strs.setrole(Format.Bold(roleToAdd.Name),
|
||||||
|
Format.Bold(targetUser.ToString())))
|
||||||
|
.SendAsync();
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
|
@ -62,8 +72,10 @@ public partial class Administration
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
await targetUser.RemoveRoleAsync(roleToRemove);
|
await targetUser.RemoveRoleAsync(roleToRemove);
|
||||||
await Response().Confirm(strs.remrole(Format.Bold(roleToRemove.Name),
|
await Response()
|
||||||
Format.Bold(targetUser.ToString()))).SendAsync();
|
.Confirm(strs.remrole(Format.Bold(roleToRemove.Name),
|
||||||
|
Format.Bold(targetUser.ToString())))
|
||||||
|
.SendAsync();
|
||||||
}
|
}
|
||||||
catch
|
catch
|
||||||
{
|
{
|
||||||
|
@ -204,5 +216,29 @@ public partial class Administration
|
||||||
await Response().Confirm(strs.sticky_roles_disabled).SendAsync();
|
await Response().Confirm(strs.sticky_roles_disabled).SendAsync();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Cmd]
|
||||||
|
[RequireContext(ContextType.Guild)]
|
||||||
|
[UserPerm(GuildPerm.Administrator)]
|
||||||
|
[BotPerm(GuildPerm.ManageRoles)]
|
||||||
|
public async Task TempRole(ParsedTimespan timespan, IUser user, [Leftover] IRole role)
|
||||||
|
{
|
||||||
|
if (!await CheckRoleHierarchy(role))
|
||||||
|
{
|
||||||
|
await Response()
|
||||||
|
.Error(strs.hierarchy)
|
||||||
|
.SendAsync();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
await _tempRoleService.AddTempRoleAsync(ctx.Guild.Id, role.Id, user.Id, timespan.Time);
|
||||||
|
|
||||||
|
|
||||||
|
await Response()
|
||||||
|
.Confirm(strs.temp_role_added(user.Mention,
|
||||||
|
Format.Bold(role.Name),
|
||||||
|
TimestampTag.FromDateTime(DateTime.UtcNow.Add(timespan.Time), TimestampTagStyles.Relative)))
|
||||||
|
.SendAsync();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
140
src/EllieBot/Modules/Administration/Role/TempRoleService.cs
Normal file
140
src/EllieBot/Modules/Administration/Role/TempRoleService.cs
Normal file
|
@ -0,0 +1,140 @@
|
||||||
|
using LinqToDB;
|
||||||
|
using LinqToDB.EntityFrameworkCore;
|
||||||
|
using EllieBot.Common.ModuleBehaviors;
|
||||||
|
using EllieBot.Db.Models;
|
||||||
|
|
||||||
|
namespace EllieBot.Modules.Administration;
|
||||||
|
|
||||||
|
public class TempRoleService : IReadyExecutor, IEService
|
||||||
|
{
|
||||||
|
private readonly DbService _db;
|
||||||
|
private readonly DiscordSocketClient _client;
|
||||||
|
private readonly IBotCreds _creds;
|
||||||
|
|
||||||
|
private TaskCompletionSource<bool> _tcs = new();
|
||||||
|
|
||||||
|
public TempRoleService(
|
||||||
|
DbService db,
|
||||||
|
DiscordSocketClient client,
|
||||||
|
IBotCreds creds)
|
||||||
|
{
|
||||||
|
_db = db;
|
||||||
|
_client = client;
|
||||||
|
_creds = creds;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task AddTempRoleAsync(
|
||||||
|
ulong guildId,
|
||||||
|
ulong roleId,
|
||||||
|
ulong userId,
|
||||||
|
TimeSpan duration)
|
||||||
|
{
|
||||||
|
if (duration == TimeSpan.Zero)
|
||||||
|
{
|
||||||
|
await using var uow = _db.GetDbContext();
|
||||||
|
await uow.GetTable<TempRole>()
|
||||||
|
.Where(x => x.GuildId == guildId && x.UserId == userId)
|
||||||
|
.DeleteAsync();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var until = DateTime.UtcNow.Add(duration);
|
||||||
|
await using var ctx = _db.GetDbContext();
|
||||||
|
await ctx.GetTable<TempRole>()
|
||||||
|
.InsertOrUpdateAsync(() => new()
|
||||||
|
{
|
||||||
|
GuildId = guildId,
|
||||||
|
RoleId = roleId,
|
||||||
|
UserId = userId,
|
||||||
|
Remove = false,
|
||||||
|
ExpiresAt = until
|
||||||
|
},
|
||||||
|
(old) => new()
|
||||||
|
{
|
||||||
|
ExpiresAt = until,
|
||||||
|
},
|
||||||
|
() => new()
|
||||||
|
{
|
||||||
|
GuildId = guildId,
|
||||||
|
UserId = userId,
|
||||||
|
RoleId = roleId
|
||||||
|
});
|
||||||
|
|
||||||
|
_tcs.TrySetResult(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task OnReadyAsync()
|
||||||
|
{
|
||||||
|
while (true)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
_tcs = new(TaskCreationOptions.RunContinuationsAsynchronously);
|
||||||
|
var latest = await _db.GetDbContext()
|
||||||
|
.GetTable<TempRole>()
|
||||||
|
.Where(x => Linq2DbExpressions.GuildOnShard(x.GuildId,
|
||||||
|
_creds.TotalShards,
|
||||||
|
_client.ShardId))
|
||||||
|
.OrderBy(x => x.ExpiresAt)
|
||||||
|
.FirstOrDefaultAsyncLinqToDB();
|
||||||
|
|
||||||
|
if (latest == default)
|
||||||
|
{
|
||||||
|
await _tcs.Task;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
var now = DateTime.UtcNow;
|
||||||
|
if (latest.ExpiresAt > now)
|
||||||
|
{
|
||||||
|
await Task.WhenAny(Task.Delay(latest.ExpiresAt - now), _tcs.Task);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
var deleted = await _db.GetDbContext()
|
||||||
|
.GetTable<TempRole>()
|
||||||
|
.Where(x => Linq2DbExpressions.GuildOnShard(x.GuildId,
|
||||||
|
_creds.TotalShards,
|
||||||
|
_client.ShardId)
|
||||||
|
&& x.ExpiresAt <= now)
|
||||||
|
.DeleteWithOutputAsync();
|
||||||
|
|
||||||
|
foreach (var d in deleted)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
await RemoveRole(d);
|
||||||
|
}
|
||||||
|
catch
|
||||||
|
{
|
||||||
|
Log.Warning("Unable to remove temp role {RoleId} from user {UserId}",
|
||||||
|
d.RoleId,
|
||||||
|
d.UserId);
|
||||||
|
}
|
||||||
|
|
||||||
|
await Task.Delay(1000);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
Log.Error(ex, "Unexpected error occurred in temprole loop");
|
||||||
|
await Task.Delay(1000);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task RemoveRole(TempRole tempRole)
|
||||||
|
{
|
||||||
|
var guild = _client.GetGuild(tempRole.GuildId);
|
||||||
|
|
||||||
|
var role = guild?.GetRole(tempRole.RoleId);
|
||||||
|
if (role is null)
|
||||||
|
return;
|
||||||
|
|
||||||
|
var user = guild?.GetUser(tempRole.UserId);
|
||||||
|
if (user is null)
|
||||||
|
return;
|
||||||
|
|
||||||
|
await user.RemoveRoleAsync(role);
|
||||||
|
}
|
||||||
|
}
|
|
@ -313,7 +313,7 @@ public partial class Administration
|
||||||
int number,
|
int number,
|
||||||
AddRole _,
|
AddRole _,
|
||||||
IRole role,
|
IRole role,
|
||||||
StoopidTime time = null)
|
ParsedTimespan timespan = null)
|
||||||
{
|
{
|
||||||
var punish = PunishmentAction.AddRole;
|
var punish = PunishmentAction.AddRole;
|
||||||
|
|
||||||
|
@ -324,12 +324,12 @@ public partial class Administration
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
var success = await _service.WarnPunish(ctx.Guild.Id, number, punish, time, role);
|
var success = await _service.WarnPunish(ctx.Guild.Id, number, punish, timespan, role);
|
||||||
|
|
||||||
if (!success)
|
if (!success)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (time is null)
|
if (timespan is null)
|
||||||
{
|
{
|
||||||
await Response()
|
await Response()
|
||||||
.Confirm(strs.warn_punish_set(Format.Bold(punish.ToString()),
|
.Confirm(strs.warn_punish_set(Format.Bold(punish.ToString()),
|
||||||
|
@ -341,7 +341,7 @@ public partial class Administration
|
||||||
await Response()
|
await Response()
|
||||||
.Confirm(strs.warn_punish_set_timed(Format.Bold(punish.ToString()),
|
.Confirm(strs.warn_punish_set_timed(Format.Bold(punish.ToString()),
|
||||||
Format.Bold(number.ToString()),
|
Format.Bold(number.ToString()),
|
||||||
Format.Bold(time.Input)))
|
Format.Bold(timespan.Input)))
|
||||||
.SendAsync();
|
.SendAsync();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -349,7 +349,7 @@ public partial class Administration
|
||||||
[Cmd]
|
[Cmd]
|
||||||
[RequireContext(ContextType.Guild)]
|
[RequireContext(ContextType.Guild)]
|
||||||
[UserPerm(GuildPerm.BanMembers)]
|
[UserPerm(GuildPerm.BanMembers)]
|
||||||
public async Task WarnPunish(int number, PunishmentAction punish, StoopidTime time = null)
|
public async Task WarnPunish(int number, PunishmentAction punish, ParsedTimespan timespan = null)
|
||||||
{
|
{
|
||||||
// this should never happen. Addrole has its own method with higher priority
|
// this should never happen. Addrole has its own method with higher priority
|
||||||
// also disallow warn punishment for getting warned
|
// also disallow warn punishment for getting warned
|
||||||
|
@ -357,15 +357,15 @@ public partial class Administration
|
||||||
return;
|
return;
|
||||||
|
|
||||||
// you must specify the time for timeout
|
// you must specify the time for timeout
|
||||||
if (punish is PunishmentAction.TimeOut && time is null)
|
if (punish is PunishmentAction.TimeOut && timespan is null)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
var success = await _service.WarnPunish(ctx.Guild.Id, number, punish, time);
|
var success = await _service.WarnPunish(ctx.Guild.Id, number, punish, timespan);
|
||||||
|
|
||||||
if (!success)
|
if (!success)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (time is null)
|
if (timespan is null)
|
||||||
{
|
{
|
||||||
await Response()
|
await Response()
|
||||||
.Confirm(strs.warn_punish_set(Format.Bold(punish.ToString()),
|
.Confirm(strs.warn_punish_set(Format.Bold(punish.ToString()),
|
||||||
|
@ -377,7 +377,7 @@ public partial class Administration
|
||||||
await Response()
|
await Response()
|
||||||
.Confirm(strs.warn_punish_set_timed(Format.Bold(punish.ToString()),
|
.Confirm(strs.warn_punish_set_timed(Format.Bold(punish.ToString()),
|
||||||
Format.Bold(number.ToString()),
|
Format.Bold(number.ToString()),
|
||||||
Format.Bold(time.Input)))
|
Format.Bold(timespan.Input)))
|
||||||
.SendAsync();
|
.SendAsync();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -417,17 +417,17 @@ public partial class Administration
|
||||||
[UserPerm(GuildPerm.BanMembers)]
|
[UserPerm(GuildPerm.BanMembers)]
|
||||||
[BotPerm(GuildPerm.BanMembers)]
|
[BotPerm(GuildPerm.BanMembers)]
|
||||||
[Priority(1)]
|
[Priority(1)]
|
||||||
public Task Ban(StoopidTime time, IUser user, [Leftover] string msg = null)
|
public Task Ban(ParsedTimespan timespan, IUser user, [Leftover] string msg = null)
|
||||||
=> Ban(time, user.Id, msg);
|
=> Ban(timespan, user.Id, msg);
|
||||||
|
|
||||||
[Cmd]
|
[Cmd]
|
||||||
[RequireContext(ContextType.Guild)]
|
[RequireContext(ContextType.Guild)]
|
||||||
[UserPerm(GuildPerm.BanMembers)]
|
[UserPerm(GuildPerm.BanMembers)]
|
||||||
[BotPerm(GuildPerm.BanMembers)]
|
[BotPerm(GuildPerm.BanMembers)]
|
||||||
[Priority(0)]
|
[Priority(0)]
|
||||||
public async Task Ban(StoopidTime time, ulong userId, [Leftover] string msg = null)
|
public async Task Ban(ParsedTimespan timespan, ulong userId, [Leftover] string msg = null)
|
||||||
{
|
{
|
||||||
if (time.Time > TimeSpan.FromDays(49))
|
if (timespan.Time > TimeSpan.FromDays(49))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
var guildUser = await ((DiscordSocketClient)Context.Client).Rest.GetGuildUserAsync(ctx.Guild.Id, userId);
|
var guildUser = await ((DiscordSocketClient)Context.Client).Rest.GetGuildUserAsync(ctx.Guild.Id, userId);
|
||||||
|
@ -444,7 +444,7 @@ public partial class Administration
|
||||||
{
|
{
|
||||||
var defaultMessage = GetText(strs.bandm(Format.Bold(ctx.Guild.Name), msg));
|
var defaultMessage = GetText(strs.bandm(Format.Bold(ctx.Guild.Name), msg));
|
||||||
var smartText =
|
var smartText =
|
||||||
await _service.GetBanUserDmEmbed(Context, guildUser, defaultMessage, msg, time.Time);
|
await _service.GetBanUserDmEmbed(Context, guildUser, defaultMessage, msg, timespan.Time);
|
||||||
if (smartText is not null)
|
if (smartText is not null)
|
||||||
await Response().User(guildUser).Text(smartText).SendAsync();
|
await Response().User(guildUser).Text(smartText).SendAsync();
|
||||||
}
|
}
|
||||||
|
@ -456,14 +456,14 @@ public partial class Administration
|
||||||
|
|
||||||
var user = await ctx.Client.GetUserAsync(userId);
|
var user = await ctx.Client.GetUserAsync(userId);
|
||||||
var banPrune = await _service.GetBanPruneAsync(ctx.Guild.Id) ?? 7;
|
var banPrune = await _service.GetBanPruneAsync(ctx.Guild.Id) ?? 7;
|
||||||
await _mute.TimedBan(ctx.Guild, userId, time.Time, (ctx.User + " | " + msg).TrimTo(512), banPrune);
|
await _mute.TimedBan(ctx.Guild, userId, timespan.Time, (ctx.User + " | " + msg).TrimTo(512), banPrune);
|
||||||
var toSend = CreateEmbed()
|
var toSend = CreateEmbed()
|
||||||
.WithOkColor()
|
.WithOkColor()
|
||||||
.WithTitle("⛔️ " + GetText(strs.banned_user))
|
.WithTitle("⛔️ " + GetText(strs.banned_user))
|
||||||
.AddField(GetText(strs.username), user?.ToString() ?? userId.ToString(), true)
|
.AddField(GetText(strs.username), user?.ToString() ?? userId.ToString(), true)
|
||||||
.AddField("ID", userId.ToString(), true)
|
.AddField("ID", userId.ToString(), true)
|
||||||
.AddField(GetText(strs.duration),
|
.AddField(GetText(strs.duration),
|
||||||
time.Time.ToPrettyStringHm(),
|
timespan.Time.ToPrettyStringHm(),
|
||||||
true);
|
true);
|
||||||
|
|
||||||
if (dmFailed)
|
if (dmFailed)
|
||||||
|
@ -601,7 +601,7 @@ public partial class Administration
|
||||||
[UserPerm(GuildPerm.BanMembers)]
|
[UserPerm(GuildPerm.BanMembers)]
|
||||||
[BotPerm(GuildPerm.BanMembers)]
|
[BotPerm(GuildPerm.BanMembers)]
|
||||||
[Priority(1)]
|
[Priority(1)]
|
||||||
public Task BanMessageTest(StoopidTime duration, [Leftover] string reason = null)
|
public Task BanMessageTest(ParsedTimespan duration, [Leftover] string reason = null)
|
||||||
=> InternalBanMessageTest(reason, duration.Time);
|
=> InternalBanMessageTest(reason, duration.Time);
|
||||||
|
|
||||||
private async Task InternalBanMessageTest(string reason, TimeSpan? duration)
|
private async Task InternalBanMessageTest(string reason, TimeSpan? duration)
|
||||||
|
@ -791,7 +791,7 @@ public partial class Administration
|
||||||
[UserPerm(GuildPerm.ModerateMembers)]
|
[UserPerm(GuildPerm.ModerateMembers)]
|
||||||
[BotPerm(GuildPerm.ModerateMembers)]
|
[BotPerm(GuildPerm.ModerateMembers)]
|
||||||
[Priority(2)]
|
[Priority(2)]
|
||||||
public async Task Timeout(IUser globalUser, StoopidTime time, [Leftover] string msg = null)
|
public async Task Timeout(IUser globalUser, ParsedTimespan timespan, [Leftover] string msg = null)
|
||||||
{
|
{
|
||||||
var user = await ctx.Guild.GetUserAsync(globalUser.Id);
|
var user = await ctx.Guild.GetUserAsync(globalUser.Id);
|
||||||
|
|
||||||
|
@ -817,7 +817,7 @@ public partial class Administration
|
||||||
dmFailed = true;
|
dmFailed = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
await user.SetTimeOutAsync(time.Time);
|
await user.SetTimeOutAsync(timespan.Time);
|
||||||
|
|
||||||
var toSend = CreateEmbed()
|
var toSend = CreateEmbed()
|
||||||
.WithOkColor()
|
.WithOkColor()
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
#nullable disable
|
#nullable disable
|
||||||
using EllieBot.Modules.Games.Services;
|
using EllieBot.Modules.Games.Services;
|
||||||
|
using System.Text;
|
||||||
|
|
||||||
namespace EllieBot.Modules.Games;
|
namespace EllieBot.Modules.Games;
|
||||||
|
|
||||||
|
@ -38,10 +39,72 @@ public partial class Games : EllieModule<GamesService>
|
||||||
return;
|
return;
|
||||||
|
|
||||||
var res = _service.GetEightballResponse(ctx.User.Id, question);
|
var res = _service.GetEightballResponse(ctx.User.Id, question);
|
||||||
await Response().Embed(CreateEmbed()
|
await Response()
|
||||||
.WithOkColor()
|
.Embed(CreateEmbed()
|
||||||
.WithDescription(ctx.User.ToString())
|
.WithOkColor()
|
||||||
.AddField("❓ " + GetText(strs.question), question)
|
.WithDescription(ctx.User.ToString())
|
||||||
.AddField("🎱 " + GetText(strs._8ball), res)).SendAsync();
|
.AddField("❓ " + GetText(strs.question), question)
|
||||||
|
.AddField("🎱 " + GetText(strs._8ball), res))
|
||||||
|
.SendAsync();
|
||||||
|
}
|
||||||
|
|
||||||
|
private readonly string[] _numberEmojis = ["0️⃣", "1️⃣", "2️⃣", "3️⃣", "4️⃣", "5️⃣", "6️⃣", "7️⃣", "8️⃣", "9️⃣"];
|
||||||
|
|
||||||
|
[Cmd]
|
||||||
|
public async Task Minesweeper(int numberOfMines = 12)
|
||||||
|
{
|
||||||
|
var boardSizeX = 9;
|
||||||
|
var boardSizeY = 10;
|
||||||
|
|
||||||
|
if (numberOfMines < 1)
|
||||||
|
{
|
||||||
|
numberOfMines = 1;
|
||||||
|
}
|
||||||
|
else if (numberOfMines > boardSizeX * boardSizeY / 2)
|
||||||
|
{
|
||||||
|
numberOfMines = boardSizeX * boardSizeY / 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
var mineIndicies = Enumerable.Range(0, boardSizeX * boardSizeY)
|
||||||
|
.ToArray()
|
||||||
|
.Shuffle()
|
||||||
|
.Take(numberOfMines)
|
||||||
|
.ToHashSet();
|
||||||
|
|
||||||
|
string GetNumberOnCell(int x, int y)
|
||||||
|
{
|
||||||
|
var count = 0;
|
||||||
|
for (var i = -1; i < 2; i++)
|
||||||
|
{
|
||||||
|
for (var j = -1; j < 2; j++)
|
||||||
|
{
|
||||||
|
if (y + j >= boardSizeY || y + j < 0)
|
||||||
|
continue;
|
||||||
|
if (x + i >= boardSizeX || x + i < 0)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
var boardIndex = (y + j) * boardSizeX + (x + i);
|
||||||
|
if (mineIndicies.Contains(boardIndex))
|
||||||
|
count++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return _numberEmojis[count];
|
||||||
|
}
|
||||||
|
|
||||||
|
var sb = new StringBuilder();
|
||||||
|
sb.AppendLine($"### Minesweeper [{numberOfMines}\\💣]");
|
||||||
|
for (var i = 0; i < boardSizeY; i++)
|
||||||
|
{
|
||||||
|
for (var j = 0; j < boardSizeX; j++)
|
||||||
|
{
|
||||||
|
var emoji = mineIndicies.Contains((i * boardSizeX) + j) ? "💣" : GetNumberOnCell(j, i);
|
||||||
|
sb.Append($"||{emoji}||");
|
||||||
|
}
|
||||||
|
|
||||||
|
sb.AppendLine();
|
||||||
|
}
|
||||||
|
|
||||||
|
await Response().Text(sb.ToString()).SendAsync();
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -9,6 +9,7 @@ public sealed class AfkService : IEService, IReadyExecutor
|
||||||
private readonly MessageSenderService _mss;
|
private readonly MessageSenderService _mss;
|
||||||
|
|
||||||
private static readonly TimeSpan _maxAfkDuration = 8.Hours();
|
private static readonly TimeSpan _maxAfkDuration = 8.Hours();
|
||||||
|
|
||||||
public AfkService(IBotCache cache, DiscordSocketClient client, MessageSenderService mss)
|
public AfkService(IBotCache cache, DiscordSocketClient client, MessageSenderService mss)
|
||||||
{
|
{
|
||||||
_cache = cache;
|
_cache = cache;
|
||||||
|
@ -19,6 +20,9 @@ public sealed class AfkService : IEService, IReadyExecutor
|
||||||
private static TypedKey<string> GetKey(ulong userId)
|
private static TypedKey<string> GetKey(ulong userId)
|
||||||
=> new($"afk:msg:{userId}");
|
=> new($"afk:msg:{userId}");
|
||||||
|
|
||||||
|
private static TypedKey<bool> GetRecentlySentKey(ulong userId, ulong channelId)
|
||||||
|
=> new($"afk:recent:{userId}:{channelId}");
|
||||||
|
|
||||||
public async Task<bool> SetAfkAsync(ulong userId, string text)
|
public async Task<bool> SetAfkAsync(ulong userId, string text)
|
||||||
{
|
{
|
||||||
var added = await _cache.AddAsync(GetKey(userId), text, _maxAfkDuration, overwrite: true);
|
var added = await _cache.AddAsync(GetKey(userId), text, _maxAfkDuration, overwrite: true);
|
||||||
|
@ -43,9 +47,7 @@ public sealed class AfkService : IEService, IReadyExecutor
|
||||||
msg.DeleteAfter(5);
|
msg.DeleteAfter(5);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
|
@ -61,7 +63,7 @@ public sealed class AfkService : IEService, IReadyExecutor
|
||||||
await Task.Delay(_maxAfkDuration);
|
await Task.Delay(_maxAfkDuration);
|
||||||
_client.MessageReceived -= StopAfk;
|
_client.MessageReceived -= StopAfk;
|
||||||
});
|
});
|
||||||
|
|
||||||
return added;
|
return added;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -72,36 +74,29 @@ public sealed class AfkService : IEService, IReadyExecutor
|
||||||
return Task.CompletedTask;
|
return Task.CompletedTask;
|
||||||
}
|
}
|
||||||
|
|
||||||
private Task TryTriggerAfkMessage(SocketMessage arg)
|
private Task TryTriggerAfkMessage(SocketMessage sm)
|
||||||
{
|
{
|
||||||
if (arg.Author.IsBot || arg.Author.IsWebhook)
|
if (sm.Author.IsBot || sm.Author.IsWebhook)
|
||||||
return Task.CompletedTask;
|
return Task.CompletedTask;
|
||||||
|
|
||||||
if (arg is not IUserMessage uMsg || uMsg.Channel is not ITextChannel tc)
|
if (sm is not IUserMessage uMsg || uMsg.Channel is not ITextChannel tc)
|
||||||
return Task.CompletedTask;
|
return Task.CompletedTask;
|
||||||
|
|
||||||
if ((arg.MentionedUsers.Count is 0 or > 3) && uMsg.ReferencedMessage is null)
|
if ((sm.MentionedUsers.Count is 0 or > 3) && uMsg.ReferencedMessage is null)
|
||||||
return Task.CompletedTask;
|
return Task.CompletedTask;
|
||||||
|
|
||||||
_ = Task.Run(async () =>
|
_ = Task.Run(async () =>
|
||||||
{
|
{
|
||||||
var botUser = await tc.Guild.GetCurrentUserAsync();
|
|
||||||
|
|
||||||
var perms = botUser.GetPermissions(tc);
|
|
||||||
|
|
||||||
if (!perms.SendMessages)
|
|
||||||
return;
|
|
||||||
|
|
||||||
ulong mentionedUserId = 0;
|
ulong mentionedUserId = 0;
|
||||||
|
|
||||||
if (arg.MentionedUsers.Count <= 3)
|
if (sm.MentionedUsers.Count <= 3)
|
||||||
{
|
{
|
||||||
foreach (var uid in uMsg.MentionedUserIds)
|
foreach (var uid in uMsg.MentionedUserIds)
|
||||||
{
|
{
|
||||||
if (uid == arg.Author.Id)
|
if (uid == sm.Author.Id)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
if (arg.Content.StartsWith($"<@{uid}>") || arg.Content.StartsWith($"<@!{uid}>"))
|
if (sm.Content.StartsWith($"<@{uid}>") || sm.Content.StartsWith($"<@!{uid}>"))
|
||||||
{
|
{
|
||||||
mentionedUserId = uid;
|
mentionedUserId = uid;
|
||||||
break;
|
break;
|
||||||
|
@ -115,7 +110,7 @@ public sealed class AfkService : IEService, IReadyExecutor
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
mentionedUserId = repliedUserId;
|
mentionedUserId = repliedUserId;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -125,16 +120,35 @@ public sealed class AfkService : IEService, IReadyExecutor
|
||||||
if (result.TryPickT0(out var msg, out _))
|
if (result.TryPickT0(out var msg, out _))
|
||||||
{
|
{
|
||||||
var st = SmartText.CreateFrom(msg);
|
var st = SmartText.CreateFrom(msg);
|
||||||
|
|
||||||
st = $"The user you've pinged (<#{mentionedUserId}>) is AFK: " + st;
|
st = $"The user you've pinged (<#{mentionedUserId}>) is AFK: " + st;
|
||||||
|
|
||||||
var toDelete = await _mss.Response(arg.Channel)
|
var toDelete = await _mss.Response(sm.Channel)
|
||||||
.User(arg.Author)
|
.User(sm.Author)
|
||||||
.Message(uMsg)
|
.Message(uMsg)
|
||||||
.Text(st)
|
.Text(st)
|
||||||
.SendAsync();
|
.SendAsync();
|
||||||
|
|
||||||
toDelete.DeleteAfter(30);
|
toDelete.DeleteAfter(30);
|
||||||
|
|
||||||
|
var botUser = await tc.Guild.GetCurrentUserAsync();
|
||||||
|
var perms = botUser.GetPermissions(tc);
|
||||||
|
if (!perms.SendMessages)
|
||||||
|
return;
|
||||||
|
|
||||||
|
var key = GetRecentlySentKey(mentionedUserId, sm.Channel.Id);
|
||||||
|
var recent = await _cache.GetAsync(key);
|
||||||
|
|
||||||
|
if (!recent.TryPickT0(out _, out _))
|
||||||
|
{
|
||||||
|
var chMsg = await _mss.Response(sm.Channel)
|
||||||
|
.Message(uMsg)
|
||||||
|
.Pending(strs.user_afk($"<@{mentionedUserId}>"))
|
||||||
|
.SendAsync();
|
||||||
|
|
||||||
|
chMsg.DeleteAfter(5);
|
||||||
|
await _cache.AddAsync(key, true, expiry: TimeSpan.FromMinutes(5));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch (HttpException ex)
|
catch (HttpException ex)
|
||||||
|
|
|
@ -98,10 +98,10 @@ public partial class Utility
|
||||||
return;
|
return;
|
||||||
|
|
||||||
var embed = CreateEmbed()
|
var embed = CreateEmbed()
|
||||||
.WithOkColor()
|
.WithOkColor()
|
||||||
.WithTitle(GetText(guildId is not null
|
.WithTitle(GetText(guildId is not null
|
||||||
? strs.reminder_server_list
|
? strs.reminder_server_list
|
||||||
: strs.reminder_list));
|
: strs.reminder_list));
|
||||||
|
|
||||||
List<Reminder> rems;
|
List<Reminder> rems;
|
||||||
if (guildId is { } gid)
|
if (guildId is { } gid)
|
||||||
|
@ -193,23 +193,14 @@ public partial class Utility
|
||||||
message = message.SanitizeAllMentions();
|
message = message.SanitizeAllMentions();
|
||||||
}
|
}
|
||||||
|
|
||||||
var rem = new Reminder
|
await _service.AddReminderAsync(ctx.User.Id,
|
||||||
{
|
targetId,
|
||||||
ChannelId = targetId,
|
ctx.Guild?.Id,
|
||||||
IsPrivate = isPrivate,
|
isPrivate,
|
||||||
When = time,
|
time,
|
||||||
Message = message,
|
message,
|
||||||
UserId = ctx.User.Id,
|
ReminderType.User);
|
||||||
ServerId = ctx.Guild?.Id ?? 0
|
|
||||||
};
|
|
||||||
|
|
||||||
await using (var uow = _db.GetDbContext())
|
|
||||||
{
|
|
||||||
uow.Set<Reminder>().Add(rem);
|
|
||||||
await uow.SaveChangesAsync();
|
|
||||||
}
|
|
||||||
|
|
||||||
// var gTime = ctx.Guild is null ? time : TimeZoneInfo.ConvertTime(time, _tz.GetTimeZoneOrUtc(ctx.Guild.Id));
|
|
||||||
await Response()
|
await Response()
|
||||||
.Confirm($"\u23f0 {GetText(strs.remind2(
|
.Confirm($"\u23f0 {GetText(strs.remind2(
|
||||||
Format.Bold(!isPrivate ? $"<#{targetId}>" : ctx.User.Username),
|
Format.Bold(!isPrivate ? $"<#{targetId}>" : ctx.User.Username),
|
||||||
|
|
|
@ -21,6 +21,8 @@ public class RemindService : IEService, IReadyExecutor, IRemindService
|
||||||
private readonly IMessageSenderService _sender;
|
private readonly IMessageSenderService _sender;
|
||||||
private readonly CultureInfo _culture;
|
private readonly CultureInfo _culture;
|
||||||
|
|
||||||
|
private TaskCompletionSource<bool> _tcs;
|
||||||
|
|
||||||
public RemindService(
|
public RemindService(
|
||||||
DiscordSocketClient client,
|
DiscordSocketClient client,
|
||||||
DbService db,
|
DbService db,
|
||||||
|
@ -44,8 +46,7 @@ public class RemindService : IEService, IReadyExecutor, IRemindService
|
||||||
|
|
||||||
public async Task OnReadyAsync()
|
public async Task OnReadyAsync()
|
||||||
{
|
{
|
||||||
using var timer = new PeriodicTimer(TimeSpan.FromSeconds(15));
|
while (true)
|
||||||
while (await timer.WaitForNextTickAsync())
|
|
||||||
{
|
{
|
||||||
await OnReminderLoopTickInternalAsync();
|
await OnReminderLoopTickInternalAsync();
|
||||||
}
|
}
|
||||||
|
@ -55,8 +56,7 @@ public class RemindService : IEService, IReadyExecutor, IRemindService
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
var now = DateTime.UtcNow;
|
var reminders = await GetRemindersBeforeAsync();
|
||||||
var reminders = await GetRemindersBeforeAsync(now);
|
|
||||||
if (reminders.Count == 0)
|
if (reminders.Count == 0)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
@ -67,7 +67,6 @@ public class RemindService : IEService, IReadyExecutor, IRemindService
|
||||||
{
|
{
|
||||||
var executedReminders = group.ToList();
|
var executedReminders = group.ToList();
|
||||||
await executedReminders.Select(ReminderTimerAction).WhenAll();
|
await executedReminders.Select(ReminderTimerAction).WhenAll();
|
||||||
await RemoveReminders(executedReminders.Select(x => x.Id));
|
|
||||||
await Task.Delay(1500);
|
await Task.Delay(1500);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -80,21 +79,51 @@ public class RemindService : IEService, IReadyExecutor, IRemindService
|
||||||
private async Task RemoveReminders(IEnumerable<int> reminders)
|
private async Task RemoveReminders(IEnumerable<int> reminders)
|
||||||
{
|
{
|
||||||
await using var uow = _db.GetDbContext();
|
await using var uow = _db.GetDbContext();
|
||||||
await uow.Set<Reminder>()
|
await uow.GetTable<Reminder>()
|
||||||
.ToLinqToDBTable()
|
|
||||||
.DeleteAsync(x => reminders.Contains(x.Id));
|
.DeleteAsync(x => reminders.Contains(x.Id));
|
||||||
|
|
||||||
await uow.SaveChangesAsync();
|
await uow.SaveChangesAsync();
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task<List<Reminder>> GetRemindersBeforeAsync(DateTime now)
|
private async Task<IReadOnlyList<Reminder>> GetRemindersBeforeAsync()
|
||||||
{
|
{
|
||||||
await using var uow = _db.GetDbContext();
|
while (true)
|
||||||
return await uow.Set<Reminder>()
|
{
|
||||||
.ToLinqToDBTable()
|
_tcs = new(TaskCreationOptions.RunContinuationsAsynchronously);
|
||||||
.Where(x => Linq2DbExpressions.GuildOnShard(x.ServerId, _creds.TotalShards, _client.ShardId)
|
await using var uow = _db.GetDbContext();
|
||||||
&& x.When < now)
|
var earliest = await uow.Set<Reminder>()
|
||||||
.ToListAsyncLinqToDB();
|
.ToLinqToDBTable()
|
||||||
|
.Where(x => Linq2DbExpressions.GuildOnShard(x.ServerId,
|
||||||
|
_creds.TotalShards,
|
||||||
|
_client.ShardId))
|
||||||
|
.OrderBy(x => x.When)
|
||||||
|
.FirstOrDefaultAsyncLinqToDB();
|
||||||
|
|
||||||
|
if (earliest == default)
|
||||||
|
{
|
||||||
|
await _tcs.Task;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
var now = DateTime.UtcNow;
|
||||||
|
if (earliest.When > now)
|
||||||
|
{
|
||||||
|
var diff = earliest.When - now;
|
||||||
|
// Log.Information("Waiting for {Diff}", diff);
|
||||||
|
await Task.WhenAny(Task.Delay(diff), _tcs.Task);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
var reminders = await uow.Set<Reminder>()
|
||||||
|
.ToLinqToDBTable()
|
||||||
|
.Where(x => Linq2DbExpressions.GuildOnShard(x.ServerId,
|
||||||
|
_creds.TotalShards,
|
||||||
|
_client.ShardId))
|
||||||
|
.Where(x => x.When <= now)
|
||||||
|
.DeleteWithOutputAsync();
|
||||||
|
|
||||||
|
return reminders;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool TryParseRemindMessage(string input, out RemindObject obj)
|
public bool TryParseRemindMessage(string input, out RemindObject obj)
|
||||||
|
@ -243,21 +272,24 @@ public class RemindService : IEService, IReadyExecutor, IRemindService
|
||||||
string message,
|
string message,
|
||||||
ReminderType reminderType)
|
ReminderType reminderType)
|
||||||
{
|
{
|
||||||
var rem = new Reminder
|
await using (var ctx = _db.GetDbContext())
|
||||||
{
|
{
|
||||||
UserId = userId,
|
await ctx.GetTable<Reminder>()
|
||||||
ChannelId = targetId,
|
.InsertAsync(() => new Reminder
|
||||||
ServerId = guildId ?? 0,
|
{
|
||||||
IsPrivate = isPrivate,
|
UserId = userId,
|
||||||
When = time,
|
ChannelId = targetId,
|
||||||
Message = message,
|
ServerId = guildId ?? 0,
|
||||||
Type = reminderType
|
IsPrivate = isPrivate,
|
||||||
};
|
When = time,
|
||||||
|
Message = message,
|
||||||
|
Type = reminderType,
|
||||||
|
DateAdded = DateTime.UtcNow
|
||||||
|
});
|
||||||
|
await ctx.SaveChangesAsync();
|
||||||
|
}
|
||||||
|
|
||||||
await using var ctx = _db.GetDbContext();
|
_tcs.SetResult(true);
|
||||||
await ctx.Set<Reminder>()
|
|
||||||
.AddAsync(rem);
|
|
||||||
await ctx.SaveChangesAsync();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<List<Reminder>> GetServerReminders(int page, ulong guildId)
|
public async Task<List<Reminder>> GetServerReminders(int page, ulong guildId)
|
||||||
|
|
|
@ -110,14 +110,14 @@ public partial class Utility
|
||||||
[RequireContext(ContextType.Guild)]
|
[RequireContext(ContextType.Guild)]
|
||||||
[UserPerm(GuildPerm.ManageMessages)]
|
[UserPerm(GuildPerm.ManageMessages)]
|
||||||
[Priority(0)]
|
[Priority(0)]
|
||||||
public Task Repeat(StoopidTime interval, [Leftover] string message)
|
public Task Repeat(ParsedTimespan interval, [Leftover] string message)
|
||||||
=> Repeat(ctx.Channel, null, interval, message);
|
=> Repeat(ctx.Channel, null, interval, message);
|
||||||
|
|
||||||
[Cmd]
|
[Cmd]
|
||||||
[RequireContext(ContextType.Guild)]
|
[RequireContext(ContextType.Guild)]
|
||||||
[UserPerm(GuildPerm.ManageMessages)]
|
[UserPerm(GuildPerm.ManageMessages)]
|
||||||
[Priority(0)]
|
[Priority(0)]
|
||||||
public Task Repeat(ITextChannel channel, StoopidTime interval, [Leftover] string message)
|
public Task Repeat(ITextChannel channel, ParsedTimespan interval, [Leftover] string message)
|
||||||
=> Repeat(channel, null, interval, message);
|
=> Repeat(channel, null, interval, message);
|
||||||
|
|
||||||
[Cmd]
|
[Cmd]
|
||||||
|
@ -138,14 +138,14 @@ public partial class Utility
|
||||||
[RequireContext(ContextType.Guild)]
|
[RequireContext(ContextType.Guild)]
|
||||||
[UserPerm(GuildPerm.ManageMessages)]
|
[UserPerm(GuildPerm.ManageMessages)]
|
||||||
[Priority(2)]
|
[Priority(2)]
|
||||||
public Task Repeat(GuildDateTime? timeOfDay, StoopidTime? interval, [Leftover] string message)
|
public Task Repeat(GuildDateTime? timeOfDay, ParsedTimespan? interval, [Leftover] string message)
|
||||||
=> Repeat(ctx.Channel, timeOfDay, interval, message);
|
=> Repeat(ctx.Channel, timeOfDay, interval, message);
|
||||||
|
|
||||||
[Cmd]
|
[Cmd]
|
||||||
[RequireContext(ContextType.Guild)]
|
[RequireContext(ContextType.Guild)]
|
||||||
[UserPerm(GuildPerm.ManageMessages)]
|
[UserPerm(GuildPerm.ManageMessages)]
|
||||||
[Priority(3)]
|
[Priority(3)]
|
||||||
public async Task Repeat(IMessageChannel channel, GuildDateTime? timeOfDay, StoopidTime? interval,
|
public async Task Repeat(IMessageChannel channel, GuildDateTime? timeOfDay, ParsedTimespan? interval,
|
||||||
[Leftover] string message)
|
[Leftover] string message)
|
||||||
{
|
{
|
||||||
if (channel is not ITextChannel txtCh || txtCh.GuildId != ctx.Guild.Id)
|
if (channel is not ITextChannel txtCh || txtCh.GuildId != ctx.Guild.Id)
|
||||||
|
|
|
@ -56,25 +56,18 @@ public partial class Xp : EllieModule<XpService>
|
||||||
public async Task XpNotify()
|
public async Task XpNotify()
|
||||||
{
|
{
|
||||||
var globalSetting = _service.GetNotificationType(ctx.User);
|
var globalSetting = _service.GetNotificationType(ctx.User);
|
||||||
var serverSetting = _service.GetNotificationType(ctx.User.Id, ctx.Guild.Id);
|
|
||||||
|
|
||||||
var embed = CreateEmbed()
|
var embed = CreateEmbed()
|
||||||
.WithOkColor()
|
.WithOkColor()
|
||||||
.AddField(GetText(strs.xpn_setting_global), GetNotifLocationString(globalSetting))
|
.AddField(GetText(strs.xpn_setting_global), GetNotifLocationString(globalSetting));
|
||||||
.AddField(GetText(strs.xpn_setting_server), GetNotifLocationString(serverSetting));
|
|
||||||
|
|
||||||
await Response().Embed(embed).SendAsync();
|
await Response().Embed(embed).SendAsync();
|
||||||
}
|
}
|
||||||
|
|
||||||
[Cmd]
|
[Cmd]
|
||||||
[RequireContext(ContextType.Guild)]
|
public async Task XpNotify(XpNotificationLocation type)
|
||||||
public async Task XpNotify(NotifyPlace place, XpNotificationLocation type)
|
|
||||||
{
|
{
|
||||||
if (place == NotifyPlace.Guild)
|
await _service.ChangeNotificationType(ctx.User, type);
|
||||||
await _service.ChangeNotificationType(ctx.User.Id, ctx.Guild.Id, type);
|
|
||||||
else
|
|
||||||
await _service.ChangeNotificationType(ctx.User, type);
|
|
||||||
|
|
||||||
await ctx.OkAsync();
|
await ctx.OkAsync();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -159,14 +159,6 @@ public class XpService : IEService, IReadyExecutor, IExecNoCommand
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public sealed class MiniGuildXpStats
|
|
||||||
{
|
|
||||||
public long Xp { get; set; }
|
|
||||||
public XpNotificationLocation NotifyOnLevelUp { get; set; }
|
|
||||||
public ulong GuildId { get; set; }
|
|
||||||
public ulong UserId { get; set; }
|
|
||||||
}
|
|
||||||
|
|
||||||
private async Task UpdateXp()
|
private async Task UpdateXp()
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
|
@ -261,7 +253,6 @@ public class XpService : IEService, IReadyExecutor, IExecNoCommand
|
||||||
GuildId = guildId,
|
GuildId = guildId,
|
||||||
Xp = group.Key,
|
Xp = group.Key,
|
||||||
DateAdded = DateTime.UtcNow,
|
DateAdded = DateTime.UtcNow,
|
||||||
NotifyOnLevelUp = XpNotificationLocation.None
|
|
||||||
},
|
},
|
||||||
_ => new()
|
_ => new()
|
||||||
{
|
{
|
||||||
|
@ -320,8 +311,7 @@ public class XpService : IEService, IReadyExecutor, IExecNoCommand
|
||||||
du.UserId,
|
du.UserId,
|
||||||
true,
|
true,
|
||||||
oldLevel.Level,
|
oldLevel.Level,
|
||||||
newLevel.Level,
|
newLevel.Level));
|
||||||
du.NotifyOnLevelUp));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -339,7 +329,7 @@ public class XpService : IEService, IReadyExecutor, IExecNoCommand
|
||||||
bool isServer,
|
bool isServer,
|
||||||
long oldLevel,
|
long oldLevel,
|
||||||
long newLevel,
|
long newLevel,
|
||||||
XpNotificationLocation notifyLoc)
|
XpNotificationLocation notifyLoc = XpNotificationLocation.None)
|
||||||
=> async () =>
|
=> async () =>
|
||||||
{
|
{
|
||||||
if (isServer)
|
if (isServer)
|
||||||
|
@ -634,21 +624,6 @@ public class XpService : IEService, IReadyExecutor, IExecNoCommand
|
||||||
.ToArrayAsyncLinqToDB();
|
.ToArrayAsyncLinqToDB();
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task ChangeNotificationType(ulong userId, ulong guildId, XpNotificationLocation type)
|
|
||||||
{
|
|
||||||
await using var uow = _db.GetDbContext();
|
|
||||||
var user = uow.GetOrCreateUserXpStats(guildId, userId);
|
|
||||||
user.NotifyOnLevelUp = type;
|
|
||||||
await uow.SaveChangesAsync();
|
|
||||||
}
|
|
||||||
|
|
||||||
public XpNotificationLocation GetNotificationType(ulong userId, ulong guildId)
|
|
||||||
{
|
|
||||||
using var uow = _db.GetDbContext();
|
|
||||||
var user = uow.GetOrCreateUserXpStats(guildId, userId);
|
|
||||||
return user.NotifyOnLevelUp;
|
|
||||||
}
|
|
||||||
|
|
||||||
public XpNotificationLocation GetNotificationType(IUser user)
|
public XpNotificationLocation GetNotificationType(IUser user)
|
||||||
{
|
{
|
||||||
using var uow = _db.GetDbContext();
|
using var uow = _db.GetDbContext();
|
||||||
|
@ -1667,9 +1642,7 @@ public class XpService : IEService, IReadyExecutor, IExecNoCommand
|
||||||
{
|
{
|
||||||
GuildId = guildId,
|
GuildId = guildId,
|
||||||
UserId = userId,
|
UserId = userId,
|
||||||
AwardedXp = 0,
|
|
||||||
Xp = lvlStats.TotalXp,
|
Xp = lvlStats.TotalXp,
|
||||||
NotifyOnLevelUp = XpNotificationLocation.None,
|
|
||||||
DateAdded = DateTime.UtcNow
|
DateAdded = DateTime.UtcNow
|
||||||
}, (old) => new()
|
}, (old) => new()
|
||||||
{
|
{
|
||||||
|
|
|
@ -3,8 +3,8 @@ namespace EllieBot.Common;
|
||||||
|
|
||||||
public enum AddRemove
|
public enum AddRemove
|
||||||
{
|
{
|
||||||
Add = int.MinValue,
|
Add = 0,
|
||||||
Remove = int.MinValue + 1,
|
Remove = 1,
|
||||||
Rem = int.MinValue + 1,
|
Rem = 1,
|
||||||
Rm = int.MinValue + 1
|
Rm = 1,
|
||||||
}
|
}
|
|
@ -2,7 +2,7 @@
|
||||||
|
|
||||||
namespace EllieBot.Common.TypeReaders.Models;
|
namespace EllieBot.Common.TypeReaders.Models;
|
||||||
|
|
||||||
public class StoopidTime
|
public class ParsedTimespan
|
||||||
{
|
{
|
||||||
private static readonly Regex _regex = new(
|
private static readonly Regex _regex = new(
|
||||||
@"^(?:(?<months>\d)mo)?(?:(?<weeks>\d{1,2})w)?(?:(?<days>\d{1,2})d)?(?:(?<hours>\d{1,4})h)?(?:(?<minutes>\d{1,5})m)?(?:(?<seconds>\d{1,6})s)?$",
|
@"^(?:(?<months>\d)mo)?(?:(?<weeks>\d{1,2})w)?(?:(?<days>\d{1,2})d)?(?:(?<hours>\d{1,4})h)?(?:(?<minutes>\d{1,5})m)?(?:(?<seconds>\d{1,6})s)?$",
|
||||||
|
@ -11,9 +11,9 @@ public class StoopidTime
|
||||||
public string Input { get; set; } = string.Empty;
|
public string Input { get; set; } = string.Empty;
|
||||||
public TimeSpan Time { get; set; } = default;
|
public TimeSpan Time { get; set; } = default;
|
||||||
|
|
||||||
private StoopidTime() { }
|
private ParsedTimespan() { }
|
||||||
|
|
||||||
public static StoopidTime FromInput(string input)
|
public static ParsedTimespan FromInput(string input)
|
||||||
{
|
{
|
||||||
var m = _regex.Match(input);
|
var m = _regex.Match(input);
|
||||||
|
|
||||||
|
@ -52,10 +52,10 @@ public class StoopidTime
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
public static implicit operator TimeSpan?(StoopidTime? st)
|
public static implicit operator TimeSpan?(ParsedTimespan? st)
|
||||||
=> st?.Time;
|
=> st?.Time;
|
||||||
|
|
||||||
public static implicit operator StoopidTime(TimeSpan ts)
|
public static implicit operator ParsedTimespan(TimeSpan ts)
|
||||||
=> new()
|
=> new()
|
||||||
{
|
{
|
||||||
Input = ts.ToString(),
|
Input = ts.ToString(),
|
||||||
|
|
|
@ -3,20 +3,20 @@ using EllieBot.Common.TypeReaders.Models;
|
||||||
|
|
||||||
namespace EllieBot.Common.TypeReaders;
|
namespace EllieBot.Common.TypeReaders;
|
||||||
|
|
||||||
public sealed class StoopidTimeTypeReader : EllieTypeReader<StoopidTime>
|
public sealed class StoopidTimeTypeReader : EllieTypeReader<ParsedTimespan>
|
||||||
{
|
{
|
||||||
public override ValueTask<TypeReaderResult<StoopidTime>> ReadAsync(ICommandContext context, string input)
|
public override ValueTask<TypeReaderResult<ParsedTimespan>> ReadAsync(ICommandContext context, string input)
|
||||||
{
|
{
|
||||||
if (string.IsNullOrWhiteSpace(input))
|
if (string.IsNullOrWhiteSpace(input))
|
||||||
return new(TypeReaderResult.FromError<StoopidTime>(CommandError.Unsuccessful, "Input is empty."));
|
return new(TypeReaderResult.FromError<ParsedTimespan>(CommandError.Unsuccessful, "Input is empty."));
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
var time = StoopidTime.FromInput(input);
|
var time = ParsedTimespan.FromInput(input);
|
||||||
return new(TypeReaderResult.FromSuccess(time));
|
return new(TypeReaderResult.FromSuccess(time));
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
return new(TypeReaderResult.FromError<StoopidTime>(CommandError.Exception, ex.Message));
|
return new(TypeReaderResult.FromError<ParsedTimespan>(CommandError.Exception, ex.Message));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -1541,4 +1541,9 @@ servercolorpending:
|
||||||
- pending
|
- pending
|
||||||
- warn
|
- warn
|
||||||
- warning
|
- warning
|
||||||
- pend
|
- pend
|
||||||
|
minesweeper:
|
||||||
|
- minesweeper
|
||||||
|
- mw
|
||||||
|
temprole:
|
||||||
|
- temprole
|
|
@ -4830,4 +4830,27 @@ xplevelset:
|
||||||
- level:
|
- level:
|
||||||
desc: "The level to set the user to."
|
desc: "The level to set the user to."
|
||||||
- user:
|
- user:
|
||||||
desc: "The user to set the level of."
|
desc: "The user to set the level of."
|
||||||
|
temprole:
|
||||||
|
desc: |-
|
||||||
|
Grants a user a temporary role for the specified number of time.
|
||||||
|
The role must exist and be lower in the role hierarchy than your highest role.
|
||||||
|
ex:
|
||||||
|
- '15m @User Jail'
|
||||||
|
- '7d @Newbie Trial Member'
|
||||||
|
params:
|
||||||
|
- days:
|
||||||
|
desc: "The time after which the role is automatically removed."
|
||||||
|
- user:
|
||||||
|
desc: "The user to give the role to."
|
||||||
|
- role:
|
||||||
|
desc: "The role to give to the user."
|
||||||
|
minesweeper:
|
||||||
|
desc: |-
|
||||||
|
Creates a spoiler-based minesweeper mini game.
|
||||||
|
You may specify the number of mines.
|
||||||
|
ex:
|
||||||
|
- '15'
|
||||||
|
params:
|
||||||
|
- mines:
|
||||||
|
desc: "The number of mines to create."
|
|
@ -1142,5 +1142,9 @@
|
||||||
"server_color_set": "Successfully set a new server color.",
|
"server_color_set": "Successfully set a new server color.",
|
||||||
"lasts_until": "Lasts Until",
|
"lasts_until": "Lasts Until",
|
||||||
"winners_count": "Winners",
|
"winners_count": "Winners",
|
||||||
"level_set": "Level of user {0} set to {1} on this server."
|
"level_set": "Level of user {0} set to {1} on this server.",
|
||||||
|
"temp_role_added": "User {0} has been given {1} role temporarily. The role expires {2}",
|
||||||
|
"user_afk": "User {0} is AFK.",
|
||||||
|
"notify_on": "Notification message will be sent on this channel when {0} event triggers.",
|
||||||
|
"notify_off": "Notification message will no longer be sent when {0} event triggers."
|
||||||
}
|
}
|
||||||
|
|
Reference in a new issue