Skip to content

Commit bf979d2

Browse files
Rewrite lockdown
1 parent fd2f473 commit bf979d2

File tree

1 file changed

+130
-111
lines changed

1 file changed

+130
-111
lines changed

Commands/LockdownCommands.cs

Lines changed: 130 additions & 111 deletions
Original file line numberDiff line numberDiff line change
@@ -12,66 +12,63 @@ public static async Task Lock(SlashCommandContext ctx)
1212
{
1313
await ctx.DeferResponseAsync(true);
1414

15-
var existingOverwrites = ctx.Channel.PermissionOverwrites.ToArray();
16-
var invokerExistingAllowedOverwrites = existingOverwrites.FirstOrDefault(o => o.Id == ctx.Member.Id);
17-
var botAllowedOverwrites = existingOverwrites.FirstOrDefault(o => o.Id == Program.Discord.CurrentUser.Id);
18-
19-
try
20-
{
21-
// Add initial overwrites for failsafes (bot & user who called /lockdown), deny everyone else Send Messages
22-
if (invokerExistingAllowedOverwrites is null)
23-
{
24-
await ctx.Channel.AddOverwriteAsync(ctx.Member, DiscordPermission.SendMessages, DiscordPermissions.None,
25-
"Failsafe for lockdown");
26-
}
27-
else
28-
{
29-
await ctx.Channel.AddOverwriteAsync(ctx.Member,
30-
invokerExistingAllowedOverwrites.Allowed | DiscordPermission.SendMessages,
31-
invokerExistingAllowedOverwrites.Denied, "Failsafe for lockdown");
32-
}
33-
34-
if (botAllowedOverwrites is null)
35-
{
36-
await ctx.Channel.AddOverwriteAsync(await ctx.Guild.GetMemberAsync(ctx.Client.CurrentUser.Id),
37-
DiscordPermission.SendMessages, DiscordPermissions.None, "Failsafe for lockdown");
38-
}
39-
else
40-
{
41-
await ctx.Channel.AddOverwriteAsync(await ctx.Guild.GetMemberAsync(ctx.Client.CurrentUser.Id),
42-
botAllowedOverwrites.Allowed | DiscordPermission.SendMessages, botAllowedOverwrites.Denied,
43-
"Failsafe for lockdown");
44-
}
45-
46-
await ctx.Channel.AddOverwriteAsync(ctx.Guild.EveryoneRole, DiscordPermissions.None, DiscordPermission.SendMessages,
47-
"Lockdown");
48-
49-
// Restore overwrites that may have been present before the lockdown
50-
51-
foreach (var overwrite in existingOverwrites)
52-
if (overwrite.Type == DiscordOverwriteType.Role)
53-
{
54-
if (await overwrite.GetRoleAsync() == ctx.Guild.EveryoneRole)
55-
await ctx.Channel.AddOverwriteAsync(await overwrite.GetRoleAsync(), overwrite.Allowed,
56-
DiscordPermission.SendMessages | overwrite.Denied,
57-
"Restoring previous overrides for lockdown");
58-
else
59-
await ctx.Channel.AddOverwriteAsync(await overwrite.GetRoleAsync(), overwrite.Allowed,
60-
overwrite.Denied, "Restoring previous overrides for lockdown");
61-
}
62-
else if (overwrite.Id != ctx.Member.Id && overwrite.Id != Program.Discord.CurrentUser.Id)
63-
{
64-
await ctx.Channel.AddOverwriteAsync(await overwrite.GetMemberAsync(), overwrite.Allowed,
65-
overwrite.Denied, "Restoring previous overrides for lockdown");
66-
}
67-
}
68-
catch (UnauthorizedException)
69-
{
70-
await ctx.FollowupAsync(new DiscordFollowupMessageBuilder().WithContent(
71-
"I don't have permission to lock this channel! Make sure I have the \"Manage Roles\" server permission, or the \"Manage Permissions\" permission on each channel you want me to be able to lock or unlock."));
72-
return;
73-
}
15+
// Get the permissions that are already on the channel, so that we can make sure they are kept when we adjust overwrites for lockdown
16+
DiscordOverwrite[] existingOverwrites = ctx.Channel.PermissionOverwrites.ToArray();
17+
18+
// Get the bot's permission set from before the lockdown
19+
var botOverwritesBeforeLockdown = existingOverwrites.Where(x => x.Id == Program.Discord.CurrentUser.Id).FirstOrDefault();
7420

21+
// Get the bot's allowed permission set
22+
var botAllowedPermissionsBeforeLockdown = DiscordPermissions.None;
23+
if (botOverwritesBeforeLockdown is not null)
24+
botAllowedPermissionsBeforeLockdown = botOverwritesBeforeLockdown.Allowed;
25+
26+
// Get the bot's denied permission set
27+
var botDeniedPermissionsBeforeLockdown = DiscordPermissions.None;
28+
if (botOverwritesBeforeLockdown is not null)
29+
botDeniedPermissionsBeforeLockdown = botOverwritesBeforeLockdown.Denied;
30+
31+
// Get the invoker's permission set from before the lockdown
32+
var invokerOverwritesBeforeLockdown = existingOverwrites.Where(x => x.Id == ctx.User.Id).FirstOrDefault();
33+
34+
// Get the invoker's allowed permission set
35+
var invokerAllowedPermissionsBeforeLockdown = DiscordPermissions.None;
36+
if (invokerOverwritesBeforeLockdown is not null)
37+
invokerAllowedPermissionsBeforeLockdown = invokerOverwritesBeforeLockdown.Allowed;
38+
39+
// Get the invoker's denied permission set
40+
var invokerDeniedPermissionsBeforeLockdown = DiscordPermissions.None;
41+
if (invokerOverwritesBeforeLockdown is not null)
42+
invokerDeniedPermissionsBeforeLockdown = invokerOverwritesBeforeLockdown.Denied;
43+
44+
// Construct failsafe permission sets
45+
// Grant Send Messages to the bot and to the invoker in addition to any permissions they might already have,
46+
var botAllowedPermissions = botAllowedPermissionsBeforeLockdown.Add(DiscordPermission.SendMessages);
47+
var invokerAllowedPermissions = invokerAllowedPermissionsBeforeLockdown.Add(DiscordPermission.SendMessages);
48+
49+
// Apply failsafes for lockdown
50+
await ctx.Channel.AddOverwriteAsync(ctx.Channel.Guild.CurrentMember, botAllowedPermissions, botDeniedPermissionsBeforeLockdown, "Failsafe 1 for Lockdown");
51+
await ctx.Channel.AddOverwriteAsync(ctx.Member, invokerAllowedPermissions, invokerDeniedPermissionsBeforeLockdown, "Failsafe 2 for Lockdown");
52+
53+
// Get the @everyone role's permission set from before the lockdown
54+
var everyoneOverwritesBeforeLockdown = existingOverwrites.Where(x => x.Id == ctx.Channel.Guild.EveryoneRole.Id).FirstOrDefault();
55+
56+
// Get the @everyone role's allowed permission set
57+
var everyoneAllowedPermissionsBeforeLockdown = DiscordPermissions.None;
58+
if (everyoneOverwritesBeforeLockdown is not null)
59+
everyoneAllowedPermissionsBeforeLockdown = everyoneOverwritesBeforeLockdown.Allowed;
60+
61+
// Get the @everyone role's denied permission set
62+
var everyoneDeniedPermissionsBeforeLockdown = DiscordPermissions.None;
63+
if (everyoneOverwritesBeforeLockdown is not null)
64+
everyoneDeniedPermissionsBeforeLockdown = everyoneOverwritesBeforeLockdown.Denied;
65+
66+
// Construct new @everyone permission set
67+
var everyoneDeniedPermissions = everyoneDeniedPermissionsBeforeLockdown.Add(DiscordPermission.SendMessages);
68+
69+
// Lock the channel
70+
await ctx.Channel.AddOverwriteAsync(ctx.Channel.Guild.EveryoneRole, everyoneAllowedPermissionsBeforeLockdown, everyoneDeniedPermissions, $"Lockdown by {ctx.User.Username}");
71+
7572
await ctx.Channel.SendMessageAsync("This channel has been locked.");
7673

7774
await ctx.FollowupAsync(new DiscordFollowupMessageBuilder().WithContent("Channel locked successfully.")
@@ -84,61 +81,83 @@ public static async Task Unlock(SlashCommandContext ctx)
8481
{
8582
await ctx.DeferResponseAsync(true);
8683

87-
try
88-
{
89-
// Checking <2 because there will always be 1 overwrite for @everyone permissions
90-
if (ctx.Channel.PermissionOverwrites.ToArray().Length < 2
91-
|| ctx.Channel.PermissionOverwrites.Any(o => o.Id == ctx.Guild.EveryoneRole.Id &&
92-
!o.Denied.HasPermission(DiscordPermission.SendMessages)))
93-
{
94-
await ctx.FollowupAsync(new DiscordFollowupMessageBuilder()
95-
.WithContent("This channel is not locked!").AsEphemeral());
96-
return;
97-
}
98-
99-
foreach (var permission in ctx.Channel.PermissionOverwrites.ToArray())
100-
if (permission.Type == DiscordOverwriteType.Role)
101-
{
102-
// Don't touch roles that aren't @everyone
103-
if (await permission.GetRoleAsync() != ctx.Guild.EveryoneRole) continue;
104-
105-
// Construct new @everyone overwrite; keep it the same but remove denial for Send Messages
106-
DiscordOverwriteBuilder newOverwrite = new(ctx.Guild.EveryoneRole)
107-
{
108-
Allowed = permission.Allowed,
109-
Denied = (DiscordPermissions)(permission.Denied - DiscordPermission.SendMessages)
110-
};
111-
112-
await ctx.Channel.AddOverwriteAsync(ctx.Guild.EveryoneRole, newOverwrite.Allowed,
113-
newOverwrite.Denied, "Lockdown cleared");
114-
}
115-
else
116-
{
117-
// Filter to user overrides that have Send Messages allowed (failsafes) so we can remove
118-
if (!permission.Allowed.HasPermission(DiscordPermission.SendMessages)) continue;
119-
120-
// Remove failsafe Send Message overrides
121-
DiscordOverwriteBuilder newOverwrite = new(await permission.GetMemberAsync())
122-
{
123-
Allowed = (DiscordPermissions)(permission.Allowed - DiscordPermission.SendMessages),
124-
Denied = permission.Denied
125-
};
126-
127-
// Check new permission set; if it's totally empty, just drop the override
128-
if (newOverwrite.Allowed == DiscordPermissions.None && newOverwrite.Denied == DiscordPermissions.None)
129-
await ctx.Channel.DeleteOverwriteAsync(await permission.GetMemberAsync(), "Lockdown cleared");
130-
else
131-
await ctx.Channel.AddOverwriteAsync(await permission.GetMemberAsync(), newOverwrite.Allowed,
132-
newOverwrite.Denied, "Lockdown cleared");
133-
}
134-
}
135-
catch (UnauthorizedException)
84+
// Checking <2 because there will always be 1 overwrite for @everyone permissions
85+
if (ctx.Channel.PermissionOverwrites.ToArray().Length < 2
86+
|| ctx.Channel.PermissionOverwrites.Any(o => o.Id == ctx.Guild.EveryoneRole.Id &&
87+
!o.Denied.HasPermission(DiscordPermission.SendMessages)))
13688
{
137-
await ctx.FollowupAsync(new DiscordFollowupMessageBuilder().WithContent(
138-
"I don't have permission to unlock this channel! Make sure I have the \"Manage Roles\" server permission, or the \"Manage Permissions\" permission on each channel you want me to be able to lock or unlock."));
89+
await ctx.FollowupAsync(new DiscordFollowupMessageBuilder()
90+
.WithContent("This channel is not locked!").AsEphemeral());
13991
return;
14092
}
141-
93+
94+
// Get the permissions that are already on the channel, so that we can make sure they are kept when we adjust overwrites for the unlock
95+
var permissions = ctx.Channel.PermissionOverwrites.ToArray();
96+
97+
// Get bot's permission set from before the unlock
98+
var botOverwritesBeforeUnlock = permissions.Where(x => x.Id == Program.Discord.CurrentUser.Id).FirstOrDefault();
99+
100+
// Get bot's allowed permission set
101+
var botAllowedPermissionsBeforeUnlock = DiscordPermissions.None;
102+
if (botOverwritesBeforeUnlock is not null)
103+
botAllowedPermissionsBeforeUnlock = botOverwritesBeforeUnlock.Allowed;
104+
105+
// Get bot's denied permission set
106+
var botDeniedPermissionsBeforeUnlock = DiscordPermissions.None;
107+
if (botOverwritesBeforeUnlock is not null)
108+
botDeniedPermissionsBeforeUnlock = botOverwritesBeforeUnlock.Denied;
109+
110+
// Get the invoker role's permission set from before the unlock
111+
var invokerOverwritesBeforeUnlock = permissions.Where(x => x.Id == ctx.User.Id).FirstOrDefault();
112+
113+
// Get the invoker role's allowed permission set
114+
var invokerAllowedPermissionsBeforeUnlock = DiscordPermissions.None;
115+
if (invokerOverwritesBeforeUnlock is not null)
116+
invokerAllowedPermissionsBeforeUnlock = invokerOverwritesBeforeUnlock.Allowed;
117+
118+
// Get the invoker role's denied permission set
119+
var invokerDeniedPermissionsBeforeUnlock = DiscordPermissions.None;
120+
if (invokerOverwritesBeforeUnlock is not null)
121+
invokerDeniedPermissionsBeforeUnlock = invokerOverwritesBeforeUnlock.Denied;
122+
123+
// Construct new permission sets for bot and invoker
124+
// Resets Send Messages and Send Messages in Threads for bot and invoker, while preserving other permissions
125+
var botAllowedPermissions = botAllowedPermissionsBeforeUnlock.Remove(DiscordPermission.SendMessages).Remove(DiscordPermission.SendThreadMessages);
126+
var invokerAllowedPermissions = invokerAllowedPermissionsBeforeUnlock.Remove(DiscordPermission.SendMessages).Remove(DiscordPermission.SendThreadMessages);
127+
128+
// Get the @everyone role's permission set from before the unlock
129+
var everyoneOverwritesBeforeUnlock = permissions.Where(x => x.Id == ctx.Channel.Guild.EveryoneRole.Id).FirstOrDefault();
130+
131+
// Get the @everyone role's allowed permission set
132+
var everyoneAllowedPermissionsBeforeUnlock = DiscordPermissions.None;
133+
if (everyoneOverwritesBeforeUnlock is not null)
134+
everyoneAllowedPermissionsBeforeUnlock = everyoneOverwritesBeforeUnlock.Allowed;
135+
136+
// Get the @everyone role's denied permission set
137+
var everyoneDeniedPermissionsBeforeUnlock = DiscordPermissions.None;
138+
if (everyoneOverwritesBeforeUnlock is not null)
139+
everyoneDeniedPermissionsBeforeUnlock = everyoneOverwritesBeforeUnlock.Denied;
140+
141+
// Construct new permission set for @everyone
142+
// Resets Send Messages while preserving other permissions
143+
var everyoneDeniedPermissions = everyoneDeniedPermissionsBeforeUnlock.Remove(DiscordPermission.SendMessages);
144+
145+
// Unlock the channel
146+
await ctx.Channel.AddOverwriteAsync(ctx.Channel.Guild.EveryoneRole, everyoneAllowedPermissionsBeforeUnlock, everyoneDeniedPermissions, $"Unlock by {ctx.User.Username}");
147+
148+
// Remove failsafes
149+
// For any failsafes where the after-unlock permission set is completely empty, delete the override entirely
150+
151+
if (botAllowedPermissions == DiscordPermissions.None && botDeniedPermissionsBeforeUnlock == DiscordPermissions.None)
152+
await ctx.Channel.DeleteOverwriteAsync(ctx.Channel.Guild.CurrentMember, "Resetting Lockdown failsafe 1 for unlock");
153+
else
154+
await ctx.Channel.AddOverwriteAsync(ctx.Channel.Guild.CurrentMember, botAllowedPermissions, botDeniedPermissionsBeforeUnlock, "Resetting Lockdown failsafe 1 for unlock");
155+
156+
if (invokerAllowedPermissions == DiscordPermissions.None && invokerDeniedPermissionsBeforeUnlock == DiscordPermissions.None)
157+
await ctx.Channel.DeleteOverwriteAsync(ctx.Member, "Resetting Lockdown failsafe 2 for unlock");
158+
else
159+
await ctx.Channel.AddOverwriteAsync(ctx.Member, invokerAllowedPermissions, invokerDeniedPermissionsBeforeUnlock, "Resetting Lockdown failsafe 2 for unlock");
160+
142161
await ctx.Channel.SendMessageAsync("This channel has been unlocked.");
143162
await ctx.FollowupAsync(new DiscordFollowupMessageBuilder()
144163
.WithContent("Channel unlocked successfully.").AsEphemeral());

0 commit comments

Comments
 (0)