mirror of
https://github.com/NoiTheCat/BirthdayBot.git
synced 2024-11-21 13:54:36 +00:00
Merge branch 'main' into cleanup
This commit is contained in:
commit
4f22d4b991
18 changed files with 461 additions and 118 deletions
|
@ -46,7 +46,7 @@ public class BirthdayModule : BotModuleBase {
|
||||||
if (user.IsNew) db.UserEntries.Add(user);
|
if (user.IsNew) db.UserEntries.Add(user);
|
||||||
user.BirthMonth = inmonth;
|
user.BirthMonth = inmonth;
|
||||||
user.BirthDay = inday;
|
user.BirthDay = inday;
|
||||||
user.TimeZone = inzone;
|
user.TimeZone = inzone ?? user.TimeZone;
|
||||||
try {
|
try {
|
||||||
await db.SaveChangesAsync();
|
await db.SaveChangesAsync();
|
||||||
} catch (Microsoft.EntityFrameworkCore.DbUpdateException e)
|
} catch (Microsoft.EntityFrameworkCore.DbUpdateException e)
|
||||||
|
@ -221,10 +221,10 @@ public class BirthdayModule : BotModuleBase {
|
||||||
private static List<ListItem> GetSortedUserList(SocketGuild guild) {
|
private static List<ListItem> GetSortedUserList(SocketGuild guild) {
|
||||||
using var db = new BotDatabaseContext();
|
using var db = new BotDatabaseContext();
|
||||||
var query = from row in db.UserEntries
|
var query = from row in db.UserEntries
|
||||||
where row.GuildId == (long)guild.Id
|
where row.GuildId == guild.Id
|
||||||
orderby row.BirthMonth, row.BirthDay
|
orderby row.BirthMonth, row.BirthDay
|
||||||
select new {
|
select new {
|
||||||
UserId = (ulong)row.UserId,
|
row.UserId,
|
||||||
Month = row.BirthMonth,
|
Month = row.BirthMonth,
|
||||||
Day = row.BirthDay,
|
Day = row.BirthDay,
|
||||||
Zone = row.TimeZone
|
Zone = row.TimeZone
|
||||||
|
|
|
@ -56,7 +56,7 @@ public class ConfigModule : BotModuleBase {
|
||||||
|
|
||||||
[SlashCommand("set-channel", HelpPfxModOnly + HelpSubCmdChannel + HelpPofxBlankUnset)]
|
[SlashCommand("set-channel", HelpPfxModOnly + HelpSubCmdChannel + HelpPofxBlankUnset)]
|
||||||
public async Task CmdSetChannel([Summary(description: HelpOptChannel)] SocketTextChannel? channel = null) {
|
public async Task CmdSetChannel([Summary(description: HelpOptChannel)] SocketTextChannel? channel = null) {
|
||||||
await DoDatabaseUpdate(Context, s => s.ChannelAnnounceId = (long?)channel?.Id);
|
await DoDatabaseUpdate(Context, s => s.AnnouncementChannel = channel?.Id);
|
||||||
await RespondAsync(":white_check_mark: The announcement channel has been " +
|
await RespondAsync(":white_check_mark: The announcement channel has been " +
|
||||||
(channel == null ? "unset." : $"set to **{channel.Name}**."));
|
(channel == null ? "unset." : $"set to **{channel.Name}**."));
|
||||||
}
|
}
|
||||||
|
@ -126,7 +126,7 @@ public class ConfigModule : BotModuleBase {
|
||||||
await RespondAsync(":x: This role cannot be used for this setting.", ephemeral: true);
|
await RespondAsync(":x: This role cannot be used for this setting.", ephemeral: true);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
await DoDatabaseUpdate(Context, s => s.RoleId = (long)role.Id);
|
await DoDatabaseUpdate(Context, s => s.BirthdayRole = role.Id);
|
||||||
await RespondAsync($":white_check_mark: The birthday role has been set to **{role.Name}**.").ConfigureAwait(false);
|
await RespondAsync($":white_check_mark: The birthday role has been set to **{role.Name}**.").ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -136,7 +136,7 @@ public class ConfigModule : BotModuleBase {
|
||||||
await RespondAsync(":x: This role cannot be used for this setting.", ephemeral: true);
|
await RespondAsync(":x: This role cannot be used for this setting.", ephemeral: true);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
await DoDatabaseUpdate(Context, s => s.ModeratorRole = (long?)role?.Id);
|
await DoDatabaseUpdate(Context, s => s.ModeratorRole = role?.Id);
|
||||||
await RespondAsync(":white_check_mark: The moderator role has been " +
|
await RespondAsync(":white_check_mark: The moderator role has been " +
|
||||||
(role == null ? "unset." : $"set to **{role.Name}**."));
|
(role == null ? "unset." : $"set to **{role.Name}**."));
|
||||||
}
|
}
|
||||||
|
@ -154,7 +154,7 @@ public class ConfigModule : BotModuleBase {
|
||||||
// setting: true to add (set), false to remove (unset)
|
// setting: true to add (set), false to remove (unset)
|
||||||
using var db = new BotDatabaseContext();
|
using var db = new BotDatabaseContext();
|
||||||
var existing = db.BlocklistEntries
|
var existing = db.BlocklistEntries
|
||||||
.Where(bl => bl.GuildId == (long)user.Guild.Id && bl.UserId == (long)user.Id).FirstOrDefault();
|
.Where(bl => bl.GuildId == user.Guild.Id && bl.UserId == user.Id).FirstOrDefault();
|
||||||
|
|
||||||
var already = (existing != null) == setting;
|
var already = (existing != null) == setting;
|
||||||
if (already) {
|
if (already) {
|
||||||
|
@ -162,7 +162,7 @@ public class ConfigModule : BotModuleBase {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (setting) db.BlocklistEntries.Add(new BlocklistEntry() { GuildId = (long)user.Guild.Id, UserId = (long)user.Id });
|
if (setting) db.BlocklistEntries.Add(new BlocklistEntry() { GuildId = user.Guild.Id, UserId = user.Id });
|
||||||
else db.Remove(existing!);
|
else db.Remove(existing!);
|
||||||
await db.SaveChangesAsync();
|
await db.SaveChangesAsync();
|
||||||
|
|
||||||
|
@ -201,7 +201,7 @@ public class ConfigModule : BotModuleBase {
|
||||||
|
|
||||||
result.AppendLine($"Server ID: `{guild.Id}` | Bot shard ID: `{Shard.ShardId:00}`");
|
result.AppendLine($"Server ID: `{guild.Id}` | Bot shard ID: `{Shard.ShardId:00}`");
|
||||||
result.AppendLine($"Number of registered birthdays: `{ guildconf.UserEntries.Count }`");
|
result.AppendLine($"Number of registered birthdays: `{ guildconf.UserEntries.Count }`");
|
||||||
result.AppendLine($"Server time zone: `{ (guildconf.TimeZone ?? "Not set - using UTC") }`");
|
result.AppendLine($"Server time zone: `{ (guildconf.GuildTimeZone ?? "Not set - using UTC") }`");
|
||||||
result.AppendLine();
|
result.AppendLine();
|
||||||
|
|
||||||
var hasMembers = Common.HasMostMembersDownloaded(guild);
|
var hasMembers = Common.HasMostMembersDownloaded(guild);
|
||||||
|
@ -211,7 +211,7 @@ public class ConfigModule : BotModuleBase {
|
||||||
result.Append(DoTestFor("Birthday processing", delegate {
|
result.Append(DoTestFor("Birthday processing", delegate {
|
||||||
if (!hasMembers) return false;
|
if (!hasMembers) return false;
|
||||||
if (guildconf.IsNew) return false;
|
if (guildconf.IsNew) return false;
|
||||||
bdayCount = BackgroundServices.BirthdayRoleUpdate.GetGuildCurrentBirthdays(guildconf.UserEntries, guildconf.TimeZone).Count;
|
bdayCount = BackgroundServices.BirthdayRoleUpdate.GetGuildCurrentBirthdays(guildconf.UserEntries, guildconf.GuildTimeZone).Count;
|
||||||
return true;
|
return true;
|
||||||
}));
|
}));
|
||||||
if (!hasMembers) result.AppendLine(" - Previous step failed.");
|
if (!hasMembers) result.AppendLine(" - Previous step failed.");
|
||||||
|
@ -221,12 +221,12 @@ public class ConfigModule : BotModuleBase {
|
||||||
|
|
||||||
result.AppendLine(DoTestFor("Birthday role set with `/config role set-birthday-role`", delegate {
|
result.AppendLine(DoTestFor("Birthday role set with `/config role set-birthday-role`", delegate {
|
||||||
if (guildconf.IsNew) return false;
|
if (guildconf.IsNew) return false;
|
||||||
SocketRole? role = guild.GetRole((ulong)(guildconf.RoleId ?? 0));
|
SocketRole? role = guild.GetRole((ulong)(guildconf.BirthdayRole ?? 0));
|
||||||
return role != null;
|
return role != null;
|
||||||
}));
|
}));
|
||||||
result.AppendLine(DoTestFor("Birthday role can be managed by bot", delegate {
|
result.AppendLine(DoTestFor("Birthday role can be managed by bot", delegate {
|
||||||
if (guildconf.IsNew) return false;
|
if (guildconf.IsNew) return false;
|
||||||
SocketRole? role = guild.GetRole((ulong)(guildconf.RoleId ?? 0));
|
SocketRole? role = guild.GetRole((ulong)(guildconf.BirthdayRole ?? 0));
|
||||||
if (role == null) return false;
|
if (role == null) return false;
|
||||||
return guild.CurrentUser.GuildPermissions.ManageRoles && role.Position < guild.CurrentUser.Hierarchy;
|
return guild.CurrentUser.GuildPermissions.ManageRoles && role.Position < guild.CurrentUser.Hierarchy;
|
||||||
}));
|
}));
|
||||||
|
@ -235,7 +235,7 @@ public class ConfigModule : BotModuleBase {
|
||||||
SocketTextChannel? announcech = null;
|
SocketTextChannel? announcech = null;
|
||||||
result.AppendLine(DoTestFor("(Optional) Announcement channel set with `bb.config channel`", delegate {
|
result.AppendLine(DoTestFor("(Optional) Announcement channel set with `bb.config channel`", delegate {
|
||||||
if (guildconf.IsNew) return false;
|
if (guildconf.IsNew) return false;
|
||||||
announcech = guild.GetTextChannel((ulong)(guildconf.ChannelAnnounceId ?? 0));
|
announcech = guild.GetTextChannel((ulong)(guildconf.AnnouncementChannel ?? 0));
|
||||||
return announcech != null;
|
return announcech != null;
|
||||||
}));
|
}));
|
||||||
var disp = announcech == null ? "announcement channel" : $"<#{announcech.Id}>";
|
var disp = announcech == null ? "announcement channel" : $"<#{announcech.Id}>";
|
||||||
|
@ -275,7 +275,7 @@ public class ConfigModule : BotModuleBase {
|
||||||
const string Response = ":white_check_mark: The server's time zone has been ";
|
const string Response = ":white_check_mark: The server's time zone has been ";
|
||||||
|
|
||||||
if (zone == null) {
|
if (zone == null) {
|
||||||
await DoDatabaseUpdate(Context, s => s.TimeZone = null);
|
await DoDatabaseUpdate(Context, s => s.GuildTimeZone = null);
|
||||||
await RespondAsync(Response + "unset.").ConfigureAwait(false);
|
await RespondAsync(Response + "unset.").ConfigureAwait(false);
|
||||||
} else {
|
} else {
|
||||||
string parsedZone;
|
string parsedZone;
|
||||||
|
@ -286,7 +286,7 @@ public class ConfigModule : BotModuleBase {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
await DoDatabaseUpdate(Context, s => s.TimeZone = parsedZone);
|
await DoDatabaseUpdate(Context, s => s.GuildTimeZone = parsedZone);
|
||||||
await RespondAsync(Response + $"set to **{parsedZone}**.").ConfigureAwait(false);
|
await RespondAsync(Response + $"set to **{parsedZone}**.").ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -23,8 +23,8 @@ class EnforceBlockingAttribute : PreconditionAttribute {
|
||||||
|
|
||||||
using var db = new BotDatabaseContext();
|
using var db = new BotDatabaseContext();
|
||||||
var settings = (from row in db.GuildConfigurations
|
var settings = (from row in db.GuildConfigurations
|
||||||
where row.GuildId == (long)guild.Id
|
where row.GuildId == guild.Id
|
||||||
select new { ModRole = (ulong?)row.ModeratorRole, ModMode = row.Moderated }).FirstOrDefault();
|
select new { ModRole = row.ModeratorRole, ModMode = row.Moderated }).FirstOrDefault();
|
||||||
if (settings != null) {
|
if (settings != null) {
|
||||||
// Bot moderators override all blocking measures in place
|
// Bot moderators override all blocking measures in place
|
||||||
if (user.Roles.Any(r => r.Id == settings.ModRole)) return Task.FromResult(PreconditionResult.FromSuccess());
|
if (user.Roles.Any(r => r.Id == settings.ModRole)) return Task.FromResult(PreconditionResult.FromSuccess());
|
||||||
|
@ -33,7 +33,7 @@ class EnforceBlockingAttribute : PreconditionAttribute {
|
||||||
if (settings.ModMode) return Task.FromResult(PreconditionResult.FromError(FailModerated));
|
if (settings.ModMode) return Task.FromResult(PreconditionResult.FromError(FailModerated));
|
||||||
|
|
||||||
// Check if user exists in blocklist
|
// Check if user exists in blocklist
|
||||||
if (db.BlocklistEntries.Where(row => row.GuildId == (long)guild.Id && row.UserId == (long)user.Id).Any())
|
if (db.BlocklistEntries.Where(row => row.GuildId == guild.Id && row.UserId == user.Id).Any())
|
||||||
return Task.FromResult(PreconditionResult.FromError(FailBlocked));
|
return Task.FromResult(PreconditionResult.FromError(FailBlocked));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -22,8 +22,8 @@ class RequireBotModeratorAttribute : PreconditionAttribute {
|
||||||
if (user.GuildPermissions.ManageGuild) return Task.FromResult(PreconditionResult.FromSuccess());
|
if (user.GuildPermissions.ManageGuild) return Task.FromResult(PreconditionResult.FromSuccess());
|
||||||
using var db = new BotDatabaseContext();
|
using var db = new BotDatabaseContext();
|
||||||
var checkRole = (ulong?)db.GuildConfigurations
|
var checkRole = (ulong?)db.GuildConfigurations
|
||||||
.Where(g => g.GuildId == (long)((SocketGuild)context.Guild).Id)
|
.Where(g => g.GuildId == ((SocketGuild)context.Guild).Id)
|
||||||
.Select(g => g.RoleId).FirstOrDefault();
|
.Select(g => g.ModeratorRole).FirstOrDefault();
|
||||||
if (checkRole.HasValue && user.Roles.Any(r => r.Id == checkRole.Value))
|
if (checkRole.HasValue && user.Roles.Any(r => r.Id == checkRole.Value))
|
||||||
return Task.FromResult(PreconditionResult.FromSuccess());
|
return Task.FromResult(PreconditionResult.FromSuccess());
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
using BirthdayBot.Data;
|
using BirthdayBot.Data;
|
||||||
|
using Microsoft.EntityFrameworkCore;
|
||||||
|
|
||||||
namespace BirthdayBot.BackgroundServices;
|
namespace BirthdayBot.BackgroundServices;
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
@ -8,13 +9,22 @@ class AutoUserDownload : BackgroundService {
|
||||||
public AutoUserDownload(ShardInstance instance) : base(instance) { }
|
public AutoUserDownload(ShardInstance instance) : base(instance) { }
|
||||||
|
|
||||||
public override async Task OnTick(int tickCount, CancellationToken token) {
|
public override async Task OnTick(int tickCount, CancellationToken token) {
|
||||||
using var db = new BotDatabaseContext();
|
|
||||||
|
|
||||||
// Take action if a guild's cache is incomplete...
|
// Take action if a guild's cache is incomplete...
|
||||||
var incompleteCaches = ShardInstance.DiscordClient.Guilds.Where(g => !g.HasAllMembers).Select(g => (long)g.Id).ToHashSet();
|
var incompleteCaches = ShardInstance.DiscordClient.Guilds.Where(g => !g.HasAllMembers).Select(g => g.Id).ToHashSet();
|
||||||
// ...and if the guild contains any user data
|
// ...and if the guild contains any user data
|
||||||
var mustFetch = db.UserEntries.Where(e => incompleteCaches.Contains(e.GuildId)).Select(e => e.GuildId).Distinct();
|
IEnumerable<ulong> mustFetch;
|
||||||
|
try {
|
||||||
|
await DbConcurrentOperationsLock.WaitAsync(token);
|
||||||
|
using var db = new BotDatabaseContext();
|
||||||
|
mustFetch = db.UserEntries.AsNoTracking()
|
||||||
|
.Where(e => incompleteCaches.Contains(e.GuildId)).Select(e => e.GuildId).Distinct()
|
||||||
|
.ToList();
|
||||||
|
} finally {
|
||||||
|
try {
|
||||||
|
DbConcurrentOperationsLock.Release();
|
||||||
|
} catch (ObjectDisposedException) { }
|
||||||
|
}
|
||||||
|
|
||||||
var processed = 0;
|
var processed = 0;
|
||||||
foreach (var item in mustFetch) {
|
foreach (var item in mustFetch) {
|
||||||
// May cause a disconnect in certain situations. Cancel all further attempts until the next pass if it happens.
|
// May cause a disconnect in certain situations. Cancel all further attempts until the next pass if it happens.
|
||||||
|
@ -27,6 +37,6 @@ class AutoUserDownload : BackgroundService {
|
||||||
processed++;
|
processed++;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (processed > 100) Log($"Explicit user list request processed for {processed} guild(s).");
|
if (processed > 25) Log($"Explicit user list request processed for {processed} guild(s).");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -27,9 +27,9 @@ class BirthdayRoleUpdate : BackgroundService {
|
||||||
private async Task ProcessBirthdaysAsync(CancellationToken token) {
|
private async Task ProcessBirthdaysAsync(CancellationToken token) {
|
||||||
// For database efficiency, fetch all database information at once before proceeding
|
// For database efficiency, fetch all database information at once before proceeding
|
||||||
using var db = new BotDatabaseContext();
|
using var db = new BotDatabaseContext();
|
||||||
var shardGuilds = ShardInstance.DiscordClient.Guilds.Select(g => (long)g.Id).ToHashSet();
|
var shardGuilds = ShardInstance.DiscordClient.Guilds.Select(g => g.Id).ToHashSet();
|
||||||
var presentGuildSettings = db.GuildConfigurations.Where(s => shardGuilds.Contains(s.GuildId));
|
var presentGuildSettings = db.GuildConfigurations.Where(s => shardGuilds.Contains(s.GuildId));
|
||||||
var guildChecks = presentGuildSettings.ToList().Select(s => Tuple.Create((ulong)s.GuildId, s));
|
var guildChecks = presentGuildSettings.ToList().Select(s => Tuple.Create(s.GuildId, s));
|
||||||
|
|
||||||
var exceptions = new List<Exception>();
|
var exceptions = new List<Exception>();
|
||||||
foreach (var (guildId, settings) in guildChecks) {
|
foreach (var (guildId, settings) in guildChecks) {
|
||||||
|
@ -46,13 +46,13 @@ class BirthdayRoleUpdate : BackgroundService {
|
||||||
|
|
||||||
try {
|
try {
|
||||||
// Verify that role settings and permissions are usable
|
// Verify that role settings and permissions are usable
|
||||||
SocketRole? role = guild.GetRole((ulong)(settings.RoleId ?? 0));
|
SocketRole? role = guild.GetRole((ulong)(settings.BirthdayRole ?? 0));
|
||||||
if (role == null
|
if (role == null
|
||||||
|| !guild.CurrentUser.GuildPermissions.ManageRoles
|
|| !guild.CurrentUser.GuildPermissions.ManageRoles
|
||||||
|| role.Position >= guild.CurrentUser.Hierarchy) continue;
|
|| role.Position >= guild.CurrentUser.Hierarchy) continue;
|
||||||
if (role.IsEveryone || role.IsManaged) {
|
if (role.IsEveryone || role.IsManaged) {
|
||||||
// Invalid role was configured. Clear the setting and quit.
|
// Invalid role was configured. Clear the setting and quit.
|
||||||
settings.RoleId = null;
|
settings.BirthdayRole = null;
|
||||||
db.Update(settings);
|
db.Update(settings);
|
||||||
await db.SaveChangesAsync(CancellationToken.None);
|
await db.SaveChangesAsync(CancellationToken.None);
|
||||||
continue;
|
continue;
|
||||||
|
@ -60,7 +60,7 @@ class BirthdayRoleUpdate : BackgroundService {
|
||||||
|
|
||||||
// Load up user configs and begin processing birthdays
|
// Load up user configs and begin processing birthdays
|
||||||
await db.Entry(settings).Collection(t => t.UserEntries).LoadAsync(CancellationToken.None);
|
await db.Entry(settings).Collection(t => t.UserEntries).LoadAsync(CancellationToken.None);
|
||||||
var birthdays = GetGuildCurrentBirthdays(settings.UserEntries, settings.TimeZone);
|
var birthdays = GetGuildCurrentBirthdays(settings.UserEntries, settings.GuildTimeZone);
|
||||||
|
|
||||||
// Add or remove roles as appropriate
|
// Add or remove roles as appropriate
|
||||||
var announcementList = await UpdateGuildBirthdayRoles(guild, role, birthdays);
|
var announcementList = await UpdateGuildBirthdayRoles(guild, role, birthdays);
|
||||||
|
@ -144,7 +144,7 @@ class BirthdayRoleUpdate : BackgroundService {
|
||||||
/// Attempts to send an announcement message.
|
/// Attempts to send an announcement message.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
internal static async Task AnnounceBirthdaysAsync(GuildConfig settings, SocketGuild g, IEnumerable<SocketGuildUser> names) {
|
internal static async Task AnnounceBirthdaysAsync(GuildConfig settings, SocketGuild g, IEnumerable<SocketGuildUser> names) {
|
||||||
var c = g.GetTextChannel((ulong)(settings.ChannelAnnounceId ?? 0));
|
var c = g.GetTextChannel((ulong)(settings.AnnouncementChannel ?? 0));
|
||||||
if (c == null) return;
|
if (c == null) return;
|
||||||
if (!c.Guild.CurrentUser.GetPermissions(c).SendMessages) return;
|
if (!c.Guild.CurrentUser.GetPermissions(c).SendMessages) return;
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
using BirthdayBot.Data;
|
using BirthdayBot.Data;
|
||||||
|
using Microsoft.EntityFrameworkCore;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
|
|
||||||
namespace BirthdayBot.BackgroundServices;
|
namespace BirthdayBot.BackgroundServices;
|
||||||
|
@ -31,34 +32,32 @@ class DataRetention : BackgroundService {
|
||||||
private async Task RemoveStaleEntriesAsync() {
|
private async Task RemoveStaleEntriesAsync() {
|
||||||
using var db = new BotDatabaseContext();
|
using var db = new BotDatabaseContext();
|
||||||
var now = DateTimeOffset.UtcNow;
|
var now = DateTimeOffset.UtcNow;
|
||||||
int updatedGuilds = 0, updatedUsers = 0;
|
|
||||||
|
|
||||||
|
// Update guilds
|
||||||
|
var localGuilds = ShardInstance.DiscordClient.Guilds.Select(g => g.Id).ToList();
|
||||||
|
var updatedGuilds = await db.GuildConfigurations
|
||||||
|
.Where(g => localGuilds.Contains(g.GuildId))
|
||||||
|
.ExecuteUpdateAsync(upd => upd.SetProperty(p => p.LastSeen, now));
|
||||||
|
|
||||||
|
// Update guild users
|
||||||
|
var updatedUsers = 0;
|
||||||
foreach (var guild in ShardInstance.DiscordClient.Guilds) {
|
foreach (var guild in ShardInstance.DiscordClient.Guilds) {
|
||||||
// Update guild, fetch users from database
|
var localUsers = guild.Users.Select(u => u.Id).ToList();
|
||||||
var dbGuild = db.GuildConfigurations.Where(s => s.GuildId == (long)guild.Id).FirstOrDefault();
|
updatedUsers += await db.UserEntries
|
||||||
if (dbGuild == null) continue;
|
.Where(gu => gu.GuildId == guild.Id)
|
||||||
dbGuild.LastSeen = now;
|
.Where(gu => localUsers.Contains(gu.UserId))
|
||||||
updatedGuilds++;
|
.ExecuteUpdateAsync(upd => upd.SetProperty(p => p.LastSeen, now));
|
||||||
|
|
||||||
// Update users
|
|
||||||
var localIds = guild.Users.Select(u => (long)u.Id);
|
|
||||||
var dbSavedIds = db.UserEntries.Where(e => e.GuildId == (long)guild.Id).Select(e => e.UserId);
|
|
||||||
var usersToUpdate = localIds.Intersect(dbSavedIds).ToHashSet();
|
|
||||||
foreach (var user in db.UserEntries.Where(e => e.GuildId == (long)guild.Id && usersToUpdate.Contains(e.UserId))) {
|
|
||||||
user.LastSeen = now;
|
|
||||||
updatedUsers++;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// And let go of old data
|
// And let go of old data
|
||||||
var staleGuilds = db.GuildConfigurations.Where(s => now - TimeSpan.FromDays(StaleGuildThreshold) > s.LastSeen);
|
var staleGuildCount = await db.GuildConfigurations
|
||||||
var staleUsers = db.UserEntries.Where(e => now - TimeSpan.FromDays(StaleUserThreashold) > e.LastSeen);
|
.Where(g => now - TimeSpan.FromDays(StaleGuildThreshold) > g.LastSeen)
|
||||||
int staleGuildCount = staleGuilds.Count(), staleUserCount = staleUsers.Count();
|
.ExecuteDeleteAsync();
|
||||||
db.GuildConfigurations.RemoveRange(staleGuilds);
|
var staleUserCount = await db.UserEntries
|
||||||
db.UserEntries.RemoveRange(staleUsers);
|
.Where(gu => now - TimeSpan.FromDays(StaleUserThreashold) > gu.LastSeen)
|
||||||
|
.ExecuteDeleteAsync();
|
||||||
await db.SaveChangesAsync(CancellationToken.None);
|
|
||||||
|
|
||||||
|
// Build report
|
||||||
var resultText = new StringBuilder();
|
var resultText = new StringBuilder();
|
||||||
resultText.Append($"Updated {updatedGuilds} guilds, {updatedUsers} users.");
|
resultText.Append($"Updated {updatedGuilds} guilds, {updatedUsers} users.");
|
||||||
if (staleGuildCount != 0 || staleUserCount != 0) {
|
if (staleGuildCount != 0 || staleUserCount != 0) {
|
||||||
|
|
|
@ -5,7 +5,7 @@
|
||||||
<TargetFramework>net6.0</TargetFramework>
|
<TargetFramework>net6.0</TargetFramework>
|
||||||
<ImplicitUsings>enable</ImplicitUsings>
|
<ImplicitUsings>enable</ImplicitUsings>
|
||||||
<Nullable>enable</Nullable>
|
<Nullable>enable</Nullable>
|
||||||
<Version>3.4.4</Version>
|
<Version>3.4.6</Version>
|
||||||
<Authors>NoiTheCat</Authors>
|
<Authors>NoiTheCat</Authors>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
|
@ -22,17 +22,17 @@
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="CommandLineParser" Version="2.9.1" />
|
<PackageReference Include="CommandLineParser" Version="2.9.1" />
|
||||||
<PackageReference Include="Discord.Net" Version="3.8.0" />
|
<PackageReference Include="Discord.Net" Version="3.8.1" />
|
||||||
<PackageReference Include="EFCore.NamingConventions" Version="6.0.0" />
|
<PackageReference Include="EFCore.NamingConventions" Version="7.0.0" />
|
||||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="6.0.8">
|
<PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="7.0.0">
|
||||||
<PrivateAssets>all</PrivateAssets>
|
<PrivateAssets>all</PrivateAssets>
|
||||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||||
</PackageReference>
|
</PackageReference>
|
||||||
<PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="6.0.0" />
|
<PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="7.0.0" />
|
||||||
<PackageReference Include="Newtonsoft.Json" Version="13.0.1" />
|
<PackageReference Include="Newtonsoft.Json" Version="13.0.1" />
|
||||||
<PackageReference Include="NodaTime" Version="3.1.2" />
|
<PackageReference Include="NodaTime" Version="3.1.3" />
|
||||||
<PackageReference Include="Npgsql" Version="6.0.6" />
|
<PackageReference Include="Npgsql" Version="7.0.0" />
|
||||||
<PackageReference Include="Npgsql.EntityFrameworkCore.PostgreSQL" Version="6.0.6" />
|
<PackageReference Include="Npgsql.EntityFrameworkCore.PostgreSQL" Version="7.0.0" />
|
||||||
<PackageReference Include="Npgsql.EntityFrameworkCore.PostgreSQL.Design" Version="1.1.0" />
|
<PackageReference Include="Npgsql.EntityFrameworkCore.PostgreSQL.Design" Version="1.1.0" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
|
|
|
@ -70,7 +70,7 @@ class Configuration {
|
||||||
SqlDatabase = ReadConfKey<string?>(jc, nameof(SqlDatabase), false);
|
SqlDatabase = ReadConfKey<string?>(jc, nameof(SqlDatabase), false);
|
||||||
SqlUsername = ReadConfKey<string>(jc, nameof(SqlUsername), true);
|
SqlUsername = ReadConfKey<string>(jc, nameof(SqlUsername), true);
|
||||||
SqlPassword = ReadConfKey<string>(jc, nameof(SqlPassword), true);
|
SqlPassword = ReadConfKey<string>(jc, nameof(SqlPassword), true);
|
||||||
SqlApplicationName = $"ClientShard{ShardStart}+{ShardAmount}";
|
SqlApplicationName = $"Shard{ShardStart:00}-{ShardStart + ShardAmount - 1:00}";
|
||||||
}
|
}
|
||||||
|
|
||||||
private static T? ReadConfKey<T>(JObject jc, string key, [DoesNotReturnIf(true)] bool failOnEmpty) {
|
private static T? ReadConfKey<T>(JObject jc, string key, [DoesNotReturnIf(true)] bool failOnEmpty) {
|
||||||
|
|
|
@ -6,11 +6,9 @@ namespace BirthdayBot.Data;
|
||||||
[Table("banned_users")]
|
[Table("banned_users")]
|
||||||
public class BlocklistEntry {
|
public class BlocklistEntry {
|
||||||
[Key]
|
[Key]
|
||||||
[Column("guild_id")]
|
public ulong GuildId { get; set; }
|
||||||
public long GuildId { get; set; }
|
|
||||||
[Key]
|
[Key]
|
||||||
[Column("user_id")]
|
public ulong UserId { get; set; }
|
||||||
public long UserId { get; set; }
|
|
||||||
|
|
||||||
[ForeignKey(nameof(GuildConfig.GuildId))]
|
[ForeignKey(nameof(GuildConfig.GuildId))]
|
||||||
[InverseProperty(nameof(GuildConfig.BlockedUsers))]
|
[InverseProperty(nameof(GuildConfig.BlockedUsers))]
|
||||||
|
|
|
@ -13,8 +13,7 @@ public class BotDatabaseContext : DbContext {
|
||||||
Database = conf.SqlDatabase,
|
Database = conf.SqlDatabase,
|
||||||
Username = conf.SqlUsername,
|
Username = conf.SqlUsername,
|
||||||
Password = conf.SqlPassword,
|
Password = conf.SqlPassword,
|
||||||
ApplicationName = conf.SqlApplicationName,
|
ApplicationName = conf.SqlApplicationName
|
||||||
MaxPoolSize = Math.Max((int)Math.Ceiling(conf.ShardAmount * 2 * 0.6), 8)
|
|
||||||
}.ToString();
|
}.ToString();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -5,14 +5,14 @@ internal static class Extensions {
|
||||||
/// If it doesn't exist in the database, <see cref="GuildConfig.IsNew"/> returns true.
|
/// If it doesn't exist in the database, <see cref="GuildConfig.IsNew"/> returns true.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public static GuildConfig GetConfigOrNew(this SocketGuild guild, BotDatabaseContext db)
|
public static GuildConfig GetConfigOrNew(this SocketGuild guild, BotDatabaseContext db)
|
||||||
=> db.GuildConfigurations.Where(g => g.GuildId == (long)guild.Id).FirstOrDefault()
|
=> db.GuildConfigurations.Where(g => g.GuildId == guild.Id).FirstOrDefault()
|
||||||
?? new GuildConfig() { IsNew = true, GuildId = (long)guild.Id };
|
?? new GuildConfig() { IsNew = true, GuildId = guild.Id };
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets the corresponding <see cref="UserEntry"/> for this user in this guild, or a new one if one does not exist.
|
/// Gets the corresponding <see cref="UserEntry"/> for this user in this guild, or a new one if one does not exist.
|
||||||
/// If it doesn't exist in the database, <see cref="UserEntry.IsNew"/> returns true.
|
/// If it doesn't exist in the database, <see cref="UserEntry.IsNew"/> returns true.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public static UserEntry GetUserEntryOrNew(this SocketGuildUser user, BotDatabaseContext db)
|
public static UserEntry GetUserEntryOrNew(this SocketGuildUser user, BotDatabaseContext db)
|
||||||
=> db.UserEntries.Where(u => u.GuildId == (long)user.Guild.Id && u.UserId == (long)user.Id).FirstOrDefault()
|
=> db.UserEntries.Where(u => u.GuildId == user.Guild.Id && u.UserId == user.Id).FirstOrDefault()
|
||||||
?? new UserEntry() { IsNew = true, GuildId = (long)user.Guild.Id, UserId = (long)user.Id };
|
?? new UserEntry() { IsNew = true, GuildId = user.Guild.Id, UserId = user.Id };
|
||||||
}
|
}
|
|
@ -10,25 +10,27 @@ public class GuildConfig {
|
||||||
}
|
}
|
||||||
|
|
||||||
[Key]
|
[Key]
|
||||||
[Column("guild_id")]
|
public ulong GuildId { get; set; }
|
||||||
public long GuildId { get; set; }
|
|
||||||
[Column("role_id")]
|
[Column("role_id")]
|
||||||
public long? RoleId { get; set; }
|
public ulong? BirthdayRole { get; set; }
|
||||||
|
|
||||||
[Column("channel_announce_id")]
|
[Column("channel_announce_id")]
|
||||||
public long? ChannelAnnounceId { get; set; }
|
public ulong? AnnouncementChannel { get; set; }
|
||||||
|
|
||||||
[Column("time_zone")]
|
[Column("time_zone")]
|
||||||
public string? TimeZone { get; set; }
|
public string? GuildTimeZone { get; set; }
|
||||||
[Column("moderated")]
|
|
||||||
public bool Moderated { get; set; }
|
public bool Moderated { get; set; }
|
||||||
[Column("moderator_role")]
|
|
||||||
public long? ModeratorRole { get; set; }
|
public ulong? ModeratorRole { get; set; }
|
||||||
[Column("announce_message")]
|
|
||||||
public string? AnnounceMessage { get; set; }
|
public string? AnnounceMessage { get; set; }
|
||||||
[Column("announce_message_pl")]
|
|
||||||
public string? AnnounceMessagePl { get; set; }
|
public string? AnnounceMessagePl { get; set; }
|
||||||
[Column("announce_ping")]
|
|
||||||
public bool AnnouncePing { get; set; }
|
public bool AnnouncePing { get; set; }
|
||||||
[Column("last_seen")]
|
|
||||||
public DateTimeOffset LastSeen { get; set; }
|
public DateTimeOffset LastSeen { get; set; }
|
||||||
|
|
||||||
[InverseProperty(nameof(BlocklistEntry.Guild))]
|
[InverseProperty(nameof(BlocklistEntry.Guild))]
|
||||||
|
|
161
Data/Migrations/20221123062847_LongToUlong.Designer.cs
generated
Normal file
161
Data/Migrations/20221123062847_LongToUlong.Designer.cs
generated
Normal file
|
@ -0,0 +1,161 @@
|
||||||
|
// <auto-generated />
|
||||||
|
using System;
|
||||||
|
using BirthdayBot.Data;
|
||||||
|
using Microsoft.EntityFrameworkCore;
|
||||||
|
using Microsoft.EntityFrameworkCore.Infrastructure;
|
||||||
|
using Microsoft.EntityFrameworkCore.Migrations;
|
||||||
|
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
|
||||||
|
using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata;
|
||||||
|
|
||||||
|
#nullable disable
|
||||||
|
|
||||||
|
namespace BirthdayBot.Data.Migrations
|
||||||
|
{
|
||||||
|
[DbContext(typeof(BotDatabaseContext))]
|
||||||
|
[Migration("20221123062847_LongToUlong")]
|
||||||
|
partial class LongToUlong
|
||||||
|
{
|
||||||
|
/// <inheritdoc />
|
||||||
|
protected override void BuildTargetModel(ModelBuilder modelBuilder)
|
||||||
|
{
|
||||||
|
#pragma warning disable 612, 618
|
||||||
|
modelBuilder
|
||||||
|
.HasAnnotation("ProductVersion", "7.0.0")
|
||||||
|
.HasAnnotation("Relational:MaxIdentifierLength", 63);
|
||||||
|
|
||||||
|
NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder);
|
||||||
|
|
||||||
|
modelBuilder.Entity("BirthdayBot.Data.BlocklistEntry", b =>
|
||||||
|
{
|
||||||
|
b.Property<decimal>("GuildId")
|
||||||
|
.HasColumnType("numeric(20,0)")
|
||||||
|
.HasColumnName("guild_id");
|
||||||
|
|
||||||
|
b.Property<decimal>("UserId")
|
||||||
|
.HasColumnType("numeric(20,0)")
|
||||||
|
.HasColumnName("user_id");
|
||||||
|
|
||||||
|
b.HasKey("GuildId", "UserId")
|
||||||
|
.HasName("banned_users_pkey");
|
||||||
|
|
||||||
|
b.ToTable("banned_users", (string)null);
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("BirthdayBot.Data.GuildConfig", b =>
|
||||||
|
{
|
||||||
|
b.Property<decimal>("GuildId")
|
||||||
|
.HasColumnType("numeric(20,0)")
|
||||||
|
.HasColumnName("guild_id");
|
||||||
|
|
||||||
|
b.Property<string>("AnnounceMessage")
|
||||||
|
.HasColumnType("text")
|
||||||
|
.HasColumnName("announce_message");
|
||||||
|
|
||||||
|
b.Property<string>("AnnounceMessagePl")
|
||||||
|
.HasColumnType("text")
|
||||||
|
.HasColumnName("announce_message_pl");
|
||||||
|
|
||||||
|
b.Property<bool>("AnnouncePing")
|
||||||
|
.HasColumnType("boolean")
|
||||||
|
.HasColumnName("announce_ping");
|
||||||
|
|
||||||
|
b.Property<decimal?>("AnnouncementChannel")
|
||||||
|
.HasColumnType("numeric(20,0)")
|
||||||
|
.HasColumnName("channel_announce_id");
|
||||||
|
|
||||||
|
b.Property<decimal?>("BirthdayRole")
|
||||||
|
.HasColumnType("numeric(20,0)")
|
||||||
|
.HasColumnName("role_id");
|
||||||
|
|
||||||
|
b.Property<string>("GuildTimeZone")
|
||||||
|
.HasColumnType("text")
|
||||||
|
.HasColumnName("time_zone");
|
||||||
|
|
||||||
|
b.Property<DateTimeOffset>("LastSeen")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("timestamp with time zone")
|
||||||
|
.HasColumnName("last_seen")
|
||||||
|
.HasDefaultValueSql("now()");
|
||||||
|
|
||||||
|
b.Property<bool>("Moderated")
|
||||||
|
.HasColumnType("boolean")
|
||||||
|
.HasColumnName("moderated");
|
||||||
|
|
||||||
|
b.Property<decimal?>("ModeratorRole")
|
||||||
|
.HasColumnType("numeric(20,0)")
|
||||||
|
.HasColumnName("moderator_role");
|
||||||
|
|
||||||
|
b.HasKey("GuildId")
|
||||||
|
.HasName("settings_pkey");
|
||||||
|
|
||||||
|
b.ToTable("settings", (string)null);
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("BirthdayBot.Data.UserEntry", b =>
|
||||||
|
{
|
||||||
|
b.Property<decimal>("GuildId")
|
||||||
|
.HasColumnType("numeric(20,0)")
|
||||||
|
.HasColumnName("guild_id");
|
||||||
|
|
||||||
|
b.Property<decimal>("UserId")
|
||||||
|
.HasColumnType("numeric(20,0)")
|
||||||
|
.HasColumnName("user_id");
|
||||||
|
|
||||||
|
b.Property<int>("BirthDay")
|
||||||
|
.HasColumnType("integer")
|
||||||
|
.HasColumnName("birth_day");
|
||||||
|
|
||||||
|
b.Property<int>("BirthMonth")
|
||||||
|
.HasColumnType("integer")
|
||||||
|
.HasColumnName("birth_month");
|
||||||
|
|
||||||
|
b.Property<DateTimeOffset>("LastSeen")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("timestamp with time zone")
|
||||||
|
.HasColumnName("last_seen")
|
||||||
|
.HasDefaultValueSql("now()");
|
||||||
|
|
||||||
|
b.Property<string>("TimeZone")
|
||||||
|
.HasColumnType("text")
|
||||||
|
.HasColumnName("time_zone");
|
||||||
|
|
||||||
|
b.HasKey("GuildId", "UserId")
|
||||||
|
.HasName("user_birthdays_pkey");
|
||||||
|
|
||||||
|
b.ToTable("user_birthdays", (string)null);
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("BirthdayBot.Data.BlocklistEntry", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("BirthdayBot.Data.GuildConfig", "Guild")
|
||||||
|
.WithMany("BlockedUsers")
|
||||||
|
.HasForeignKey("GuildId")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade)
|
||||||
|
.IsRequired()
|
||||||
|
.HasConstraintName("banned_users_guild_id_fkey");
|
||||||
|
|
||||||
|
b.Navigation("Guild");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("BirthdayBot.Data.UserEntry", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("BirthdayBot.Data.GuildConfig", "Guild")
|
||||||
|
.WithMany("UserEntries")
|
||||||
|
.HasForeignKey("GuildId")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade)
|
||||||
|
.IsRequired()
|
||||||
|
.HasConstraintName("user_birthdays_guild_id_fkey");
|
||||||
|
|
||||||
|
b.Navigation("Guild");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("BirthdayBot.Data.GuildConfig", b =>
|
||||||
|
{
|
||||||
|
b.Navigation("BlockedUsers");
|
||||||
|
|
||||||
|
b.Navigation("UserEntries");
|
||||||
|
});
|
||||||
|
#pragma warning restore 612, 618
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
177
Data/Migrations/20221123062847_LongToUlong.cs
Normal file
177
Data/Migrations/20221123062847_LongToUlong.cs
Normal file
|
@ -0,0 +1,177 @@
|
||||||
|
using Microsoft.EntityFrameworkCore.Migrations;
|
||||||
|
|
||||||
|
#nullable disable
|
||||||
|
|
||||||
|
namespace BirthdayBot.Data.Migrations
|
||||||
|
{
|
||||||
|
/// <inheritdoc />
|
||||||
|
public partial class LongToUlong : Migration
|
||||||
|
{
|
||||||
|
/// <inheritdoc />
|
||||||
|
protected override void Up(MigrationBuilder migrationBuilder)
|
||||||
|
{
|
||||||
|
// NOTE: manually edited - must drop and re-add foreign key due to altered types
|
||||||
|
migrationBuilder.DropForeignKey(
|
||||||
|
name: "user_birthdays_guild_id_fkey",
|
||||||
|
table: "user_birthdays");
|
||||||
|
|
||||||
|
migrationBuilder.AlterColumn<decimal>(
|
||||||
|
name: "user_id",
|
||||||
|
table: "user_birthdays",
|
||||||
|
type: "numeric(20,0)",
|
||||||
|
nullable: false,
|
||||||
|
oldClrType: typeof(long),
|
||||||
|
oldType: "bigint");
|
||||||
|
|
||||||
|
migrationBuilder.AlterColumn<decimal>(
|
||||||
|
name: "guild_id",
|
||||||
|
table: "user_birthdays",
|
||||||
|
type: "numeric(20,0)",
|
||||||
|
nullable: false,
|
||||||
|
oldClrType: typeof(long),
|
||||||
|
oldType: "bigint");
|
||||||
|
|
||||||
|
migrationBuilder.AlterColumn<decimal>(
|
||||||
|
name: "role_id",
|
||||||
|
table: "settings",
|
||||||
|
type: "numeric(20,0)",
|
||||||
|
nullable: true,
|
||||||
|
oldClrType: typeof(long),
|
||||||
|
oldType: "bigint",
|
||||||
|
oldNullable: true);
|
||||||
|
|
||||||
|
migrationBuilder.AlterColumn<decimal>(
|
||||||
|
name: "moderator_role",
|
||||||
|
table: "settings",
|
||||||
|
type: "numeric(20,0)",
|
||||||
|
nullable: true,
|
||||||
|
oldClrType: typeof(long),
|
||||||
|
oldType: "bigint",
|
||||||
|
oldNullable: true);
|
||||||
|
|
||||||
|
migrationBuilder.AlterColumn<decimal>(
|
||||||
|
name: "channel_announce_id",
|
||||||
|
table: "settings",
|
||||||
|
type: "numeric(20,0)",
|
||||||
|
nullable: true,
|
||||||
|
oldClrType: typeof(long),
|
||||||
|
oldType: "bigint",
|
||||||
|
oldNullable: true);
|
||||||
|
|
||||||
|
migrationBuilder.AlterColumn<decimal>(
|
||||||
|
name: "guild_id",
|
||||||
|
table: "settings",
|
||||||
|
type: "numeric(20,0)",
|
||||||
|
nullable: false,
|
||||||
|
oldClrType: typeof(long),
|
||||||
|
oldType: "bigint");
|
||||||
|
|
||||||
|
migrationBuilder.AlterColumn<decimal>(
|
||||||
|
name: "user_id",
|
||||||
|
table: "banned_users",
|
||||||
|
type: "numeric(20,0)",
|
||||||
|
nullable: false,
|
||||||
|
oldClrType: typeof(long),
|
||||||
|
oldType: "bigint");
|
||||||
|
|
||||||
|
migrationBuilder.AlterColumn<decimal>(
|
||||||
|
name: "guild_id",
|
||||||
|
table: "banned_users",
|
||||||
|
type: "numeric(20,0)",
|
||||||
|
nullable: false,
|
||||||
|
oldClrType: typeof(long),
|
||||||
|
oldType: "bigint");
|
||||||
|
|
||||||
|
migrationBuilder.AddForeignKey(
|
||||||
|
name: "user_birthdays_guild_id_fkey",
|
||||||
|
table: "user_birthdays",
|
||||||
|
column: "guild_id",
|
||||||
|
principalTable: "settings",
|
||||||
|
principalColumn: "guild_id",
|
||||||
|
onDelete: ReferentialAction.Cascade);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
protected override void Down(MigrationBuilder migrationBuilder)
|
||||||
|
{
|
||||||
|
migrationBuilder.DropForeignKey(
|
||||||
|
name: "user_birthdays_guild_id_fkey",
|
||||||
|
table: "user_birthdays");
|
||||||
|
|
||||||
|
migrationBuilder.AlterColumn<long>(
|
||||||
|
name: "user_id",
|
||||||
|
table: "user_birthdays",
|
||||||
|
type: "bigint",
|
||||||
|
nullable: false,
|
||||||
|
oldClrType: typeof(decimal),
|
||||||
|
oldType: "numeric(20,0)");
|
||||||
|
|
||||||
|
migrationBuilder.AlterColumn<long>(
|
||||||
|
name: "guild_id",
|
||||||
|
table: "user_birthdays",
|
||||||
|
type: "bigint",
|
||||||
|
nullable: false,
|
||||||
|
oldClrType: typeof(decimal),
|
||||||
|
oldType: "numeric(20,0)");
|
||||||
|
|
||||||
|
migrationBuilder.AlterColumn<long>(
|
||||||
|
name: "role_id",
|
||||||
|
table: "settings",
|
||||||
|
type: "bigint",
|
||||||
|
nullable: true,
|
||||||
|
oldClrType: typeof(decimal),
|
||||||
|
oldType: "numeric(20,0)",
|
||||||
|
oldNullable: true);
|
||||||
|
|
||||||
|
migrationBuilder.AlterColumn<long>(
|
||||||
|
name: "moderator_role",
|
||||||
|
table: "settings",
|
||||||
|
type: "bigint",
|
||||||
|
nullable: true,
|
||||||
|
oldClrType: typeof(decimal),
|
||||||
|
oldType: "numeric(20,0)",
|
||||||
|
oldNullable: true);
|
||||||
|
|
||||||
|
migrationBuilder.AlterColumn<long>(
|
||||||
|
name: "channel_announce_id",
|
||||||
|
table: "settings",
|
||||||
|
type: "bigint",
|
||||||
|
nullable: true,
|
||||||
|
oldClrType: typeof(decimal),
|
||||||
|
oldType: "numeric(20,0)",
|
||||||
|
oldNullable: true);
|
||||||
|
|
||||||
|
migrationBuilder.AlterColumn<long>(
|
||||||
|
name: "guild_id",
|
||||||
|
table: "settings",
|
||||||
|
type: "bigint",
|
||||||
|
nullable: false,
|
||||||
|
oldClrType: typeof(decimal),
|
||||||
|
oldType: "numeric(20,0)");
|
||||||
|
|
||||||
|
migrationBuilder.AlterColumn<long>(
|
||||||
|
name: "user_id",
|
||||||
|
table: "banned_users",
|
||||||
|
type: "bigint",
|
||||||
|
nullable: false,
|
||||||
|
oldClrType: typeof(decimal),
|
||||||
|
oldType: "numeric(20,0)");
|
||||||
|
|
||||||
|
migrationBuilder.AlterColumn<long>(
|
||||||
|
name: "guild_id",
|
||||||
|
table: "banned_users",
|
||||||
|
type: "bigint",
|
||||||
|
nullable: false,
|
||||||
|
oldClrType: typeof(decimal),
|
||||||
|
oldType: "numeric(20,0)");
|
||||||
|
|
||||||
|
migrationBuilder.AddForeignKey(
|
||||||
|
name: "user_birthdays_guild_id_fkey",
|
||||||
|
table: "user_birthdays",
|
||||||
|
column: "guild_id",
|
||||||
|
principalTable: "settings",
|
||||||
|
principalColumn: "guild_id",
|
||||||
|
onDelete: ReferentialAction.Cascade);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -17,19 +17,19 @@ namespace BirthdayBot.Data.Migrations
|
||||||
{
|
{
|
||||||
#pragma warning disable 612, 618
|
#pragma warning disable 612, 618
|
||||||
modelBuilder
|
modelBuilder
|
||||||
.HasAnnotation("ProductVersion", "6.0.3")
|
.HasAnnotation("ProductVersion", "7.0.0")
|
||||||
.HasAnnotation("Relational:MaxIdentifierLength", 63);
|
.HasAnnotation("Relational:MaxIdentifierLength", 63);
|
||||||
|
|
||||||
NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder);
|
NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder);
|
||||||
|
|
||||||
modelBuilder.Entity("BirthdayBot.Data.BlocklistEntry", b =>
|
modelBuilder.Entity("BirthdayBot.Data.BlocklistEntry", b =>
|
||||||
{
|
{
|
||||||
b.Property<long>("GuildId")
|
b.Property<decimal>("GuildId")
|
||||||
.HasColumnType("bigint")
|
.HasColumnType("numeric(20,0)")
|
||||||
.HasColumnName("guild_id");
|
.HasColumnName("guild_id");
|
||||||
|
|
||||||
b.Property<long>("UserId")
|
b.Property<decimal>("UserId")
|
||||||
.HasColumnType("bigint")
|
.HasColumnType("numeric(20,0)")
|
||||||
.HasColumnName("user_id");
|
.HasColumnName("user_id");
|
||||||
|
|
||||||
b.HasKey("GuildId", "UserId")
|
b.HasKey("GuildId", "UserId")
|
||||||
|
@ -40,8 +40,8 @@ namespace BirthdayBot.Data.Migrations
|
||||||
|
|
||||||
modelBuilder.Entity("BirthdayBot.Data.GuildConfig", b =>
|
modelBuilder.Entity("BirthdayBot.Data.GuildConfig", b =>
|
||||||
{
|
{
|
||||||
b.Property<long>("GuildId")
|
b.Property<decimal>("GuildId")
|
||||||
.HasColumnType("bigint")
|
.HasColumnType("numeric(20,0)")
|
||||||
.HasColumnName("guild_id");
|
.HasColumnName("guild_id");
|
||||||
|
|
||||||
b.Property<string>("AnnounceMessage")
|
b.Property<string>("AnnounceMessage")
|
||||||
|
@ -56,10 +56,18 @@ namespace BirthdayBot.Data.Migrations
|
||||||
.HasColumnType("boolean")
|
.HasColumnType("boolean")
|
||||||
.HasColumnName("announce_ping");
|
.HasColumnName("announce_ping");
|
||||||
|
|
||||||
b.Property<long?>("ChannelAnnounceId")
|
b.Property<decimal?>("AnnouncementChannel")
|
||||||
.HasColumnType("bigint")
|
.HasColumnType("numeric(20,0)")
|
||||||
.HasColumnName("channel_announce_id");
|
.HasColumnName("channel_announce_id");
|
||||||
|
|
||||||
|
b.Property<decimal?>("BirthdayRole")
|
||||||
|
.HasColumnType("numeric(20,0)")
|
||||||
|
.HasColumnName("role_id");
|
||||||
|
|
||||||
|
b.Property<string>("GuildTimeZone")
|
||||||
|
.HasColumnType("text")
|
||||||
|
.HasColumnName("time_zone");
|
||||||
|
|
||||||
b.Property<DateTimeOffset>("LastSeen")
|
b.Property<DateTimeOffset>("LastSeen")
|
||||||
.ValueGeneratedOnAdd()
|
.ValueGeneratedOnAdd()
|
||||||
.HasColumnType("timestamp with time zone")
|
.HasColumnType("timestamp with time zone")
|
||||||
|
@ -70,18 +78,10 @@ namespace BirthdayBot.Data.Migrations
|
||||||
.HasColumnType("boolean")
|
.HasColumnType("boolean")
|
||||||
.HasColumnName("moderated");
|
.HasColumnName("moderated");
|
||||||
|
|
||||||
b.Property<long?>("ModeratorRole")
|
b.Property<decimal?>("ModeratorRole")
|
||||||
.HasColumnType("bigint")
|
.HasColumnType("numeric(20,0)")
|
||||||
.HasColumnName("moderator_role");
|
.HasColumnName("moderator_role");
|
||||||
|
|
||||||
b.Property<long?>("RoleId")
|
|
||||||
.HasColumnType("bigint")
|
|
||||||
.HasColumnName("role_id");
|
|
||||||
|
|
||||||
b.Property<string>("TimeZone")
|
|
||||||
.HasColumnType("text")
|
|
||||||
.HasColumnName("time_zone");
|
|
||||||
|
|
||||||
b.HasKey("GuildId")
|
b.HasKey("GuildId")
|
||||||
.HasName("settings_pkey");
|
.HasName("settings_pkey");
|
||||||
|
|
||||||
|
@ -90,12 +90,12 @@ namespace BirthdayBot.Data.Migrations
|
||||||
|
|
||||||
modelBuilder.Entity("BirthdayBot.Data.UserEntry", b =>
|
modelBuilder.Entity("BirthdayBot.Data.UserEntry", b =>
|
||||||
{
|
{
|
||||||
b.Property<long>("GuildId")
|
b.Property<decimal>("GuildId")
|
||||||
.HasColumnType("bigint")
|
.HasColumnType("numeric(20,0)")
|
||||||
.HasColumnName("guild_id");
|
.HasColumnName("guild_id");
|
||||||
|
|
||||||
b.Property<long>("UserId")
|
b.Property<decimal>("UserId")
|
||||||
.HasColumnType("bigint")
|
.HasColumnType("numeric(20,0)")
|
||||||
.HasColumnName("user_id");
|
.HasColumnName("user_id");
|
||||||
|
|
||||||
b.Property<int>("BirthDay")
|
b.Property<int>("BirthDay")
|
||||||
|
|
|
@ -5,18 +5,16 @@ namespace BirthdayBot.Data;
|
||||||
[Table("user_birthdays")]
|
[Table("user_birthdays")]
|
||||||
public class UserEntry {
|
public class UserEntry {
|
||||||
[Key]
|
[Key]
|
||||||
[Column("guild_id")]
|
public ulong GuildId { get; set; }
|
||||||
public long GuildId { get; set; }
|
|
||||||
[Key]
|
[Key]
|
||||||
[Column("user_id")]
|
public ulong UserId { get; set; }
|
||||||
public long UserId { get; set; }
|
|
||||||
[Column("birth_month")]
|
|
||||||
public int BirthMonth { get; set; }
|
public int BirthMonth { get; set; }
|
||||||
[Column("birth_day")]
|
|
||||||
public int BirthDay { get; set; }
|
public int BirthDay { get; set; }
|
||||||
[Column("time_zone")]
|
|
||||||
public string? TimeZone { get; set; }
|
public string? TimeZone { get; set; }
|
||||||
[Column("last_seen")]
|
|
||||||
public DateTimeOffset LastSeen { get; set; }
|
public DateTimeOffset LastSeen { get; set; }
|
||||||
|
|
||||||
[ForeignKey(nameof(GuildConfig.GuildId))]
|
[ForeignKey(nameof(GuildConfig.GuildId))]
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
global using Discord;
|
global using Discord;
|
||||||
global using Discord.WebSocket;
|
global using Discord.WebSocket;
|
||||||
using BirthdayBot.BackgroundServices;
|
|
||||||
using Discord.Interactions;
|
using Discord.Interactions;
|
||||||
using Microsoft.Extensions.DependencyInjection;
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
|
@ -18,7 +17,7 @@ class ShardManager : IDisposable {
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Number of concurrent shard startups to happen on each check.
|
/// Number of concurrent shard startups to happen on each check.
|
||||||
/// This value is also used in <see cref="DataRetention"/>.
|
/// This value also determines the maximum amount of concurrent background database operations.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public const int MaxConcurrentOperations = 4;
|
public const int MaxConcurrentOperations = 4;
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue