Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Migrate from joinwatch to notes #246

Merged
merged 7 commits into from
Dec 15, 2024
67 changes: 3 additions & 64 deletions Commands/InteractionCommands/JoinwatchInteractions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -11,82 +11,21 @@ public async Task JoinwatchAdd(InteractionContext ctx,
[Option("user", "The user to watch for joins and leaves of.")] DiscordUser user,
[Option("note", "An optional note for context.")] string note = "")
{
var joinWatchlist = await Program.db.ListRangeAsync("joinWatchedUsers");

if (joinWatchlist.Contains(user.Id))
{
// User is already watched

// Get current note; if it's the same, do nothing
var currentNote = await Program.db.HashGetAsync("joinWatchedUsersNotes", user.Id);
if (currentNote == note || (string.IsNullOrWhiteSpace(currentNote) && string.IsNullOrWhiteSpace(note)))
{
await ctx.RespondAsync($"{Program.cfgjson.Emoji.Error} {user.Mention} is already being watched with the same note! Nothing to do.");
return;
}

// If note is different, update it

// If new note is empty, remove instead of changing to empty string!
if (string.IsNullOrWhiteSpace(note))
{
await Program.db.HashDeleteAsync("joinWatchedUsersNotes", user.Id);
await ctx.RespondAsync($"{Program.cfgjson.Emoji.Success} Successfully removed the note for {user.Mention}! They are still being watched.");
}
else
{
await Program.db.HashSetAsync("joinWatchedUsersNotes", user.Id, note);
await ctx.RespondAsync($"{Program.cfgjson.Emoji.Success} Successfully updated the note for {user.Mention}:\n> {note}");
}
}
else
{
// User is not joinwatched, watch
await Program.db.ListRightPushAsync("joinWatchedUsers", user.Id);
if (note != "")
await Program.db.HashSetAsync("joinWatchedUsersNotes", user.Id, note);
await ctx.RespondAsync($"{Program.cfgjson.Emoji.Success} Now watching for joins/leaves of {user.Mention} to send to the investigations channel"
+ (note == "" ? "!" : $" with the following note:\n>>> {note}"));
}
await ctx.RespondAsync($"{Program.cfgjson.Emoji.Error} This command is deprecated and no longer works; all joinwatches have been converted to notes. Please use `/note add` instead, like this: `/note add user:{user.Id} note:{(string.IsNullOrEmpty(note) ? "<context>" : note)} show_on_join_and_leave:True`");
}

[SlashCommand("remove", "Stop watching for joins and leaves of a user.")]
public async Task JoinwatchRemove(InteractionContext ctx,
[Option("user", "The user to stop watching for joins and leaves of.")] DiscordUser user)
{
var joinWatchlist = await Program.db.ListRangeAsync("joinWatchedUsers");

// Check user watch status first; error if not watched
if (!joinWatchlist.Contains(user.Id))
{
await ctx.RespondAsync($"{Program.cfgjson.Emoji.Error} {user.Mention} is not being watched! Nothing to do.");
return;
}

Program.db.ListRemove("joinWatchedUsers", joinWatchlist.First(x => x == user.Id));
await Program.db.HashDeleteAsync("joinWatchedUsersNotes", user.Id);
await ctx.RespondAsync($"{Program.cfgjson.Emoji.Success} Successfully unwatched {user.Mention}!");
await ctx.RespondAsync($"{Program.cfgjson.Emoji.Error} This command is deprecated and no longer works; all joinwatches have been converted to notes. Please use `/note delete` instead, like this: `/note delete user:{user.Id} note:<note>`");
}

