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

Add nickname change event for OOO #318

Merged
merged 5 commits into from
Nov 1, 2024
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
113 changes: 101 additions & 12 deletions discord-scripts/discord-webhook.ts
Original file line number Diff line number Diff line change
Expand Up @@ -51,25 +51,82 @@ export default async function webhookDiscord(
}
}

async function getUserIdByName(
guildId: string,
username: string,
): Promise<string | null> {
const guild = discordClient.guilds.cache.get(guildId)
if (!guild) throw new Error("Guild not found")

await guild.members.fetch()
// WIP, output list of all members for matching
guild.members.cache.forEach((member) => {
robot.logger.info(`Username: ${member.user.username}`)
})
Comment on lines +62 to +65
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we drop those?

Also wondering if we need to start wrapping stuff in an environment check.


const matchedMember = guild.members.cache.find((member) =>
member.user.username.includes(username),
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Shouldn't we be looking for a direct (case-insensitive) match here?

)

return matchedMember ? matchedMember.user.id : null
}

async function updateServerNickname(
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This isn't just about updating the server nickname since it does all the OOO stuff, right? Let's be very specific about what this function does in the name.

username: string,
guildId: string,
addSuffix: boolean,
date?: string,
) {
const guild = discordClient.guilds.cache.get(guildId)
if (!guild) throw new Error("Guild not found")

const userId = await getUserIdByName(guildId, username)
if (!userId) throw new Error("User not found with the specified name")

const member = await guild.members.fetch(userId)
const currentNickname = member.nickname || member.user.username

const suffixWithDate = date ? `(OOO ${date})` : "(OOO)"
const suffixRegex = /\s*\(OOO.*$/

const newNickname = addSuffix
? `${currentNickname
.replace(suffixRegex, "")
.trim()} ${suffixWithDate}`.trim()
: currentNickname.replace(suffixRegex, "").trim()

if (newNickname !== currentNickname) {
await member.setNickname(newNickname)
robot.logger.info(
`${addSuffix ? "Added" : "Removed"} '${suffixWithDate}' for ${
member.user.username
} in ${guild.name}`,
)
}
}

if (process.env.HUBOT_WEBHOOK_URL) {
const webhookUrl = process.env.HUBOT_WEBHOOK_URL
const requiredAuth = process.env.HUBOT_WEBHOOK_AUTH
robot.logger.info("Webhook URL has been set: ", webhookUrl)
robot.logger.info("Webhook Auth has been set: ", requiredAuth)

const handleAuth = (
req: express.Request,
res: express.Response,
next: express.NextFunction,
) => {
const authHeader = req.headers.authorization
if (!authHeader || authHeader !== requiredAuth) {
res.status(401).send("Unauthorized")
} else {
next()
}
}

robot.router.post(
`${webhookUrl}`,
(
req: express.Request,
res: express.Response,
next: express.NextFunction,
) => {
const authHeader = req.headers.authorization
if (!authHeader || authHeader !== requiredAuth) {
res.status(401).send("Unauthorized")
} else {
next()
}
},
handleAuth,
async (req: express.Request, res: express.Response) => {
const isBodyInvalid = ["channelName", "title", "message"].some(
(field) => {
Expand Down Expand Up @@ -97,5 +154,37 @@ export default async function webhookDiscord(
},
)
robot.logger.info("Webhook is now enabled")

robot.router.post("/start-date", handleAuth, async (req, res) => {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should look at scoping this very specifically and making it a little more REST-like. Something like:

robot.router.post(`${webhookUrl}/user/:username/out-of-office`...

robot.router.delete(`${webhookUrl}/user/:username/out-of-office`...

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

(I say this not remembering what webhookUrl is. We should also probably scope the message poster webhook to /message or similar.)

try {
const { username, guildId, date } = req.body
if (!username || !guildId) {
return res.status(400).send("Missing username or guildId")
}
await updateServerNickname(username, guildId, true, date)
return res.status(200).send("Nickname updated to add (OOO)")
} catch (error) {
robot.logger.error("Error in start-date route:", error)
return res.status(500).send("Internal Server Error")
}
})

robot.router.post(
"/end-date",
handleAuth,
async (req: express.Request, res: express.Response) => {
const { username, guildId } = req.body
if (!username || !guildId) {
return res.status(400).send("Missing username or guildId")
}

await updateServerNickname(username, guildId, false)
return res.status(200).send("Nickname updated to remove (OOO)")
},
)

robot.logger.info(
"Webhook is now enabled with OOO routes /start-date and /end-date",
)
}
}
Loading