sar rework, improved
This commit is contained in:
parent
af71e88985
commit
3532554a13
30 changed files with 8417 additions and 569 deletions
|
@ -2,6 +2,7 @@
|
||||||
using Microsoft.EntityFrameworkCore;
|
using Microsoft.EntityFrameworkCore;
|
||||||
using Microsoft.Extensions.Logging;
|
using Microsoft.Extensions.Logging;
|
||||||
using EllieBot.Db.Models;
|
using EllieBot.Db.Models;
|
||||||
|
using EllieBot.Modules.Administration.Services;
|
||||||
|
|
||||||
// ReSharper disable UnusedAutoPropertyAccessor.Global
|
// ReSharper disable UnusedAutoPropertyAccessor.Global
|
||||||
|
|
||||||
|
@ -14,7 +15,6 @@ public abstract class EllieContext : DbContext
|
||||||
|
|
||||||
public DbSet<Quote> Quotes { get; set; }
|
public DbSet<Quote> Quotes { get; set; }
|
||||||
public DbSet<Reminder> Reminders { get; set; }
|
public DbSet<Reminder> Reminders { get; set; }
|
||||||
public DbSet<SelfAssignedRole> SelfAssignableRoles { get; set; }
|
|
||||||
public DbSet<MusicPlaylist> MusicPlaylists { get; set; }
|
public DbSet<MusicPlaylist> MusicPlaylists { get; set; }
|
||||||
public DbSet<EllieExpression> Expressions { get; set; }
|
public DbSet<EllieExpression> Expressions { get; set; }
|
||||||
public DbSet<CurrencyTransaction> CurrencyTransactions { get; set; }
|
public DbSet<CurrencyTransaction> CurrencyTransactions { get; set; }
|
||||||
|
@ -74,6 +74,34 @@ public abstract class EllieContext : DbContext
|
||||||
|
|
||||||
protected override void OnModelCreating(ModelBuilder modelBuilder)
|
protected override void OnModelCreating(ModelBuilder modelBuilder)
|
||||||
{
|
{
|
||||||
|
#region New Sar
|
||||||
|
|
||||||
|
modelBuilder.Entity<SarGroup>(sg =>
|
||||||
|
{
|
||||||
|
sg.HasAlternateKey(x => new
|
||||||
|
{
|
||||||
|
x.GuildId,
|
||||||
|
x.GroupNumber
|
||||||
|
});
|
||||||
|
|
||||||
|
sg.HasMany(x => x.Roles)
|
||||||
|
.WithOne()
|
||||||
|
.OnDelete(DeleteBehavior.Cascade);
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity<Sar>()
|
||||||
|
.HasAlternateKey(x => new
|
||||||
|
{
|
||||||
|
x.GuildId,
|
||||||
|
x.RoleId
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity<SarAutoDelete>()
|
||||||
|
.HasIndex(x => x.GuildId)
|
||||||
|
.IsUnique();
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
#region Rakeback
|
#region Rakeback
|
||||||
|
|
||||||
modelBuilder.Entity<Rakeback>()
|
modelBuilder.Entity<Rakeback>()
|
||||||
|
@ -84,16 +112,23 @@ public abstract class EllieContext : DbContext
|
||||||
#region UserBetStats
|
#region UserBetStats
|
||||||
|
|
||||||
modelBuilder.Entity<UserBetStats>()
|
modelBuilder.Entity<UserBetStats>()
|
||||||
.HasIndex(x => new { x.UserId, x.Game })
|
.HasIndex(x => new
|
||||||
|
{
|
||||||
|
x.UserId,
|
||||||
|
x.Game
|
||||||
|
})
|
||||||
.IsUnique();
|
.IsUnique();
|
||||||
|
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
#region Flag Translate
|
#region Flag Translate
|
||||||
|
|
||||||
modelBuilder.Entity<FlagTranslateChannel>()
|
modelBuilder.Entity<FlagTranslateChannel>()
|
||||||
.HasIndex(x => new { x.GuildId, x.ChannelId })
|
.HasIndex(x => new
|
||||||
|
{
|
||||||
|
x.GuildId,
|
||||||
|
x.ChannelId
|
||||||
|
})
|
||||||
.IsUnique();
|
.IsUnique();
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
@ -286,11 +321,6 @@ public abstract class EllieContext : DbContext
|
||||||
.HasForeignKey(x => x.GuildConfigId)
|
.HasForeignKey(x => x.GuildConfigId)
|
||||||
.OnDelete(DeleteBehavior.Cascade);
|
.OnDelete(DeleteBehavior.Cascade);
|
||||||
|
|
||||||
modelBuilder.Entity<GuildConfig>()
|
|
||||||
.HasMany(x => x.SelfAssignableRoleGroupNames)
|
|
||||||
.WithOne()
|
|
||||||
.OnDelete(DeleteBehavior.Cascade);
|
|
||||||
|
|
||||||
modelBuilder.Entity<FeedSub>()
|
modelBuilder.Entity<FeedSub>()
|
||||||
.HasAlternateKey(x => new
|
.HasAlternateKey(x => new
|
||||||
{
|
{
|
||||||
|
@ -319,21 +349,6 @@ public abstract class EllieContext : DbContext
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
#region Self Assignable Roles
|
|
||||||
|
|
||||||
var selfassignableRolesEntity = modelBuilder.Entity<SelfAssignedRole>();
|
|
||||||
|
|
||||||
selfassignableRolesEntity.HasIndex(s => new
|
|
||||||
{
|
|
||||||
s.GuildId,
|
|
||||||
s.RoleId
|
|
||||||
})
|
|
||||||
.IsUnique();
|
|
||||||
|
|
||||||
selfassignableRolesEntity.Property(x => x.Group).HasDefaultValue(0);
|
|
||||||
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
#region MusicPlaylists
|
#region MusicPlaylists
|
||||||
|
|
||||||
var musicPlaylistEntity = modelBuilder.Entity<MusicPlaylist>();
|
var musicPlaylistEntity = modelBuilder.Entity<MusicPlaylist>();
|
||||||
|
@ -401,10 +416,10 @@ public abstract class EllieContext : DbContext
|
||||||
|
|
||||||
var xps = modelBuilder.Entity<UserXpStats>();
|
var xps = modelBuilder.Entity<UserXpStats>();
|
||||||
xps.HasIndex(x => new
|
xps.HasIndex(x => new
|
||||||
{
|
{
|
||||||
x.UserId,
|
x.UserId,
|
||||||
x.GuildId
|
x.GuildId
|
||||||
})
|
})
|
||||||
.IsUnique();
|
.IsUnique();
|
||||||
|
|
||||||
xps.HasIndex(x => x.UserId);
|
xps.HasIndex(x => x.UserId);
|
||||||
|
@ -450,9 +465,9 @@ public abstract class EllieContext : DbContext
|
||||||
.OnDelete(DeleteBehavior.SetNull);
|
.OnDelete(DeleteBehavior.SetNull);
|
||||||
|
|
||||||
ci.HasIndex(x => new
|
ci.HasIndex(x => new
|
||||||
{
|
{
|
||||||
x.Name
|
x.Name
|
||||||
})
|
})
|
||||||
.IsUnique();
|
.IsUnique();
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
@ -516,23 +531,6 @@ public abstract class EllieContext : DbContext
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
#region GroupName
|
|
||||||
|
|
||||||
modelBuilder.Entity<GroupName>()
|
|
||||||
.HasIndex(x => new
|
|
||||||
{
|
|
||||||
x.GuildConfigId,
|
|
||||||
x.Number
|
|
||||||
})
|
|
||||||
.IsUnique();
|
|
||||||
|
|
||||||
modelBuilder.Entity<GroupName>()
|
|
||||||
.HasOne(x => x.GuildConfig)
|
|
||||||
.WithMany(x => x.SelfAssignableRoleGroupNames)
|
|
||||||
.IsRequired();
|
|
||||||
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
#region BanTemplate
|
#region BanTemplate
|
||||||
|
|
||||||
modelBuilder.Entity<BanTemplate>().HasIndex(x => x.GuildId).IsUnique();
|
modelBuilder.Entity<BanTemplate>().HasIndex(x => x.GuildId).IsUnique();
|
||||||
|
@ -571,10 +569,10 @@ public abstract class EllieContext : DbContext
|
||||||
.IsUnique(false);
|
.IsUnique(false);
|
||||||
|
|
||||||
rr2.HasIndex(x => new
|
rr2.HasIndex(x => new
|
||||||
{
|
{
|
||||||
x.MessageId,
|
x.MessageId,
|
||||||
x.Emote
|
x.Emote
|
||||||
})
|
})
|
||||||
.IsUnique();
|
.IsUnique();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -649,11 +647,11 @@ public abstract class EllieContext : DbContext
|
||||||
{
|
{
|
||||||
// user can own only one of each item
|
// user can own only one of each item
|
||||||
x.HasIndex(model => new
|
x.HasIndex(model => new
|
||||||
{
|
{
|
||||||
model.UserId,
|
model.UserId,
|
||||||
model.ItemType,
|
model.ItemType,
|
||||||
model.ItemKey
|
model.ItemKey
|
||||||
})
|
})
|
||||||
.IsUnique();
|
.IsUnique();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -678,10 +676,10 @@ public abstract class EllieContext : DbContext
|
||||||
#region Sticky Roles
|
#region Sticky Roles
|
||||||
|
|
||||||
modelBuilder.Entity<StickyRole>(sr => sr.HasIndex(x => new
|
modelBuilder.Entity<StickyRole>(sr => sr.HasIndex(x => new
|
||||||
{
|
{
|
||||||
x.GuildId,
|
x.GuildId,
|
||||||
x.UserId
|
x.UserId
|
||||||
})
|
})
|
||||||
.IsUnique());
|
.IsUnique());
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
@ -726,10 +724,10 @@ public abstract class EllieContext : DbContext
|
||||||
|
|
||||||
modelBuilder
|
modelBuilder
|
||||||
.Entity<GreetSettings>(gs => gs.HasIndex(x => new
|
.Entity<GreetSettings>(gs => gs.HasIndex(x => new
|
||||||
{
|
{
|
||||||
x.GuildId,
|
x.GuildId,
|
||||||
x.GreetType
|
x.GreetType
|
||||||
})
|
})
|
||||||
.IsUnique());
|
.IsUnique());
|
||||||
|
|
||||||
modelBuilder.Entity<GreetSettings>(gs =>
|
modelBuilder.Entity<GreetSettings>(gs =>
|
||||||
|
|
|
@ -1,5 +1,4 @@
|
||||||
#nullable disable
|
using LinqToDB;
|
||||||
using LinqToDB;
|
|
||||||
using LinqToDB.EntityFrameworkCore;
|
using LinqToDB.EntityFrameworkCore;
|
||||||
using Microsoft.EntityFrameworkCore;
|
using Microsoft.EntityFrameworkCore;
|
||||||
using EllieBot.Db.Models;
|
using EllieBot.Db.Models;
|
||||||
|
@ -8,6 +7,9 @@ namespace EllieBot.Db;
|
||||||
|
|
||||||
public static class UserXpExtensions
|
public static class UserXpExtensions
|
||||||
{
|
{
|
||||||
|
public static async Task<UserXpStats?> GetGuildUserXp(this ITable<UserXpStats> table, ulong guildId, ulong userId)
|
||||||
|
=> await table.FirstOrDefaultAsyncLinqToDB(x => x.GuildId == guildId && x.UserId == userId);
|
||||||
|
|
||||||
public static UserXpStats GetOrCreateUserXpStats(this DbContext ctx, ulong guildId, ulong userId)
|
public static UserXpStats GetOrCreateUserXpStats(this DbContext ctx, ulong guildId, ulong userId)
|
||||||
{
|
{
|
||||||
var usr = ctx.Set<UserXpStats>().FirstOrDefault(x => x.UserId == userId && x.GuildId == guildId);
|
var usr = ctx.Set<UserXpStats>().FirstOrDefault(x => x.UserId == userId && x.GuildId == guildId);
|
||||||
|
|
|
@ -9,7 +9,8 @@ public class FollowedStream : DbEntity
|
||||||
Picarto = 3,
|
Picarto = 3,
|
||||||
Youtube = 4,
|
Youtube = 4,
|
||||||
Facebook = 5,
|
Facebook = 5,
|
||||||
Trovo = 6
|
Trovo = 6,
|
||||||
|
Kick = 7,
|
||||||
}
|
}
|
||||||
|
|
||||||
public ulong GuildId { get; set; }
|
public ulong GuildId { get; set; }
|
||||||
|
|
|
@ -1,11 +1,18 @@
|
||||||
#nullable disable
|
using System.ComponentModel.DataAnnotations;
|
||||||
|
|
||||||
namespace EllieBot.Db.Models;
|
namespace EllieBot.Db.Models;
|
||||||
|
|
||||||
public class GroupName : DbEntity
|
public sealed class SarGroup : DbEntity
|
||||||
{
|
{
|
||||||
public int GuildConfigId { get; set; }
|
[Key]
|
||||||
public GuildConfig GuildConfig { get; set; }
|
public int Id { get; set; }
|
||||||
|
|
||||||
public int Number { get; set; }
|
public int GroupNumber { get; set; }
|
||||||
public string Name { get; set; }
|
public ulong GuildId { get; set; }
|
||||||
|
public ulong? RoleReq { get; set; }
|
||||||
|
public ICollection<Sar> Roles { get; set; } = [];
|
||||||
|
public bool IsExclusive { get; set; }
|
||||||
|
|
||||||
|
[MaxLength(100)]
|
||||||
|
public string? Name { get; set; }
|
||||||
}
|
}
|
|
@ -31,10 +31,11 @@ public class GuildConfig : DbEntity
|
||||||
// public bool SendBoostMessage { get; set; }
|
// public bool SendBoostMessage { get; set; }
|
||||||
// pulic int BoostMessageDeleteAfter { get; set; }
|
// pulic int BoostMessageDeleteAfter { get; set; }
|
||||||
|
|
||||||
//self assignable roles
|
//todo FUTURE: DELETE, UNUSED
|
||||||
public bool ExclusiveSelfAssignedRoles { get; set; }
|
public bool ExclusiveSelfAssignedRoles { get; set; }
|
||||||
public bool AutoDeleteSelfAssignedRoleMessages { get; set; }
|
public bool AutoDeleteSelfAssignedRoleMessages { get; set; }
|
||||||
|
|
||||||
|
|
||||||
//stream notifications
|
//stream notifications
|
||||||
public HashSet<FollowedStream> FollowedStreams { get; set; } = new();
|
public HashSet<FollowedStream> FollowedStreams { get; set; } = new();
|
||||||
|
|
||||||
|
@ -91,7 +92,6 @@ public class GuildConfig : DbEntity
|
||||||
public List<FeedSub> FeedSubs { get; set; } = new();
|
public List<FeedSub> FeedSubs { get; set; } = new();
|
||||||
public bool NotifyStreamOffline { get; set; }
|
public bool NotifyStreamOffline { get; set; }
|
||||||
public bool DeleteStreamOnlineMessage { get; set; }
|
public bool DeleteStreamOnlineMessage { get; set; }
|
||||||
public List<GroupName> SelfAssignableRoleGroupNames { get; set; }
|
|
||||||
public int WarnExpireHours { get; set; }
|
public int WarnExpireHours { get; set; }
|
||||||
public WarnExpireAction WarnExpireAction { get; set; } = WarnExpireAction.Clear;
|
public WarnExpireAction WarnExpireAction { get; set; } = WarnExpireAction.Clear;
|
||||||
|
|
||||||
|
|
|
@ -1,11 +1,24 @@
|
||||||
#nullable disable
|
using System.ComponentModel.DataAnnotations;
|
||||||
|
|
||||||
namespace EllieBot.Db.Models;
|
namespace EllieBot.Db.Models;
|
||||||
|
|
||||||
public class SelfAssignedRole : DbEntity
|
public sealed class Sar
|
||||||
{
|
{
|
||||||
|
[Key]
|
||||||
|
public int Id { get; set; }
|
||||||
|
|
||||||
public ulong GuildId { get; set; }
|
public ulong GuildId { get; set; }
|
||||||
public ulong RoleId { get; set; }
|
public ulong RoleId { get; set; }
|
||||||
|
|
||||||
public int Group { get; set; }
|
public int SarGroupId { get; set; }
|
||||||
public int LevelRequirement { get; set; }
|
public int LevelReq { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public sealed class SarAutoDelete
|
||||||
|
{
|
||||||
|
[Key]
|
||||||
|
public int Id { get; set; }
|
||||||
|
|
||||||
|
public ulong GuildId { get; set; }
|
||||||
|
public bool IsEnabled { get; set; } = false;
|
||||||
}
|
}
|
|
@ -4,7 +4,7 @@
|
||||||
<Nullable>enable</Nullable>
|
<Nullable>enable</Nullable>
|
||||||
<ImplicitUsings>true</ImplicitUsings>
|
<ImplicitUsings>true</ImplicitUsings>
|
||||||
<SatelliteResourceLanguages>en</SatelliteResourceLanguages>
|
<SatelliteResourceLanguages>en</SatelliteResourceLanguages>
|
||||||
<Version>5.1.20</Version>
|
<Version>5.2.0</Version>
|
||||||
|
|
||||||
<!-- Output/build -->
|
<!-- Output/build -->
|
||||||
<RunWorkingDirectory>$(MSBuildProjectDirectory)</RunWorkingDirectory>
|
<RunWorkingDirectory>$(MSBuildProjectDirectory)</RunWorkingDirectory>
|
||||||
|
|
|
@ -5,6 +5,37 @@ namespace EllieBot.Migrations;
|
||||||
|
|
||||||
public static class MigrationQueries
|
public static class MigrationQueries
|
||||||
{
|
{
|
||||||
|
public static void MigrateSar(MigrationBuilder migrationBuilder)
|
||||||
|
{
|
||||||
|
migrationBuilder.Sql("""
|
||||||
|
INSERT INTO GroupName (Number, GuildConfigId)
|
||||||
|
SELECT DISTINCT "Group", GC.Id
|
||||||
|
FROM SelfAssignableRoles as SAR
|
||||||
|
INNER JOIN GuildConfigs as GC
|
||||||
|
ON SAR.GuildId = GC.GuildId
|
||||||
|
WHERE SAR.GuildId not in (SELECT GuildConfigs.GuildId from GroupName LEFT JOIN GuildConfigs ON GroupName.GuildConfigId = GuildConfigs.Id);
|
||||||
|
|
||||||
|
INSERT INTO SarGroup (Id, GroupNumber, Name, IsExclusive, GuildId)
|
||||||
|
SELECT GN.Id, GN.Number, GN.Name, GC.ExclusiveSelfAssignedRoles, GC.GuildId
|
||||||
|
FROM GroupName as GN
|
||||||
|
INNER JOIN GuildConfigs as GC ON GN.GuildConfigId = GC.Id;
|
||||||
|
|
||||||
|
INSERT INTO Sar (GuildId, RoleId, SarGroupId, LevelReq)
|
||||||
|
SELECT SAR.GuildId, SAR.RoleId, MIN(SG2.Id), MIN(SAR.LevelRequirement)
|
||||||
|
FROM SelfAssignableRoles as SAR
|
||||||
|
INNER JOIN (SELECT GuildId FROM GroupName as gn
|
||||||
|
INNER JOIN GuildConfigs as gc ON gn.GuildConfigId =gc.Id
|
||||||
|
) as SG
|
||||||
|
ON SG.GuildId = SAR.GuildId
|
||||||
|
INNER JOIN GroupName as SG2
|
||||||
|
ON SG2.Number = SAR."Group"
|
||||||
|
GROUP BY SAR.GuildId, SAR.RoleId;
|
||||||
|
|
||||||
|
INSERT INTO SarAutoDelete (GuildId, IsEnabled)
|
||||||
|
SELECT GuildId, AutoDeleteSelfAssignedRoleMessages FROM GuildConfigs WHERE AutoDeleteSelfAssignedRoleMessages = TRUE;
|
||||||
|
""");
|
||||||
|
}
|
||||||
|
|
||||||
public static void UpdateUsernames(MigrationBuilder migrationBuilder)
|
public static void UpdateUsernames(MigrationBuilder migrationBuilder)
|
||||||
{
|
{
|
||||||
migrationBuilder.Sql("UPDATE DiscordUser SET Username = '??' || Username WHERE Discriminator = '????';");
|
migrationBuilder.Sql("UPDATE DiscordUser SET Username = '??' || Username WHERE Discriminator = '????';");
|
||||||
|
|
|
@ -12,8 +12,6 @@ namespace EllieBot.Migrations.PostgreSql
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
protected override void Up(MigrationBuilder migrationBuilder)
|
protected override void Up(MigrationBuilder migrationBuilder)
|
||||||
{
|
{
|
||||||
MigrationQueries.UpdateUsernames(migrationBuilder);
|
|
||||||
|
|
||||||
migrationBuilder.DropColumn(
|
migrationBuilder.DropColumn(
|
||||||
name: "discriminator",
|
name: "discriminator",
|
||||||
table: "discorduser");
|
table: "discorduser");
|
||||||
|
|
3951
src/EllieBot/Migrations/PostgreSql/20241127092257_sar-rework.Designer.cs
generated
Normal file
3951
src/EllieBot/Migrations/PostgreSql/20241127092257_sar-rework.Designer.cs
generated
Normal file
File diff suppressed because it is too large
Load diff
153
src/EllieBot/Migrations/PostgreSql/20241127092257_sar-rework.cs
Normal file
153
src/EllieBot/Migrations/PostgreSql/20241127092257_sar-rework.cs
Normal file
|
@ -0,0 +1,153 @@
|
||||||
|
using System;
|
||||||
|
using Microsoft.EntityFrameworkCore.Migrations;
|
||||||
|
using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata;
|
||||||
|
|
||||||
|
#nullable disable
|
||||||
|
|
||||||
|
namespace EllieBot.Migrations.PostgreSql
|
||||||
|
{
|
||||||
|
/// <inheritdoc />
|
||||||
|
public partial class sarrework : Migration
|
||||||
|
{
|
||||||
|
/// <inheritdoc />
|
||||||
|
protected override void Up(MigrationBuilder migrationBuilder)
|
||||||
|
{
|
||||||
|
migrationBuilder.DropTable(
|
||||||
|
name: "groupname");
|
||||||
|
|
||||||
|
migrationBuilder.DropTable(
|
||||||
|
name: "selfassignableroles");
|
||||||
|
|
||||||
|
migrationBuilder.CreateTable(
|
||||||
|
name: "sarautodelete",
|
||||||
|
columns: table => new
|
||||||
|
{
|
||||||
|
id = table.Column<int>(type: "integer", nullable: false)
|
||||||
|
.Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn),
|
||||||
|
guildid = table.Column<decimal>(type: "numeric(20,0)", nullable: false),
|
||||||
|
isenabled = table.Column<bool>(type: "boolean", nullable: false)
|
||||||
|
},
|
||||||
|
constraints: table =>
|
||||||
|
{
|
||||||
|
table.PrimaryKey("pk_sarautodelete", x => x.id);
|
||||||
|
});
|
||||||
|
|
||||||
|
migrationBuilder.CreateTable(
|
||||||
|
name: "sargroup",
|
||||||
|
columns: table => new
|
||||||
|
{
|
||||||
|
id = table.Column<int>(type: "integer", nullable: false)
|
||||||
|
.Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn),
|
||||||
|
groupnumber = table.Column<int>(type: "integer", nullable: false),
|
||||||
|
guildid = table.Column<decimal>(type: "numeric(20,0)", nullable: false),
|
||||||
|
rolereq = table.Column<decimal>(type: "numeric(20,0)", nullable: true),
|
||||||
|
isexclusive = table.Column<bool>(type: "boolean", nullable: false),
|
||||||
|
name = table.Column<string>(type: "character varying(100)", maxLength: 100, nullable: true),
|
||||||
|
dateadded = table.Column<DateTime>(type: "timestamp without time zone", nullable: true)
|
||||||
|
},
|
||||||
|
constraints: table =>
|
||||||
|
{
|
||||||
|
table.PrimaryKey("pk_sargroup", x => x.id);
|
||||||
|
table.UniqueConstraint("ak_sargroup_guildid_groupnumber", x => new { x.guildid, x.groupnumber });
|
||||||
|
});
|
||||||
|
|
||||||
|
migrationBuilder.CreateTable(
|
||||||
|
name: "sar",
|
||||||
|
columns: table => new
|
||||||
|
{
|
||||||
|
id = table.Column<int>(type: "integer", nullable: false)
|
||||||
|
.Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn),
|
||||||
|
guildid = table.Column<decimal>(type: "numeric(20,0)", nullable: false),
|
||||||
|
roleid = table.Column<decimal>(type: "numeric(20,0)", nullable: false),
|
||||||
|
sargroupid = table.Column<int>(type: "integer", nullable: false),
|
||||||
|
levelreq = table.Column<int>(type: "integer", nullable: false)
|
||||||
|
},
|
||||||
|
constraints: table =>
|
||||||
|
{
|
||||||
|
table.PrimaryKey("pk_sar", x => x.id);
|
||||||
|
table.UniqueConstraint("ak_sar_guildid_roleid", x => new { x.guildid, x.roleid });
|
||||||
|
table.ForeignKey(
|
||||||
|
name: "fk_sar_sargroup_sargroupid",
|
||||||
|
column: x => x.sargroupid,
|
||||||
|
principalTable: "sargroup",
|
||||||
|
principalColumn: "id",
|
||||||
|
onDelete: ReferentialAction.Cascade);
|
||||||
|
});
|
||||||
|
|
||||||
|
migrationBuilder.CreateIndex(
|
||||||
|
name: "ix_sar_sargroupid",
|
||||||
|
table: "sar",
|
||||||
|
column: "sargroupid");
|
||||||
|
|
||||||
|
migrationBuilder.CreateIndex(
|
||||||
|
name: "ix_sarautodelete_guildid",
|
||||||
|
table: "sarautodelete",
|
||||||
|
column: "guildid",
|
||||||
|
unique: true);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
protected override void Down(MigrationBuilder migrationBuilder)
|
||||||
|
{
|
||||||
|
migrationBuilder.DropTable(
|
||||||
|
name: "sar");
|
||||||
|
|
||||||
|
migrationBuilder.DropTable(
|
||||||
|
name: "sarautodelete");
|
||||||
|
|
||||||
|
migrationBuilder.DropTable(
|
||||||
|
name: "sargroup");
|
||||||
|
|
||||||
|
migrationBuilder.CreateTable(
|
||||||
|
name: "groupname",
|
||||||
|
columns: table => new
|
||||||
|
{
|
||||||
|
id = table.Column<int>(type: "integer", nullable: false)
|
||||||
|
.Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn),
|
||||||
|
guildconfigid = table.Column<int>(type: "integer", nullable: false),
|
||||||
|
dateadded = table.Column<DateTime>(type: "timestamp without time zone", nullable: true),
|
||||||
|
name = table.Column<string>(type: "text", nullable: true),
|
||||||
|
number = table.Column<int>(type: "integer", nullable: false)
|
||||||
|
},
|
||||||
|
constraints: table =>
|
||||||
|
{
|
||||||
|
table.PrimaryKey("pk_groupname", x => x.id);
|
||||||
|
table.ForeignKey(
|
||||||
|
name: "fk_groupname_guildconfigs_guildconfigid",
|
||||||
|
column: x => x.guildconfigid,
|
||||||
|
principalTable: "guildconfigs",
|
||||||
|
principalColumn: "id",
|
||||||
|
onDelete: ReferentialAction.Cascade);
|
||||||
|
});
|
||||||
|
|
||||||
|
migrationBuilder.CreateTable(
|
||||||
|
name: "selfassignableroles",
|
||||||
|
columns: table => new
|
||||||
|
{
|
||||||
|
id = table.Column<int>(type: "integer", nullable: false)
|
||||||
|
.Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn),
|
||||||
|
dateadded = table.Column<DateTime>(type: "timestamp without time zone", nullable: true),
|
||||||
|
group = table.Column<int>(type: "integer", nullable: false, defaultValue: 0),
|
||||||
|
guildid = table.Column<decimal>(type: "numeric(20,0)", nullable: false),
|
||||||
|
levelrequirement = table.Column<int>(type: "integer", nullable: false),
|
||||||
|
roleid = table.Column<decimal>(type: "numeric(20,0)", nullable: false)
|
||||||
|
},
|
||||||
|
constraints: table =>
|
||||||
|
{
|
||||||
|
table.PrimaryKey("pk_selfassignableroles", x => x.id);
|
||||||
|
});
|
||||||
|
|
||||||
|
migrationBuilder.CreateIndex(
|
||||||
|
name: "ix_groupname_guildconfigid_number",
|
||||||
|
table: "groupname",
|
||||||
|
columns: new[] { "guildconfigid", "number" },
|
||||||
|
unique: true);
|
||||||
|
|
||||||
|
migrationBuilder.CreateIndex(
|
||||||
|
name: "ix_selfassignableroles_guildid_roleid",
|
||||||
|
table: "selfassignableroles",
|
||||||
|
columns: new[] { "guildid", "roleid" },
|
||||||
|
unique: true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -1253,41 +1253,6 @@ namespace EllieBot.Migrations.PostgreSql
|
||||||
b.ToTable("giveawayuser", (string)null);
|
b.ToTable("giveawayuser", (string)null);
|
||||||
});
|
});
|
||||||
|
|
||||||
modelBuilder.Entity("EllieBot.Db.Models.GroupName", b =>
|
|
||||||
{
|
|
||||||
b.Property<int>("Id")
|
|
||||||
.ValueGeneratedOnAdd()
|
|
||||||
.HasColumnType("integer")
|
|
||||||
.HasColumnName("id");
|
|
||||||
|
|
||||||
NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id"));
|
|
||||||
|
|
||||||
b.Property<DateTime?>("DateAdded")
|
|
||||||
.HasColumnType("timestamp without time zone")
|
|
||||||
.HasColumnName("dateadded");
|
|
||||||
|
|
||||||
b.Property<int>("GuildConfigId")
|
|
||||||
.HasColumnType("integer")
|
|
||||||
.HasColumnName("guildconfigid");
|
|
||||||
|
|
||||||
b.Property<string>("Name")
|
|
||||||
.HasColumnType("text")
|
|
||||||
.HasColumnName("name");
|
|
||||||
|
|
||||||
b.Property<int>("Number")
|
|
||||||
.HasColumnType("integer")
|
|
||||||
.HasColumnName("number");
|
|
||||||
|
|
||||||
b.HasKey("Id")
|
|
||||||
.HasName("pk_groupname");
|
|
||||||
|
|
||||||
b.HasIndex("GuildConfigId", "Number")
|
|
||||||
.IsUnique()
|
|
||||||
.HasDatabaseName("ix_groupname_guildconfigid_number");
|
|
||||||
|
|
||||||
b.ToTable("groupname", (string)null);
|
|
||||||
});
|
|
||||||
|
|
||||||
modelBuilder.Entity("EllieBot.Db.Models.GuildConfig", b =>
|
modelBuilder.Entity("EllieBot.Db.Models.GuildConfig", b =>
|
||||||
{
|
{
|
||||||
b.Property<int>("Id")
|
b.Property<int>("Id")
|
||||||
|
@ -2200,7 +2165,71 @@ namespace EllieBot.Migrations.PostgreSql
|
||||||
b.ToTable("rotatingstatus", (string)null);
|
b.ToTable("rotatingstatus", (string)null);
|
||||||
});
|
});
|
||||||
|
|
||||||
modelBuilder.Entity("EllieBot.Db.Models.SelfAssignedRole", b =>
|
modelBuilder.Entity("EllieBot.Db.Models.Sar", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("integer")
|
||||||
|
.HasColumnName("id");
|
||||||
|
|
||||||
|
NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id"));
|
||||||
|
|
||||||
|
b.Property<decimal>("GuildId")
|
||||||
|
.HasColumnType("numeric(20,0)")
|
||||||
|
.HasColumnName("guildid");
|
||||||
|
|
||||||
|
b.Property<int>("LevelReq")
|
||||||
|
.HasColumnType("integer")
|
||||||
|
.HasColumnName("levelreq");
|
||||||
|
|
||||||
|
b.Property<decimal>("RoleId")
|
||||||
|
.HasColumnType("numeric(20,0)")
|
||||||
|
.HasColumnName("roleid");
|
||||||
|
|
||||||
|
b.Property<int>("SarGroupId")
|
||||||
|
.HasColumnType("integer")
|
||||||
|
.HasColumnName("sargroupid");
|
||||||
|
|
||||||
|
b.HasKey("Id")
|
||||||
|
.HasName("pk_sar");
|
||||||
|
|
||||||
|
b.HasAlternateKey("GuildId", "RoleId")
|
||||||
|
.HasName("ak_sar_guildid_roleid");
|
||||||
|
|
||||||
|
b.HasIndex("SarGroupId")
|
||||||
|
.HasDatabaseName("ix_sar_sargroupid");
|
||||||
|
|
||||||
|
b.ToTable("sar", (string)null);
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("EllieBot.Db.Models.SarAutoDelete", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("integer")
|
||||||
|
.HasColumnName("id");
|
||||||
|
|
||||||
|
NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id"));
|
||||||
|
|
||||||
|
b.Property<decimal>("GuildId")
|
||||||
|
.HasColumnType("numeric(20,0)")
|
||||||
|
.HasColumnName("guildid");
|
||||||
|
|
||||||
|
b.Property<bool>("IsEnabled")
|
||||||
|
.HasColumnType("boolean")
|
||||||
|
.HasColumnName("isenabled");
|
||||||
|
|
||||||
|
b.HasKey("Id")
|
||||||
|
.HasName("pk_sarautodelete");
|
||||||
|
|
||||||
|
b.HasIndex("GuildId")
|
||||||
|
.IsUnique()
|
||||||
|
.HasDatabaseName("ix_sarautodelete_guildid");
|
||||||
|
|
||||||
|
b.ToTable("sarautodelete", (string)null);
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("EllieBot.Db.Models.SarGroup", b =>
|
||||||
{
|
{
|
||||||
b.Property<int>("Id")
|
b.Property<int>("Id")
|
||||||
.ValueGeneratedOnAdd()
|
.ValueGeneratedOnAdd()
|
||||||
|
@ -2213,32 +2242,34 @@ namespace EllieBot.Migrations.PostgreSql
|
||||||
.HasColumnType("timestamp without time zone")
|
.HasColumnType("timestamp without time zone")
|
||||||
.HasColumnName("dateadded");
|
.HasColumnName("dateadded");
|
||||||
|
|
||||||
b.Property<int>("Group")
|
b.Property<int>("GroupNumber")
|
||||||
.ValueGeneratedOnAdd()
|
|
||||||
.HasColumnType("integer")
|
.HasColumnType("integer")
|
||||||
.HasDefaultValue(0)
|
.HasColumnName("groupnumber");
|
||||||
.HasColumnName("group");
|
|
||||||
|
|
||||||
b.Property<decimal>("GuildId")
|
b.Property<decimal>("GuildId")
|
||||||
.HasColumnType("numeric(20,0)")
|
.HasColumnType("numeric(20,0)")
|
||||||
.HasColumnName("guildid");
|
.HasColumnName("guildid");
|
||||||
|
|
||||||
b.Property<int>("LevelRequirement")
|
b.Property<bool>("IsExclusive")
|
||||||
.HasColumnType("integer")
|
.HasColumnType("boolean")
|
||||||
.HasColumnName("levelrequirement");
|
.HasColumnName("isexclusive");
|
||||||
|
|
||||||
b.Property<decimal>("RoleId")
|
b.Property<string>("Name")
|
||||||
|
.HasMaxLength(100)
|
||||||
|
.HasColumnType("character varying(100)")
|
||||||
|
.HasColumnName("name");
|
||||||
|
|
||||||
|
b.Property<decimal?>("RoleReq")
|
||||||
.HasColumnType("numeric(20,0)")
|
.HasColumnType("numeric(20,0)")
|
||||||
.HasColumnName("roleid");
|
.HasColumnName("rolereq");
|
||||||
|
|
||||||
b.HasKey("Id")
|
b.HasKey("Id")
|
||||||
.HasName("pk_selfassignableroles");
|
.HasName("pk_sargroup");
|
||||||
|
|
||||||
b.HasIndex("GuildId", "RoleId")
|
b.HasAlternateKey("GuildId", "GroupNumber")
|
||||||
.IsUnique()
|
.HasName("ak_sargroup_guildid_groupnumber");
|
||||||
.HasDatabaseName("ix_selfassignableroles_guildid_roleid");
|
|
||||||
|
|
||||||
b.ToTable("selfassignableroles", (string)null);
|
b.ToTable("sargroup", (string)null);
|
||||||
});
|
});
|
||||||
|
|
||||||
modelBuilder.Entity("EllieBot.Db.Models.ShopEntry", b =>
|
modelBuilder.Entity("EllieBot.Db.Models.ShopEntry", b =>
|
||||||
|
@ -3527,18 +3558,6 @@ namespace EllieBot.Migrations.PostgreSql
|
||||||
.HasConstraintName("fk_giveawayuser_giveawaymodel_giveawayid");
|
.HasConstraintName("fk_giveawayuser_giveawaymodel_giveawayid");
|
||||||
});
|
});
|
||||||
|
|
||||||
modelBuilder.Entity("EllieBot.Db.Models.GroupName", b =>
|
|
||||||
{
|
|
||||||
b.HasOne("EllieBot.Db.Models.GuildConfig", "GuildConfig")
|
|
||||||
.WithMany("SelfAssignableRoleGroupNames")
|
|
||||||
.HasForeignKey("GuildConfigId")
|
|
||||||
.OnDelete(DeleteBehavior.Cascade)
|
|
||||||
.IsRequired()
|
|
||||||
.HasConstraintName("fk_groupname_guildconfigs_guildconfigid");
|
|
||||||
|
|
||||||
b.Navigation("GuildConfig");
|
|
||||||
});
|
|
||||||
|
|
||||||
modelBuilder.Entity("EllieBot.Db.Models.IgnoredLogItem", b =>
|
modelBuilder.Entity("EllieBot.Db.Models.IgnoredLogItem", b =>
|
||||||
{
|
{
|
||||||
b.HasOne("EllieBot.Db.Models.LogSetting", "LogSetting")
|
b.HasOne("EllieBot.Db.Models.LogSetting", "LogSetting")
|
||||||
|
@ -3578,6 +3597,16 @@ namespace EllieBot.Migrations.PostgreSql
|
||||||
.HasConstraintName("fk_playlistsong_musicplaylists_musicplaylistid");
|
.HasConstraintName("fk_playlistsong_musicplaylists_musicplaylistid");
|
||||||
});
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("EllieBot.Db.Models.Sar", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("EllieBot.Db.Models.SarGroup", null)
|
||||||
|
.WithMany("Roles")
|
||||||
|
.HasForeignKey("SarGroupId")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade)
|
||||||
|
.IsRequired()
|
||||||
|
.HasConstraintName("fk_sar_sargroup_sargroupid");
|
||||||
|
});
|
||||||
|
|
||||||
modelBuilder.Entity("EllieBot.Db.Models.ShopEntry", b =>
|
modelBuilder.Entity("EllieBot.Db.Models.ShopEntry", b =>
|
||||||
{
|
{
|
||||||
b.HasOne("EllieBot.Db.Models.GuildConfig", null)
|
b.HasOne("EllieBot.Db.Models.GuildConfig", null)
|
||||||
|
@ -3854,8 +3883,6 @@ namespace EllieBot.Migrations.PostgreSql
|
||||||
|
|
||||||
b.Navigation("Permissions");
|
b.Navigation("Permissions");
|
||||||
|
|
||||||
b.Navigation("SelfAssignableRoleGroupNames");
|
|
||||||
|
|
||||||
b.Navigation("ShopEntries");
|
b.Navigation("ShopEntries");
|
||||||
|
|
||||||
b.Navigation("SlowmodeIgnoredRoles");
|
b.Navigation("SlowmodeIgnoredRoles");
|
||||||
|
@ -3885,6 +3912,11 @@ namespace EllieBot.Migrations.PostgreSql
|
||||||
b.Navigation("Songs");
|
b.Navigation("Songs");
|
||||||
});
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("EllieBot.Db.Models.SarGroup", b =>
|
||||||
|
{
|
||||||
|
b.Navigation("Roles");
|
||||||
|
});
|
||||||
|
|
||||||
modelBuilder.Entity("EllieBot.Db.Models.ShopEntry", b =>
|
modelBuilder.Entity("EllieBot.Db.Models.ShopEntry", b =>
|
||||||
{
|
{
|
||||||
b.Navigation("Items");
|
b.Navigation("Items");
|
||||||
|
|
|
@ -11,8 +11,6 @@ namespace EllieBot.Migrations
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
protected override void Up(MigrationBuilder migrationBuilder)
|
protected override void Up(MigrationBuilder migrationBuilder)
|
||||||
{
|
{
|
||||||
MigrationQueries.UpdateUsernames(migrationBuilder);
|
|
||||||
|
|
||||||
migrationBuilder.DropColumn(
|
migrationBuilder.DropColumn(
|
||||||
name: "Discriminator",
|
name: "Discriminator",
|
||||||
table: "DiscordUser");
|
table: "DiscordUser");
|
||||||
|
|
3048
src/EllieBot/Migrations/Sqlite/20241127092212_sar-rework.Designer.cs
generated
Normal file
3048
src/EllieBot/Migrations/Sqlite/20241127092212_sar-rework.Designer.cs
generated
Normal file
File diff suppressed because it is too large
Load diff
152
src/EllieBot/Migrations/Sqlite/20241127092212_sar-rework.cs
Normal file
152
src/EllieBot/Migrations/Sqlite/20241127092212_sar-rework.cs
Normal file
|
@ -0,0 +1,152 @@
|
||||||
|
using System;
|
||||||
|
using Microsoft.EntityFrameworkCore.Migrations;
|
||||||
|
|
||||||
|
#nullable disable
|
||||||
|
|
||||||
|
namespace EllieBot.Migrations
|
||||||
|
{
|
||||||
|
/// <inheritdoc />
|
||||||
|
public partial class sarrework : Migration
|
||||||
|
{
|
||||||
|
/// <inheritdoc />
|
||||||
|
protected override void Up(MigrationBuilder migrationBuilder)
|
||||||
|
{
|
||||||
|
migrationBuilder.DropTable(
|
||||||
|
name: "GroupName");
|
||||||
|
|
||||||
|
migrationBuilder.DropTable(
|
||||||
|
name: "SelfAssignableRoles");
|
||||||
|
|
||||||
|
migrationBuilder.CreateTable(
|
||||||
|
name: "SarAutoDelete",
|
||||||
|
columns: table => new
|
||||||
|
{
|
||||||
|
Id = table.Column<int>(type: "INTEGER", nullable: false)
|
||||||
|
.Annotation("Sqlite:Autoincrement", true),
|
||||||
|
GuildId = table.Column<ulong>(type: "INTEGER", nullable: false),
|
||||||
|
IsEnabled = table.Column<bool>(type: "INTEGER", nullable: false)
|
||||||
|
},
|
||||||
|
constraints: table =>
|
||||||
|
{
|
||||||
|
table.PrimaryKey("PK_SarAutoDelete", x => x.Id);
|
||||||
|
});
|
||||||
|
|
||||||
|
migrationBuilder.CreateTable(
|
||||||
|
name: "SarGroup",
|
||||||
|
columns: table => new
|
||||||
|
{
|
||||||
|
Id = table.Column<int>(type: "INTEGER", nullable: false)
|
||||||
|
.Annotation("Sqlite:Autoincrement", true),
|
||||||
|
GroupNumber = table.Column<int>(type: "INTEGER", nullable: false),
|
||||||
|
GuildId = table.Column<ulong>(type: "INTEGER", nullable: false),
|
||||||
|
RoleReq = table.Column<ulong>(type: "INTEGER", nullable: true),
|
||||||
|
IsExclusive = table.Column<bool>(type: "INTEGER", nullable: false),
|
||||||
|
Name = table.Column<string>(type: "TEXT", maxLength: 100, nullable: true),
|
||||||
|
DateAdded = table.Column<DateTime>(type: "TEXT", nullable: true)
|
||||||
|
},
|
||||||
|
constraints: table =>
|
||||||
|
{
|
||||||
|
table.PrimaryKey("PK_SarGroup", x => x.Id);
|
||||||
|
table.UniqueConstraint("AK_SarGroup_GuildId_GroupNumber", x => new { x.GuildId, x.GroupNumber });
|
||||||
|
});
|
||||||
|
|
||||||
|
migrationBuilder.CreateTable(
|
||||||
|
name: "Sar",
|
||||||
|
columns: table => new
|
||||||
|
{
|
||||||
|
Id = table.Column<int>(type: "INTEGER", nullable: false)
|
||||||
|
.Annotation("Sqlite:Autoincrement", true),
|
||||||
|
GuildId = table.Column<ulong>(type: "INTEGER", nullable: false),
|
||||||
|
RoleId = table.Column<ulong>(type: "INTEGER", nullable: false),
|
||||||
|
SarGroupId = table.Column<int>(type: "INTEGER", nullable: false),
|
||||||
|
LevelReq = table.Column<int>(type: "INTEGER", nullable: false)
|
||||||
|
},
|
||||||
|
constraints: table =>
|
||||||
|
{
|
||||||
|
table.PrimaryKey("PK_Sar", x => x.Id);
|
||||||
|
table.UniqueConstraint("AK_Sar_GuildId_RoleId", x => new { x.GuildId, x.RoleId });
|
||||||
|
table.ForeignKey(
|
||||||
|
name: "FK_Sar_SarGroup_SarGroupId",
|
||||||
|
column: x => x.SarGroupId,
|
||||||
|
principalTable: "SarGroup",
|
||||||
|
principalColumn: "Id",
|
||||||
|
onDelete: ReferentialAction.Cascade);
|
||||||
|
});
|
||||||
|
|
||||||
|
migrationBuilder.CreateIndex(
|
||||||
|
name: "IX_Sar_SarGroupId",
|
||||||
|
table: "Sar",
|
||||||
|
column: "SarGroupId");
|
||||||
|
|
||||||
|
migrationBuilder.CreateIndex(
|
||||||
|
name: "IX_SarAutoDelete_GuildId",
|
||||||
|
table: "SarAutoDelete",
|
||||||
|
column: "GuildId",
|
||||||
|
unique: true);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
protected override void Down(MigrationBuilder migrationBuilder)
|
||||||
|
{
|
||||||
|
migrationBuilder.DropTable(
|
||||||
|
name: "Sar");
|
||||||
|
|
||||||
|
migrationBuilder.DropTable(
|
||||||
|
name: "SarAutoDelete");
|
||||||
|
|
||||||
|
migrationBuilder.DropTable(
|
||||||
|
name: "SarGroup");
|
||||||
|
|
||||||
|
migrationBuilder.CreateTable(
|
||||||
|
name: "GroupName",
|
||||||
|
columns: table => new
|
||||||
|
{
|
||||||
|
Id = table.Column<int>(type: "INTEGER", nullable: false)
|
||||||
|
.Annotation("Sqlite:Autoincrement", true),
|
||||||
|
GuildConfigId = table.Column<int>(type: "INTEGER", nullable: false),
|
||||||
|
DateAdded = table.Column<DateTime>(type: "TEXT", nullable: true),
|
||||||
|
Name = table.Column<string>(type: "TEXT", nullable: true),
|
||||||
|
Number = table.Column<int>(type: "INTEGER", nullable: false)
|
||||||
|
},
|
||||||
|
constraints: table =>
|
||||||
|
{
|
||||||
|
table.PrimaryKey("PK_GroupName", x => x.Id);
|
||||||
|
table.ForeignKey(
|
||||||
|
name: "FK_GroupName_GuildConfigs_GuildConfigId",
|
||||||
|
column: x => x.GuildConfigId,
|
||||||
|
principalTable: "GuildConfigs",
|
||||||
|
principalColumn: "Id",
|
||||||
|
onDelete: ReferentialAction.Cascade);
|
||||||
|
});
|
||||||
|
|
||||||
|
migrationBuilder.CreateTable(
|
||||||
|
name: "SelfAssignableRoles",
|
||||||
|
columns: table => new
|
||||||
|
{
|
||||||
|
Id = table.Column<int>(type: "INTEGER", nullable: false)
|
||||||
|
.Annotation("Sqlite:Autoincrement", true),
|
||||||
|
DateAdded = table.Column<DateTime>(type: "TEXT", nullable: true),
|
||||||
|
Group = table.Column<int>(type: "INTEGER", nullable: false, defaultValue: 0),
|
||||||
|
GuildId = table.Column<ulong>(type: "INTEGER", nullable: false),
|
||||||
|
LevelRequirement = table.Column<int>(type: "INTEGER", nullable: false),
|
||||||
|
RoleId = table.Column<ulong>(type: "INTEGER", nullable: false)
|
||||||
|
},
|
||||||
|
constraints: table =>
|
||||||
|
{
|
||||||
|
table.PrimaryKey("PK_SelfAssignableRoles", x => x.Id);
|
||||||
|
});
|
||||||
|
|
||||||
|
migrationBuilder.CreateIndex(
|
||||||
|
name: "IX_GroupName_GuildConfigId_Number",
|
||||||
|
table: "GroupName",
|
||||||
|
columns: new[] { "GuildConfigId", "Number" },
|
||||||
|
unique: true);
|
||||||
|
|
||||||
|
migrationBuilder.CreateIndex(
|
||||||
|
name: "IX_SelfAssignableRoles_GuildId_RoleId",
|
||||||
|
table: "SelfAssignableRoles",
|
||||||
|
columns: new[] { "GuildId", "RoleId" },
|
||||||
|
unique: true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -932,32 +932,6 @@ namespace EllieBot.Migrations
|
||||||
b.ToTable("GiveawayUser");
|
b.ToTable("GiveawayUser");
|
||||||
});
|
});
|
||||||
|
|
||||||
modelBuilder.Entity("EllieBot.Db.Models.GroupName", b =>
|
|
||||||
{
|
|
||||||
b.Property<int>("Id")
|
|
||||||
.ValueGeneratedOnAdd()
|
|
||||||
.HasColumnType("INTEGER");
|
|
||||||
|
|
||||||
b.Property<DateTime?>("DateAdded")
|
|
||||||
.HasColumnType("TEXT");
|
|
||||||
|
|
||||||
b.Property<int>("GuildConfigId")
|
|
||||||
.HasColumnType("INTEGER");
|
|
||||||
|
|
||||||
b.Property<string>("Name")
|
|
||||||
.HasColumnType("TEXT");
|
|
||||||
|
|
||||||
b.Property<int>("Number")
|
|
||||||
.HasColumnType("INTEGER");
|
|
||||||
|
|
||||||
b.HasKey("Id");
|
|
||||||
|
|
||||||
b.HasIndex("GuildConfigId", "Number")
|
|
||||||
.IsUnique();
|
|
||||||
|
|
||||||
b.ToTable("GroupName");
|
|
||||||
});
|
|
||||||
|
|
||||||
modelBuilder.Entity("EllieBot.Db.Models.GuildConfig", b =>
|
modelBuilder.Entity("EllieBot.Db.Models.GuildConfig", b =>
|
||||||
{
|
{
|
||||||
b.Property<int>("Id")
|
b.Property<int>("Id")
|
||||||
|
@ -1640,7 +1614,54 @@ namespace EllieBot.Migrations
|
||||||
b.ToTable("RotatingStatus");
|
b.ToTable("RotatingStatus");
|
||||||
});
|
});
|
||||||
|
|
||||||
modelBuilder.Entity("EllieBot.Db.Models.SelfAssignedRole", b =>
|
modelBuilder.Entity("EllieBot.Db.Models.Sar", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<ulong>("GuildId")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<int>("LevelReq")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<ulong>("RoleId")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<int>("SarGroupId")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.HasAlternateKey("GuildId", "RoleId");
|
||||||
|
|
||||||
|
b.HasIndex("SarGroupId");
|
||||||
|
|
||||||
|
b.ToTable("Sar");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("EllieBot.Db.Models.SarAutoDelete", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<ulong>("GuildId")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<bool>("IsEnabled")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.HasIndex("GuildId")
|
||||||
|
.IsUnique();
|
||||||
|
|
||||||
|
b.ToTable("SarAutoDelete");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("EllieBot.Db.Models.SarGroup", b =>
|
||||||
{
|
{
|
||||||
b.Property<int>("Id")
|
b.Property<int>("Id")
|
||||||
.ValueGeneratedOnAdd()
|
.ValueGeneratedOnAdd()
|
||||||
|
@ -1649,26 +1670,27 @@ namespace EllieBot.Migrations
|
||||||
b.Property<DateTime?>("DateAdded")
|
b.Property<DateTime?>("DateAdded")
|
||||||
.HasColumnType("TEXT");
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
b.Property<int>("Group")
|
b.Property<int>("GroupNumber")
|
||||||
.ValueGeneratedOnAdd()
|
.HasColumnType("INTEGER");
|
||||||
.HasColumnType("INTEGER")
|
|
||||||
.HasDefaultValue(0);
|
|
||||||
|
|
||||||
b.Property<ulong>("GuildId")
|
b.Property<ulong>("GuildId")
|
||||||
.HasColumnType("INTEGER");
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
b.Property<int>("LevelRequirement")
|
b.Property<bool>("IsExclusive")
|
||||||
.HasColumnType("INTEGER");
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
b.Property<ulong>("RoleId")
|
b.Property<string>("Name")
|
||||||
|
.HasMaxLength(100)
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<ulong?>("RoleReq")
|
||||||
.HasColumnType("INTEGER");
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
b.HasKey("Id");
|
b.HasKey("Id");
|
||||||
|
|
||||||
b.HasIndex("GuildId", "RoleId")
|
b.HasAlternateKey("GuildId", "GroupNumber");
|
||||||
.IsUnique();
|
|
||||||
|
|
||||||
b.ToTable("SelfAssignableRoles");
|
b.ToTable("SarGroup");
|
||||||
});
|
});
|
||||||
|
|
||||||
modelBuilder.Entity("EllieBot.Db.Models.ShopEntry", b =>
|
modelBuilder.Entity("EllieBot.Db.Models.ShopEntry", b =>
|
||||||
|
@ -2660,17 +2682,6 @@ namespace EllieBot.Migrations
|
||||||
.IsRequired();
|
.IsRequired();
|
||||||
});
|
});
|
||||||
|
|
||||||
modelBuilder.Entity("EllieBot.Db.Models.GroupName", b =>
|
|
||||||
{
|
|
||||||
b.HasOne("EllieBot.Db.Models.GuildConfig", "GuildConfig")
|
|
||||||
.WithMany("SelfAssignableRoleGroupNames")
|
|
||||||
.HasForeignKey("GuildConfigId")
|
|
||||||
.OnDelete(DeleteBehavior.Cascade)
|
|
||||||
.IsRequired();
|
|
||||||
|
|
||||||
b.Navigation("GuildConfig");
|
|
||||||
});
|
|
||||||
|
|
||||||
modelBuilder.Entity("EllieBot.Db.Models.IgnoredLogItem", b =>
|
modelBuilder.Entity("EllieBot.Db.Models.IgnoredLogItem", b =>
|
||||||
{
|
{
|
||||||
b.HasOne("EllieBot.Db.Models.LogSetting", "LogSetting")
|
b.HasOne("EllieBot.Db.Models.LogSetting", "LogSetting")
|
||||||
|
@ -2706,6 +2717,15 @@ namespace EllieBot.Migrations
|
||||||
.OnDelete(DeleteBehavior.Cascade);
|
.OnDelete(DeleteBehavior.Cascade);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("EllieBot.Db.Models.Sar", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("EllieBot.Db.Models.SarGroup", null)
|
||||||
|
.WithMany("Roles")
|
||||||
|
.HasForeignKey("SarGroupId")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade)
|
||||||
|
.IsRequired();
|
||||||
|
});
|
||||||
|
|
||||||
modelBuilder.Entity("EllieBot.Db.Models.ShopEntry", b =>
|
modelBuilder.Entity("EllieBot.Db.Models.ShopEntry", b =>
|
||||||
{
|
{
|
||||||
b.HasOne("EllieBot.Db.Models.GuildConfig", null)
|
b.HasOne("EllieBot.Db.Models.GuildConfig", null)
|
||||||
|
@ -2960,8 +2980,6 @@ namespace EllieBot.Migrations
|
||||||
|
|
||||||
b.Navigation("Permissions");
|
b.Navigation("Permissions");
|
||||||
|
|
||||||
b.Navigation("SelfAssignableRoleGroupNames");
|
|
||||||
|
|
||||||
b.Navigation("ShopEntries");
|
b.Navigation("ShopEntries");
|
||||||
|
|
||||||
b.Navigation("SlowmodeIgnoredRoles");
|
b.Navigation("SlowmodeIgnoredRoles");
|
||||||
|
@ -2991,6 +3009,11 @@ namespace EllieBot.Migrations
|
||||||
b.Navigation("Songs");
|
b.Navigation("Songs");
|
||||||
});
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("EllieBot.Db.Models.SarGroup", b =>
|
||||||
|
{
|
||||||
|
b.Navigation("Roles");
|
||||||
|
});
|
||||||
|
|
||||||
modelBuilder.Entity("EllieBot.Db.Models.ShopEntry", b =>
|
modelBuilder.Entity("EllieBot.Db.Models.ShopEntry", b =>
|
||||||
{
|
{
|
||||||
b.Navigation("Items");
|
b.Navigation("Items");
|
||||||
|
|
|
@ -75,7 +75,7 @@ public sealed class CleanupService : ICleanupService, IReadyExecutor, IEService
|
||||||
Log.Information("Leaving {RemainingCount} guilds, 1 every second. {DontDeleteCount} will remain",
|
Log.Information("Leaving {RemainingCount} guilds, 1 every second. {DontDeleteCount} will remain",
|
||||||
allGuildIds.Length - dontDelete.Count,
|
allGuildIds.Length - dontDelete.Count,
|
||||||
dontDelete.Count);
|
dontDelete.Count);
|
||||||
|
|
||||||
foreach (var guildId in allGuildIds)
|
foreach (var guildId in allGuildIds)
|
||||||
{
|
{
|
||||||
if (dontDelete.Contains(guildId))
|
if (dontDelete.Contains(guildId))
|
||||||
|
@ -136,7 +136,7 @@ public sealed class CleanupService : ICleanupService, IReadyExecutor, IEService
|
||||||
await using var linqCtx = ctx.CreateLinqToDBContext();
|
await using var linqCtx = ctx.CreateLinqToDBContext();
|
||||||
await using var tempTable = linqCtx.CreateTempTable<CleanupId>();
|
await using var tempTable = linqCtx.CreateTempTable<CleanupId>();
|
||||||
|
|
||||||
foreach (var chunk in allIds.Chunk(20000))
|
foreach (var chunk in allIds.Chunk(10000))
|
||||||
{
|
{
|
||||||
await tempTable.BulkCopyAsync(chunk.Select(x => new CleanupId()
|
await tempTable.BulkCopyAsync(chunk.Select(x => new CleanupId()
|
||||||
{
|
{
|
||||||
|
@ -187,13 +187,6 @@ public sealed class CleanupService : ICleanupService, IReadyExecutor, IEService
|
||||||
.Contains(x.GuildId))
|
.Contains(x.GuildId))
|
||||||
.DeleteAsync();
|
.DeleteAsync();
|
||||||
|
|
||||||
// delete ignored users
|
|
||||||
await ctx.GetTable<DiscordPermOverride>()
|
|
||||||
.Where(x => x.GuildId != null
|
|
||||||
&& !tempTable.Select(x => x.GuildId)
|
|
||||||
.Contains(x.GuildId.Value))
|
|
||||||
.DeleteAsync();
|
|
||||||
|
|
||||||
// delete perm overrides
|
// delete perm overrides
|
||||||
await ctx.GetTable<DiscordPermOverride>()
|
await ctx.GetTable<DiscordPermOverride>()
|
||||||
.Where(x => x.GuildId != null
|
.Where(x => x.GuildId != null
|
||||||
|
@ -219,6 +212,48 @@ public sealed class CleanupService : ICleanupService, IReadyExecutor, IEService
|
||||||
.Contains(x.GuildId))
|
.Contains(x.GuildId))
|
||||||
.DeleteAsync();
|
.DeleteAsync();
|
||||||
|
|
||||||
|
// delete sar
|
||||||
|
await ctx.GetTable<SarGroup>()
|
||||||
|
.Where(x => !tempTable.Select(x => x.GuildId)
|
||||||
|
.Contains(x.GuildId))
|
||||||
|
.DeleteAsync();
|
||||||
|
|
||||||
|
// delete warnings
|
||||||
|
await ctx.GetTable<Warning>()
|
||||||
|
.Where(x => !tempTable.Select(x => x.GuildId)
|
||||||
|
.Contains(x.GuildId))
|
||||||
|
.DeleteAsync();
|
||||||
|
|
||||||
|
// delete warn punishments
|
||||||
|
await ctx.GetTable<WarningPunishment>()
|
||||||
|
.Where(x => !tempTable.Select(x => x.GuildId)
|
||||||
|
.Contains(x.GuildId))
|
||||||
|
.DeleteAsync();
|
||||||
|
|
||||||
|
// delete sticky roles
|
||||||
|
await ctx.GetTable<StickyRole>()
|
||||||
|
.Where(x => !tempTable.Select(x => x.GuildId)
|
||||||
|
.Contains(x.GuildId))
|
||||||
|
.DeleteAsync();
|
||||||
|
|
||||||
|
// delete at channels
|
||||||
|
await ctx.GetTable<AutoTranslateChannel>()
|
||||||
|
.Where(x => !tempTable.Select(x => x.GuildId)
|
||||||
|
.Contains(x.GuildId))
|
||||||
|
.DeleteAsync();
|
||||||
|
|
||||||
|
// delete ban templates
|
||||||
|
await ctx.GetTable<BanTemplate>()
|
||||||
|
.Where(x => !tempTable.Select(x => x.GuildId)
|
||||||
|
.Contains(x.GuildId))
|
||||||
|
.DeleteAsync();
|
||||||
|
|
||||||
|
// delete reminders
|
||||||
|
await ctx.GetTable<Reminder>()
|
||||||
|
.Where(x => !tempTable.Select(x => x.GuildId)
|
||||||
|
.Contains(x.ServerId))
|
||||||
|
.DeleteAsync();
|
||||||
|
|
||||||
return new()
|
return new()
|
||||||
{
|
{
|
||||||
GuildCount = guildIds.Keys.Count,
|
GuildCount = guildIds.Keys.Count,
|
||||||
|
|
|
@ -6,16 +6,155 @@ namespace EllieBot.Modules.Administration;
|
||||||
|
|
||||||
public partial class Administration
|
public partial class Administration
|
||||||
{
|
{
|
||||||
[Group]
|
public partial class SelfAssignedRolesHelpers : EllieModule<SelfAssignedRolesService>
|
||||||
|
{
|
||||||
|
private readonly SarAssignerService _sas;
|
||||||
|
|
||||||
|
public SelfAssignedRolesHelpers(SarAssignerService sas)
|
||||||
|
{
|
||||||
|
_sas = sas;
|
||||||
|
}
|
||||||
|
|
||||||
|
[Cmd]
|
||||||
|
[RequireContext(ContextType.Guild)]
|
||||||
|
public async Task Iam([Leftover] IRole role)
|
||||||
|
{
|
||||||
|
var guildUser = (IGuildUser)ctx.User;
|
||||||
|
|
||||||
|
var group = await _service.GetRoleGroup(ctx.User.Id, role.Id);
|
||||||
|
|
||||||
|
IUserMessage msg = null;
|
||||||
|
try
|
||||||
|
{
|
||||||
|
if (group is null)
|
||||||
|
{
|
||||||
|
msg = await Response().Error(strs.self_assign_not).SendAsync();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var tcs = new TaskCompletionSource<SarAssignResult>(TaskCreationOptions.RunContinuationsAsynchronously);
|
||||||
|
await _sas.Add(new()
|
||||||
|
{
|
||||||
|
Group = group,
|
||||||
|
RoleId = role.Id,
|
||||||
|
User = guildUser,
|
||||||
|
CompletionTask = tcs
|
||||||
|
});
|
||||||
|
|
||||||
|
var res = await tcs.Task;
|
||||||
|
|
||||||
|
if (res.TryPickT0(out _, out var error))
|
||||||
|
{
|
||||||
|
msg = await Response()
|
||||||
|
.Confirm(strs.self_assign_success(Format.Bold(role.Name)))
|
||||||
|
.SendAsync();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
var resStr = error.Match(
|
||||||
|
_ => strs.error_occured,
|
||||||
|
lvlReq => strs.self_assign_not_level(Format.Bold(lvlReq.Level.ToString())),
|
||||||
|
roleRq => strs.self_assign_role_req(Format.Bold(ctx.Guild.GetRole(roleRq.RoleId).ToString()
|
||||||
|
?? "missing role " + roleRq.RoleId),
|
||||||
|
group.Name),
|
||||||
|
_ => strs.self_assign_already(Format.Bold(role.Name)),
|
||||||
|
_ => strs.self_assign_perms);
|
||||||
|
|
||||||
|
msg = await Response().Error(resStr).SendAsync();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
var ad = _service.GetAutoDelete(ctx.Guild.Id);
|
||||||
|
|
||||||
|
if (ad)
|
||||||
|
{
|
||||||
|
msg?.DeleteAfter(3);
|
||||||
|
ctx.Message.DeleteAfter(3);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[Cmd]
|
||||||
|
[RequireContext(ContextType.Guild)]
|
||||||
|
public async Task Iamnot([Leftover] IRole role)
|
||||||
|
{
|
||||||
|
var guildUser = (IGuildUser)ctx.User;
|
||||||
|
|
||||||
|
IUserMessage msg = null;
|
||||||
|
try
|
||||||
|
{
|
||||||
|
if (guildUser.RoleIds.Contains(role.Id))
|
||||||
|
{
|
||||||
|
msg = await Response().Error(strs.self_assign_not_have(Format.Bold(role.Name))).SendAsync();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var group = await _service.GetRoleGroup(role.Guild.Id, role.Id);
|
||||||
|
|
||||||
|
if (group is null || group.Roles.All(x => x.RoleId != role.Id))
|
||||||
|
{
|
||||||
|
msg = await Response().Error(strs.self_assign_not).SendAsync();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (role.Position >= ((SocketGuild)ctx.Guild).CurrentUser.Roles.Max(x => x.Position))
|
||||||
|
{
|
||||||
|
msg = await Response().Error(strs.self_assign_perms).SendAsync();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
await guildUser.RemoveRoleAsync(role);
|
||||||
|
msg = await Response().Confirm(strs.self_assign_remove(Format.Bold(role.Name))).SendAsync();
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
var ad = _service.GetAutoDelete(ctx.Guild.Id);
|
||||||
|
if (ad)
|
||||||
|
{
|
||||||
|
msg?.DeleteAfter(3);
|
||||||
|
ctx.Message.DeleteAfter(3);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[Group("sar")]
|
||||||
public partial class SelfAssignedRolesCommands : EllieModule<SelfAssignedRolesService>
|
public partial class SelfAssignedRolesCommands : EllieModule<SelfAssignedRolesService>
|
||||||
{
|
{
|
||||||
|
private readonly SarAssignerService _sas;
|
||||||
|
|
||||||
|
public SelfAssignedRolesCommands(SarAssignerService sas)
|
||||||
|
{
|
||||||
|
_sas = sas;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected async Task<bool> CheckRoleHierarchy(IRole role)
|
||||||
|
{
|
||||||
|
var botUser = ((SocketGuild)ctx.Guild).CurrentUser;
|
||||||
|
var ownerId = ctx.Guild.OwnerId;
|
||||||
|
var modMaxRole = ((IGuildUser)ctx.User).GetRoles().Max(r => r.Position);
|
||||||
|
var botMaxRole = botUser.GetRoles().Max(r => r.Position);
|
||||||
|
|
||||||
|
// role must be lower than the bot role
|
||||||
|
// and the mod must have a higher role
|
||||||
|
if (botMaxRole <= role.Position
|
||||||
|
|| (ctx.User.Id != ownerId && role.Position >= modMaxRole))
|
||||||
|
{
|
||||||
|
await Response().Error(strs.hierarchy).SendAsync();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
[Cmd]
|
[Cmd]
|
||||||
[RequireContext(ContextType.Guild)]
|
[RequireContext(ContextType.Guild)]
|
||||||
[UserPerm(GuildPerm.ManageMessages)]
|
[UserPerm(GuildPerm.ManageMessages)]
|
||||||
[BotPerm(GuildPerm.ManageMessages)]
|
[BotPerm(GuildPerm.ManageMessages)]
|
||||||
public async Task AdSarm()
|
public async Task SarAutoDelete()
|
||||||
{
|
{
|
||||||
var newVal = _service.ToggleAdSarm(ctx.Guild.Id);
|
var newVal = await _service.ToggleAutoDelete(ctx.Guild.Id);
|
||||||
|
|
||||||
if (newVal)
|
if (newVal)
|
||||||
await Response().Confirm(strs.adsarm_enable(prefix)).SendAsync();
|
await Response().Confirm(strs.adsarm_enable(prefix)).SendAsync();
|
||||||
|
@ -28,30 +167,24 @@ public partial class Administration
|
||||||
[UserPerm(GuildPerm.ManageRoles)]
|
[UserPerm(GuildPerm.ManageRoles)]
|
||||||
[BotPerm(GuildPerm.ManageRoles)]
|
[BotPerm(GuildPerm.ManageRoles)]
|
||||||
[Priority(1)]
|
[Priority(1)]
|
||||||
public Task Asar([Leftover] IRole role)
|
public Task SarAdd([Leftover] IRole role)
|
||||||
=> Asar(0, role);
|
=> SarAdd(0, role);
|
||||||
|
|
||||||
[Cmd]
|
[Cmd]
|
||||||
[RequireContext(ContextType.Guild)]
|
[RequireContext(ContextType.Guild)]
|
||||||
[UserPerm(GuildPerm.ManageRoles)]
|
[UserPerm(GuildPerm.ManageRoles)]
|
||||||
[BotPerm(GuildPerm.ManageRoles)]
|
[BotPerm(GuildPerm.ManageRoles)]
|
||||||
[Priority(0)]
|
[Priority(0)]
|
||||||
public async Task Asar(int group, [Leftover] IRole role)
|
public async Task SarAdd(int group, [Leftover] IRole role)
|
||||||
{
|
{
|
||||||
var guser = (IGuildUser)ctx.User;
|
if (!await CheckRoleHierarchy(role))
|
||||||
if (ctx.User.Id != guser.Guild.OwnerId && guser.GetRoles().Max(x => x.Position) <= role.Position)
|
|
||||||
return;
|
return;
|
||||||
|
|
||||||
var succ = _service.AddNew(ctx.Guild.Id, role, group);
|
await _service.AddAsync(ctx.Guild.Id, role.Id, group);
|
||||||
|
|
||||||
if (succ)
|
await Response()
|
||||||
{
|
.Confirm(strs.role_added(Format.Bold(role.Name), Format.Bold(group.ToString())))
|
||||||
await Response()
|
.SendAsync();
|
||||||
.Confirm(strs.role_added(Format.Bold(role.Name), Format.Bold(group.ToString())))
|
|
||||||
.SendAsync();
|
|
||||||
}
|
|
||||||
else
|
|
||||||
await Response().Error(strs.role_in_list(Format.Bold(role.Name))).SendAsync();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
[Cmd]
|
[Cmd]
|
||||||
|
@ -59,9 +192,9 @@ public partial class Administration
|
||||||
[UserPerm(GuildPerm.ManageRoles)]
|
[UserPerm(GuildPerm.ManageRoles)]
|
||||||
[BotPerm(GuildPerm.ManageRoles)]
|
[BotPerm(GuildPerm.ManageRoles)]
|
||||||
[Priority(0)]
|
[Priority(0)]
|
||||||
public async Task Sargn(int group, [Leftover] string name = null)
|
public async Task SarGroupName(int group, [Leftover] string name = null)
|
||||||
{
|
{
|
||||||
var set = await _service.SetNameAsync(ctx.Guild.Id, group, name);
|
var set = await _service.SetGroupNameAsync(ctx.Guild.Id, group, name);
|
||||||
|
|
||||||
if (set)
|
if (set)
|
||||||
{
|
{
|
||||||
|
@ -70,19 +203,19 @@ public partial class Administration
|
||||||
.SendAsync();
|
.SendAsync();
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
{
|
||||||
await Response().Confirm(strs.group_name_removed(Format.Bold(group.ToString()))).SendAsync();
|
await Response().Confirm(strs.group_name_removed(Format.Bold(group.ToString()))).SendAsync();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
[Cmd]
|
[Cmd]
|
||||||
[RequireContext(ContextType.Guild)]
|
[RequireContext(ContextType.Guild)]
|
||||||
[UserPerm(GuildPerm.ManageRoles)]
|
[UserPerm(GuildPerm.ManageRoles)]
|
||||||
public async Task Rsar([Leftover] IRole role)
|
public async Task SarRemove([Leftover] IRole role)
|
||||||
{
|
{
|
||||||
var guser = (IGuildUser)ctx.User;
|
var guser = (IGuildUser)ctx.User;
|
||||||
if (ctx.User.Id != guser.Guild.OwnerId && guser.GetRoles().Max(x => x.Position) <= role.Position)
|
|
||||||
return;
|
|
||||||
|
|
||||||
var success = _service.RemoveSar(role.Guild.Id, role.Id);
|
var success = await _service.RemoveAsync(role.Guild.Id, role.Id);
|
||||||
if (!success)
|
if (!success)
|
||||||
await Response().Error(strs.self_assign_not).SendAsync();
|
await Response().Error(strs.self_assign_not).SendAsync();
|
||||||
else
|
else
|
||||||
|
@ -91,59 +224,81 @@ public partial class Administration
|
||||||
|
|
||||||
[Cmd]
|
[Cmd]
|
||||||
[RequireContext(ContextType.Guild)]
|
[RequireContext(ContextType.Guild)]
|
||||||
public async Task Lsar(int page = 1)
|
public async Task SarList(int page = 1)
|
||||||
{
|
{
|
||||||
if (--page < 0)
|
if (--page < 0)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
var (exclusive, roles, groups) = _service.GetRoles(ctx.Guild);
|
var groups = await _service.GetSarsAsync(ctx.Guild.Id);
|
||||||
|
|
||||||
|
var gDict = groups.ToDictionary(x => x.Id, x => x);
|
||||||
|
|
||||||
await Response()
|
await Response()
|
||||||
.Paginated()
|
.Paginated()
|
||||||
.Items(roles.OrderBy(x => x.Model.Group).ToList())
|
.Items(groups.SelectMany(x => x.Roles).ToList())
|
||||||
.PageSize(20)
|
.PageSize(20)
|
||||||
.CurrentPage(page)
|
.CurrentPage(page)
|
||||||
.Page((items, _) =>
|
.Page(async (items, _) =>
|
||||||
{
|
{
|
||||||
var rolesStr = new StringBuilder();
|
|
||||||
var roleGroups = items
|
var roleGroups = items
|
||||||
.GroupBy(x => x.Model.Group)
|
.GroupBy(x => x.SarGroupId)
|
||||||
.OrderBy(x => x.Key);
|
.OrderBy(x => x.Key);
|
||||||
|
|
||||||
|
var eb = _sender.CreateEmbed()
|
||||||
|
.WithOkColor()
|
||||||
|
.WithTitle(GetText(strs.self_assign_list(groups.Sum(x => x.Roles.Count))));
|
||||||
|
|
||||||
foreach (var kvp in roleGroups)
|
foreach (var kvp in roleGroups)
|
||||||
{
|
{
|
||||||
string groupNameText;
|
var group = gDict[kvp.Key];
|
||||||
if (!groups.TryGetValue(kvp.Key, out var name))
|
|
||||||
groupNameText = Format.Bold(GetText(strs.self_assign_group(kvp.Key)));
|
|
||||||
else
|
|
||||||
groupNameText = Format.Bold($"{kvp.Key} - {name.TrimTo(25, true)}");
|
|
||||||
|
|
||||||
rolesStr.AppendLine("\t\t\t\t ⟪" + groupNameText + "⟫");
|
var groupNameText = "";
|
||||||
foreach (var (model, role) in kvp.AsEnumerable())
|
|
||||||
|
if (!string.IsNullOrWhiteSpace(group.Name))
|
||||||
|
groupNameText += $" **{group.Name}**";
|
||||||
|
|
||||||
|
groupNameText = $"`{group.GroupNumber}` {groupNameText}";
|
||||||
|
|
||||||
|
var rolesStr = new StringBuilder();
|
||||||
|
|
||||||
|
if (group.IsExclusive)
|
||||||
{
|
{
|
||||||
if (role is null)
|
rolesStr.AppendLine(Format.Italics(GetText(strs.choose_one)));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (group.RoleReq is ulong rrId)
|
||||||
|
{
|
||||||
|
var rr = ctx.Guild.GetRole(rrId);
|
||||||
|
|
||||||
|
if (rr is null)
|
||||||
{
|
{
|
||||||
|
await _service.SetGroupRoleReq(group.GuildId, group.GroupNumber, null);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// first character is invisible space
|
rolesStr.AppendLine(
|
||||||
if (model.LevelRequirement == 0)
|
Format.Italics(GetText(strs.requires_role(Format.Bold(rr.Name)))));
|
||||||
rolesStr.AppendLine(" " + role.Name);
|
|
||||||
else
|
|
||||||
rolesStr.AppendLine(" " + role.Name + $" (lvl {model.LevelRequirement}+)");
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
rolesStr.AppendLine();
|
foreach (var sar in kvp)
|
||||||
|
{
|
||||||
|
var roleName = (ctx.Guild.GetRole(sar.RoleId)?.Name ?? (sar.RoleId + " (deleted)"));
|
||||||
|
rolesStr.Append("- " + Format.Code(roleName));
|
||||||
|
|
||||||
|
if (sar.LevelReq > 0)
|
||||||
|
{
|
||||||
|
rolesStr.Append($" *[lvl {sar.LevelReq}+]*");
|
||||||
|
}
|
||||||
|
|
||||||
|
rolesStr.AppendLine();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
eb.AddField(groupNameText, rolesStr, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
return _sender.CreateEmbed()
|
return eb;
|
||||||
.WithOkColor()
|
|
||||||
.WithTitle(Format.Bold(GetText(strs.self_assign_list(roles.Count()))))
|
|
||||||
.WithDescription(rolesStr.ToString())
|
|
||||||
.WithFooter(exclusive
|
|
||||||
? GetText(strs.self_assign_are_exclusive)
|
|
||||||
: GetText(strs.self_assign_are_not_exclusive));
|
|
||||||
})
|
})
|
||||||
.SendAsync();
|
.SendAsync();
|
||||||
}
|
}
|
||||||
|
@ -152,9 +307,9 @@ public partial class Administration
|
||||||
[RequireContext(ContextType.Guild)]
|
[RequireContext(ContextType.Guild)]
|
||||||
[UserPerm(GuildPerm.ManageRoles)]
|
[UserPerm(GuildPerm.ManageRoles)]
|
||||||
[BotPerm(GuildPerm.ManageRoles)]
|
[BotPerm(GuildPerm.ManageRoles)]
|
||||||
public async Task Togglexclsar()
|
public async Task SarExclusive(int groupNumber)
|
||||||
{
|
{
|
||||||
var areExclusive = _service.ToggleEsar(ctx.Guild.Id);
|
var areExclusive = await _service.SetGroupExclusivityAsync(ctx.Guild.Id, groupNumber);
|
||||||
if (areExclusive)
|
if (areExclusive)
|
||||||
await Response().Confirm(strs.self_assign_excl).SendAsync();
|
await Response().Confirm(strs.self_assign_excl).SendAsync();
|
||||||
else
|
else
|
||||||
|
@ -165,12 +320,12 @@ public partial class Administration
|
||||||
[RequireContext(ContextType.Guild)]
|
[RequireContext(ContextType.Guild)]
|
||||||
[UserPerm(GuildPerm.ManageRoles)]
|
[UserPerm(GuildPerm.ManageRoles)]
|
||||||
[BotPerm(GuildPerm.ManageRoles)]
|
[BotPerm(GuildPerm.ManageRoles)]
|
||||||
public async Task RoleLevelReq(int level, [Leftover] IRole role)
|
public async Task SarRoleLevelReq(int level, [Leftover] IRole role)
|
||||||
{
|
{
|
||||||
if (level < 0)
|
if (level < 0)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
var succ = _service.SetLevelReq(ctx.Guild.Id, role, level);
|
var succ = await _service.SetRoleLevelReq(ctx.Guild.Id, role.Id, level);
|
||||||
|
|
||||||
if (!succ)
|
if (!succ)
|
||||||
{
|
{
|
||||||
|
@ -186,54 +341,35 @@ public partial class Administration
|
||||||
|
|
||||||
[Cmd]
|
[Cmd]
|
||||||
[RequireContext(ContextType.Guild)]
|
[RequireContext(ContextType.Guild)]
|
||||||
public async Task Iam([Leftover] IRole role)
|
[UserPerm(GuildPerm.ManageRoles)]
|
||||||
|
[BotPerm(GuildPerm.ManageRoles)]
|
||||||
|
public async Task SarGroupRoleReq(int groupNumber, [Leftover] IRole role)
|
||||||
{
|
{
|
||||||
var guildUser = (IGuildUser)ctx.User;
|
var succ = await _service.SetGroupRoleReq(ctx.Guild.Id, groupNumber, role.Id);
|
||||||
|
|
||||||
var (result, autoDelete, extra) = await _service.Assign(guildUser, role);
|
if (!succ)
|
||||||
|
|
||||||
IUserMessage msg;
|
|
||||||
if (result == SelfAssignedRolesService.AssignResult.ErrNotAssignable)
|
|
||||||
msg = await Response().Error(strs.self_assign_not).SendAsync();
|
|
||||||
else if (result == SelfAssignedRolesService.AssignResult.ErrLvlReq)
|
|
||||||
msg = await Response().Error(strs.self_assign_not_level(Format.Bold(extra.ToString()))).SendAsync();
|
|
||||||
else if (result == SelfAssignedRolesService.AssignResult.ErrAlreadyHave)
|
|
||||||
msg = await Response().Error(strs.self_assign_already(Format.Bold(role.Name))).SendAsync();
|
|
||||||
else if (result == SelfAssignedRolesService.AssignResult.ErrNotPerms)
|
|
||||||
msg = await Response().Error(strs.self_assign_perms).SendAsync();
|
|
||||||
else
|
|
||||||
msg = await Response().Confirm(strs.self_assign_success(Format.Bold(role.Name))).SendAsync();
|
|
||||||
|
|
||||||
if (autoDelete)
|
|
||||||
{
|
{
|
||||||
msg.DeleteAfter(3);
|
await Response().Error(strs.sar_group_not_found).SendAsync();
|
||||||
ctx.Message.DeleteAfter(3);
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
await Response()
|
||||||
|
.Confirm(strs.self_assign_group_role_req(
|
||||||
|
Format.Bold(groupNumber.ToString()),
|
||||||
|
Format.Bold(role.Name)))
|
||||||
|
.SendAsync();
|
||||||
}
|
}
|
||||||
|
|
||||||
[Cmd]
|
[Cmd]
|
||||||
[RequireContext(ContextType.Guild)]
|
[RequireContext(ContextType.Guild)]
|
||||||
public async Task Iamnot([Leftover] IRole role)
|
[UserPerm(GuildPerm.ManageRoles)]
|
||||||
|
public async Task SarGroupDelete(int groupNumber)
|
||||||
{
|
{
|
||||||
var guildUser = (IGuildUser)ctx.User;
|
var succ = await _service.DeleteRoleGroup(ctx.Guild.Id, groupNumber);
|
||||||
|
if (succ)
|
||||||
var (result, autoDelete) = await _service.Remove(guildUser, role);
|
await Response().Confirm(strs.sar_group_deleted(Format.Bold(groupNumber.ToString()))).SendAsync();
|
||||||
|
|
||||||
IUserMessage msg;
|
|
||||||
if (result == SelfAssignedRolesService.RemoveResult.ErrNotAssignable)
|
|
||||||
msg = await Response().Error(strs.self_assign_not).SendAsync();
|
|
||||||
else if (result == SelfAssignedRolesService.RemoveResult.ErrNotHave)
|
|
||||||
msg = await Response().Error(strs.self_assign_not_have(Format.Bold(role.Name))).SendAsync();
|
|
||||||
else if (result == SelfAssignedRolesService.RemoveResult.ErrNotPerms)
|
|
||||||
msg = await Response().Error(strs.self_assign_perms).SendAsync();
|
|
||||||
else
|
else
|
||||||
msg = await Response().Confirm(strs.self_assign_remove(Format.Bold(role.Name))).SendAsync();
|
await Response().Error(strs.sar_group_not_found).SendAsync();
|
||||||
|
|
||||||
if (autoDelete)
|
|
||||||
{
|
|
||||||
msg.DeleteAfter(3);
|
|
||||||
ctx.Message.DeleteAfter(3);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -1,233 +1,327 @@
|
||||||
#nullable disable
|
using LinqToDB;
|
||||||
|
using LinqToDB.EntityFrameworkCore;
|
||||||
using Microsoft.EntityFrameworkCore;
|
using Microsoft.EntityFrameworkCore;
|
||||||
|
using EllieBot.Common.ModuleBehaviors;
|
||||||
using EllieBot.Db.Models;
|
using EllieBot.Db.Models;
|
||||||
|
using EllieBot.Modules.Xp.Services;
|
||||||
|
using OneOf;
|
||||||
|
using OneOf.Types;
|
||||||
|
using System.ComponentModel.DataAnnotations;
|
||||||
|
using System.Threading.Channels;
|
||||||
|
|
||||||
namespace EllieBot.Modules.Administration.Services;
|
namespace EllieBot.Modules.Administration.Services;
|
||||||
|
|
||||||
public class SelfAssignedRolesService : IEService
|
public class SelfAssignedRolesService : IEService, IReadyExecutor
|
||||||
{
|
{
|
||||||
public enum AssignResult
|
private readonly DbService _db;
|
||||||
|
private readonly DiscordSocketClient _client;
|
||||||
|
private readonly IBotCreds _creds;
|
||||||
|
|
||||||
|
private ConcurrentHashSet<ulong> _sarAds = new();
|
||||||
|
|
||||||
|
public SelfAssignedRolesService(DbService db, DiscordSocketClient client, IBotCreds creds)
|
||||||
{
|
{
|
||||||
Assigned, // successfully removed
|
_db = db;
|
||||||
ErrNotAssignable, // not assignable (error)
|
_client = client;
|
||||||
ErrAlreadyHave, // you already have that role (error)
|
_creds = creds;
|
||||||
ErrNotPerms, // bot doesn't have perms (error)
|
|
||||||
ErrLvlReq // you are not required level (error)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public enum RemoveResult
|
public async Task AddAsync(ulong guildId, ulong roleId, int groupNumber)
|
||||||
{
|
{
|
||||||
Removed, // successfully removed
|
await using var ctx = _db.GetDbContext();
|
||||||
ErrNotAssignable, // not assignable (error)
|
|
||||||
ErrNotHave, // you don't have a role you want to remove (error)
|
await ctx.GetTable<SarGroup>()
|
||||||
ErrNotPerms // bot doesn't have perms (error)
|
.InsertOrUpdateAsync(() => new()
|
||||||
|
{
|
||||||
|
GuildId = guildId,
|
||||||
|
GroupNumber = groupNumber,
|
||||||
|
IsExclusive = false
|
||||||
|
},
|
||||||
|
_ => new()
|
||||||
|
{
|
||||||
|
},
|
||||||
|
() => new()
|
||||||
|
{
|
||||||
|
GuildId = guildId,
|
||||||
|
GroupNumber = groupNumber
|
||||||
|
});
|
||||||
|
|
||||||
|
await ctx.GetTable<Sar>()
|
||||||
|
.InsertOrUpdateAsync(() => new()
|
||||||
|
{
|
||||||
|
RoleId = roleId,
|
||||||
|
LevelReq = 0,
|
||||||
|
GuildId = guildId,
|
||||||
|
SarGroupId = ctx.GetTable<SarGroup>()
|
||||||
|
.Where(x => x.GuildId == guildId && x.GroupNumber == groupNumber)
|
||||||
|
.Select(x => x.Id)
|
||||||
|
.First()
|
||||||
|
},
|
||||||
|
_ => new()
|
||||||
|
{
|
||||||
|
},
|
||||||
|
() => new()
|
||||||
|
{
|
||||||
|
RoleId = roleId,
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public async Task<bool> RemoveAsync(ulong guildId, ulong roleId)
|
||||||
|
{
|
||||||
|
await using var ctx = _db.GetDbContext();
|
||||||
|
|
||||||
|
var deleted = await ctx.GetTable<Sar>()
|
||||||
|
.Where(x => x.RoleId == roleId && x.GuildId == guildId)
|
||||||
|
.DeleteAsync();
|
||||||
|
|
||||||
|
return deleted > 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<bool> SetGroupNameAsync(ulong guildId, int groupNumber, string? name)
|
||||||
|
{
|
||||||
|
await using var ctx = _db.GetDbContext();
|
||||||
|
|
||||||
|
var changes = await ctx.GetTable<SarGroup>()
|
||||||
|
.Where(x => x.GuildId == guildId && x.GroupNumber == groupNumber)
|
||||||
|
.UpdateAsync(x => new()
|
||||||
|
{
|
||||||
|
Name = name
|
||||||
|
});
|
||||||
|
|
||||||
|
return changes > 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<IReadOnlyCollection<SarGroup>> GetSarsAsync(ulong guildId)
|
||||||
|
{
|
||||||
|
await using var ctx = _db.GetDbContext();
|
||||||
|
|
||||||
|
var sgs = await ctx.GetTable<SarGroup>()
|
||||||
|
.Where(x => x.GuildId == guildId)
|
||||||
|
.LoadWith(x => x.Roles)
|
||||||
|
.ToListAsyncLinqToDB();
|
||||||
|
|
||||||
|
return sgs;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<bool> SetRoleLevelReq(ulong guildId, ulong roleId, int levelReq)
|
||||||
|
{
|
||||||
|
await using var ctx = _db.GetDbContext();
|
||||||
|
var changes = await ctx.GetTable<Sar>()
|
||||||
|
.Where(x => x.GuildId == guildId && x.RoleId == roleId)
|
||||||
|
.UpdateAsync(_ => new()
|
||||||
|
{
|
||||||
|
LevelReq = levelReq,
|
||||||
|
});
|
||||||
|
|
||||||
|
return changes > 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<bool> SetGroupRoleReq(ulong guildId, int groupNumber, ulong? roleId)
|
||||||
|
{
|
||||||
|
await using var ctx = _db.GetDbContext();
|
||||||
|
var changes = await ctx.GetTable<SarGroup>()
|
||||||
|
.Where(x => x.GuildId == guildId && x.GroupNumber == groupNumber)
|
||||||
|
.UpdateAsync(_ => new()
|
||||||
|
{
|
||||||
|
RoleReq = roleId
|
||||||
|
});
|
||||||
|
|
||||||
|
return changes > 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<bool> SetGroupExclusivityAsync(ulong guildId, int groupNumber)
|
||||||
|
{
|
||||||
|
await using var ctx = _db.GetDbContext();
|
||||||
|
var changes = await ctx.GetTable<SarGroup>()
|
||||||
|
.Where(x => x.GuildId == guildId && x.GroupNumber == groupNumber)
|
||||||
|
.UpdateWithOutputAsync(old => new()
|
||||||
|
{
|
||||||
|
IsExclusive = !old.IsExclusive
|
||||||
|
},
|
||||||
|
(o, n) => n.IsExclusive);
|
||||||
|
|
||||||
|
if (changes.Length == 0)
|
||||||
|
{
|
||||||
|
// todo group not found
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return changes[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<SarGroup?> GetRoleGroup(ulong guildId, ulong roleId)
|
||||||
|
{
|
||||||
|
await using var ctx = _db.GetDbContext();
|
||||||
|
|
||||||
|
var group = await ctx.GetTable<SarGroup>()
|
||||||
|
.Where(x => x.Roles.Any(x => x.RoleId == roleId))
|
||||||
|
.LoadWith(x => x.Roles)
|
||||||
|
.FirstOrDefaultAsyncLinqToDB();
|
||||||
|
|
||||||
|
|
||||||
|
return group;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<bool> DeleteRoleGroup(ulong guildId, int groupNumber)
|
||||||
|
{
|
||||||
|
await using var ctx = _db.GetDbContext();
|
||||||
|
|
||||||
|
var deleted = await ctx.GetTable<SarGroup>()
|
||||||
|
.Where(x => x.GuildId == guildId && x.GroupNumber == groupNumber)
|
||||||
|
.DeleteAsync();
|
||||||
|
|
||||||
|
return deleted > 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<bool> ToggleAutoDelete(ulong guildId)
|
||||||
|
{
|
||||||
|
await using var ctx = _db.GetDbContext();
|
||||||
|
|
||||||
|
var delted = await ctx.GetTable<SarAutoDelete>()
|
||||||
|
.DeleteAsync(x => x.GuildId == guildId);
|
||||||
|
|
||||||
|
if (delted > 0)
|
||||||
|
{
|
||||||
|
_sarAds.TryRemove(guildId);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
await ctx.GetTable<SarAutoDelete>()
|
||||||
|
.InsertOrUpdateAsync(() => new()
|
||||||
|
{
|
||||||
|
IsEnabled = true,
|
||||||
|
GuildId = guildId,
|
||||||
|
},
|
||||||
|
(_) => new()
|
||||||
|
{
|
||||||
|
IsEnabled = true
|
||||||
|
},
|
||||||
|
() => new()
|
||||||
|
{
|
||||||
|
GuildId = guildId
|
||||||
|
});
|
||||||
|
|
||||||
|
_sarAds.Add(guildId);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool GetAutoDelete(ulong guildId)
|
||||||
|
=> _sarAds.Contains(guildId);
|
||||||
|
|
||||||
|
public async Task OnReadyAsync()
|
||||||
|
{
|
||||||
|
await using var uow = _db.GetDbContext();
|
||||||
|
var guilds = await uow.GetTable<SarAutoDelete>()
|
||||||
|
.Where(x => x.IsEnabled && Linq2DbExpressions.GuildOnShard(x.GuildId, _creds.TotalShards, _client.ShardId))
|
||||||
|
.Select(x => x.GuildId)
|
||||||
|
.ToListAsyncLinqToDB();
|
||||||
|
|
||||||
|
_sarAds = new(guilds);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public sealed class SarAssignerService : IEService, IReadyExecutor
|
||||||
|
{
|
||||||
|
private readonly XpService _xp;
|
||||||
private readonly DbService _db;
|
private readonly DbService _db;
|
||||||
|
|
||||||
public SelfAssignedRolesService(DbService db)
|
private readonly Channel<SarAssignerDataItem> _channel =
|
||||||
=> _db = db;
|
Channel.CreateBounded<SarAssignerDataItem>(100);
|
||||||
|
|
||||||
public bool AddNew(ulong guildId, IRole role, int group)
|
|
||||||
|
public SarAssignerService(XpService xp, DbService db)
|
||||||
{
|
{
|
||||||
using var uow = _db.GetDbContext();
|
_xp = xp;
|
||||||
var roles = uow.Set<SelfAssignedRole>().GetFromGuild(guildId);
|
_db = db;
|
||||||
if (roles.Any(s => s.RoleId == role.Id && s.GuildId == role.Guild.Id))
|
|
||||||
return false;
|
|
||||||
|
|
||||||
uow.Set<SelfAssignedRole>().Add(new()
|
|
||||||
{
|
|
||||||
Group = group,
|
|
||||||
RoleId = role.Id,
|
|
||||||
GuildId = role.Guild.Id
|
|
||||||
});
|
|
||||||
uow.SaveChanges();
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool ToggleAdSarm(ulong guildId)
|
public async Task OnReadyAsync()
|
||||||
{
|
{
|
||||||
bool newval;
|
var reader = _channel.Reader;
|
||||||
using var uow = _db.GetDbContext();
|
while (true)
|
||||||
var config = uow.GuildConfigsForId(guildId, set => set);
|
|
||||||
newval = config.AutoDeleteSelfAssignedRoleMessages = !config.AutoDeleteSelfAssignedRoleMessages;
|
|
||||||
uow.SaveChanges();
|
|
||||||
return newval;
|
|
||||||
}
|
|
||||||
|
|
||||||
public async Task<(AssignResult Result, bool AutoDelete, object extra)> Assign(IGuildUser guildUser, IRole role)
|
|
||||||
{
|
|
||||||
LevelStats userLevelData;
|
|
||||||
await using (var uow = _db.GetDbContext())
|
|
||||||
{
|
{
|
||||||
var stats = uow.GetOrCreateUserXpStats(guildUser.Guild.Id, guildUser.Id);
|
var item = await reader.ReadAsync();
|
||||||
userLevelData = new(stats.Xp + stats.AwardedXp);
|
|
||||||
}
|
|
||||||
|
|
||||||
var (autoDelete, exclusive, roles) = GetAdAndRoles(guildUser.Guild.Id);
|
try
|
||||||
|
|
||||||
var theRoleYouWant = roles.FirstOrDefault(r => r.RoleId == role.Id);
|
|
||||||
if (theRoleYouWant is null)
|
|
||||||
return (AssignResult.ErrNotAssignable, autoDelete, null);
|
|
||||||
if (theRoleYouWant.LevelRequirement > userLevelData.Level)
|
|
||||||
return (AssignResult.ErrLvlReq, autoDelete, theRoleYouWant.LevelRequirement);
|
|
||||||
if (guildUser.RoleIds.Contains(role.Id))
|
|
||||||
return (AssignResult.ErrAlreadyHave, autoDelete, null);
|
|
||||||
|
|
||||||
var roleIds = roles.Where(x => x.Group == theRoleYouWant.Group).Select(x => x.RoleId).ToArray();
|
|
||||||
if (exclusive)
|
|
||||||
{
|
|
||||||
var sameRoles = guildUser.RoleIds.Where(r => roleIds.Contains(r));
|
|
||||||
|
|
||||||
foreach (var roleId in sameRoles)
|
|
||||||
{
|
{
|
||||||
var sameRole = guildUser.Guild.GetRole(roleId);
|
var sar = item.Group.Roles.First(x => x.RoleId == item.RoleId);
|
||||||
if (sameRole is not null)
|
|
||||||
|
if (item.User.RoleIds.Contains(item.RoleId))
|
||||||
{
|
{
|
||||||
try
|
item.CompletionTask.TrySetResult(new SarAlreadyHasRole());
|
||||||
{
|
continue;
|
||||||
await guildUser.RemoveRoleAsync(sameRole);
|
|
||||||
await Task.Delay(300);
|
|
||||||
}
|
|
||||||
catch
|
|
||||||
{
|
|
||||||
// ignored
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (item.Group.RoleReq is { } rid)
|
||||||
|
{
|
||||||
|
if (!item.User.RoleIds.Contains(rid))
|
||||||
|
{
|
||||||
|
item.CompletionTask.TrySetResult(new SarRoleRequirement(rid));
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// passed
|
||||||
|
}
|
||||||
|
|
||||||
|
// check level requirement
|
||||||
|
if (sar.LevelReq > 0)
|
||||||
|
{
|
||||||
|
await using var ctx = _db.GetDbContext();
|
||||||
|
var xpStats = await ctx.GetTable<UserXpStats>().GetGuildUserXp(sar.GuildId, item.User.Id);
|
||||||
|
var lvlData = new LevelStats(xpStats?.Xp ?? 0);
|
||||||
|
|
||||||
|
if (lvlData.Level < sar.LevelReq)
|
||||||
|
{
|
||||||
|
item.CompletionTask.TrySetResult(new SarLevelRequirement(sar.LevelReq));
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// passed
|
||||||
|
}
|
||||||
|
|
||||||
|
if (item.Group.IsExclusive)
|
||||||
|
{
|
||||||
|
var rolesToRemove = item.Group.Roles.Select(x => x.RoleId);
|
||||||
|
await item.User.RemoveRolesAsync(rolesToRemove);
|
||||||
|
}
|
||||||
|
|
||||||
|
await item.User.AddRoleAsync(item.RoleId);
|
||||||
|
|
||||||
|
item.CompletionTask.TrySetResult(new Success());
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
Log.Error(ex, "Unknown error ocurred in SAR runner: {Error}", ex.Message);
|
||||||
|
item.CompletionTask.TrySetResult(new Error());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
try
|
|
||||||
{
|
|
||||||
await guildUser.AddRoleAsync(role);
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
return (AssignResult.ErrNotPerms, autoDelete, ex);
|
|
||||||
}
|
|
||||||
|
|
||||||
return (AssignResult.Assigned, autoDelete, null);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<bool> SetNameAsync(ulong guildId, int group, string name)
|
public async Task Add(SarAssignerDataItem item)
|
||||||
{
|
{
|
||||||
var set = false;
|
await _channel.Writer.WriteAsync(item);
|
||||||
await using var uow = _db.GetDbContext();
|
|
||||||
var gc = uow.GuildConfigsForId(guildId, y => y.Include(x => x.SelfAssignableRoleGroupNames));
|
|
||||||
var toUpdate = gc.SelfAssignableRoleGroupNames.FirstOrDefault(x => x.Number == group);
|
|
||||||
|
|
||||||
if (string.IsNullOrWhiteSpace(name))
|
|
||||||
{
|
|
||||||
if (toUpdate is not null)
|
|
||||||
gc.SelfAssignableRoleGroupNames.Remove(toUpdate);
|
|
||||||
}
|
|
||||||
else if (toUpdate is null)
|
|
||||||
{
|
|
||||||
gc.SelfAssignableRoleGroupNames.Add(new()
|
|
||||||
{
|
|
||||||
Name = name,
|
|
||||||
Number = group
|
|
||||||
});
|
|
||||||
set = true;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
toUpdate.Name = name;
|
|
||||||
set = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
await uow.SaveChangesAsync();
|
|
||||||
|
|
||||||
return set;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<(RemoveResult Result, bool AutoDelete)> Remove(IGuildUser guildUser, IRole role)
|
}
|
||||||
{
|
|
||||||
var (autoDelete, _, roles) = GetAdAndRoles(guildUser.Guild.Id);
|
|
||||||
|
|
||||||
if (roles.FirstOrDefault(r => r.RoleId == role.Id) is null)
|
public sealed class SarAssignerDataItem
|
||||||
return (RemoveResult.ErrNotAssignable, autoDelete);
|
{
|
||||||
if (!guildUser.RoleIds.Contains(role.Id))
|
public required SarGroup Group { get; init; }
|
||||||
return (RemoveResult.ErrNotHave, autoDelete);
|
public required IGuildUser User { get; init; }
|
||||||
try
|
public required ulong RoleId { get; init; }
|
||||||
{
|
public required TaskCompletionSource<SarAssignResult> CompletionTask { get; init; }
|
||||||
await guildUser.RemoveRoleAsync(role);
|
}
|
||||||
}
|
|
||||||
catch (Exception)
|
|
||||||
{
|
|
||||||
return (RemoveResult.ErrNotPerms, autoDelete);
|
|
||||||
}
|
|
||||||
|
|
||||||
return (RemoveResult.Removed, autoDelete);
|
[GenerateOneOf]
|
||||||
}
|
public sealed partial class SarAssignResult
|
||||||
|
: OneOfBase<Success, Error, SarLevelRequirement, SarRoleRequirement, SarAlreadyHasRole, SarInsuffPerms>
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
public bool RemoveSar(ulong guildId, ulong roleId)
|
public record class SarLevelRequirement(int Level);
|
||||||
{
|
|
||||||
bool success;
|
|
||||||
using var uow = _db.GetDbContext();
|
|
||||||
success = uow.Set<SelfAssignedRole>().DeleteByGuildAndRoleId(guildId, roleId);
|
|
||||||
uow.SaveChanges();
|
|
||||||
return success;
|
|
||||||
}
|
|
||||||
|
|
||||||
public (bool AutoDelete, bool Exclusive, IReadOnlyCollection<SelfAssignedRole>) GetAdAndRoles(ulong guildId)
|
public record class SarRoleRequirement(ulong RoleId);
|
||||||
{
|
|
||||||
using var uow = _db.GetDbContext();
|
|
||||||
var gc = uow.GuildConfigsForId(guildId, set => set);
|
|
||||||
var autoDelete = gc.AutoDeleteSelfAssignedRoleMessages;
|
|
||||||
var exclusive = gc.ExclusiveSelfAssignedRoles;
|
|
||||||
var roles = uow.Set<SelfAssignedRole>().GetFromGuild(guildId);
|
|
||||||
|
|
||||||
return (autoDelete, exclusive, roles);
|
public record class SarAlreadyHasRole();
|
||||||
}
|
|
||||||
|
|
||||||
public bool SetLevelReq(ulong guildId, IRole role, int level)
|
public record class SarInsuffPerms();
|
||||||
{
|
|
||||||
using var uow = _db.GetDbContext();
|
|
||||||
var roles = uow.Set<SelfAssignedRole>().GetFromGuild(guildId);
|
|
||||||
var sar = roles.FirstOrDefault(x => x.RoleId == role.Id);
|
|
||||||
if (sar is not null)
|
|
||||||
{
|
|
||||||
sar.LevelRequirement = level;
|
|
||||||
uow.SaveChanges();
|
|
||||||
}
|
|
||||||
else
|
|
||||||
return false;
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool ToggleEsar(ulong guildId)
|
|
||||||
{
|
|
||||||
bool areExclusive;
|
|
||||||
using var uow = _db.GetDbContext();
|
|
||||||
var config = uow.GuildConfigsForId(guildId, set => set);
|
|
||||||
|
|
||||||
areExclusive = config.ExclusiveSelfAssignedRoles = !config.ExclusiveSelfAssignedRoles;
|
|
||||||
uow.SaveChanges();
|
|
||||||
return areExclusive;
|
|
||||||
}
|
|
||||||
|
|
||||||
public (bool Exclusive, IReadOnlyCollection<(SelfAssignedRole Model, IRole Role)> Roles, IDictionary<int, string>
|
|
||||||
GroupNames
|
|
||||||
) GetRoles(IGuild guild)
|
|
||||||
{
|
|
||||||
var exclusive = false;
|
|
||||||
|
|
||||||
IReadOnlyCollection<(SelfAssignedRole Model, IRole Role)> roles;
|
|
||||||
IDictionary<int, string> groupNames;
|
|
||||||
using (var uow = _db.GetDbContext())
|
|
||||||
{
|
|
||||||
var gc = uow.GuildConfigsForId(guild.Id, set => set.Include(x => x.SelfAssignableRoleGroupNames));
|
|
||||||
exclusive = gc.ExclusiveSelfAssignedRoles;
|
|
||||||
groupNames = gc.SelfAssignableRoleGroupNames.ToDictionary(x => x.Number, x => x.Name);
|
|
||||||
var roleModels = uow.Set<SelfAssignedRole>().GetFromGuild(guild.Id);
|
|
||||||
roles = roleModels.Select(x => (Model: x, Role: guild.GetRole(x.RoleId)))
|
|
||||||
.ToList();
|
|
||||||
uow.Set<SelfAssignedRole>().RemoveRange(roles.Where(x => x.Role is null).Select(x => x.Model).ToArray());
|
|
||||||
uow.SaveChanges();
|
|
||||||
}
|
|
||||||
|
|
||||||
return (exclusive, roles.Where(x => x.Role is not null).ToList(), groupNames);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -23,27 +23,6 @@ public partial class Administration
|
||||||
_mute = mute;
|
_mute = mute;
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task<bool> CheckRoleHierarchy(IGuildUser target)
|
|
||||||
{
|
|
||||||
var curUser = ((SocketGuild)ctx.Guild).CurrentUser;
|
|
||||||
var ownerId = ctx.Guild.OwnerId;
|
|
||||||
var modMaxRole = ((IGuildUser)ctx.User).GetRoles().Max(r => r.Position);
|
|
||||||
var targetMaxRole = target.GetRoles().Max(r => r.Position);
|
|
||||||
var botMaxRole = curUser.GetRoles().Max(r => r.Position);
|
|
||||||
// bot can't punish a user who is higher in the hierarchy. Discord will return 403
|
|
||||||
// moderator can be owner, in which case role hierarchy doesn't matter
|
|
||||||
// otherwise, moderator has to have a higher role
|
|
||||||
if (botMaxRole <= targetMaxRole
|
|
||||||
|| (ctx.User.Id != ownerId && targetMaxRole >= modMaxRole)
|
|
||||||
|| target.Id == ownerId)
|
|
||||||
{
|
|
||||||
await Response().Error(strs.hierarchy).SendAsync();
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
[Cmd]
|
[Cmd]
|
||||||
[RequireContext(ContextType.Guild)]
|
[RequireContext(ContextType.Guild)]
|
||||||
[UserPerm(GuildPerm.BanMembers)]
|
[UserPerm(GuildPerm.BanMembers)]
|
||||||
|
|
|
@ -6,9 +6,9 @@ namespace EllieBot.Modules.Gambling.Common.AnimalRacing;
|
||||||
|
|
||||||
public sealed class AnimalRace : IDisposable
|
public sealed class AnimalRace : IDisposable
|
||||||
{
|
{
|
||||||
public const double BASE_MULTIPLIER = 0.82;
|
public const double BASE_MULTIPLIER = 0.87;
|
||||||
public const double MAX_MULTIPLIER = 0.94;
|
public const double MAX_MULTIPLIER = 0.94;
|
||||||
public const double MULTI_PER_USER = 0.01;
|
public const double MULTI_PER_USER = 0.005;
|
||||||
|
|
||||||
public enum Phase
|
public enum Phase
|
||||||
{
|
{
|
||||||
|
|
|
@ -154,16 +154,16 @@ public partial class Gambling : GamblingModule<GamblingService>
|
||||||
{
|
{
|
||||||
var password = _service.GeneratePassword();
|
var password = _service.GeneratePassword();
|
||||||
|
|
||||||
var img = new Image<Rgba32>(70, 35);
|
var img = new Image<Rgba32>(60, 30);
|
||||||
|
|
||||||
var font = _fonts.NotoSans.CreateFont(30);
|
var font = _fonts.NotoSans.CreateFont(25);
|
||||||
var outlinePen = new SolidPen(Color.Black, 1f);
|
var outlinePen = new SolidPen(Color.Black, 1f);
|
||||||
var strikeoutRun = new RichTextRun
|
var strikeoutRun = new RichTextRun
|
||||||
{
|
{
|
||||||
Start = 0,
|
Start = 0,
|
||||||
End = password.GetGraphemeCount(),
|
End = password.GetGraphemeCount(),
|
||||||
Font = font,
|
Font = font,
|
||||||
StrikeoutPen = new SolidPen(Color.White, 3),
|
StrikeoutPen = new SolidPen(Color.White, 4),
|
||||||
TextDecorations = TextDecorations.Strikeout
|
TextDecorations = TextDecorations.Strikeout
|
||||||
};
|
};
|
||||||
// draw password on the image
|
// draw password on the image
|
||||||
|
|
92
src/EllieBot/Modules/Gambling/Loan/LoanCommands.cs
Normal file
92
src/EllieBot/Modules/Gambling/Loan/LoanCommands.cs
Normal file
|
@ -0,0 +1,92 @@
|
||||||
|
// namespace EllieBot.Modules.Gambling;
|
||||||
|
// public sealed class Loan
|
||||||
|
// {
|
||||||
|
// public int Id { get; set; }
|
||||||
|
// public ulong LenderId { get; set; }
|
||||||
|
// public string LenderName { get; set; }
|
||||||
|
// public ulong BorrowerId { get; set; }
|
||||||
|
// public string BorrowerName { get; set; }
|
||||||
|
// public long Amount { get; set; }
|
||||||
|
// public decimal Interest { get; set; }
|
||||||
|
// public DateTime DueDate { get; set; }
|
||||||
|
// public bool Repaid { get; set; }
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// public sealed class LoanService : INService
|
||||||
|
// {
|
||||||
|
// public async Task<IReadOnlyList<Loan>> GetLoans(ulong userId)
|
||||||
|
// {
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// public async Task<object> RepayAsync(object loandId)
|
||||||
|
// {
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// public partial class Gambling
|
||||||
|
// {
|
||||||
|
// public partial class LoanCommands : EllieModule<LoanService>
|
||||||
|
// {
|
||||||
|
// [Cmd]
|
||||||
|
// public async Task Loan(
|
||||||
|
// IUser lender,
|
||||||
|
// long amount,
|
||||||
|
// decimal interest = 0,
|
||||||
|
// TimeSpan dueIn = default)
|
||||||
|
// {
|
||||||
|
// var eb = _sender.CreateEmbed()
|
||||||
|
// .WithOkColor()
|
||||||
|
// .WithDescription("User 0 Requests a loan from User {1}")
|
||||||
|
// .AddField("Amount", amount, true)
|
||||||
|
// .AddField("Interest", (interest * 0.01m).ToString("P2"), true);
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// public Task Loans()
|
||||||
|
// => Loans(ctx.User);
|
||||||
|
//
|
||||||
|
// public async Task Loans([Leftover] IUser user)
|
||||||
|
// {
|
||||||
|
// var loans = await _service.GetLoans(user.Id);
|
||||||
|
//
|
||||||
|
// Response()
|
||||||
|
// .Paginated()
|
||||||
|
// .PageItems(loans)
|
||||||
|
// .Page((items, page) =>
|
||||||
|
// {
|
||||||
|
// var eb = _sender.CreateEmbed()
|
||||||
|
// .WithOkColor()
|
||||||
|
// .WithDescription("Current Loans");
|
||||||
|
//
|
||||||
|
// foreach (var item in items)
|
||||||
|
// {
|
||||||
|
// eb.AddField(new kwum(item.id).ToString(),
|
||||||
|
// $"""
|
||||||
|
// To: {item.LenderName}
|
||||||
|
// Amount: {}
|
||||||
|
// """,
|
||||||
|
// true);
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// return eb;
|
||||||
|
// });
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// [Cmd]
|
||||||
|
// public async Task Repay(kwum loanId)
|
||||||
|
// {
|
||||||
|
// var res = await _service.RepayAsync(loandId);
|
||||||
|
//
|
||||||
|
// if (res.TryPickT0(out var _, out var err))
|
||||||
|
// {
|
||||||
|
// }
|
||||||
|
// else
|
||||||
|
// {
|
||||||
|
// var errStr = err.Match(
|
||||||
|
// _ => "Not enough funds",
|
||||||
|
// _ => "Loan not found");
|
||||||
|
//
|
||||||
|
// await Response().Error(errStr).SendAsync();
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// }
|
|
@ -5,6 +5,48 @@ using JsonSerializer = System.Text.Json.JsonSerializer;
|
||||||
|
|
||||||
namespace EllieBot.Modules.Searches.Common.StreamNotifications.Providers;
|
namespace EllieBot.Modules.Searches.Common.StreamNotifications.Providers;
|
||||||
|
|
||||||
|
public sealed class YoutubeProvide : Provider
|
||||||
|
{
|
||||||
|
private readonly IGoogleApiService _api;
|
||||||
|
private readonly IHttpClientFactory _httpFactory;
|
||||||
|
|
||||||
|
public override FollowedStream.FType Platform
|
||||||
|
=> FollowedStream.FType.Youtube;
|
||||||
|
|
||||||
|
public YoutubeProvide(IGoogleApiService api, IHttpClientFactory httpFactory)
|
||||||
|
{
|
||||||
|
_api = api;
|
||||||
|
_httpFactory = httpFactory;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override async Task<bool> IsValidUrl(string url)
|
||||||
|
{
|
||||||
|
await Task.Yield();
|
||||||
|
// todo implement
|
||||||
|
return url.Contains("youtube.com");
|
||||||
|
}
|
||||||
|
|
||||||
|
public override Task<StreamData?> GetStreamDataByUrlAsync(string url)
|
||||||
|
{
|
||||||
|
return default;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override Task<StreamData?> GetStreamDataAsync(string login)
|
||||||
|
{
|
||||||
|
var client = _httpFactory.CreateClient();
|
||||||
|
|
||||||
|
client.GetAsync();
|
||||||
|
|
||||||
|
|
||||||
|
return default;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override Task<IReadOnlyCollection<StreamData>> GetStreamDataAsync(List<string> usernames)
|
||||||
|
{
|
||||||
|
return default;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public sealed class TwitchHelixProvider : Provider
|
public sealed class TwitchHelixProvider : Provider
|
||||||
{
|
{
|
||||||
private readonly IHttpClientFactory _httpClientFactory;
|
private readonly IHttpClientFactory _httpClientFactory;
|
||||||
|
@ -94,9 +136,9 @@ public sealed class TwitchHelixProvider : Provider
|
||||||
var loginsSet = logins.Select(x => x.ToLowerInvariant())
|
var loginsSet = logins.Select(x => x.ToLowerInvariant())
|
||||||
.Distinct()
|
.Distinct()
|
||||||
.ToHashSet();
|
.ToHashSet();
|
||||||
|
|
||||||
var dataDict = new Dictionary<string, StreamData>();
|
var dataDict = new Dictionary<string, StreamData>();
|
||||||
|
|
||||||
foreach (var chunk in logins.Chunk(100))
|
foreach (var chunk in logins.Chunk(100))
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
|
@ -125,13 +167,13 @@ public sealed class TwitchHelixProvider : Provider
|
||||||
return [];
|
return [];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// any item left over loginsSet is an invalid username
|
// any item left over loginsSet is an invalid username
|
||||||
foreach (var login in loginsSet)
|
foreach (var login in loginsSet)
|
||||||
{
|
{
|
||||||
_failingStreams.TryAdd(login, DateTime.UtcNow);
|
_failingStreams.TryAdd(login, DateTime.UtcNow);
|
||||||
}
|
}
|
||||||
|
|
||||||
// only get streams for users which exist
|
// only get streams for users which exist
|
||||||
foreach (var chunk in dataDict.Keys.Chunk(100))
|
foreach (var chunk in dataDict.Keys.Chunk(100))
|
||||||
{
|
{
|
||||||
|
@ -178,7 +220,7 @@ public sealed class TwitchHelixProvider : Provider
|
||||||
StreamType = FollowedStream.FType.Twitch,
|
StreamType = FollowedStream.FType.Twitch,
|
||||||
Preview = user.OfflineImageUrl
|
Preview = user.OfflineImageUrl
|
||||||
};
|
};
|
||||||
|
|
||||||
private StreamData FillStreamData(StreamData partial, HelixStreamsResponse.StreamData apiData)
|
private StreamData FillStreamData(StreamData partial, HelixStreamsResponse.StreamData apiData)
|
||||||
=> partial with
|
=> partial with
|
||||||
{
|
{
|
||||||
|
|
|
@ -1,7 +1,9 @@
|
||||||
|
using EllieBot.Db.Models;
|
||||||
|
|
||||||
namespace Ellie.Common;
|
namespace Ellie.Common;
|
||||||
|
|
||||||
public static class Extensions
|
public static class Extensions
|
||||||
{
|
{
|
||||||
public static long ToTimestamp(this in DateTime value)
|
public static long ToTimestamp(this in DateTime value)
|
||||||
=> (value.Ticks - 621355968000000000) / 10000000;
|
=> (value.Ticks 621355968000000000) / 10000000;
|
||||||
}
|
}
|
|
@ -100,6 +100,27 @@ public abstract class EllieModule : ModuleBase
|
||||||
return Task.CompletedTask;
|
return Task.CompletedTask;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected async Task<bool> CheckRoleHierarchy(IGuildUser target)
|
||||||
|
{
|
||||||
|
var curUser = ((SocketGuild)ctx.Guild).CurrentUser;
|
||||||
|
var ownerId = ctx.Guild.OwnerId;
|
||||||
|
var modMaxRole = ((IGuildUser)ctx.User).GetRoles().Max(r => r.Position);
|
||||||
|
var targetMaxRole = target.GetRoles().Max(r => r.Position);
|
||||||
|
var botMaxRole = curUser.GetRoles().Max(r => r.Position);
|
||||||
|
// bot can't punish a user who is higher in the hierarchy. Discord will return 403
|
||||||
|
// moderator can be owner, in which case role hierarchy doesn't matter
|
||||||
|
// otherwise, moderator has to have a higher role
|
||||||
|
if (botMaxRole <= targetMaxRole
|
||||||
|
|| (ctx.User.Id != ownerId && targetMaxRole >= modMaxRole)
|
||||||
|
|| target.Id == ownerId)
|
||||||
|
{
|
||||||
|
await Response().Error(strs.hierarchy).SendAsync();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public abstract class EllieModule<TService> : EllieModule
|
public abstract class EllieModule<TService> : EllieModule
|
||||||
|
|
|
@ -81,17 +81,43 @@ vcrole:
|
||||||
- vcrole
|
- vcrole
|
||||||
vcrolerm:
|
vcrolerm:
|
||||||
- vcrolerm
|
- vcrolerm
|
||||||
asar:
|
saradd:
|
||||||
|
- add
|
||||||
|
- a
|
||||||
- asar
|
- asar
|
||||||
rsar:
|
sarremove:
|
||||||
|
- remove
|
||||||
|
- rm
|
||||||
|
- rem
|
||||||
- rsar
|
- rsar
|
||||||
lsar:
|
sarlist:
|
||||||
|
- list
|
||||||
|
- l
|
||||||
|
- ls
|
||||||
- lsar
|
- lsar
|
||||||
sargn:
|
sarautodelete:
|
||||||
|
- ad
|
||||||
|
- autodel
|
||||||
|
- adsarm
|
||||||
|
sargroupname:
|
||||||
|
- groupname
|
||||||
|
- gn
|
||||||
- sargn
|
- sargn
|
||||||
togglexclsar:
|
sargrouprolereq:
|
||||||
- togglexclsar
|
- grouprolereq
|
||||||
|
- grr
|
||||||
|
sargroupdelete:
|
||||||
|
- groupdelete
|
||||||
|
- gd
|
||||||
|
- gdel
|
||||||
|
sarexclusive:
|
||||||
|
- exclusive
|
||||||
|
- ex
|
||||||
|
- excl
|
||||||
- tesar
|
- tesar
|
||||||
|
sarrolelevelreq:
|
||||||
|
- rolelvlreq
|
||||||
|
- rlr
|
||||||
iam:
|
iam:
|
||||||
- iam
|
- iam
|
||||||
iamnot:
|
iamnot:
|
||||||
|
@ -772,8 +798,6 @@ voicemute:
|
||||||
muterole:
|
muterole:
|
||||||
- muterole
|
- muterole
|
||||||
- setmuterole
|
- setmuterole
|
||||||
adsarm:
|
|
||||||
- adsarm
|
|
||||||
setstream:
|
setstream:
|
||||||
- setstream
|
- setstream
|
||||||
chatunmute:
|
chatunmute:
|
||||||
|
@ -1184,9 +1208,6 @@ timelyreset:
|
||||||
crypto:
|
crypto:
|
||||||
- crypto
|
- crypto
|
||||||
- c
|
- c
|
||||||
rolelevelreq:
|
|
||||||
- rolelevelreq
|
|
||||||
- rlr
|
|
||||||
massban:
|
massban:
|
||||||
- massban
|
- massban
|
||||||
masskill:
|
masskill:
|
||||||
|
|
|
@ -28,7 +28,7 @@ betRoll:
|
||||||
multiplyBy: 10
|
multiplyBy: 10
|
||||||
- whenAbove: 90
|
- whenAbove: 90
|
||||||
multiplyBy: 4
|
multiplyBy: 4
|
||||||
- whenAbove: 65
|
- whenAbove: 64
|
||||||
multiplyBy: 2
|
multiplyBy: 2
|
||||||
# Automatic currency generation settings.
|
# Automatic currency generation settings.
|
||||||
generation:
|
generation:
|
||||||
|
|
|
@ -323,7 +323,7 @@ vcrolerm:
|
||||||
params:
|
params:
|
||||||
- vcId:
|
- vcId:
|
||||||
desc: "The voice channel ID to remove the vcrole from."
|
desc: "The voice channel ID to remove the vcrole from."
|
||||||
asar:
|
saradd:
|
||||||
desc: Adds a role to the list of self-assignable roles. You can also specify a group. If 'Exclusive self-assignable roles' feature is enabled (`{0}tesar`), users will be able to pick one role per group.
|
desc: Adds a role to the list of self-assignable roles. You can also specify a group. If 'Exclusive self-assignable roles' feature is enabled (`{0}tesar`), users will be able to pick one role per group.
|
||||||
ex:
|
ex:
|
||||||
- Gamer
|
- Gamer
|
||||||
|
@ -336,7 +336,7 @@ asar:
|
||||||
desc: "The ID of a group that the designated role should belong to."
|
desc: "The ID of a group that the designated role should belong to."
|
||||||
role:
|
role:
|
||||||
desc: "The role that can be assigned by the user."
|
desc: "The role that can be assigned by the user."
|
||||||
rsar:
|
sarremove:
|
||||||
desc: Removes a specified role from the list of self-assignable roles.
|
desc: Removes a specified role from the list of self-assignable roles.
|
||||||
ex:
|
ex:
|
||||||
- Gamer
|
- Gamer
|
||||||
|
@ -345,7 +345,7 @@ rsar:
|
||||||
params:
|
params:
|
||||||
- role:
|
- role:
|
||||||
desc: "The role to remove from the list of self-assignable roles."
|
desc: "The role to remove from the list of self-assignable roles."
|
||||||
lsar:
|
sarlist:
|
||||||
desc: Lists self-assignable roles. Shows 20 roles per page.
|
desc: Lists self-assignable roles. Shows 20 roles per page.
|
||||||
ex:
|
ex:
|
||||||
- ''
|
- ''
|
||||||
|
@ -353,22 +353,53 @@ lsar:
|
||||||
params:
|
params:
|
||||||
- page:
|
- page:
|
||||||
desc: "The page number to show."
|
desc: "The page number to show."
|
||||||
sargn:
|
sarautodelete:
|
||||||
|
desc: Toggles the automatic deletion of the user's message and Nadeko's confirmations for `{0}iam` and `{0}iamn` commands.
|
||||||
|
ex:
|
||||||
|
- ''
|
||||||
|
params:
|
||||||
|
- { }
|
||||||
|
sargroupname:
|
||||||
desc: Sets a self assignable role group name. Provide no name to remove.
|
desc: Sets a self assignable role group name. Provide no name to remove.
|
||||||
ex:
|
ex:
|
||||||
- 1 Faction
|
- 1 Faction
|
||||||
- 2
|
- 2
|
||||||
params:
|
params:
|
||||||
- group:
|
- group:
|
||||||
desc: "The ID of the group to name."
|
desc: "The group number"
|
||||||
name:
|
name:
|
||||||
desc: "The name to assign."
|
desc: "The name to assign."
|
||||||
togglexclsar:
|
sargroupdelete:
|
||||||
|
desc: "Deletes a self-assignable role group"
|
||||||
|
ex:
|
||||||
|
- 0
|
||||||
|
params:
|
||||||
|
- group:
|
||||||
|
desc: "The number of the group to delete."
|
||||||
|
sarexclusive:
|
||||||
desc: Toggles whether self-assigned roles are exclusive. While enabled, users can only have one self-assignable role per group.
|
desc: Toggles whether self-assigned roles are exclusive. While enabled, users can only have one self-assignable role per group.
|
||||||
ex:
|
ex:
|
||||||
- ''
|
- ''
|
||||||
params:
|
params:
|
||||||
- { }
|
- { }
|
||||||
|
sarrolelevelreq:
|
||||||
|
desc: Set a level requirement on a self-assignable role.
|
||||||
|
ex:
|
||||||
|
- 5 SomeRole
|
||||||
|
params:
|
||||||
|
- level:
|
||||||
|
desc: "The minimum level required for the role."
|
||||||
|
role:
|
||||||
|
desc: "The role that must be assigned before the user can assign this one."
|
||||||
|
sargrouprolereq:
|
||||||
|
desc: Set a role that users have to have in order to assign a self-assignable role from the specified group.
|
||||||
|
ex:
|
||||||
|
- 1 SomeRole
|
||||||
|
params:
|
||||||
|
- group:
|
||||||
|
desc: "The group number."
|
||||||
|
role:
|
||||||
|
desc: "The role that is required."
|
||||||
iam:
|
iam:
|
||||||
desc: Adds a role to you that you choose. Role must be on the list of self-assignable roles.
|
desc: Adds a role to you that you choose. Role must be on the list of self-assignable roles.
|
||||||
ex:
|
ex:
|
||||||
|
@ -2464,12 +2495,6 @@ muterole:
|
||||||
params:
|
params:
|
||||||
- role:
|
- role:
|
||||||
desc: "The role that determines whether users are muted or not."
|
desc: "The role that determines whether users are muted or not."
|
||||||
adsarm:
|
|
||||||
desc: Toggles the automatic deletion of the user's message and Ellie's confirmations for `{0}iam` and `{0}iamn` commands.
|
|
||||||
ex:
|
|
||||||
- ''
|
|
||||||
params:
|
|
||||||
- { }
|
|
||||||
setstream:
|
setstream:
|
||||||
desc: Sets the bots stream. First parameter is the twitch link, second parameter is stream name.
|
desc: Sets the bots stream. First parameter is the twitch link, second parameter is stream name.
|
||||||
ex:
|
ex:
|
||||||
|
@ -3356,7 +3381,7 @@ globalcommand:
|
||||||
globalmodule:
|
globalmodule:
|
||||||
desc: Toggles whether a module can be used on any server.
|
desc: Toggles whether a module can be used on any server.
|
||||||
ex:
|
ex:
|
||||||
- 'Gambling'
|
- 'Gambling'
|
||||||
params:
|
params:
|
||||||
- module:
|
- module:
|
||||||
desc: "The type of module or configuration information being toggled."
|
desc: "The type of module or configuration information being toggled."
|
||||||
|
@ -3919,15 +3944,6 @@ stock:
|
||||||
params:
|
params:
|
||||||
- query:
|
- query:
|
||||||
desc: "The ticker symbol or company name used to retrieve the stock's information."
|
desc: "The ticker symbol or company name used to retrieve the stock's information."
|
||||||
rolelevelreq:
|
|
||||||
desc: Set a level requirement on a self-assignable role.
|
|
||||||
ex:
|
|
||||||
- 5 SomeRole
|
|
||||||
params:
|
|
||||||
- level:
|
|
||||||
desc: "The minimum level required for the role."
|
|
||||||
role:
|
|
||||||
desc: "The role that must be assigned before the user can assign this one."
|
|
||||||
massban:
|
massban:
|
||||||
desc: Bans multiple users at once. Specify a space separated list of IDs of users who you wish to ban.
|
desc: Bans multiple users at once. Specify a space separated list of IDs of users who you wish to ban.
|
||||||
ex:
|
ex:
|
||||||
|
@ -4676,7 +4692,7 @@ betstats:
|
||||||
- '@someone lula'
|
- '@someone lula'
|
||||||
- 'bd'
|
- 'bd'
|
||||||
params:
|
params:
|
||||||
- {}
|
- { }
|
||||||
- user:
|
- user:
|
||||||
desc: 'The user for who to show the betstats for.'
|
desc: 'The user for who to show the betstats for.'
|
||||||
- user:
|
- user:
|
||||||
|
@ -4691,10 +4707,10 @@ rakeback:
|
||||||
Rakeback is accumulated by betting (not by winning or losing).
|
Rakeback is accumulated by betting (not by winning or losing).
|
||||||
Default rakeback is 0.05 * house edge
|
Default rakeback is 0.05 * house edge
|
||||||
House edge is defined per game
|
House edge is defined per game
|
||||||
ex:
|
ex:
|
||||||
- ''
|
- ''
|
||||||
params:
|
params:
|
||||||
- {}
|
- { }
|
||||||
snipe:
|
snipe:
|
||||||
desc: |-
|
desc: |-
|
||||||
Snipe the message you replied to with this command.
|
Snipe the message you replied to with this command.
|
||||||
|
|
|
@ -896,9 +896,6 @@
|
||||||
"rank": "Rank",
|
"rank": "Rank",
|
||||||
"template_reloaded": "Xp template has been reloaded.",
|
"template_reloaded": "Xp template has been reloaded.",
|
||||||
"expr_edited": "Expression Edited",
|
"expr_edited": "Expression Edited",
|
||||||
"self_assign_are_exclusive": "You can only choose 1 role from each group.",
|
|
||||||
"self_assign_are_not_exclusive": "You can choose any number of roles from any group.",
|
|
||||||
"self_assign_group": "Group {0}",
|
|
||||||
"new_reaction_event": "Add {0} reaction to this message to get {1}\n{2} left to be awarded.",
|
"new_reaction_event": "Add {0} reaction to this message to get {1}\n{2} left to be awarded.",
|
||||||
"new_gamestatus_event": "Type the secret code in any channel to receive {1}\n{2} left to be awarded.",
|
"new_gamestatus_event": "Type the secret code in any channel to receive {1}\n{2} left to be awarded.",
|
||||||
"event_duration_footer": "This event is active for up to {0} hours.",
|
"event_duration_footer": "This event is active for up to {0} hours.",
|
||||||
|
@ -947,6 +944,7 @@
|
||||||
"did_you_mean": "Did you mean {0}?",
|
"did_you_mean": "Did you mean {0}?",
|
||||||
"self_assign_level_req": "Self assignable role {0} now requires at least server level {1}.",
|
"self_assign_level_req": "Self assignable role {0} now requires at least server level {1}.",
|
||||||
"self_assign_not_level": "That self-assignable role requires at least server level {0}.",
|
"self_assign_not_level": "That self-assignable role requires at least server level {0}.",
|
||||||
|
"self_assign_role_req": "You need {0} role in order to assign yourself a role from group {1}",
|
||||||
"invalid": "Invalid / Can't be found ({0})",
|
"invalid": "Invalid / Can't be found ({0})",
|
||||||
"mass_kill_in_progress": "Mass Banning and Blacklisting of {0} users is in progress...",
|
"mass_kill_in_progress": "Mass Banning and Blacklisting of {0} users is in progress...",
|
||||||
"mass_ban_in_progress": "Banning {0} users...",
|
"mass_ban_in_progress": "Banning {0} users...",
|
||||||
|
@ -1118,5 +1116,10 @@
|
||||||
"rakeback_claimed": "You've claimed {0} as rakeback!",
|
"rakeback_claimed": "You've claimed {0} as rakeback!",
|
||||||
"rakeback_none": "You don't have any rakeback to claim yet.",
|
"rakeback_none": "You don't have any rakeback to claim yet.",
|
||||||
"rakeback_available": "You have {0} rakeback available. Click the button to claim.",
|
"rakeback_available": "You have {0} rakeback available. Click the button to claim.",
|
||||||
"sniped_by": "Sniped by {0}"
|
"sniped_by": "Sniped by {0}",
|
||||||
|
"self_assign_group_role_req": "Users can now self-assign a role from group {0} only if they have {1} role.",
|
||||||
|
"sar_group_not_found": "Group with that number doesn't exist.",
|
||||||
|
"sar_group_deleted": "Group {0} deleted.",
|
||||||
|
"choose_one": "Choose one",
|
||||||
|
"requires_role": "Requires role: {0}"
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue