Skip to content

Commit 2598bb5

Browse files
Add #insiders-info interactions
1 parent 3c75a57 commit 2598bb5

File tree

4 files changed

+185
-0
lines changed

4 files changed

+185
-0
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
namespace Cliptok.Commands.InteractionCommands
2+
{
3+
public class InsidersInteractions : ApplicationCommandModule
4+
{
5+
[SlashCommand("send-insiders-info-buttons", "Sends a message with buttons to get Insider roles for #insiders-info.")]
6+
public static async Task SendInsidersInfoButtonMessage(InteractionContext ctx)
7+
{
8+
if (Program.cfgjson.InsiderInfoChannel != 0 && ctx.Channel.Id != Program.cfgjson.InsiderInfoChannel)
9+
{
10+
await ctx.RespondAsync($"{Program.cfgjson.Emoji.Error} This command only works in <#{Program.cfgjson.InsiderInfoChannel}>!", ephemeral: true);
11+
return;
12+
}
13+
14+
DiscordComponent[] buttons =
15+
[
16+
new DiscordButtonComponent(DiscordButtonStyle.Primary, "insiders-info-roles-menu-callback", "Choose your Insider roles"),
17+
new DiscordButtonComponent(DiscordButtonStyle.Secondary, "insiders-info-chat-btn-callback", "I just want to chat for now")
18+
];
19+
20+
var builder = new DiscordInteractionResponseBuilder()
21+
.WithContent($"{Program.cfgjson.Emoji.Insider} Choose your Insider roles here! Or, you can choose to chat in <#{Program.cfgjson.InsidersChannel}> without being notified about new builds.")
22+
.AddComponents(buttons);
23+
24+
await ctx.CreateResponseAsync(builder);
25+
}
26+
}
27+
}

Events/InteractionEvents.cs

