Skip to content

Commit 0e91739

Browse files
Add tqsunmute command
1 parent dbea72a commit 0e91739

File tree

2 files changed

+108
-17
lines changed

2 files changed

+108
-17
lines changed

Commands/MuteCmds.cs

+85-2
Original file line numberDiff line numberDiff line change
@@ -202,6 +202,91 @@ public async Task TqsMuteSlashCommand(
202202
if (ctx is SlashCommandContext)
203203
await ctx.EditResponseAsync(new DiscordWebhookBuilder().WithContent("Done. Please open a modmail thread for this user if you haven't already!"));
204204
}
205+
206+
[Command("tqsunmute")]
207+
[TextAlias("tqs-unmute", "untqsmute")]
208+
[Description("Removes a TQS Mute from a previously TQS-muted user. See also: tqsmute")]
209+
[AllowedProcessors(typeof(TextCommandProcessor), typeof(SlashCommandProcessor))]
210+
[HomeServer, RequireHomeserverPerm(ServerPermLevel.TechnicalQueriesSlayer)]
211+
public async Task TqsUnmuteCmd(CommandContext ctx, [Parameter("user"), Description("The user you're trying to unmute.")] DiscordUser targetUser, [Description("The reason for the unmute.")] string reason)
212+
{
213+
if (ctx is SlashCommandContext)
214+
await ctx.As<SlashCommandContext>().DeferResponseAsync();
215+
216+
// only work if TQS mute role is configured
217+
if (Program.cfgjson.TqsMutedRole == 0)
218+
{
219+
if (ctx is SlashCommandContext)
220+
await ctx.EditResponseAsync(new DiscordWebhookBuilder().WithContent($"{Program.cfgjson.Emoji.Error} TQS mutes are not configured, so this command does nothing. Please contact the bot maintainer if this is unexpected."));
221+
else
222+
await ctx.RespondAsync($"{Program.cfgjson.Emoji.Error} TQS mutes are not configured, so this command does nothing. Please contact the bot maintainer if this is unexpected.");
223+
return;
224+
}
225+
226+
// Only allow usage in #tech-support, #tech-support-forum, and their threads
227+
if (ctx.Channel.Id != Program.cfgjson.TechSupportChannel &&
228+
ctx.Channel.Id != Program.cfgjson.SupportForumId &&
229+
ctx.Channel.Parent.Id != Program.cfgjson.TechSupportChannel &&
230+
ctx.Channel.Parent.Id != Program.cfgjson.SupportForumId)
231+
{
232+
if (ctx is SlashCommandContext)
233+
await ctx.EditResponseAsync(new DiscordWebhookBuilder().WithContent($"{Program.cfgjson.Emoji.Error} This command can only be used in <#{Program.cfgjson.TechSupportChannel}>, <#{Program.cfgjson.SupportForumId}>, and threads in those channels!"));
234+
else
235+
await ctx.RespondAsync($"{Program.cfgjson.Emoji.Error} This command can only be used in <#{Program.cfgjson.TechSupportChannel}>, <#{Program.cfgjson.SupportForumId}>, and threads in those channels!");
236+
return;
237+
}
238+
239+
// Get muted roles
240+
DiscordRole mutedRole = await ctx.Guild.GetRoleAsync(Program.cfgjson.MutedRole);
241+
DiscordRole tqsMutedRole = await ctx.Guild.GetRoleAsync(Program.cfgjson.TqsMutedRole);
242+
243+
// Get member
244+
DiscordMember targetMember = default;
245+
try
246+
{
247+
targetMember = await ctx.Guild.GetMemberAsync(targetUser.Id);
248+
}
249+
catch (DSharpPlus.Exceptions.NotFoundException)
250+
{
251+
// handled below
252+
}
253+
254+
if (await Program.db.HashExistsAsync("mutes", targetUser.Id) && targetMember is not null && targetMember.Roles.Contains(tqsMutedRole))
255+
{
256+
// If the member has a regular mute, leave the TQS mute alone (it's only a role now & it has no effect if they also have Muted); it will be removed when they are unmuted
257+
if (targetMember.Roles.Contains(mutedRole))
258+
{
259+
if (ctx is SlashCommandContext)
260+
await ctx.EditResponseAsync($"{Program.cfgjson.Emoji.Error} {targetUser.Mention} has been muted by a Moderator! Their TQS Mute will be removed when the Moderator-issued mute expires.");
261+
else
262+
await ctx.RespondAsync($"{Program.cfgjson.Emoji.Error} {targetUser.Mention} has been muted by a Moderator! Their TQS Mute will be removed when the Moderator-issued mute expires.");
263+
return;
264+
}
265+
266+
// user is TQS-muted; unmute
267+
await MuteHelpers.UnmuteUserAsync(targetUser, reason, true, ctx.User, true);
268+
if (ctx is SlashCommandContext)
269+
await ctx.EditResponseAsync($"{Program.cfgjson.Emoji.Success} Successfully unmuted {targetUser.Mention}!");
270+
else
271+
await ctx.RespondAsync($"{Program.cfgjson.Emoji.Success} Successfully unmuted {targetUser.Mention}!");
272+
}
273+
else if (targetMember is null)
274+
{
275+
// couldn't fetch member, fail
276+
if (ctx is SlashCommandContext)
277+
await ctx.EditResponseAsync($"{Program.cfgjson.Emoji.Error} That user doesn't appear to be in the server!");
278+
else
279+
await ctx.RespondAsync($"{Program.cfgjson.Emoji.Error} That user doesn't appear to be in the server!");
280+
}
281+
else
282+
{
283+
// member is not TQS-muted, fail
284+
if (ctx is SlashCommandContext)
285+
await ctx.EditResponseAsync($"{Program.cfgjson.Emoji.Error} That user doesn't appear to be TQS-muted!");
286+
else
287+
await ctx.RespondAsync($"{Program.cfgjson.Emoji.Error} That user doesn't appear to be TQS-muted!");
288+
}
289+
}
205290