[SlashCommand("status", "Check the joinwatch status for a user.")]
public async Task JoinwatchStatus(InteractionContext ctx,
[Option("user", "The user whose joinwatch status to check.")] DiscordUser user)
{
var joinWatchlist = await Program.db.ListRangeAsync("joinWatchedUsers");

if (joinWatchlist.Contains(user.Id))
{
var note = await Program.db.HashGetAsync("joinWatchedUsersNotes", user.Id);

if (string.IsNullOrWhiteSpace(note))
await ctx.RespondAsync($"{Program.cfgjson.Emoji.Information} {user.Mention} is currently being watched, but no note is set.");
else
await ctx.RespondAsync($"{Program.cfgjson.Emoji.Information} {user.Mention} is currently being watched with the following note:\n> {note}");
}
else
{
await ctx.RespondAsync($"{Program.cfgjson.Emoji.Error} {user.Mention} is not being watched!");
}
await ctx.RespondAsync($"{Program.cfgjson.Emoji.Error} This command is deprecated and no longer works; all joinwatches have been converted to notes. Please use `/note list user:{user.Id}` to show all of this user's notes, or `/note details user:{user.Id} note:<note>` for details on a specific note, instead. Notes with \"Show on Join & Leave\" enabled will behave like joinwatches.");
}
}
}
Expand Down
12 changes: 9 additions & 3 deletions Commands/InteractionCommands/UserNoteInteractions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,8 @@ public async Task AddUserNoteAsync(InteractionContext ctx,
[Option("show_on_modmail", "Whether to show the note when the user opens a modmail thread. Default: true")] bool showOnModmail = true,
[Option("show_on_warn", "Whether to show the note when the user is warned. Default: true")] bool showOnWarn = true,
[Option("show_all_mods", "Whether to show this note to all mods, versus just yourself. Default: true")] bool showAllMods = true,
[Option("show_once", "Whether to show this note once and then discard it. Default: false")] bool showOnce = false)
[Option("show_once", "Whether to show this note once and then discard it. Default: false")] bool showOnce = false,
[Option("show_on_join_and_leave", "Whether to show this note when the user joins & leaves. Works like joinwatch. Default: false")] bool showOnJoinAndLeave = false)
{
await ctx.DeferAsync();

Expand All @@ -30,6 +31,7 @@ public async Task AddUserNoteAsync(InteractionContext ctx,
ShowOnWarn = showOnWarn,
ShowAllMods = showAllMods,
ShowOnce = showOnce,
ShowOnJoinAndLeave = showOnJoinAndLeave,
NoteId = noteId,
Timestamp = DateTime.Now,
Type = WarningType.Note
Expand Down Expand Up @@ -88,7 +90,8 @@ public async Task EditUserNoteAsync(InteractionContext ctx,
[Option("show_on_modmail", "Whether to show the note when the user opens a modmail thread.")] bool? showOnModmail = null,
[Option("show_on_warn", "Whether to show the note when the user is warned.")] bool? showOnWarn = null,
[Option("show_all_mods", "Whether to show this note to all mods, versus just yourself.")] bool? showAllMods = null,
[Option("show_once", "Whether to show this note once and then discard it.")] bool? showOnce = null)
[Option("show_once", "Whether to show this note once and then discard it.")] bool? showOnce = null,
[Option("show_on_join_and_leave", "Whether to show this note when the user joins & leaves. Works like joinwatch. Default: false")] bool? showOnJoinAndLeave = false)
{
// Get note
UserNote note;
Expand All @@ -107,7 +110,7 @@ public async Task EditUserNoteAsync(InteractionContext ctx,
newNoteText = note.NoteText;

// If no changes are made, refuse the request
if (note.NoteText == newNoteText && showOnModmail is null && showOnWarn is null && showAllMods is null && showOnce is null)
if (note.NoteText == newNoteText && showOnModmail is null && showOnWarn is null && showAllMods is null && showOnce is null && showOnJoinAndLeave is null)
{
await ctx.CreateResponseAsync(new DiscordInteractionResponseBuilder().WithContent($"{Program.cfgjson.Emoji.Error} You didn't change anything about the note!").AsEphemeral());
return;
Expand All @@ -129,6 +132,8 @@ public async Task EditUserNoteAsync(InteractionContext ctx,
showAllMods = note.ShowAllMods;
if (showOnce is null)
showOnce = note.ShowOnce;
if (showOnJoinAndLeave is null)
showOnJoinAndLeave = note.ShowOnJoinAndLeave;

// Assemble new note
note.ModUserId = ctx.User.Id;
Expand All @@ -137,6 +142,7 @@ public async Task EditUserNoteAsync(InteractionContext ctx,
note.ShowOnWarn = (bool)showOnWarn;
note.ShowAllMods = (bool)showAllMods;
note.ShowOnce = (bool)showOnce;
note.ShowOnJoinAndLeave = (bool)showOnJoinAndLeave;
note.Type = WarningType.Note;

await Program.db.HashSetAsync(user.Id.ToString(), note.NoteId, JsonConvert.SerializeObject(note));
Expand Down
37 changes: 1 addition & 36 deletions Commands/Lists.cs
Original file line number Diff line number Diff line change
Expand Up @@ -173,42 +173,7 @@ public async Task JoinWatch(
[Description("An optional note for context."), RemainingText] string note = ""
)
{
var joinWatchlist = await Program.db.ListRangeAsync("joinWatchedUsers");

if (joinWatchlist.Contains(user.Id))
{
if (note != "")
{
// User is already joinwatched, just update note

// Get current note; if it's the same, do nothing
var currentNote = await Program.db.HashGetAsync("joinWatchedUsersNotes", user.Id);
if (currentNote == note || (string.IsNullOrWhiteSpace(currentNote) && string.IsNullOrWhiteSpace(note)))
{
await ctx.RespondAsync($"{Program.cfgjson.Emoji.Error} {user.Mention} is already being watched with the same note! Nothing to do.");
return;
}

// If note is different, update it
await Program.db.HashSetAsync("joinWatchedUsersNotes", user.Id, note);
await ctx.RespondAsync($"{Program.cfgjson.Emoji.Success} Successfully updated the note for {user.Mention} (run again with no note to unwatch):\n> {note}");
return;
}

// User is already joinwatched, unwatch
Program.db.ListRemove("joinWatchedUsers", joinWatchlist.First(x => x == user.Id));
await Program.db.HashDeleteAsync("joinWatchedUsersNotes", user.Id);
await ctx.RespondAsync($"{Program.cfgjson.Emoji.Success} Successfully unwatched {user.Mention}, since they were already in the list.");
}
else
{
// User is not joinwatched, watch
await Program.db.ListRightPushAsync("joinWatchedUsers", user.Id);
if (note != "")
await Program.db.HashSetAsync("joinWatchedUsersNotes", user.Id, note);
await ctx.RespondAsync($"{Program.cfgjson.Emoji.Success} Now watching for joins/leaves of {user.Mention} to send to the investigations channel"
+ (note == "" ? "!" : $" with the following note:\n>>> {note}"));
}
await ctx.RespondAsync($"{Program.cfgjson.Emoji.Error} This command is deprecated and no longer works; all joinwatches have been converted to notes. To add a note for this user, please use `/note add user:{user.Id} note:{(string.IsNullOrEmpty(note) ? "<context>" : note)} show_on_join_and_leave:True`; to remove one, use `/note delete user:{user.Id} note:<note>`.");
}

[Command("appealblock")]
Expand Down
49 changes: 27 additions & 22 deletions Events/MemberEvents.cs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ public static async Task GuildMemberAdded(DiscordClient client, GuildMemberAdded
if (e.Guild.Id != cfgjson.ServerID)
return;

var embed = new DiscordEmbedBuilder()
var userLogEmbed = new DiscordEmbedBuilder()
.WithColor(new DiscordColor(0x3E9D28))
.WithTimestamp(DateTimeOffset.Now)
.WithThumbnail(e.Member.AvatarUrl)
Expand All @@ -24,18 +24,20 @@ public static async Task GuildMemberAdded(DiscordClient client, GuildMemberAdded
.AddField("Action", "Joined the server", false)
.WithFooter($"{client.CurrentUser.Username}JoinEvent");

LogChannelHelper.LogMessageAsync("users", $"{cfgjson.Emoji.UserJoin} **Member joined the server!** - {e.Member.Id}", embed);
LogChannelHelper.LogMessageAsync("users", $"{cfgjson.Emoji.UserJoin} **Member joined the server!** - {e.Member.Id}", userLogEmbed);

var joinWatchlist = await db.ListRangeAsync("joinWatchedUsers");
// Get this user's notes that are set to show on join/leave
var userNotes = db.HashGetAll(e.Member.Id.ToString())
.Where(x => JsonConvert.DeserializeObject<UserNote>(x.Value).Type == WarningType.Note
&& JsonConvert.DeserializeObject<UserNote>(x.Value).ShowOnJoinAndLeave).ToDictionary(
x => x.Name.ToString(),
x => JsonConvert.DeserializeObject<UserNote>(x.Value)
);

if (joinWatchlist.Contains(e.Member.Id))
if (userNotes.Count > 0)
{
if (await db.HashExistsAsync("joinWatchedUsersNotes", e.Member.Id))
{
embed.AddField($"Joinwatch Note", await db.HashGetAsync("joinWatchedUsersNotes", e.Member.Id));
}

LogChannelHelper.LogMessageAsync("investigations", $"{cfgjson.Emoji.Warning} Watched user {e.Member.Mention} just joined the server!", embed);
var notesEmbed = await UserNoteHelpers.GenerateUserNotesEmbedAsync(e.Member, false, userNotes);
LogChannelHelper.LogMessageAsync("investigations", $"{cfgjson.Emoji.Warning} {e.Member.Mention} just joined the server with notes set to show on join!", notesEmbed);
}

if (db.HashExists("raidmode", e.Guild.Id))
Expand Down Expand Up @@ -155,7 +157,7 @@ public static async Task GuildMemberRemoved(DiscordClient client, GuildMemberRem
}
}

var embed = new DiscordEmbedBuilder()
var userLogEmbed = new DiscordEmbedBuilder()
.WithColor(new DiscordColor(0xBA4119))
.WithTimestamp(DateTimeOffset.Now)
.WithThumbnail(e.Member.AvatarUrl)
Expand All @@ -169,18 +171,21 @@ public static async Task GuildMemberRemoved(DiscordClient client, GuildMemberRem
.AddField("Roles", rolesStr)
.WithFooter($"{client.CurrentUser.Username}LeaveEvent");

LogChannelHelper.LogMessageAsync("users", $"{cfgjson.Emoji.UserLeave} **Member left the server!** - {e.Member.Id}", embed);

var joinWatchlist = await db.ListRangeAsync("joinWatchedUsers");

if (joinWatchlist.Contains(e.Member.Id))
LogChannelHelper.LogMessageAsync("users", $"{cfgjson.Emoji.UserLeave} **Member left the server!** - {e.Member.Id}", userLogEmbed);

// Get this user's notes that are set to show on join/leave
var userNotes = db.HashGetAll(e.Member.Id.ToString())
.Where(x => JsonConvert.DeserializeObject<UserNote>(x.Value).Type == WarningType.Note
&& JsonConvert.DeserializeObject<UserNote>(x.Value).ShowOnJoinAndLeave).ToDictionary(
x => x.Name.ToString(),
x => JsonConvert.DeserializeObject<UserNote>(x.Value)
);

DiscordEmbed notesEmbed;
if (userNotes.Count > 0)
{
if (await db.HashExistsAsync("joinWatchedUsersNotes", e.Member.Id))
{
embed.AddField($"Joinwatch Note", await db.HashGetAsync("joinWatchedUsersNotes", e.Member.Id));
}

LogChannelHelper.LogMessageAsync("investigations", $"{cfgjson.Emoji.Warning} Watched user {e.Member.Mention} just left the server!", embed);
notesEmbed = await UserNoteHelpers.GenerateUserNotesEmbedAsync(e.Member, false, userNotes);
LogChannelHelper.LogMessageAsync("investigations", $"{cfgjson.Emoji.Warning} {e.Member.Mention} just left the server with notes set to show on leave!", notesEmbed);
}
}

Expand Down
9 changes: 9 additions & 0 deletions Events/ReadyEvent.cs
Original file line number Diff line number Diff line change
Expand Up @@ -168,6 +168,15 @@ public static async Task OnStartup(DiscordClient client)
discord.Logger.LogError("Heartbeat ping sent: {status} {content}", (int)response.StatusCode, await response.Content.ReadAsStringAsync());
}
}

try
{
await Migrations.JoinwatchMigration.MigrateJoinwatchesToNotesAsync();
}
catch (Exception ex)
{
client.Logger.LogError(ex, "Failed to migrate joinwatches to notes!");
}

client.Logger.LogInformation(CliptokEventID, "Startup event complete, logged in as {user}", $"{DiscordHelpers.UniqueUsername(client.CurrentUser)}");
}
Expand Down
1 change: 1 addition & 0 deletions Helpers/UserNoteHelpers.cs
Original file line number Diff line number Diff line change
Expand Up @@ -120,6 +120,7 @@ await LykosAvatarMethods.UserOrMemberAvatarURL(user, Program.homeGuild, "png")
.AddField("Show on Warn", note.ShowOnWarn ? "Yes" : "No", true)
.AddField("Show all Mods", note.ShowAllMods ? "Yes" : "No", true)
.AddField("Show Once", note.ShowOnce ? "Yes" : "No", true)
.AddField("Show on Join & Leave", note.ShowOnJoinAndLeave ? "Yes" : "No", true)
.AddField("Responsible moderator", $"<@{note.ModUserId}>", true)
.AddField("Time", $"<t:{TimeHelpers.ToUnixTimestamp(note.Timestamp)}:f>", true);

Expand Down
Loading
Loading