+146
Original file line numberDiff line numberDiff line change
@@ -200,6 +200,152 @@ await LogChannelHelper.LogDeletedMessagesAsync(
200200
// Respond
201201
await e.Message.ModifyAsync(new DiscordMessageBuilder().WithContent($"{cfgjson.Emoji.Success} Override successfully added. <@{newOverwrite.Id}> already had an override in <#{pendingOverride.ChannelId}>, so here are their new permissions:\n**Allowed:** {newOverwrite.Allowed}\n**Denied:** {newOverwrite.Denied}"));
202202
}
203+
else if (e.Id == "insiders-info-roles-menu-callback")
204+
{
205+
// Shows a menu in #insider-info that allows a user to toggle their Insider roles
206+
207+
// Defer interaction
208+
await e.Interaction.DeferAsync(ephemeral: true);
209+
210+
// Fetch member
211+
var member = await e.Guild.GetMemberAsync(e.User.Id);
212+
213+
// Fetch Insider roles to check whether member already has them
214+
var insiderCanaryRole = await e.Guild.GetRoleAsync(cfgjson.UserRoles.InsiderCanary);
215+
var insiderDevRole = await e.Guild.GetRoleAsync(cfgjson.UserRoles.InsiderDev);
216+
var insiderBetaRole = await e.Guild.GetRoleAsync(cfgjson.UserRoles.InsiderBeta);
217+
var insiderRPRole = await e.Guild.GetRoleAsync(cfgjson.UserRoles.InsiderRP);
218+
var insider10RPRole = await e.Guild.GetRoleAsync(cfgjson.UserRoles.Insider10RP);
219+
var patchTuesdayRole = await e.Guild.GetRoleAsync(cfgjson.UserRoles.PatchTuesday);
220+
221+
// Show menu with current Insider roles, apply new roles based on user selection
222+
var menu = new DiscordSelectComponent("insiders-info-roles-menu-response-callback", "Choose your Insider roles",
223+
new List<DiscordSelectComponentOption>()
224+
{
225+
new("Windows 11 Canary channel", "insiders-info-w11-canary", isDefault: member.Roles.Contains(insiderCanaryRole)),
226+
new("Windows 11 Dev channel", "insiders-info-w11-dev", isDefault: member.Roles.Contains(insiderDevRole)),
227+
new("Windows 11 Beta channel", "insiders-info-w11-beta", isDefault: member.Roles.Contains(insiderBetaRole)),
228+
new("Windows 11 Release Preview channel", "insiders-info-w11-rp", isDefault: member.Roles.Contains(insiderRPRole)),
229+
new("Windows 10 Release Preview channel", "insiders-info-w10-rp", isDefault: member.Roles.Contains(insider10RPRole)),
230+
new("Patch Tuesday", "insiders-info-pt", isDefault: member.Roles.Contains(patchTuesdayRole)),
231+
}, minOptions: 0, maxOptions: 6);
232+
233+
var builder = new DiscordFollowupMessageBuilder()
234+
.WithContent($"{cfgjson.Emoji.Insider} Use the menu below to toggle your Insider roles!")
235+
.AddComponents(menu)
236+
.AsEphemeral(true);
237+
238+
await e.Interaction.CreateFollowupMessageAsync(builder);
239+
}
240+
else if (e.Id == "insiders-info-roles-menu-response-callback")
241+
{
242+
// User has selected new Insider roles w/ menu above
243+
// Compare selection against current roles; add or remove roles as necessary to match selection
244+
245+
// Defer
246+
await e.Interaction.DeferAsync(ephemeral: true);
247+
248+
// Get member
249+
var member = await e.Guild.GetMemberAsync(e.User.Id);
250+
251+
// Map role select options to role IDs
252+
var insiderRoles = new Dictionary<string, ulong>
253+
{
254+
{ "insiders-info-w11-canary", cfgjson.UserRoles.InsiderCanary },
255+
{ "insiders-info-w11-dev", cfgjson.UserRoles.InsiderDev },
256+
{ "insiders-info-w11-beta", cfgjson.UserRoles.InsiderBeta },
257+
{ "insiders-info-w11-rp", cfgjson.UserRoles.InsiderRP },
258+
{ "insiders-info-w10-rp", cfgjson.UserRoles.Insider10RP },
259+
{ "insiders-info-pt", cfgjson.UserRoles.PatchTuesday }
260+
};
261+
262+
// Get a list of the member's current roles that we can add to or remove from
263+
// Then we can apply this in a single request with member.ReplaceRolesAsync to avoid making repeated member update requests
264+
List<DiscordRole> memberRoles = member.Roles.ToList();
265+
266+
var selection = e.Values.Select(x => insiderRoles[x]).ToList();
267+
268+
foreach (var roleId in insiderRoles.Values)
269+
{
270+
var role = await e.Guild.GetRoleAsync(roleId);
271+
272+
if (selection.Contains(roleId))
273+
{
274+
// Member should have the role
275+
if (!memberRoles.Contains(role))
276+
memberRoles.Add(role);
277+
}
278+
else
279+
{
280+
// Member should not have the role
281+
if (memberRoles.Contains(role))
282+
memberRoles.Remove(role);
283+
}
284+
}
285+
286+
await member.ReplaceRolesAsync(memberRoles, "Applying Insider roles chosen in #insiders-info");
287+
288+
await e.Interaction.CreateFollowupMessageAsync(new DiscordFollowupMessageBuilder().WithContent($"{cfgjson.Emoji.Success} Your Insider roles have been updated!").AsEphemeral(true));
289+
}
290+
else if (e.Id == "insiders-info-chat-btn-callback")
291+
{
292+
// Button in #insiders-info that checks whether user has 'insiderChat' role and asks them to confirm granting/revoking it
293+
294+
// Defer
295+
await e.Interaction.DeferAsync(ephemeral: true);
296+
297+
// Get member
298+
var member = await e.Guild.GetMemberAsync(e.User.Id);
299+
300+
var insiderChatRole = await e.Guild.GetRoleAsync(cfgjson.UserRoles.InsiderChat);
301+
if (member.Roles.Contains(insiderChatRole))
302+
{
303+
// Member already has the role
304+
// Ask them if they'd like to remove it
305+
var confirmResponse = new DiscordFollowupMessageBuilder()
306+
.WithContent($"{cfgjson.Emoji.Warning} You already have the {insiderChatRole.Mention} role! Would you like to remove it?")
307+
.AddComponents(new DiscordButtonComponent(DiscordButtonStyle.Danger, "insiders-info-chat-btn-remove-confirm-callback", "Remove"));
308+
309+
await e.Interaction.CreateFollowupMessageAsync(confirmResponse);
310+
}
311+
else
312+
{
313+
// Member does not have the role; show a confirmation message with a button that will give it to them
314+
await e.Interaction.CreateFollowupMessageAsync(new DiscordFollowupMessageBuilder()
315+
.WithContent($"{cfgjson.Emoji.Warning} Please note that <#{cfgjson.InsidersChannel}> is **not for tech support**! If you need tech support, please ask in the appropriate channels instead. Press the button to acknowledge this and get the {insiderChatRole.Mention} role.")
316+
.AddComponents(new DiscordButtonComponent(DiscordButtonStyle.Secondary, "insiders-info-chat-btn-confirm-callback", "I understand")));
317+
}
318+
}
319+
else if (e.Id == "insiders-info-chat-btn-confirm-callback")
320+
{
321+
// Confirmation for granting insiderChat role, see above
322+
323+
// Defer
324+
await e.Interaction.CreateResponseAsync(DiscordInteractionResponseType.DeferredMessageUpdate);
325+
326+
// Give member insider chat role
327+
var member = await e.Guild.GetMemberAsync(e.User.Id);
328+
var insiderChatRole = await e.Guild.GetRoleAsync(cfgjson.UserRoles.InsiderChat);
329+
await member.GrantRoleAsync(insiderChatRole);
330+
331+
// Respond
332+
await e.Interaction.EditFollowupMessageAsync(e.Message.Id, new DiscordWebhookBuilder().WithContent($"{cfgjson.Emoji.Success} You have been given the {insiderChatRole.Mention} role!"));
333+
}
334+
else if (e.Id == "insiders-info-chat-btn-remove-confirm-callback")
335+
{
336+
// Confirmation for revoking insiderChat role, see above
337+
338+
// Defer
339+
await e.Interaction.CreateResponseAsync(DiscordInteractionResponseType.DeferredMessageUpdate);
340+
341+
// Get member
342+
var member = await e.Guild.GetMemberAsync(e.User.Id);
343+
344+
var insiderChatRole = await e.Guild.GetRoleAsync(cfgjson.UserRoles.InsiderChat);
345+
await member.RevokeRoleAsync(insiderChatRole);
346+
347+
await e.Interaction.EditFollowupMessageAsync(e.Message.Id, new DiscordWebhookBuilder().WithContent($"{cfgjson.Emoji.Success} You have been removed from the {insiderChatRole.Mention} role!"));
348+
}
203349
else
204350
{
205351
await e.Interaction.CreateResponseAsync(DiscordInteractionResponseType.ChannelMessageWithSource, new DiscordInteractionResponseBuilder().WithContent("Unknown interaction. I don't know what you are asking me for.").AsEphemeral(true));

Structs.cs

+9
Original file line numberDiff line numberDiff line change
@@ -262,9 +262,15 @@ public class ConfigJson
262262

263263
[JsonProperty("forumIntroPosts")]
264264
public List<ulong> ForumIntroPosts { get; private set; } = new();
265+
266+
[JsonProperty("insiderInfoChannel")]
267+
public ulong InsiderInfoChannel { get; private set; }
265268

266269
[JsonProperty("insiderAnnouncementChannel")]
267270
public ulong InsiderAnnouncementChannel { get; private set; } = 0;
271+
272+
[JsonProperty("insidersChannel")]
273+
public ulong InsidersChannel { get; private set; }
268274

269275
[JsonProperty("insiderCommandLockedToChannel")]
270276
public ulong InsiderCommandLockedToChannel { get; private set; } = 0;
@@ -486,6 +492,9 @@ public class UserRoleConfig
486492

487493
[JsonProperty("insider10RP")]
488494
public ulong Insider10RP { get; private set; }
495+
496+
[JsonProperty("insiderChat")]
497+
public ulong InsiderChat { get; private set; }
489498

490499
[JsonProperty("patchTuesday")]
491500
public ulong PatchTuesday { get; private set; }

config.json

+3
Original file line numberDiff line numberDiff line change
@@ -228,6 +228,7 @@
228228
"insiderBeta": 643712828217360394,
229229
"insiderRP": 288729239921098752,
230230
"insider10RP": 910319453491839069,
231+
"insiderChat": 0,
231232
"patchTuesday": 445773142233710594,
232233
"giveaways": 1169336992455200820
233234
},
@@ -315,6 +316,8 @@
315316
1065659890036646019
316317
],
317318
"insiderAnnouncementChannel": 1043898319883219004,
319+
"insiderInfoChannel": 1279201622651572317,
320+
"insidersChannel": 187649467611086849,
318321
"insiderCommandLockedToChannel": 187649467611086849,
319322
"dmAutoresponseTimeLimit": 6,
320323
"autoDeleteEmptyThreads": true,

0 commit comments

Comments
 (0)