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)
|
||||
{
|
||||
#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
|
||||
|
||||
modelBuilder.Entity<GuildColors>()
|
||||
|
@ -449,7 +478,6 @@ public abstract class EllieContext : DbContext
|
|||
xps.HasIndex(x => x.UserId);
|
||||
xps.HasIndex(x => x.GuildId);
|
||||
xps.HasIndex(x => x.Xp);
|
||||
xps.HasIndex(x => x.AwardedXp);
|
||||
|
||||
#endregion
|
||||
|
||||
|
|
|
@ -20,7 +20,6 @@ public static class UserXpExtensions
|
|||
{
|
||||
Xp = 0,
|
||||
UserId = userId,
|
||||
NotifyOnLevelUp = XpNotificationLocation.None,
|
||||
GuildId = guildId
|
||||
});
|
||||
}
|
||||
|
|
|
@ -36,29 +36,37 @@ public class GuildConfig : DbEntity
|
|||
public HashSet<FilterChannelId> FilterInvitesChannelIds { 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 HashSet<FilteredWord> FilteredWords { get; set; } = new();
|
||||
public HashSet<FilterWordsChannelId> FilterWordsChannelIds { get; set; } = new();
|
||||
|
||||
// mute
|
||||
public HashSet<MutedUserId> MutedUsers { get; set; } = new();
|
||||
|
||||
public string MuteRoleName { get; set; }
|
||||
|
||||
// chatterbot
|
||||
public bool CleverbotEnabled { get; set; }
|
||||
|
||||
// protection
|
||||
public AntiRaidSetting AntiRaidSetting { get; set; }
|
||||
public AntiSpamSetting AntiSpamSetting { get; set; }
|
||||
public AntiAltSetting AntiAltSetting { get; set; }
|
||||
|
||||
// time
|
||||
public string Locale { get; set; }
|
||||
public string TimeZoneId { get; set; }
|
||||
|
||||
|
||||
// timers
|
||||
public HashSet<UnmuteTimer> UnmuteTimers { get; set; } = new();
|
||||
public HashSet<UnbanTimer> UnbanTimer { get; set; } = new();
|
||||
public HashSet<UnroleTimer> UnroleTimer { get; set; } = new();
|
||||
|
||||
// vcrole
|
||||
public HashSet<VcRoleInfo> VcRoleInfos { get; set; }
|
||||
|
||||
// aliases
|
||||
public HashSet<CommandAlias> CommandAliases { get; set; } = new();
|
||||
public bool WarningsInitialized { 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 GuildId { 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);
|
||||
});
|
||||
|
||||
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 =>
|
||||
{
|
||||
b.Property<decimal>("UserId")
|
||||
|
@ -2339,10 +2375,6 @@ namespace EllieBot.Migrations.PostgreSql
|
|||
|
||||
NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id"));
|
||||
|
||||
b.Property<DateTime?>("DateAdded")
|
||||
.HasColumnType("timestamp without time zone")
|
||||
.HasColumnName("dateadded");
|
||||
|
||||
b.Property<int>("GroupNumber")
|
||||
.HasColumnType("integer")
|
||||
.HasColumnName("groupnumber");
|
||||
|
@ -2706,6 +2738,47 @@ namespace EllieBot.Migrations.PostgreSql
|
|||
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 =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
|
@ -2862,10 +2935,6 @@ namespace EllieBot.Migrations.PostgreSql
|
|||
|
||||
NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id"));
|
||||
|
||||
b.Property<long>("AwardedXp")
|
||||
.HasColumnType("bigint")
|
||||
.HasColumnName("awardedxp");
|
||||
|
||||
b.Property<DateTime?>("DateAdded")
|
||||
.HasColumnType("timestamp without time zone")
|
||||
.HasColumnName("dateadded");
|
||||
|
@ -2874,10 +2943,6 @@ namespace EllieBot.Migrations.PostgreSql
|
|||
.HasColumnType("numeric(20,0)")
|
||||
.HasColumnName("guildid");
|
||||
|
||||
b.Property<int>("NotifyOnLevelUp")
|
||||
.HasColumnType("integer")
|
||||
.HasColumnName("notifyonlevelup");
|
||||
|
||||
b.Property<decimal>("UserId")
|
||||
.HasColumnType("numeric(20,0)")
|
||||
.HasColumnName("userid");
|
||||
|
@ -2889,9 +2954,6 @@ namespace EllieBot.Migrations.PostgreSql
|
|||
b.HasKey("Id")
|
||||
.HasName("pk_userxpstats");
|
||||
|
||||
b.HasIndex("AwardedXp")
|
||||
.HasDatabaseName("ix_userxpstats_awardedxp");
|
||||
|
||||
b.HasIndex("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");
|
||||
});
|
||||
|
||||
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 =>
|
||||
{
|
||||
b.Property<ulong>("UserId")
|
||||
|
@ -1744,9 +1771,6 @@ namespace EllieBot.Migrations
|
|||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<DateTime?>("DateAdded")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<int>("GroupNumber")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
|
@ -2016,6 +2040,36 @@ namespace EllieBot.Migrations
|
|||
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 =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
|
@ -2130,18 +2184,12 @@ namespace EllieBot.Migrations
|
|||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<long>("AwardedXp")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<DateTime?>("DateAdded")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<ulong>("GuildId")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<int>("NotifyOnLevelUp")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<ulong>("UserId")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
|
@ -2150,8 +2198,6 @@ namespace EllieBot.Migrations
|
|||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("AwardedXp");
|
||||
|
||||
b.HasIndex("GuildId");
|
||||
|
||||
b.HasIndex("UserId");
|
||||
|
|
|
@ -46,7 +46,7 @@ public partial class Administration : EllieModule<AdministrationService>
|
|||
[RequireContext(ContextType.Guild)]
|
||||
[UserPerm(GuildPerm.Administrator)]
|
||||
[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);
|
||||
if (newValue)
|
||||
|
@ -59,7 +59,7 @@ public partial class Administration : EllieModule<AdministrationService>
|
|||
[RequireContext(ContextType.Guild)]
|
||||
[UserPerm(GuildPerm.Administrator)]
|
||||
[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);
|
||||
if (newValue)
|
||||
|
@ -72,10 +72,10 @@ public partial class Administration : EllieModule<AdministrationService>
|
|||
[RequireContext(ContextType.Guild)]
|
||||
[UserPerm(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;
|
||||
if (time is not null && (time.Time < TimeSpan.FromSeconds(0) || time.Time > TimeSpan.FromHours(6)))
|
||||
var seconds = (int?)timespan?.Time.TotalSeconds ?? 0;
|
||||
if (timespan is not null && (timespan.Time < TimeSpan.FromSeconds(0) || timespan.Time > TimeSpan.FromHours(6)))
|
||||
return;
|
||||
|
||||
await ((ITextChannel)ctx.Channel).ModifyAsync(tcp =>
|
||||
|
@ -298,18 +298,18 @@ public partial class Administration : EllieModule<AdministrationService>
|
|||
[RequireContext(ContextType.Guild)]
|
||||
[UserPerm(ChannelPerm.ManageMessages)]
|
||||
[BotPerm(ChannelPerm.ManageMessages)]
|
||||
public Task Delete(ulong messageId, StoopidTime time = null)
|
||||
=> Delete((ITextChannel)ctx.Channel, messageId, time);
|
||||
public Task Delete(ulong messageId, ParsedTimespan timespan = null)
|
||||
=> Delete((ITextChannel)ctx.Channel, messageId, timespan);
|
||||
|
||||
[Cmd]
|
||||
[RequireContext(ContextType.Guild)]
|
||||
public async Task Delete(ITextChannel channel, ulong messageId, StoopidTime time = null)
|
||||
=> await InternalMessageAction(channel, messageId, time, msg => msg.DeleteAsync());
|
||||
public async Task Delete(ITextChannel channel, ulong messageId, ParsedTimespan timespan = null)
|
||||
=> await InternalMessageAction(channel, messageId, timespan, msg => msg.DeleteAsync());
|
||||
|
||||
private async Task InternalMessageAction(
|
||||
ITextChannel channel,
|
||||
ulong messageId,
|
||||
StoopidTime time,
|
||||
ParsedTimespan timespan,
|
||||
Func<IMessage, Task> func)
|
||||
{
|
||||
var userPerms = ((SocketGuildUser)ctx.User).GetPermissions(channel);
|
||||
|
@ -334,13 +334,13 @@ public partial class Administration : EllieModule<AdministrationService>
|
|||
return;
|
||||
}
|
||||
|
||||
if (time is null)
|
||||
if (timespan is null)
|
||||
await msg.DeleteAsync();
|
||||
else if (time.Time <= TimeSpan.FromDays(7))
|
||||
else if (timespan.Time <= TimeSpan.FromDays(7))
|
||||
{
|
||||
_ = Task.Run(async () =>
|
||||
{
|
||||
await Task.Delay(time.Time);
|
||||
await Task.Delay(timespan.Time);
|
||||
await msg.DeleteAsync();
|
||||
});
|
||||
}
|
||||
|
@ -450,7 +450,8 @@ public partial class Administration : EllieModule<AdministrationService>
|
|||
public async Task SetServerBanner([Leftover] string img = null)
|
||||
{
|
||||
// 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);
|
||||
|
||||
|
|
|
@ -72,18 +72,18 @@ public partial class Administration
|
|||
[RequireContext(ContextType.Guild)]
|
||||
[UserPerm(GuildPerm.ManageRoles | GuildPerm.MuteMembers)]
|
||||
[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;
|
||||
try
|
||||
{
|
||||
if (!await VerifyMutePermissions((IGuildUser)ctx.User, user))
|
||||
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()),
|
||||
(int)time.Time.TotalMinutes)).SendAsync();
|
||||
(int)timespan.Time.TotalMinutes)).SendAsync();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
|
@ -133,18 +133,18 @@ public partial class Administration
|
|||
[RequireContext(ContextType.Guild)]
|
||||
[UserPerm(GuildPerm.ManageRoles)]
|
||||
[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;
|
||||
try
|
||||
{
|
||||
if (!await VerifyMutePermissions((IGuildUser)ctx.User, user))
|
||||
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()),
|
||||
(int)time.Time.TotalMinutes)).SendAsync();
|
||||
(int)timespan.Time.TotalMinutes)).SendAsync();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
|
@ -193,18 +193,18 @@ public partial class Administration
|
|||
[RequireContext(ContextType.Guild)]
|
||||
[UserPerm(GuildPerm.MuteMembers)]
|
||||
[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;
|
||||
try
|
||||
{
|
||||
if (!await VerifyMutePermissions((IGuildUser)ctx.User, user))
|
||||
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()),
|
||||
(int)time.Time.TotalMinutes)).SendAsync();
|
||||
(int)timespan.Time.TotalMinutes)).SendAsync();
|
||||
}
|
||||
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)]
|
||||
[UserPerm(GuildPerm.Administrator)]
|
||||
public async Task AntiAlt(
|
||||
StoopidTime minAge,
|
||||
ParsedTimespan minAge,
|
||||
PunishmentAction action,
|
||||
[Leftover] StoopidTime punishTime = null)
|
||||
[Leftover] ParsedTimespan punishTimespan = null)
|
||||
{
|
||||
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)
|
||||
return;
|
||||
|
||||
var minutes = (int?)punishTime?.Time.TotalMinutes ?? 0;
|
||||
var minutes = (int?)punishTimespan?.Time.TotalMinutes ?? 0;
|
||||
if (action is PunishmentAction.TimeOut && minutes < 1)
|
||||
minutes = 1;
|
||||
|
||||
|
@ -53,7 +53,7 @@ public partial class Administration
|
|||
[Cmd]
|
||||
[RequireContext(ContextType.Guild)]
|
||||
[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;
|
||||
|
||||
|
@ -86,8 +86,8 @@ public partial class Administration
|
|||
int userThreshold,
|
||||
int seconds,
|
||||
PunishmentAction action,
|
||||
[Leftover] StoopidTime punishTime)
|
||||
=> InternalAntiRaid(userThreshold, seconds, action, punishTime);
|
||||
[Leftover] ParsedTimespan punishTimespan)
|
||||
=> InternalAntiRaid(userThreshold, seconds, action, punishTimespan);
|
||||
|
||||
[Cmd]
|
||||
[RequireContext(ContextType.Guild)]
|
||||
|
@ -100,7 +100,7 @@ public partial class Administration
|
|||
int userThreshold,
|
||||
int seconds = 10,
|
||||
PunishmentAction action = PunishmentAction.Mute,
|
||||
StoopidTime punishTime = null)
|
||||
ParsedTimespan punishTimespan = null)
|
||||
{
|
||||
if (action == PunishmentAction.AddRole)
|
||||
{
|
||||
|
@ -120,13 +120,13 @@ public partial class Administration
|
|||
return;
|
||||
}
|
||||
|
||||
if (punishTime is not null)
|
||||
if (punishTimespan is not null)
|
||||
{
|
||||
if (!_service.IsDurationAllowed(action))
|
||||
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)
|
||||
return;
|
||||
|
||||
|
@ -170,8 +170,8 @@ public partial class Administration
|
|||
[RequireContext(ContextType.Guild)]
|
||||
[UserPerm(GuildPerm.Administrator)]
|
||||
[Priority(1)]
|
||||
public Task AntiSpam(int messageCount, PunishmentAction action, [Leftover] StoopidTime punishTime)
|
||||
=> InternalAntiSpam(messageCount, action, punishTime);
|
||||
public Task AntiSpam(int messageCount, PunishmentAction action, [Leftover] ParsedTimespan punishTimespan)
|
||||
=> InternalAntiSpam(messageCount, action, punishTimespan);
|
||||
|
||||
[Cmd]
|
||||
[RequireContext(ContextType.Guild)]
|
||||
|
@ -183,19 +183,19 @@ public partial class Administration
|
|||
private async Task InternalAntiSpam(
|
||||
int messageCount,
|
||||
PunishmentAction action,
|
||||
StoopidTime timeData = null,
|
||||
ParsedTimespan timespanData = null,
|
||||
IRole role = null)
|
||||
{
|
||||
if (messageCount is < 2 or > 10)
|
||||
return;
|
||||
|
||||
if (timeData is not null)
|
||||
if (timespanData is not null)
|
||||
{
|
||||
if (!_service.IsDurationAllowed(action))
|
||||
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)
|
||||
return;
|
||||
|
||||
|
|
|
@ -1,4 +1,6 @@
|
|||
#nullable disable
|
||||
using Google.Protobuf.WellKnownTypes;
|
||||
using EllieBot.Common.TypeReaders.Models;
|
||||
using SixLabors.ImageSharp.PixelFormats;
|
||||
using Color = SixLabors.ImageSharp.Color;
|
||||
|
||||
|
@ -13,13 +15,18 @@ public partial class Administration
|
|||
Excl
|
||||
}
|
||||
|
||||
private readonly TempRoleService _tempRoleService;
|
||||
private readonly IServiceProvider _services;
|
||||
private StickyRolesService _stickyRoleSvc;
|
||||
|
||||
public RoleCommands(IServiceProvider services, StickyRolesService stickyRoleSvc)
|
||||
public RoleCommands(
|
||||
IServiceProvider services,
|
||||
StickyRolesService stickyRoleSvc,
|
||||
TempRoleService tempRoleService)
|
||||
{
|
||||
_services = services;
|
||||
_stickyRoleSvc = stickyRoleSvc;
|
||||
_tempRoleService = tempRoleService;
|
||||
}
|
||||
|
||||
[Cmd]
|
||||
|
@ -34,13 +41,16 @@ public partial class Administration
|
|||
return;
|
||||
try
|
||||
{
|
||||
await targetUser.AddRoleAsync(roleToAdd, new RequestOptions()
|
||||
{
|
||||
AuditLogReason = $"Added by [{ctx.User.Username}]"
|
||||
});
|
||||
await targetUser.AddRoleAsync(roleToAdd,
|
||||
new RequestOptions()
|
||||
{
|
||||
AuditLogReason = $"Added by [{ctx.User.Username}]"
|
||||
});
|
||||
|
||||
await Response().Confirm(strs.setrole(Format.Bold(roleToAdd.Name),
|
||||
Format.Bold(targetUser.ToString()))).SendAsync();
|
||||
await Response()
|
||||
.Confirm(strs.setrole(Format.Bold(roleToAdd.Name),
|
||||
Format.Bold(targetUser.ToString())))
|
||||
.SendAsync();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
|
@ -62,8 +72,10 @@ public partial class Administration
|
|||
try
|
||||
{
|
||||
await targetUser.RemoveRoleAsync(roleToRemove);
|
||||
await Response().Confirm(strs.remrole(Format.Bold(roleToRemove.Name),
|
||||
Format.Bold(targetUser.ToString()))).SendAsync();
|
||||
await Response()
|
||||
.Confirm(strs.remrole(Format.Bold(roleToRemove.Name),
|
||||
Format.Bold(targetUser.ToString())))
|
||||
.SendAsync();
|
||||
}
|
||||
catch
|
||||
{
|
||||
|
@ -204,5 +216,29 @@ public partial class Administration
|
|||
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,
|
||||
AddRole _,
|
||||
IRole role,
|
||||
StoopidTime time = null)
|
||||
ParsedTimespan timespan = null)
|
||||
{
|
||||
var punish = PunishmentAction.AddRole;
|
||||
|
||||
|
@ -324,12 +324,12 @@ public partial class Administration
|
|||
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)
|
||||
return;
|
||||
|
||||
if (time is null)
|
||||
if (timespan is null)
|
||||
{
|
||||
await Response()
|
||||
.Confirm(strs.warn_punish_set(Format.Bold(punish.ToString()),
|
||||
|
@ -341,7 +341,7 @@ public partial class Administration
|
|||
await Response()
|
||||
.Confirm(strs.warn_punish_set_timed(Format.Bold(punish.ToString()),
|
||||
Format.Bold(number.ToString()),
|
||||
Format.Bold(time.Input)))
|
||||
Format.Bold(timespan.Input)))
|
||||
.SendAsync();
|
||||
}
|
||||
}
|
||||
|
@ -349,7 +349,7 @@ public partial class Administration
|
|||
[Cmd]
|
||||
[RequireContext(ContextType.Guild)]
|
||||
[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
|
||||
// also disallow warn punishment for getting warned
|
||||
|
@ -357,15 +357,15 @@ public partial class Administration
|
|||
return;
|
||||
|
||||
// you must specify the time for timeout
|
||||
if (punish is PunishmentAction.TimeOut && time is null)
|
||||
if (punish is PunishmentAction.TimeOut && timespan is null)
|
||||
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)
|
||||
return;
|
||||
|
||||
if (time is null)
|
||||
if (timespan is null)
|
||||
{
|
||||
await Response()
|
||||
.Confirm(strs.warn_punish_set(Format.Bold(punish.ToString()),
|
||||
|
@ -377,7 +377,7 @@ public partial class Administration
|
|||
await Response()
|
||||
.Confirm(strs.warn_punish_set_timed(Format.Bold(punish.ToString()),
|
||||
Format.Bold(number.ToString()),
|
||||
Format.Bold(time.Input)))
|
||||
Format.Bold(timespan.Input)))
|
||||
.SendAsync();
|
||||
}
|
||||
}
|
||||
|
@ -417,17 +417,17 @@ public partial class Administration
|
|||
[UserPerm(GuildPerm.BanMembers)]
|
||||
[BotPerm(GuildPerm.BanMembers)]
|
||||
[Priority(1)]
|
||||
public Task Ban(StoopidTime time, IUser user, [Leftover] string msg = null)
|
||||
=> Ban(time, user.Id, msg);
|
||||
public Task Ban(ParsedTimespan timespan, IUser user, [Leftover] string msg = null)
|
||||
=> Ban(timespan, user.Id, msg);
|
||||
|
||||
[Cmd]
|
||||
[RequireContext(ContextType.Guild)]
|
||||
[UserPerm(GuildPerm.BanMembers)]
|
||||
[BotPerm(GuildPerm.BanMembers)]
|
||||
[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;
|
||||
|
||||
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 smartText =
|
||||
await _service.GetBanUserDmEmbed(Context, guildUser, defaultMessage, msg, time.Time);
|
||||
await _service.GetBanUserDmEmbed(Context, guildUser, defaultMessage, msg, timespan.Time);
|
||||
if (smartText is not null)
|
||||
await Response().User(guildUser).Text(smartText).SendAsync();
|
||||
}
|
||||
|
@ -456,14 +456,14 @@ public partial class Administration
|
|||
|
||||
var user = await ctx.Client.GetUserAsync(userId);
|
||||
var banPrune = await _service.GetBanPruneAsync(ctx.Guild.Id) ?? 7;
|
||||
await _mute.TimedBan(ctx.Guild, userId, time.Time, (ctx.User + " | " + msg).TrimTo(512), banPrune);
|
||||
await _mute.TimedBan(ctx.Guild, userId, timespan.Time, (ctx.User + " | " + msg).TrimTo(512), banPrune);
|
||||
var toSend = CreateEmbed()
|
||||
.WithOkColor()
|
||||
.WithTitle("⛔️ " + GetText(strs.banned_user))
|
||||
.AddField(GetText(strs.username), user?.ToString() ?? userId.ToString(), true)
|
||||
.AddField("ID", userId.ToString(), true)
|
||||
.AddField(GetText(strs.duration),
|
||||
time.Time.ToPrettyStringHm(),
|
||||
timespan.Time.ToPrettyStringHm(),
|
||||
true);
|
||||
|
||||
if (dmFailed)
|
||||
|
@ -601,7 +601,7 @@ public partial class Administration
|
|||
[UserPerm(GuildPerm.BanMembers)]
|
||||
[BotPerm(GuildPerm.BanMembers)]
|
||||
[Priority(1)]
|
||||
public Task BanMessageTest(StoopidTime duration, [Leftover] string reason = null)
|
||||
public Task BanMessageTest(ParsedTimespan duration, [Leftover] string reason = null)
|
||||
=> InternalBanMessageTest(reason, duration.Time);
|
||||
|
||||
private async Task InternalBanMessageTest(string reason, TimeSpan? duration)
|
||||
|
@ -791,7 +791,7 @@ public partial class Administration
|
|||
[UserPerm(GuildPerm.ModerateMembers)]
|
||||
[BotPerm(GuildPerm.ModerateMembers)]
|
||||
[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);
|
||||
|
||||
|
@ -817,7 +817,7 @@ public partial class Administration
|
|||
dmFailed = true;
|
||||
}
|
||||
|
||||
await user.SetTimeOutAsync(time.Time);
|
||||
await user.SetTimeOutAsync(timespan.Time);
|
||||
|
||||
var toSend = CreateEmbed()
|
||||
.WithOkColor()
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
#nullable disable
|
||||
using EllieBot.Modules.Games.Services;
|
||||
using System.Text;
|
||||
|
||||
namespace EllieBot.Modules.Games;
|
||||
|
||||
|
@ -38,10 +39,72 @@ public partial class Games : EllieModule<GamesService>
|
|||
return;
|
||||
|
||||
var res = _service.GetEightballResponse(ctx.User.Id, question);
|
||||
await Response().Embed(CreateEmbed()
|
||||
.WithOkColor()
|
||||
.WithDescription(ctx.User.ToString())
|
||||
.AddField("❓ " + GetText(strs.question), question)
|
||||
.AddField("🎱 " + GetText(strs._8ball), res)).SendAsync();
|
||||
await Response()
|
||||
.Embed(CreateEmbed()
|
||||
.WithOkColor()
|
||||
.WithDescription(ctx.User.ToString())
|
||||
.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 static readonly TimeSpan _maxAfkDuration = 8.Hours();
|
||||
|
||||
public AfkService(IBotCache cache, DiscordSocketClient client, MessageSenderService mss)
|
||||
{
|
||||
_cache = cache;
|
||||
|
@ -19,6 +20,9 @@ public sealed class AfkService : IEService, IReadyExecutor
|
|||
private static TypedKey<string> GetKey(ulong 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)
|
||||
{
|
||||
var added = await _cache.AddAsync(GetKey(userId), text, _maxAfkDuration, overwrite: true);
|
||||
|
@ -43,9 +47,7 @@ public sealed class AfkService : IEService, IReadyExecutor
|
|||
msg.DeleteAfter(5);
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
|
@ -72,36 +74,29 @@ public sealed class AfkService : IEService, IReadyExecutor
|
|||
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;
|
||||
|
||||
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;
|
||||
|
||||
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;
|
||||
|
||||
_ = Task.Run(async () =>
|
||||
{
|
||||
var botUser = await tc.Guild.GetCurrentUserAsync();
|
||||
|
||||
var perms = botUser.GetPermissions(tc);
|
||||
|
||||
if (!perms.SendMessages)
|
||||
return;
|
||||
|
||||
ulong mentionedUserId = 0;
|
||||
|
||||
if (arg.MentionedUsers.Count <= 3)
|
||||
if (sm.MentionedUsers.Count <= 3)
|
||||
{
|
||||
foreach (var uid in uMsg.MentionedUserIds)
|
||||
{
|
||||
if (uid == arg.Author.Id)
|
||||
if (uid == sm.Author.Id)
|
||||
continue;
|
||||
|
||||
if (arg.Content.StartsWith($"<@{uid}>") || arg.Content.StartsWith($"<@!{uid}>"))
|
||||
if (sm.Content.StartsWith($"<@{uid}>") || sm.Content.StartsWith($"<@!{uid}>"))
|
||||
{
|
||||
mentionedUserId = uid;
|
||||
break;
|
||||
|
@ -128,13 +123,32 @@ public sealed class AfkService : IEService, IReadyExecutor
|
|||
|
||||
st = $"The user you've pinged (<#{mentionedUserId}>) is AFK: " + st;
|
||||
|
||||
var toDelete = await _mss.Response(arg.Channel)
|
||||
.User(arg.Author)
|
||||
var toDelete = await _mss.Response(sm.Channel)
|
||||
.User(sm.Author)
|
||||
.Message(uMsg)
|
||||
.Text(st)
|
||||
.SendAsync();
|
||||
|
||||
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)
|
||||
|
|
|
@ -98,10 +98,10 @@ public partial class Utility
|
|||
return;
|
||||
|
||||
var embed = CreateEmbed()
|
||||
.WithOkColor()
|
||||
.WithTitle(GetText(guildId is not null
|
||||
? strs.reminder_server_list
|
||||
: strs.reminder_list));
|
||||
.WithOkColor()
|
||||
.WithTitle(GetText(guildId is not null
|
||||
? strs.reminder_server_list
|
||||
: strs.reminder_list));
|
||||
|
||||
List<Reminder> rems;
|
||||
if (guildId is { } gid)
|
||||
|
@ -193,23 +193,14 @@ public partial class Utility
|
|||
message = message.SanitizeAllMentions();
|
||||
}
|
||||
|
||||
var rem = new Reminder
|
||||
{
|
||||
ChannelId = targetId,
|
||||
IsPrivate = isPrivate,
|
||||
When = time,
|
||||
Message = message,
|
||||
UserId = ctx.User.Id,
|
||||
ServerId = ctx.Guild?.Id ?? 0
|
||||
};
|
||||
await _service.AddReminderAsync(ctx.User.Id,
|
||||
targetId,
|
||||
ctx.Guild?.Id,
|
||||
isPrivate,
|
||||
time,
|
||||
message,
|
||||
ReminderType.User);
|
||||
|
||||
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()
|
||||
.Confirm($"\u23f0 {GetText(strs.remind2(
|
||||
Format.Bold(!isPrivate ? $"<#{targetId}>" : ctx.User.Username),
|
||||
|
|
|
@ -21,6 +21,8 @@ public class RemindService : IEService, IReadyExecutor, IRemindService
|
|||
private readonly IMessageSenderService _sender;
|
||||
private readonly CultureInfo _culture;
|
||||
|
||||
private TaskCompletionSource<bool> _tcs;
|
||||
|
||||
public RemindService(
|
||||
DiscordSocketClient client,
|
||||
DbService db,
|
||||
|
@ -44,8 +46,7 @@ public class RemindService : IEService, IReadyExecutor, IRemindService
|
|||
|
||||
public async Task OnReadyAsync()
|
||||
{
|
||||
using var timer = new PeriodicTimer(TimeSpan.FromSeconds(15));
|
||||
while (await timer.WaitForNextTickAsync())
|
||||
while (true)
|
||||
{
|
||||
await OnReminderLoopTickInternalAsync();
|
||||
}
|
||||
|
@ -55,8 +56,7 @@ public class RemindService : IEService, IReadyExecutor, IRemindService
|
|||
{
|
||||
try
|
||||
{
|
||||
var now = DateTime.UtcNow;
|
||||
var reminders = await GetRemindersBeforeAsync(now);
|
||||
var reminders = await GetRemindersBeforeAsync();
|
||||
if (reminders.Count == 0)
|
||||
return;
|
||||
|
||||
|
@ -67,7 +67,6 @@ public class RemindService : IEService, IReadyExecutor, IRemindService
|
|||
{
|
||||
var executedReminders = group.ToList();
|
||||
await executedReminders.Select(ReminderTimerAction).WhenAll();
|
||||
await RemoveReminders(executedReminders.Select(x => x.Id));
|
||||
await Task.Delay(1500);
|
||||
}
|
||||
}
|
||||
|
@ -80,21 +79,51 @@ public class RemindService : IEService, IReadyExecutor, IRemindService
|
|||
private async Task RemoveReminders(IEnumerable<int> reminders)
|
||||
{
|
||||
await using var uow = _db.GetDbContext();
|
||||
await uow.Set<Reminder>()
|
||||
.ToLinqToDBTable()
|
||||
await uow.GetTable<Reminder>()
|
||||
.DeleteAsync(x => reminders.Contains(x.Id));
|
||||
|
||||
await uow.SaveChangesAsync();
|
||||
}
|
||||
|
||||
private async Task<List<Reminder>> GetRemindersBeforeAsync(DateTime now)
|
||||
private async Task<IReadOnlyList<Reminder>> GetRemindersBeforeAsync()
|
||||
{
|
||||
await using var uow = _db.GetDbContext();
|
||||
return await uow.Set<Reminder>()
|
||||
.ToLinqToDBTable()
|
||||
.Where(x => Linq2DbExpressions.GuildOnShard(x.ServerId, _creds.TotalShards, _client.ShardId)
|
||||
&& x.When < now)
|
||||
.ToListAsyncLinqToDB();
|
||||
while (true)
|
||||
{
|
||||
_tcs = new(TaskCreationOptions.RunContinuationsAsynchronously);
|
||||
await using var uow = _db.GetDbContext();
|
||||
var earliest = await uow.Set<Reminder>()
|
||||
.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)
|
||||
|
@ -243,21 +272,24 @@ public class RemindService : IEService, IReadyExecutor, IRemindService
|
|||
string message,
|
||||
ReminderType reminderType)
|
||||
{
|
||||
var rem = new Reminder
|
||||
await using (var ctx = _db.GetDbContext())
|
||||
{
|
||||
UserId = userId,
|
||||
ChannelId = targetId,
|
||||
ServerId = guildId ?? 0,
|
||||
IsPrivate = isPrivate,
|
||||
When = time,
|
||||
Message = message,
|
||||
Type = reminderType
|
||||
};
|
||||
await ctx.GetTable<Reminder>()
|
||||
.InsertAsync(() => new Reminder
|
||||
{
|
||||
UserId = userId,
|
||||
ChannelId = targetId,
|
||||
ServerId = guildId ?? 0,
|
||||
IsPrivate = isPrivate,
|
||||
When = time,
|
||||
Message = message,
|
||||
Type = reminderType,
|
||||
DateAdded = DateTime.UtcNow
|
||||
});
|
||||
await ctx.SaveChangesAsync();
|
||||
}
|
||||
|
||||
await using var ctx = _db.GetDbContext();
|
||||
await ctx.Set<Reminder>()
|
||||
.AddAsync(rem);
|
||||
await ctx.SaveChangesAsync();
|
||||
_tcs.SetResult(true);
|
||||
}
|
||||
|
||||
public async Task<List<Reminder>> GetServerReminders(int page, ulong guildId)
|
||||
|
|
|
@ -110,14 +110,14 @@ public partial class Utility
|
|||
[RequireContext(ContextType.Guild)]
|
||||
[UserPerm(GuildPerm.ManageMessages)]
|
||||
[Priority(0)]
|
||||
public Task Repeat(StoopidTime interval, [Leftover] string message)
|
||||
public Task Repeat(ParsedTimespan interval, [Leftover] string message)
|
||||
=> Repeat(ctx.Channel, null, interval, message);
|
||||
|
||||
[Cmd]
|
||||
[RequireContext(ContextType.Guild)]
|
||||
[UserPerm(GuildPerm.ManageMessages)]
|
||||
[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);
|
||||
|
||||
[Cmd]
|
||||
|
@ -138,14 +138,14 @@ public partial class Utility
|
|||
[RequireContext(ContextType.Guild)]
|
||||
[UserPerm(GuildPerm.ManageMessages)]
|
||||
[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);
|
||||
|
||||
[Cmd]
|
||||
[RequireContext(ContextType.Guild)]
|
||||
[UserPerm(GuildPerm.ManageMessages)]
|
||||
[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)
|
||||
{
|
||||
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()
|
||||
{
|
||||
var globalSetting = _service.GetNotificationType(ctx.User);
|
||||
var serverSetting = _service.GetNotificationType(ctx.User.Id, ctx.Guild.Id);
|
||||
|
||||
var embed = CreateEmbed()
|
||||
.WithOkColor()
|
||||
.AddField(GetText(strs.xpn_setting_global), GetNotifLocationString(globalSetting))
|
||||
.AddField(GetText(strs.xpn_setting_server), GetNotifLocationString(serverSetting));
|
||||
.AddField(GetText(strs.xpn_setting_global), GetNotifLocationString(globalSetting));
|
||||
|
||||
await Response().Embed(embed).SendAsync();
|
||||
}
|
||||
|
||||
[Cmd]
|
||||
[RequireContext(ContextType.Guild)]
|
||||
public async Task XpNotify(NotifyPlace place, XpNotificationLocation type)
|
||||
public async Task XpNotify(XpNotificationLocation type)
|
||||
{
|
||||
if (place == NotifyPlace.Guild)
|
||||
await _service.ChangeNotificationType(ctx.User.Id, ctx.Guild.Id, type);
|
||||
else
|
||||
await _service.ChangeNotificationType(ctx.User, type);
|
||||
|
||||
await _service.ChangeNotificationType(ctx.User, type);
|
||||
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()
|
||||
{
|
||||
try
|
||||
|
@ -261,7 +253,6 @@ public class XpService : IEService, IReadyExecutor, IExecNoCommand
|
|||
GuildId = guildId,
|
||||
Xp = group.Key,
|
||||
DateAdded = DateTime.UtcNow,
|
||||
NotifyOnLevelUp = XpNotificationLocation.None
|
||||
},
|
||||
_ => new()
|
||||
{
|
||||
|
@ -320,8 +311,7 @@ public class XpService : IEService, IReadyExecutor, IExecNoCommand
|
|||
du.UserId,
|
||||
true,
|
||||
oldLevel.Level,
|
||||
newLevel.Level,
|
||||
du.NotifyOnLevelUp));
|
||||
newLevel.Level));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -339,7 +329,7 @@ public class XpService : IEService, IReadyExecutor, IExecNoCommand
|
|||
bool isServer,
|
||||
long oldLevel,
|
||||
long newLevel,
|
||||
XpNotificationLocation notifyLoc)
|
||||
XpNotificationLocation notifyLoc = XpNotificationLocation.None)
|
||||
=> async () =>
|
||||
{
|
||||
if (isServer)
|
||||
|
@ -634,21 +624,6 @@ public class XpService : IEService, IReadyExecutor, IExecNoCommand
|
|||
.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)
|
||||
{
|
||||
using var uow = _db.GetDbContext();
|
||||
|
@ -1667,9 +1642,7 @@ public class XpService : IEService, IReadyExecutor, IExecNoCommand
|
|||
{
|
||||
GuildId = guildId,
|
||||
UserId = userId,
|
||||
AwardedXp = 0,
|
||||
Xp = lvlStats.TotalXp,
|
||||
NotifyOnLevelUp = XpNotificationLocation.None,
|
||||
DateAdded = DateTime.UtcNow
|
||||
}, (old) => new()
|
||||
{
|
||||
|
|
|
@ -3,8 +3,8 @@ namespace EllieBot.Common;
|
|||
|
||||
public enum AddRemove
|
||||
{
|
||||
Add = int.MinValue,
|
||||
Remove = int.MinValue + 1,
|
||||
Rem = int.MinValue + 1,
|
||||
Rm = int.MinValue + 1
|
||||
Add = 0,
|
||||
Remove = 1,
|
||||
Rem = 1,
|
||||
Rm = 1,
|
||||
}
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
namespace EllieBot.Common.TypeReaders.Models;
|
||||
|
||||
public class StoopidTime
|
||||
public class ParsedTimespan
|
||||
{
|
||||
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)?$",
|
||||
|
@ -11,9 +11,9 @@ public class StoopidTime
|
|||
public string Input { get; set; } = string.Empty;
|
||||
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);
|
||||
|
||||
|
@ -52,10 +52,10 @@ public class StoopidTime
|
|||
};
|
||||
}
|
||||
|
||||
public static implicit operator TimeSpan?(StoopidTime? st)
|
||||
public static implicit operator TimeSpan?(ParsedTimespan? st)
|
||||
=> st?.Time;
|
||||
|
||||
public static implicit operator StoopidTime(TimeSpan ts)
|
||||
public static implicit operator ParsedTimespan(TimeSpan ts)
|
||||
=> new()
|
||||
{
|
||||
Input = ts.ToString(),
|
||||
|
|
|
@ -3,20 +3,20 @@ using EllieBot.Common.TypeReaders.Models;
|
|||
|
||||
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))
|
||||
return new(TypeReaderResult.FromError<StoopidTime>(CommandError.Unsuccessful, "Input is empty."));
|
||||
return new(TypeReaderResult.FromError<ParsedTimespan>(CommandError.Unsuccessful, "Input is empty."));
|
||||
try
|
||||
{
|
||||
var time = StoopidTime.FromInput(input);
|
||||
var time = ParsedTimespan.FromInput(input);
|
||||
return new(TypeReaderResult.FromSuccess(time));
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
return new(TypeReaderResult.FromError<StoopidTime>(CommandError.Exception, ex.Message));
|
||||
return new(TypeReaderResult.FromError<ParsedTimespan>(CommandError.Exception, ex.Message));
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1542,3 +1542,8 @@ servercolorpending:
|
|||
- warn
|
||||
- warning
|
||||
- pend
|
||||
minesweeper:
|
||||
- minesweeper
|
||||
- mw
|
||||
temprole:
|
||||
- temprole
|
|
@ -4831,3 +4831,26 @@ xplevelset:
|
|||
desc: "The level to set the user to."
|
||||
- user:
|
||||
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.",
|
||||
"lasts_until": "Lasts Until",
|
||||
"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