-
Notifications
You must be signed in to change notification settings - Fork 5
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
Invite management #297
Invite management #297
Changes from all commits
6a862f2
2907156
7fb60aa
3f40889
ffa505a
9efb406
239a6f7
33988c1
61069f5
ced8c34
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change | ||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
@@ -0,0 +1,144 @@ | ||||||||||||||
import { Robot } from "hubot" | ||||||||||||||
import { Client, TextChannel } from "discord.js" | ||||||||||||||
import { DAY, MILLISECOND, WEEK } from "../lib/globals.ts" | ||||||||||||||
|
||||||||||||||
const EXTERNAL_AUDIT_CHANNEL_REGEXP = /^ext-(?<client>.*)-audit$/ | ||||||||||||||
|
||||||||||||||
async function createInvite( | ||||||||||||||
channel: TextChannel, | ||||||||||||||
maxAge = (1 * WEEK) / MILLISECOND, | ||||||||||||||
maxUses = 10, | ||||||||||||||
): Promise<{ url: string; maxAge: number; maxUses: number }> { | ||||||||||||||
const invite = await channel.createInvite({ | ||||||||||||||
maxAge, | ||||||||||||||
maxUses, | ||||||||||||||
unique: true, | ||||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Interesting. Wonder what happens if this is off lol. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @Shadowfiend Looks like it defaults to 24 hours, infinite uses = 0 😁 There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Oh I just meant the |
||||||||||||||
}) | ||||||||||||||
|
||||||||||||||
return { | ||||||||||||||
url: invite.url, | ||||||||||||||
maxAge, | ||||||||||||||
maxUses, | ||||||||||||||
} | ||||||||||||||
} | ||||||||||||||
|
||||||||||||||
export default async function sendInvite(discordClient: Client, robot: Robot) { | ||||||||||||||
const { application } = discordClient | ||||||||||||||
|
||||||||||||||
if (application) { | ||||||||||||||
// Check if create-invite command already exists, if not create it | ||||||||||||||
const existingInviteCommand = (await application.commands.fetch()).find( | ||||||||||||||
(command) => command.name === "create-invite", | ||||||||||||||
) | ||||||||||||||
if (existingInviteCommand === undefined) { | ||||||||||||||
robot.logger.info("No create-invite command found, creating it!") | ||||||||||||||
await application.commands.set([ | ||||||||||||||
{ | ||||||||||||||
name: "create-invite", | ||||||||||||||
description: "Creates a new invite", | ||||||||||||||
}, | ||||||||||||||
]) | ||||||||||||||
robot.logger.info("create invite command set") | ||||||||||||||
} | ||||||||||||||
// Create an invite based of the command and channel where the command has been run | ||||||||||||||
discordClient.on("interactionCreate", async (interaction) => { | ||||||||||||||
if ( | ||||||||||||||
!interaction.isCommand() || | ||||||||||||||
interaction.commandName !== "create-invite" | ||||||||||||||
) { | ||||||||||||||
return | ||||||||||||||
Shadowfiend marked this conversation as resolved.
Show resolved
Hide resolved
|
||||||||||||||
} | ||||||||||||||
|
||||||||||||||
if (!interaction.guild) { | ||||||||||||||
await interaction.reply("This command can only be used in a server.") | ||||||||||||||
return | ||||||||||||||
} | ||||||||||||||
|
||||||||||||||
try { | ||||||||||||||
const { channel } = interaction | ||||||||||||||
if (channel instanceof TextChannel) { | ||||||||||||||
const invite = await createInvite(channel) | ||||||||||||||
if (invite) { | ||||||||||||||
await interaction.reply( | ||||||||||||||
`Here is your invite link: ${ | ||||||||||||||
invite.url | ||||||||||||||
}\nThis invite expires in ${ | ||||||||||||||
(invite.maxAge / DAY) * MILLISECOND | ||||||||||||||
} days and has a maximum of ${invite.maxUses} uses.`, | ||||||||||||||
) | ||||||||||||||
} | ||||||||||||||
} else { | ||||||||||||||
await interaction.reply( | ||||||||||||||
"Cannot create an invite for this type of channel.", | ||||||||||||||
) | ||||||||||||||
} | ||||||||||||||
} catch (error) { | ||||||||||||||
await interaction.reply("An error occurred while creating the invite.") | ||||||||||||||
} | ||||||||||||||
}) | ||||||||||||||
|
||||||||||||||
// Generates an invite if the channel name matches ext-*-audit format | ||||||||||||||
discordClient.on("channelCreate", async (channel) => { | ||||||||||||||
if ( | ||||||||||||||
channel.parent && | ||||||||||||||
channel.parent.name === "defense" && | ||||||||||||||
channel instanceof TextChannel && | ||||||||||||||
EXTERNAL_AUDIT_CHANNEL_REGEXP.test(channel.name) | ||||||||||||||
) { | ||||||||||||||
try { | ||||||||||||||
const defenseInvite = await createInvite(channel) | ||||||||||||||
if (defenseInvite) { | ||||||||||||||
robot.logger.info( | ||||||||||||||
`New invite created for defense audit channel: ${channel.name}, URL: ${defenseInvite.url}`, | ||||||||||||||
) | ||||||||||||||
channel.send( | ||||||||||||||
`Here is your invite link: ${ | ||||||||||||||
defenseInvite.url | ||||||||||||||
}\nThis invite expires in ${ | ||||||||||||||
(defenseInvite.maxAge / DAY) * MILLISECOND | ||||||||||||||
} days and has a maximum of ${defenseInvite.maxUses} uses.`, | ||||||||||||||
) | ||||||||||||||
} | ||||||||||||||
// Create a new role with the client name extracted and set permissions to that channel | ||||||||||||||
const clientName = channel.name | ||||||||||||||
.split("-") | ||||||||||||||
.slice(1, -1) | ||||||||||||||
.map( | ||||||||||||||
(segment) => | ||||||||||||||
segment.substring(0, 1).toUpperCase() + segment.substring(1), | ||||||||||||||
) | ||||||||||||||
.join(" ") | ||||||||||||||
|
||||||||||||||
if (clientName) { | ||||||||||||||
const roleName = clientName | ||||||||||||||
? `Defense: ${clientName}` | ||||||||||||||
: `Defense: ${channel.name}` | ||||||||||||||
Comment on lines
+112
to
+115
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Since we have the
Suggested change
|
||||||||||||||
|
||||||||||||||
const role = await channel.guild.roles.create({ | ||||||||||||||
name: roleName, | ||||||||||||||
reason: `Role for ${channel.name} channel`, | ||||||||||||||
}) | ||||||||||||||
|
||||||||||||||
await channel.permissionOverwrites.create(role, { | ||||||||||||||
ViewChannel: true, | ||||||||||||||
}) | ||||||||||||||
channel.send( | ||||||||||||||
`**${role.name}** role created and permissions set for **${channel.name}**`, | ||||||||||||||
) | ||||||||||||||
robot.logger.info( | ||||||||||||||
`${role.name} role created and permissions set for channel ${channel.name}`, | ||||||||||||||
) | ||||||||||||||
} else { | ||||||||||||||
robot.logger.info( | ||||||||||||||
`Skipping role creation due to empty client name for channel ${channel.name}`, | ||||||||||||||
) | ||||||||||||||
} | ||||||||||||||
} catch (error) { | ||||||||||||||
robot.logger.error( | ||||||||||||||
`An error occurred setting up the defense audit channel: ${error}`, | ||||||||||||||
) | ||||||||||||||
} | ||||||||||||||
} | ||||||||||||||
}) | ||||||||||||||
} | ||||||||||||||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,3 +1,7 @@ | ||
export const HOST = process.env.HUBOT_HOST | ||
export const SECOND = 1000 | ||
export const MILLISECOND = 1000 | ||
export const SECOND = 1 * MILLISECOND | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Realizing this should really be phrased as: export const MILLISECOND = 1 // Base unit of time for our code.
export const SECOND = 1000 * MILLISECOND
... |
||
export const MINUTE = 60 * SECOND | ||
export const HOUR = 60 * MINUTE | ||
export const DAY = 24 * HOUR | ||
export const WEEK = 7 * DAY |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not blocking, but let's do this conversion inside, when we call
channel.createInvite
—so the caller can always pass things and receive things in terms of our base time unit (the ms) throughout the codebase, and we only convert when we touch the external entity that requires a different denomination.