Update commands to use EF queries

This commit is contained in:
Noi 2022-03-20 01:07:17 -07:00
parent 67decd6fb4
commit b1b7c60211
4 changed files with 164 additions and 95 deletions

View file

@ -41,8 +41,13 @@ public class BirthdayModule : BotModuleBase {
} }
} }
var user = await ((SocketGuildUser)Context.User).GetConfigAsync().ConfigureAwait(false); using var db = new BotDatabaseContext();
await user.UpdateAsync(inmonth, inday, inzone ?? user.TimeZone).ConfigureAwait(false); var user = ((SocketGuildUser)Context.User).GetUserEntryOrNew(db);
if (user.IsNew) db.UserEntries.Add(user);
user.BirthMonth = inmonth;
user.BirthDay = inday;
user.TimeZone = inzone;
await db.SaveChangesAsync();
await RespondAsync($":white_check_mark: Your birthday has been set to **{FormatDate(inmonth, inday)}**" + await RespondAsync($":white_check_mark: Your birthday has been set to **{FormatDate(inmonth, inday)}**" +
(inzone == null ? "" : $", with time zone {inzone}") + ".").ConfigureAwait(false); (inzone == null ? "" : $", with time zone {inzone}") + ".").ConfigureAwait(false);
@ -50,31 +55,35 @@ public class BirthdayModule : BotModuleBase {
[SlashCommand("timezone", HelpCmdSetZone)] [SlashCommand("timezone", HelpCmdSetZone)]
public async Task CmdSetZone([Summary(description: HelpOptZone)] string zone) { public async Task CmdSetZone([Summary(description: HelpOptZone)] string zone) {
var user = await ((SocketGuildUser)Context.User).GetConfigAsync().ConfigureAwait(false); using var db = new BotDatabaseContext();
if (!user.IsKnown) {
var user = ((SocketGuildUser)Context.User).GetUserEntryOrNew(db);
if (user.IsNew) {
await RespondAsync(":x: You do not have a birthday set.", ephemeral: true).ConfigureAwait(false); await RespondAsync(":x: You do not have a birthday set.", ephemeral: true).ConfigureAwait(false);
return; return;
} }
string inzone; string newzone;
try { try {
inzone = ParseTimeZone(zone); newzone = ParseTimeZone(zone);
} catch (FormatException e) { } catch (FormatException e) {
await RespondAsync(e.Message, ephemeral: true).ConfigureAwait(false); await RespondAsync(e.Message, ephemeral: true).ConfigureAwait(false);
return; return;
} }
await user.UpdateAsync(user.BirthMonth, user.BirthDay, inzone).ConfigureAwait(false); user.TimeZone = newzone;
await RespondAsync($":white_check_mark: Your time zone has been set to **{inzone}**.").ConfigureAwait(false); await db.SaveChangesAsync();
await RespondAsync($":white_check_mark: Your time zone has been set to **{newzone}**.").ConfigureAwait(false);
} }
} }
[SlashCommand("remove", HelpCmdRemove)] [SlashCommand("remove", HelpCmdRemove)]
public async Task CmdRemove() { public async Task CmdRemove() {
var user = await ((SocketGuildUser)Context.User).GetConfigAsync().ConfigureAwait(false); using var db = new BotDatabaseContext();
if (user.IsKnown) { var user = ((SocketGuildUser)Context.User).GetUserEntryOrNew(db);
await user.DeleteAsync().ConfigureAwait(false); if (!user.IsNew) {
await RespondAsync(":white_check_mark: Your birthday in this server has been removed.") db.UserEntries.Remove(user);
.ConfigureAwait(false); await db.SaveChangesAsync();
await RespondAsync(":white_check_mark: Your birthday in this server has been removed.");
} else { } else {
await RespondAsync(":white_check_mark: Your birthday is not registered.") await RespondAsync(":white_check_mark: Your birthday is not registered.")
.ConfigureAwait(false); .ConfigureAwait(false);
@ -83,12 +92,15 @@ public class BirthdayModule : BotModuleBase {
[SlashCommand("get", "Gets a user's birthday.")] [SlashCommand("get", "Gets a user's birthday.")]
public async Task CmdGetBday([Summary(description: "Optional: The user's birthday to look up.")] SocketGuildUser? user = null) { public async Task CmdGetBday([Summary(description: "Optional: The user's birthday to look up.")] SocketGuildUser? user = null) {
var self = user is null; using var db = new BotDatabaseContext();
if (self) user = (SocketGuildUser)Context.User;
var targetdata = await user!.GetConfigAsync().ConfigureAwait(false);
if (!targetdata.IsKnown) { var isSelf = user is null;
if (self) await RespondAsync(":x: You do not have your birthday registered.", ephemeral: true).ConfigureAwait(false); if (isSelf) user = (SocketGuildUser)Context.User;
var targetdata = user!.GetUserEntryOrNew(db);
if (targetdata.IsNew) {
if (isSelf) await RespondAsync(":x: You do not have your birthday registered.", ephemeral: true).ConfigureAwait(false);
else await RespondAsync(":x: The given user does not have their birthday registered.", ephemeral: true).ConfigureAwait(false); else await RespondAsync(":x: The given user does not have their birthday registered.", ephemeral: true).ConfigureAwait(false);
return; return;
} }
@ -111,7 +123,7 @@ public class BirthdayModule : BotModuleBase {
var search = DateIndex(now.Month, now.Day) - 8; // begin search 8 days prior to current date UTC var search = DateIndex(now.Month, now.Day) - 8; // begin search 8 days prior to current date UTC
if (search <= 0) search = 366 - Math.Abs(search); if (search <= 0) search = 366 - Math.Abs(search);
var query = await GetSortedUsersAsync(Context.Guild).ConfigureAwait(false); var query = GetSortedUserList(Context.Guild);
// TODO pagination instead of this workaround // TODO pagination instead of this workaround
bool hasOutputOneLine = false; bool hasOutputOneLine = false;
@ -182,7 +194,7 @@ public class BirthdayModule : BotModuleBase {
return; return;
} }
var bdlist = await GetSortedUsersAsync(Context.Guild).ConfigureAwait(false); var bdlist = GetSortedUserList(Context.Guild);
var filename = "birthdaybot-" + Context.Guild.Id; var filename = "birthdaybot-" + Context.Guild.Id;
Stream fileoutput; Stream fileoutput;
@ -201,27 +213,26 @@ public class BirthdayModule : BotModuleBase {
/// Fetches all guild birthdays and places them into an easily usable structure. /// Fetches all guild birthdays and places them into an easily usable structure.
/// Users currently not in the guild are not included in the result. /// Users currently not in the guild are not included in the result.
/// </summary> /// </summary>
private static async Task<List<ListItem>> GetSortedUsersAsync(SocketGuild guild) { private static List<ListItem> GetSortedUserList(SocketGuild guild) {
using var db = await Database.OpenConnectionAsync(); using var db = new BotDatabaseContext();
using var c = db.CreateCommand(); var query = from row in db.UserEntries
c.CommandText = "select user_id, birth_month, birth_day from " + GuildUserConfiguration.BackingTable where row.GuildId == (long)guild.Id
+ " where guild_id = @Gid order by birth_month, birth_day"; orderby row.BirthMonth, row.BirthDay
c.Parameters.Add("@Gid", NpgsqlTypes.NpgsqlDbType.Bigint).Value = (long)guild.Id; select new {
c.Prepare(); UserId = (ulong)row.UserId,
using var r = await c.ExecuteReaderAsync(); Month = row.BirthMonth,
var result = new List<ListItem>(); Day = row.BirthDay
while (await r.ReadAsync()) { };
var id = (ulong)r.GetInt64(0);
var month = r.GetInt32(1);
var day = r.GetInt32(2);
var guildUser = guild.GetUser(id); var result = new List<ListItem>();
foreach (var row in query) {
var guildUser = guild.GetUser(row.UserId);
if (guildUser == null) continue; // Skip user not in guild if (guildUser == null) continue; // Skip user not in guild
result.Add(new ListItem() { result.Add(new ListItem() {
BirthMonth = month, BirthMonth = row.Month,
BirthDay = day, BirthDay = row.Day,
DateIndex = DateIndex(month, day), DateIndex = DateIndex(row.Month, row.Day),
UserId = guildUser.Id, UserId = guildUser.Id,
DisplayName = Common.FormatName(guildUser, false) DisplayName = Common.FormatName(guildUser, false)
}); });

View file

@ -24,8 +24,12 @@ public class BirthdayOverrideModule : BotModuleBase {
return; return;
} }
var user = await target.GetConfigAsync().ConfigureAwait(false); using var db = new BotDatabaseContext();
await user.UpdateAsync(inmonth, inday, user.TimeZone).ConfigureAwait(false); var user = target.GetUserEntryOrNew(db);
if (user.IsNew) db.UserEntries.Add(user);
user.BirthMonth = inmonth;
user.BirthDay = inday;
await db.SaveChangesAsync();
await RespondAsync($":white_check_mark: {Common.FormatName(target, false)}'s birthday has been set to " + await RespondAsync($":white_check_mark: {Common.FormatName(target, false)}'s birthday has been set to " +
$"**{FormatDate(inmonth, inday)}**.").ConfigureAwait(false); $"**{FormatDate(inmonth, inday)}**.").ConfigureAwait(false);
@ -34,30 +38,35 @@ public class BirthdayOverrideModule : BotModuleBase {
[SlashCommand("set-timezone", HelpPfxModOnly + "Set a user's time zone on their behalf.")] [SlashCommand("set-timezone", HelpPfxModOnly + "Set a user's time zone on their behalf.")]
public async Task OvSetTimezone([Summary(description: HelpOptOvTarget)]SocketGuildUser target, public async Task OvSetTimezone([Summary(description: HelpOptOvTarget)]SocketGuildUser target,
[Summary(description: HelpOptZone)]string zone) { [Summary(description: HelpOptZone)]string zone) {
var user = await target.GetConfigAsync().ConfigureAwait(false); using var db = new BotDatabaseContext();
if (!user.IsKnown) {
var user = target.GetUserEntryOrNew(db);
if (user.IsNew) {
await RespondAsync($":x: {Common.FormatName(target, false)} does not have a birthday set.") await RespondAsync($":x: {Common.FormatName(target, false)} does not have a birthday set.")
.ConfigureAwait(false); .ConfigureAwait(false);
return; return;
} }
string inzone; string newzone;
try { try {
inzone = ParseTimeZone(zone); newzone = ParseTimeZone(zone);
} catch (FormatException e) { } catch (FormatException e) {
await RespondAsync(e.Message, ephemeral: true).ConfigureAwait(false); await RespondAsync(e.Message, ephemeral: true).ConfigureAwait(false);
return; return;
} }
await user.UpdateAsync(user.BirthMonth, user.BirthDay, inzone).ConfigureAwait(false); user.TimeZone = newzone;
await db.SaveChangesAsync();
await RespondAsync($":white_check_mark: {Common.FormatName(target, false)}'s time zone has been set to " + await RespondAsync($":white_check_mark: {Common.FormatName(target, false)}'s time zone has been set to " +
$"**{inzone}**.").ConfigureAwait(false); $"**{newzone}**.").ConfigureAwait(false);
} }
[SlashCommand("remove-birthday", HelpPfxModOnly + "Remove a user's birthday information on their behalf.")] [SlashCommand("remove-birthday", HelpPfxModOnly + "Remove a user's birthday information on their behalf.")]
public async Task OvRemove([Summary(description: HelpOptOvTarget)]SocketGuildUser target) { public async Task OvRemove([Summary(description: HelpOptOvTarget)]SocketGuildUser target) {
var user = await target.GetConfigAsync().ConfigureAwait(false); using var db = new BotDatabaseContext();
if (user.IsKnown) { var user = ((SocketGuildUser)Context.User).GetUserEntryOrNew(db);
await user.DeleteAsync().ConfigureAwait(false); if (!user.IsNew) {
db.UserEntries.Remove(user);
await db.SaveChangesAsync();
await RespondAsync($":white_check_mark: {Common.FormatName(target, false)}'s birthday in this server has been removed.") await RespondAsync($":white_check_mark: {Common.FormatName(target, false)}'s birthday in this server has been removed.")
.ConfigureAwait(false); .ConfigureAwait(false);
} else { } else {

View file

@ -53,9 +53,7 @@ public class ConfigModule : BotModuleBase {
[SlashCommand("set-channel", HelpPfxModOnly + HelpSubCmdChannel + HelpPofxBlankUnset)] [SlashCommand("set-channel", HelpPfxModOnly + HelpSubCmdChannel + HelpPofxBlankUnset)]
public async Task CmdSetChannel([Summary(description: HelpOptRole)] SocketTextChannel? channel = null) { public async Task CmdSetChannel([Summary(description: HelpOptRole)] SocketTextChannel? channel = null) {
var gconf = await Context.Guild.GetConfigAsync().ConfigureAwait(false); await DoDatabaseUpdate(Context, s => s.ChannelAnnounceId = (long?)channel?.Id);
gconf.AnnounceChannelId = channel?.Id;
await gconf.UpdateAsync().ConfigureAwait(false);
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}**."));
} }
@ -71,9 +69,7 @@ public class ConfigModule : BotModuleBase {
[SlashCommand("set-ping", HelpPfxModOnly + HelpSubCmdPing)] [SlashCommand("set-ping", HelpPfxModOnly + HelpSubCmdPing)]
public async Task CmdSetPing([Summary(description: "Set True to ping users, False to display them normally.")]bool option) { public async Task CmdSetPing([Summary(description: "Set True to ping users, False to display them normally.")]bool option) {
var gconf = await Context.Guild.GetConfigAsync().ConfigureAwait(false); await DoDatabaseUpdate(Context, s => s.AnnouncePing = option);
gconf.AnnouncePing = option;
await gconf.UpdateAsync().ConfigureAwait(false);
await RespondAsync($":white_check_mark: Announcement pings are now **{(option ? "on" : "off")}**.").ConfigureAwait(false); await RespondAsync($":white_check_mark: Announcement pings are now **{(option ? "on" : "off")}**.").ConfigureAwait(false);
} }
} }
@ -82,17 +78,13 @@ public class ConfigModule : BotModuleBase {
public class SubCmdsConfigRole : BotModuleBase { public class SubCmdsConfigRole : BotModuleBase {
[SlashCommand("set-birthday-role", HelpPfxModOnly + "Set the role given to users having a birthday.")] [SlashCommand("set-birthday-role", HelpPfxModOnly + "Set the role given to users having a birthday.")]
public async Task CmdSetBRole([Summary(description: HelpOptRole)] SocketRole role) { public async Task CmdSetBRole([Summary(description: HelpOptRole)] SocketRole role) {
var gconf = await Context.Guild.GetConfigAsync().ConfigureAwait(false); await DoDatabaseUpdate(Context, s => s.RoleId = (long)role.Id);
gconf.RoleId = role.Id;
await gconf.UpdateAsync().ConfigureAwait(false);
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);
} }
[SlashCommand("set-moderator-role", HelpPfxModOnly + "Designate a role whose members can configure the bot." + HelpPofxBlankUnset)] [SlashCommand("set-moderator-role", HelpPfxModOnly + "Designate a role whose members can configure the bot." + HelpPofxBlankUnset)]
public async Task CmdSetModRole([Summary(description: HelpOptRole)]SocketRole? role = null) { public async Task CmdSetModRole([Summary(description: HelpOptRole)]SocketRole? role = null) {
var gconf = await Context.Guild.GetConfigAsync().ConfigureAwait(false); await DoDatabaseUpdate(Context, s => s.ModeratorRole = (long?)role?.Id);
gconf.ModeratorRole = role?.Id;
await gconf.UpdateAsync().ConfigureAwait(false);
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}**."));
} }
@ -107,26 +99,36 @@ public class ConfigModule : BotModuleBase {
public Task CmdDelBlock([Summary(description: "The user to unblock.")] SocketGuildUser user) => UpdateBlockAsync(user, false); public Task CmdDelBlock([Summary(description: "The user to unblock.")] SocketGuildUser user) => UpdateBlockAsync(user, false);
private async Task UpdateBlockAsync(SocketGuildUser user, bool setting) { private async Task UpdateBlockAsync(SocketGuildUser user, bool setting) {
var gconf = await Context.Guild.GetConfigAsync().ConfigureAwait(false); // setting: true to add (set), false to remove (unset)
bool already = setting == await gconf.IsUserBlockedAsync(user.Id).ConfigureAwait(false); using var db = new BotDatabaseContext();
var existing = db.BlocklistEntries
.Where(bl => bl.GuildId == (long)user.Guild.Id && bl.UserId == (long)user.Id).FirstOrDefault();
bool already = (existing != null) == setting;
if (already) { if (already) {
await RespondAsync($":white_check_mark: User is already {(setting ? "" : "not ")}blocked.").ConfigureAwait(false); await RespondAsync($":white_check_mark: User is already {(setting ? "" : "not ")}blocked.").ConfigureAwait(false);
} else { return;
if (setting) await gconf.BlockUserAsync(user.Id).ConfigureAwait(false);
else await gconf.UnblockUserAsync(user.Id).ConfigureAwait(false);
await RespondAsync($":white_check_mark: {Common.FormatName(user, false)} has been {(setting ? "" : "un")}blocked.");
} }
if (setting) db.BlocklistEntries.Add(new BlocklistEntry() { GuildId = (long)user.Guild.Id, UserId = (long)user.Id });
else db.Remove(existing!);
await db.SaveChangesAsync();
await RespondAsync($":white_check_mark: {Common.FormatName(user, false)} has been {(setting ? "" : "un")}blocked.");
} }
[SlashCommand("set-moderated", HelpPfxModOnly + "Set moderated mode on the server.")] [SlashCommand("set-moderated", HelpPfxModOnly + "Set moderated mode on the server.")]
public async Task CmdAddBlock([Summary(name: "enable", description: "The moderated mode setting.")] bool setting) { public async Task CmdSetModerated([Summary(name: "enable", description: "The moderated mode setting.")] bool setting) {
var gconf = await Context.Guild.GetConfigAsync().ConfigureAwait(false); bool current = false;
bool already = setting == gconf.IsModerated; await DoDatabaseUpdate(Context, s => {
current = s.Moderated;
s.Moderated = setting;
});
bool already = setting == current;
if (already) { if (already) {
await RespondAsync($":white_check_mark: Moderated mode is already **{(setting ? "en" : "dis")}abled**.").ConfigureAwait(false); await RespondAsync($":white_check_mark: Moderated mode is already **{(setting ? "en" : "dis")}abled**.");
} else { } else {
gconf.IsModerated = setting;
await gconf.UpdateAsync().ConfigureAwait(false);
await RespondAsync($":white_check_mark: Moderated mode is now **{(setting ? "en" : "dis")}abled**.").ConfigureAwait(false); await RespondAsync($":white_check_mark: Moderated mode is now **{(setting ? "en" : "dis")}abled**.").ConfigureAwait(false);
} }
} }
@ -135,15 +137,19 @@ public class ConfigModule : BotModuleBase {
[SlashCommand("check", HelpPfxModOnly + HelpCmdCheck)] [SlashCommand("check", HelpPfxModOnly + HelpCmdCheck)]
public async Task CmdCheck() { public async Task CmdCheck() {
static string DoTestFor(string label, Func<bool> test) => $"{label}: { (test() ? ":white_check_mark: Yes" : ":x: No") }"; static string DoTestFor(string label, Func<bool> test) => $"{label}: { (test() ? ":white_check_mark: Yes" : ":x: No") }";
var result = new StringBuilder();
SocketTextChannel channel = (SocketTextChannel)Context.Channel; SocketTextChannel channel = (SocketTextChannel)Context.Channel;
var guild = Context.Guild; var guild = Context.Guild;
var conf = await guild.GetConfigAsync().ConfigureAwait(false);
var usercfgs = await guild.GetUserConfigurationsAsync().ConfigureAwait(false); using var db = new BotDatabaseContext();
var guildconf = guild.GetConfigOrNew(db);
await db.Entry(guildconf).Collection(t => t.UserEntries).LoadAsync();
var result = new StringBuilder();
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: `{ usercfgs.Count() }`"); result.AppendLine($"Number of registered birthdays: `{ guildconf.UserEntries.Count() }`");
result.AppendLine($"Server time zone: `{ (conf?.TimeZone ?? "Not set - using UTC") }`"); result.AppendLine($"Server time zone: `{ (guildconf.TimeZone ?? "Not set - using UTC") }`");
result.AppendLine(); result.AppendLine();
bool hasMembers = Common.HasMostMembersDownloaded(guild); bool hasMembers = Common.HasMostMembersDownloaded(guild);
@ -152,7 +158,7 @@ public class ConfigModule : BotModuleBase {
int bdayCount = -1; int bdayCount = -1;
result.Append(DoTestFor("Birthday processing", delegate { result.Append(DoTestFor("Birthday processing", delegate {
if (!hasMembers) return false; if (!hasMembers) return false;
bdayCount = BackgroundServices.BirthdayRoleUpdate.GetGuildCurrentBirthdays(usercfgs, conf?.TimeZone).Count; bdayCount = BackgroundServices.BirthdayRoleUpdate.GetGuildCurrentBirthdays(guildconf.UserEntries, guildconf.TimeZone).Count;
return true; return true;
})); }));
if (hasMembers) result.AppendLine($" - `{bdayCount}` user(s) currently having a birthday."); if (hasMembers) result.AppendLine($" - `{bdayCount}` user(s) currently having a birthday.");
@ -160,13 +166,13 @@ public class ConfigModule : BotModuleBase {
result.AppendLine(); result.AppendLine();
result.AppendLine(DoTestFor("Birthday role set with `bb.config role`", delegate { result.AppendLine(DoTestFor("Birthday role set with `bb.config role`", delegate {
if (conf == null) return false; if (guildconf.IsNew) return false;
SocketRole? role = guild.GetRole(conf.RoleId ?? 0); SocketRole? role = guild.GetRole((ulong)(guildconf.RoleId ?? 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 (conf == null) return false; if (guildconf.IsNew) return false;
SocketRole? role = guild.GetRole(conf.RoleId ?? 0); SocketRole? role = guild.GetRole((ulong)(guildconf.RoleId ?? 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;
})); }));
@ -174,8 +180,8 @@ 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 (conf == null) return false; if (guildconf.IsNew) return false;
announcech = guild.GetTextChannel(conf.AnnounceChannelId ?? 0); announcech = guild.GetTextChannel((ulong)(guildconf.ChannelAnnounceId ?? 0));
return announcech != null; return announcech != null;
})); }));
string disp = announcech == null ? "announcement channel" : $"<#{announcech.Id}>"; string disp = announcech == null ? "announcement channel" : $"<#{announcech.Id}>";
@ -197,14 +203,14 @@ public class ConfigModule : BotModuleBase {
result.AppendLine($"> {line}"); result.AppendLine($"> {line}");
return result.ToString(); return result.ToString();
} }
if (conf != null && (conf.AnnounceMessages.Item1 != null || conf.AnnounceMessages.Item2 != null)) { if (!guildconf.IsNew && (guildconf.AnnounceMessage != null || guildconf.AnnounceMessagePl != null)) {
var em = new EmbedBuilder().WithAuthor(new EmbedAuthorBuilder() { Name = "Custom announce messages:" }); var em = new EmbedBuilder().WithAuthor(new EmbedAuthorBuilder() { Name = "Custom announce messages:" });
var dispAnnounces = new StringBuilder("Custom announcement message(s):\n"); var dispAnnounces = new StringBuilder("Custom announcement message(s):\n");
if (conf.AnnounceMessages.Item1 != null) { if (guildconf.AnnounceMessage != null) {
em = em.AddField("Single", prepareAnnouncePreview(conf.AnnounceMessages.Item1)); em = em.AddField("Single", prepareAnnouncePreview(guildconf.AnnounceMessage));
} }
if (conf.AnnounceMessages.Item2 != null) { if (guildconf.AnnounceMessagePl != null) {
em = em.AddField("Multi", prepareAnnouncePreview(conf.AnnounceMessages.Item2)); em = em.AddField("Multi", prepareAnnouncePreview(guildconf.AnnounceMessagePl));
} }
await ReplyAsync(embed: em.Build()).ConfigureAwait(false); await ReplyAsync(embed: em.Build()).ConfigureAwait(false);
} }
@ -213,11 +219,9 @@ public class ConfigModule : BotModuleBase {
[SlashCommand("set-timezone", HelpPfxModOnly + "Configure the time zone to use by default in the server." + HelpPofxBlankUnset)] [SlashCommand("set-timezone", HelpPfxModOnly + "Configure the time zone to use by default in the server." + HelpPofxBlankUnset)]
public async Task CmdSetTimezone([Summary(description: HelpOptZone)] string? zone = null) { public async Task CmdSetTimezone([Summary(description: HelpOptZone)] string? zone = null) {
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 ";
var gconf = await Context.Guild.GetConfigAsync().ConfigureAwait(false);
if (zone == null) { if (zone == null) {
gconf.TimeZone = null; await DoDatabaseUpdate(Context, s => s.TimeZone = null);
await gconf.UpdateAsync().ConfigureAwait(false);
await RespondAsync(Response + "unset.").ConfigureAwait(false); await RespondAsync(Response + "unset.").ConfigureAwait(false);
} else { } else {
string parsedZone; string parsedZone;
@ -228,9 +232,22 @@ public class ConfigModule : BotModuleBase {
return; return;
} }
gconf.TimeZone = parsedZone; await DoDatabaseUpdate(Context, s => s.TimeZone = parsedZone);
await gconf.UpdateAsync().ConfigureAwait(false); await RespondAsync(Response + $"set to **{parsedZone}**.").ConfigureAwait(false);
await RespondAsync(Response + $"set to **{zone}**.").ConfigureAwait(false);
} }
} }
/// <summary>
/// Helper method for updating arbitrary <see cref="GuildConfig"/> values without all the boilerplate.
/// </summary>
/// <param name="valueUpdater">A delegate which modifies <see cref="GuildConfig"/> properties as needed.</param>
private static async Task DoDatabaseUpdate(SocketInteractionContext context, Action<GuildConfig> valueUpdater) {
using var db = new BotDatabaseContext();
var settings = context.Guild.GetConfigOrNew(db);
valueUpdater(settings);
if (settings.IsNew) db.GuildConfigurations.Add(settings);
await db.SaveChangesAsync();
}
} }

View file

@ -77,6 +77,9 @@ class BirthdayRoleUpdate : BackgroundService {
/// Gets all known users from the given guild and returns a list including only those who are /// Gets all known users from the given guild and returns a list including only those who are
/// currently experiencing a birthday in the respective time zone. /// currently experiencing a birthday in the respective time zone.
/// </summary> /// </summary>
#pragma warning disable 618
[Obsolete(Database.ObsoleteReason)]
#pragma warning restore 618
public static HashSet<ulong> GetGuildCurrentBirthdays(IEnumerable<GuildUserConfiguration> guildUsers, string? defaultTzStr) { public static HashSet<ulong> GetGuildCurrentBirthdays(IEnumerable<GuildUserConfiguration> guildUsers, string? defaultTzStr) {
var tzdb = DateTimeZoneProviders.Tzdb; var tzdb = DateTimeZoneProviders.Tzdb;
DateTimeZone defaultTz = (defaultTzStr != null ? DateTimeZoneProviders.Tzdb.GetZoneOrNull(defaultTzStr) : null) ?? tzdb.GetZoneOrNull("UTC")!; DateTimeZone defaultTz = (defaultTzStr != null ? DateTimeZoneProviders.Tzdb.GetZoneOrNull(defaultTzStr) : null) ?? tzdb.GetZoneOrNull("UTC")!;
@ -102,6 +105,35 @@ class BirthdayRoleUpdate : BackgroundService {
return birthdayUsers; return birthdayUsers;
} }
/// <summary>
/// Gets all known users from the given guild and returns a list including only those who are
/// currently experiencing a birthday in the respective time zone.
/// </summary>
public static HashSet<ulong> GetGuildCurrentBirthdays(IEnumerable<UserEntry> guildUsers, string? defaultTzStr) {
var tzdb = DateTimeZoneProviders.Tzdb;
DateTimeZone defaultTz = (defaultTzStr != null ? DateTimeZoneProviders.Tzdb.GetZoneOrNull(defaultTzStr) : null) ?? tzdb.GetZoneOrNull("UTC")!;
var birthdayUsers = new HashSet<ulong>();
foreach (var item in guildUsers) {
// Determine final time zone to use for calculation
DateTimeZone tz = (item.TimeZone != null ? tzdb.GetZoneOrNull(item.TimeZone) : null) ?? defaultTz;
var targetMonth = item.BirthMonth;
var targetDay = item.BirthDay;
var checkNow = SystemClock.Instance.GetCurrentInstant().InZone(tz);
// Special case: If birthday is February 29 and it's not a leap year, recognize it on March 1st
if (targetMonth == 2 && targetDay == 29 && !DateTime.IsLeapYear(checkNow.Year)) {
targetMonth = 3;
targetDay = 1;
}
if (targetMonth == checkNow.Month && targetDay == checkNow.Day) {
birthdayUsers.Add((ulong)item.UserId);
}
}
return birthdayUsers;
}
/// <summary> /// <summary>
/// Sets the birthday role to all applicable users. Unsets it from all others who may have it. /// Sets the birthday role to all applicable users. Unsets it from all others who may have it.
/// </summary> /// </summary>