206291
[Command("muteinfo")]
207292
[Description("Show information about the mute for a user.")]
@@ -223,8 +308,6 @@ public async Task MuteInfoSlashCommand(
223308
[HomeServer, RequireHomeserverPerm(ServerPermLevel.TrialModerator)]
224309
public async Task UnmuteCmd(TextCommandContext ctx, [Description("The user you're trying to unmute.")] DiscordUser targetUser, string reason = "No reason provided.")
225310
{
226-
reason = $"[Manual unmute by {DiscordHelpers.UniqueUsername(ctx.User)}]: {reason}";
227-
228311
// todo: store per-guild
229312
DiscordRole mutedRole = await ctx.Guild.GetRoleAsync(Program.cfgjson.MutedRole);
230313
DiscordRole tqsMutedRole = default;

Helpers/MuteHelpers.cs

+23-15
Original file line numberDiff line numberDiff line change
@@ -319,8 +319,12 @@ public static (int MuteHours, int WarnsSinceThreshold) GetHoursToMuteFor(Diction
319319
return output;
320320
}
321321

322-
public static async Task<bool> UnmuteUserAsync(DiscordUser targetUser, string reason = "", bool manual = true, DiscordUser modUser = default)
322+
public static async Task<bool> UnmuteUserAsync(DiscordUser targetUser, string reason = "", bool manual = true, DiscordUser modUser = default, bool isTqsUnmute = false)
323323
{
324+
var auditLogReason = reason;
325+
if (manual && modUser is not null)
326+
auditLogReason = $"[Manual {(isTqsUnmute ? "TQS " : "")}unmute by {DiscordHelpers.UniqueUsername(modUser)}]: {reason}";
327+
324328
var muteDetailsJson = await Program.db.HashGetAsync("mutes", targetUser.Id);
325329
bool success = false;
326330
bool wasTqsMute = false;
@@ -346,7 +350,7 @@ public static async Task<bool> UnmuteUserAsync(DiscordUser targetUser, string re
346350
{
347351
await LogChannelHelper.LogMessageAsync("mod",
348352
new DiscordMessageBuilder()
349-
.WithContent($"{Program.cfgjson.Emoji.Information} Attempt to remove Muted role from {targetUser.Mention} failed because the user could not be found.\nThis is expected if the user was banned or left.")
353+
.WithContent($"{Program.cfgjson.Emoji.Information} Attempt to remove {(isTqsUnmute ? "TQS " : "")}Muted role from {targetUser.Mention} failed because the user could not be found.\nThis is expected if the user was banned or left.")
350354
.WithAllowedMentions(Mentions.None)
351355
);
352356
}
@@ -361,29 +365,33 @@ await LogChannelHelper.LogMessageAsync("mod",
361365
// If both attempts fail, do standard failure error handling.
362366
try
363367
{
364-
await member.RevokeRoleAsync(role: mutedRole, reason);
368+
await member.RevokeRoleAsync(role: mutedRole, auditLogReason);
365369
}
366370
finally
367371
{
368372
// Check member roles for TQS mute role
369373
if (member.Roles.Contains(tqsMutedRole))
370374
{
371-
await member.RevokeRoleAsync(role: tqsMutedRole, reason);
375+
await member.RevokeRoleAsync(role: tqsMutedRole, auditLogReason);
372376
wasTqsMute = true; // only true if TQS mute role was found & removed
373377
}
374378
}
375379

376-
foreach (var role in member.Roles)
380+
// Skip if not TQS unmute...
381+
if (!isTqsUnmute)
377382
{
378-
if (role.Name == "Muted" && role.Id != Program.cfgjson.MutedRole)
383+
foreach (var role in member.Roles)
379384
{
380-
try
381-
{
382-
await member.RevokeRoleAsync(role: role, reason: reason);
383-
}
384-
catch
385+
if (role.Name == "Muted" && role.Id != Program.cfgjson.MutedRole)
385386
{
386-
// ignore, continue to next role
387+
try
388+
{
389+
await member.RevokeRoleAsync(role: role, reason: auditLogReason);
390+
}
391+
catch
392+
{
393+
// ignore, continue to next role
394+
}
387395
}
388396
}
389397
}
@@ -393,7 +401,7 @@ await LogChannelHelper.LogMessageAsync("mod",
393401
{
394402
await LogChannelHelper.LogMessageAsync("mod",
395403
new DiscordMessageBuilder()
396-
.WithContent($"{Program.cfgjson.Emoji.Error} Attempt to removed Muted role from {targetUser.Mention} failed because of a Discord API error!" +
404+
.WithContent($"{Program.cfgjson.Emoji.Error} Attempt to remove {(isTqsUnmute ? "TQS " : "")}Muted role from {targetUser.Mention} failed because of a Discord API error!" +
397405
$"\nIf the role was removed manually, this error can be disregarded safely.")
398406
.WithAllowedMentions(Mentions.None)
399407
);
@@ -404,7 +412,7 @@ await LogChannelHelper.LogMessageAsync("mod",
404412
// TQS mutes are not server-wide so this would fail every time for TQS mutes,
405413
// and we don't want to log a failure for every removed TQS mute
406414
if (!wasTqsMute)
407-
await member.TimeoutAsync(until: null, reason: reason);
415+
await member.TimeoutAsync(until: null, reason: auditLogReason);
408416
}
409417
catch (Exception ex)
410418
{
@@ -414,7 +422,7 @@ await LogChannelHelper.LogMessageAsync("mod",
414422
if (success)
415423
{
416424
string unmuteMsg = manual
417-
? $"{Program.cfgjson.Emoji.Information} {targetUser.Mention} was successfully unmuted by {modUser.Mention}!"
425+
? $"{Program.cfgjson.Emoji.Information} {targetUser.Mention} was successfully {(isTqsUnmute ? "TQS-" : "")}unmuted by {modUser.Mention}!\nReason: **{reason}**"
418426
: $"{Program.cfgjson.Emoji.Information} Successfully unmuted {targetUser.Mention}!";
419427

420428
await LogChannelHelper.LogMessageAsync("mod", new DiscordMessageBuilder().WithContent(unmuteMsg).WithAllowedMentions(Mentions.None));

0 commit comments

Comments
 (0)