From af92920ec92c035480d3e85e770e2755ffcf5153 Mon Sep 17 00:00:00 2001 From: "Ean Milligan (Bastion)" Date: Wed, 2 Jun 2021 12:27:05 -0400 Subject: [PATCH] V0.2.1 More error handling, better time parsing, basic feature set fully flushed out. --- README.md | 2 +- config.example.ts | 2 +- mod.ts | 454 ++++++++++++++++++++++++-------------------- src/constantCmds.ts | 11 ++ src/intervals.ts | 129 ++++++++----- src/lfgHandlers.ts | 94 ++++++--- 6 files changed, 402 insertions(+), 290 deletions(-) diff --git a/README.md b/README.md index 0e0f34d..8ba1137 100644 --- a/README.md +++ b/README.md @@ -2,4 +2,4 @@ Group Up is a Discord bot built for scheduling events in your Guild. # Invite Link -https://discord.com/api/oauth2/authorize?client_id=847256159123013722&permissions=75776&scope=bot +https://discord.com/api/oauth2/authorize?client_id=847256159123013722&permissions=92160&scope=bot diff --git a/config.example.ts b/config.example.ts index f7f9e73..702e426 100644 --- a/config.example.ts +++ b/config.example.ts @@ -1,6 +1,6 @@ export const config = { "name": "Group Up", // Name of the bot - "version": "0.0.0", // Version of the bot + "version": "0.2.1", // Version of the bot "token": "the_bot_token", // Discord API Token for this bot "localtoken": "local_testing_token", // Discord API Token for a secondary OPTIONAL testing bot, THIS MUST BE DIFFERENT FROM "token" "prefix": "[[", // Prefix for all commands diff --git a/mod.ts b/mod.ts index f271afc..65460de 100644 --- a/mod.ts +++ b/mod.ts @@ -19,7 +19,7 @@ import intervals from "./src/intervals.ts"; import { LFGActivities } from "./src/games.ts"; import { JoinLeaveType } from "./src/lfgHandlers.d.ts"; import { handleLFGStep, handleMemberJoin, handleMemberLeave } from "./src/lfgHandlers.ts"; -import { constantCmds, editBtns } from "./src/constantCmds.ts"; +import { constantCmds, editBtns, lfgStepQuestions } from "./src/constantCmds.ts"; import { DEBUG, LOCALMODE } from "./flags.ts"; import config from "./config.ts"; @@ -35,7 +35,7 @@ const dbClient = await new Client().connect({ // Initialize logging client with folder to use for logs, needs --allow-write set on Deno startup initLog("logs", DEBUG); -log(LT.INFO, `${config.name} Starting up . . .`) +log(LT.INFO, `${config.name} Starting up . . .`); // Handle idling out the active builders const activeBuilders: Array = []; @@ -158,10 +158,12 @@ startBot({ } ] } + }).catch(e =>{ + log(LT.WARN, `Failed to send message | ${JSON.stringify(e)}`); }); } - else if (hasGuildPermissions(message.guildId, message.authorId, ["ADMINISTRATOR"])) { + else if (await hasGuildPermissions(message.guildId, message.authorId, ["ADMINISTRATOR"])) { const newPrefix = message.content.replace(`<@!${botId}>`, "").trim(); if (newPrefix.length <= 10) { @@ -191,6 +193,8 @@ startBot({ } ] } + }).catch(e =>{ + log(LT.WARN, `Failed to send message | ${JSON.stringify(e)}`); }); } else { message.send({ @@ -202,6 +206,8 @@ startBot({ } ] } + }).catch(e =>{ + log(LT.WARN, `Failed to send message | ${JSON.stringify(e)}`); }); } } else { @@ -214,6 +220,8 @@ startBot({ } ] } + }).catch(e =>{ + log(LT.WARN, `Failed to send message | ${JSON.stringify(e)}`); }); } } @@ -282,6 +290,8 @@ startBot({ ] } ] + }).catch(e =>{ + log(LT.WARN, `Failed to edit message | ${JSON.stringify(e)}`); }); activeLFGPosts.push({ @@ -298,10 +308,14 @@ startBot({ )); } - await activeBuilders[activeIdx].questionMsg.delete() + await activeBuilders[activeIdx].questionMsg.delete().catch(e =>{ + log(LT.WARN, `Failed to delete message | ${JSON.stringify(e)}`); + }); activeBuilders.splice(activeIdx, 1); } - await message.delete(); + await message.delete().catch(e =>{ + log(LT.WARN, `Failed to delete message | ${JSON.stringify(e)}`); + }); } return; } @@ -359,242 +373,257 @@ startBot({ // Create a new LFG else if (subcmd === "create" || subcmd === "c") { - const lfgMsg = await message.send(`Creating new LFG post for <@${message.authorId}>. Please reply with the requested information and watch as your LFG post gets created!`); + try { + const lfgMsg = await message.send(`Creating new LFG post for <@${message.authorId}>. Please reply with the requested information and watch as your LFG post gets created!`); - const gameButtons: Array = Object.keys(LFGActivities).map(game => { - return { - type: 2, - label: game, - customId: `building@set_game#${game}`, - style: DiscordButtonStyles.Primary - }; - }); + const gameButtons: Array = Object.keys(LFGActivities).map(game => { + return { + type: 2, + label: game, + customId: `building@set_game#${game}`, + style: DiscordButtonStyles.Primary + }; + }); - const buttonComps: Array = []; + const buttonComps: Array = []; - const temp: Array = []; + const temp: Array = []; - gameButtons.forEach((btn, idx) => { - if (!temp[Math.floor(idx/5)]) { - temp[Math.floor(idx/5)] = [btn]; - } else { - temp[Math.floor(idx/5)].push(btn); - } - }); + gameButtons.forEach((btn, idx) => { + if (!temp[Math.floor(idx/5)]) { + temp[Math.floor(idx/5)] = [btn]; + } else { + temp[Math.floor(idx/5)].push(btn); + } + }); - temp.forEach(btns => { - if (btns.length && btns.length <= 5) { - buttonComps.push({ - type: 1, - components: btns - }); - } - }); + temp.forEach(btns => { + if (btns.length && btns.length <= 5) { + buttonComps.push({ + type: 1, + components: btns + }); + } + }); - const question = await message.send({ - content: "Please select a game from the list below. If your game is not listed, please type it out:", - components: buttonComps - }); + const question = await message.send({ + content: lfgStepQuestions.set_game, + components: buttonComps + }); - activeBuilders.push({ - userId: message.authorId, - channelId: message.channelId, - step: "set_game", - lfgMsg: lfgMsg, - questionMsg: question, - lastTouch: new Date(), - maxIdle: 60, - editing: false - }); + activeBuilders.push({ + userId: message.authorId, + channelId: message.channelId, + step: "set_game", + lfgMsg: lfgMsg, + questionMsg: question, + lastTouch: new Date(), + maxIdle: 60, + editing: false + }); - message.delete(); + message.delete(); + } + catch (e) { + log(LT.WARN, `LFG failed at step | create | ${JSON.stringify(e)}`); + } } // Delete an existing LFG else if (subcmd === "delete" || subcmd === "d") { - // User provided a Uid, use it - if (lfgUid) { - const matches = activeLFGPosts.filter(lfg => (message.authorId === lfg.ownerId && message.channelId === lfg.channelId && lfgUid === lfg.lfgUid)); + try { + // User provided a Uid, use it + if (lfgUid) { + const matches = activeLFGPosts.filter(lfg => (message.authorId === lfg.ownerId && message.channelId === lfg.channelId && lfgUid === lfg.lfgUid)); - // Found one, delete - if (matches.length) { - await deleteMessage(matches[0].channelId, matches[0].messageId, "User requested LFG to be deleted."); - const lfgIdx = activeLFGPosts.findIndex(lfg => (message.authorId === lfg.ownerId && message.channelId === lfg.channelId && lfgUid === lfg.lfgUid)); - - activeLFGPosts.splice(lfgIdx, 1); - - localStorage.setItem("activeLFGPosts", JSON.stringify(activeLFGPosts, (_key, value) => - typeof value === "bigint" ? value.toString() + "n" : value - )); + // Found one, delete + if (matches.length) { + await deleteMessage(matches[0].channelId, matches[0].messageId, "User requested LFG to be deleted."); + const lfgIdx = activeLFGPosts.findIndex(lfg => (message.authorId === lfg.ownerId && message.channelId === lfg.channelId && lfgUid === lfg.lfgUid)); + + activeLFGPosts.splice(lfgIdx, 1); + + localStorage.setItem("activeLFGPosts", JSON.stringify(activeLFGPosts, (_key, value) => + typeof value === "bigint" ? value.toString() + "n" : value + )); - const m = await message.send(constantCmds.lfgDelete3); - setTimeout(() => { - m.delete(); - message.delete(); - }, 5000); + const m = await message.send(constantCmds.lfgDelete3); + setTimeout(() => { + m.delete(); + message.delete(); + }, 5000); + } + + // Did not find one + else { + const m = await message.send(constantCmds.lfgDelete1); + setTimeout(() => { + m.delete(); + message.delete(); + }, 5000); + } } - // Did not find one + // User did not provide a Uid, find it automatically else { - const m = await message.send(constantCmds.lfgDelete1); - setTimeout(() => { - m.delete(); - message.delete(); - }, 5000); - } + const matches = activeLFGPosts.filter(lfg => (message.authorId === lfg.ownerId && message.channelId === lfg.channelId)); + + // Found one, delete + if (matches.length === 1) { + await deleteMessage(matches[0].channelId, matches[0].messageId, "User requested LFG to be deleted."); + const lfgIdx = activeLFGPosts.findIndex(lfg => (message.authorId === lfg.ownerId && message.channelId === lfg.channelId)); + + activeLFGPosts.splice(lfgIdx, 1); + + localStorage.setItem("activeLFGPosts", JSON.stringify(activeLFGPosts, (_key, value) => + typeof value === "bigint" ? value.toString() + "n" : value + )); + + const m = await message.send(constantCmds.lfgDelete3); + setTimeout(() => { + m.delete(); + message.delete(); + }, 5000); + } + + // Found multiple, notify user + else if (matches.length) { + const deleteMsg = constantCmds.lfgDelete2; + const deepCloningFailedSoThisIsTheSolution = constantCmds.lfgDelete2.embed.fields[0].value; + matches.forEach(mt => { + deleteMsg.embed.fields[0].value += `[${mt.lfgUid}](https://discord.com/channels/${message.guildId}/${mt.channelId}/${mt.messageId})\n` + }); + + deleteMsg.embed.fields[0].value += "\nThis message will self descruct in 30 seconds." + + const m = await message.send(deleteMsg); + constantCmds.lfgDelete2.embed.fields[0].value = deepCloningFailedSoThisIsTheSolution; + setTimeout(() => { + m.delete(); + message.delete(); + }, 30000); + } + + // Found none, notify user you cannot delete other's lfgs + else { + const m = await message.send(constantCmds.lfgDelete1); + setTimeout(() => { + m.delete(); + message.delete(); + }, 5000); + } + } } - - // User did not provide a Uid, find it automatically - else { - const matches = activeLFGPosts.filter(lfg => (message.authorId === lfg.ownerId && message.channelId === lfg.channelId)); - - // Found one, delete - if (matches.length === 1) { - await deleteMessage(matches[0].channelId, matches[0].messageId, "User requested LFG to be deleted."); - const lfgIdx = activeLFGPosts.findIndex(lfg => (message.authorId === lfg.ownerId && message.channelId === lfg.channelId)); - - activeLFGPosts.splice(lfgIdx, 1); - - localStorage.setItem("activeLFGPosts", JSON.stringify(activeLFGPosts, (_key, value) => - typeof value === "bigint" ? value.toString() + "n" : value - )); - - const m = await message.send(constantCmds.lfgDelete3); - setTimeout(() => { - m.delete(); - message.delete(); - }, 5000); - } - - // Found multiple, notify user - else if (matches.length) { - const deleteMsg = constantCmds.lfgDelete2; - const deepCloningFailedSoThisIsTheSolution = constantCmds.lfgDelete2.embed.fields[0].value; - matches.forEach(mt => { - deleteMsg.embed.fields[0].value += `[${mt.lfgUid}](https://discord.com/channels/${message.guildId}/${mt.channelId}/${mt.messageId})\n` - }); - - deleteMsg.embed.fields[0].value += "\nThis message will self descruct in 30 seconds." - - const m = await message.send(deleteMsg); - constantCmds.lfgDelete2.embed.fields[0].value = deepCloningFailedSoThisIsTheSolution; - setTimeout(() => { - m.delete(); - message.delete(); - }, 30000); - } - - // Found none, notify user you cannot delete other's lfgs - else { - const m = await message.send(constantCmds.lfgDelete1); - setTimeout(() => { - m.delete(); - message.delete(); - }, 5000); - } + catch (e) { + log(LT.WARN, `LFG failed at step | delete | ${JSON.stringify(e)}`); } } // Edit an existing LFG else if (subcmd === "edit" || subcmd === "e") { - // User provided a Uid, use it - if (lfgUid) { - const matches = activeLFGPosts.filter(lfg => (message.authorId === lfg.ownerId && message.channelId === lfg.channelId && lfgUid === lfg.lfgUid)); + try { + // User provided a Uid, use it + if (lfgUid) { + const matches = activeLFGPosts.filter(lfg => (message.authorId === lfg.ownerId && message.channelId === lfg.channelId && lfgUid === lfg.lfgUid)); - // Found one, edit - if (matches.length) { - const lfgMessage = await (await getMessage(matches[0].channelId, matches[0].messageId)).edit({ - content: `Editing new LFG post for <@${matches[0].ownerId}>. Please reply with the requested information and watch as your LFG post gets edited!` - }); - const question = await message.send({ - content: "Please select an item to edit from the buttons below:", - components: [{ - type: 1, - components: editBtns - }] - }); + // Found one, edit + if (matches.length) { + const lfgMessage = await (await getMessage(matches[0].channelId, matches[0].messageId)).edit({ + content: `Editing new LFG post for <@${matches[0].ownerId}>. Please reply with the requested information and watch as your LFG post gets edited!` + }); + const question = await message.send({ + content: "Please select an item to edit from the buttons below:", + components: [{ + type: 1, + components: editBtns + }] + }); - activeBuilders.push({ - userId: matches[0].ownerId, - channelId: matches[0].channelId, - step: "edit_btn", - lfgMsg: lfgMessage, - questionMsg: question, - lastTouch: new Date(), - maxIdle: 60, - editing: true - }); + activeBuilders.push({ + userId: matches[0].ownerId, + channelId: matches[0].channelId, + step: "edit_btn", + lfgMsg: lfgMessage, + questionMsg: question, + lastTouch: new Date(), + maxIdle: 60, + editing: true + }); - message.delete(); + message.delete(); + } + + // Did not find one + else { + const m = await message.send(constantCmds.lfgEdit1); + setTimeout(() => { + m.delete(); + message.delete(); + }, 5000); + } } - // Did not find one + // User did not provide a Uid, find it automatically else { - const m = await message.send(constantCmds.lfgEdit1); - setTimeout(() => { - m.delete(); + const matches = activeLFGPosts.filter(lfg => (message.authorId === lfg.ownerId && message.channelId === lfg.channelId)); + + // Found one, edit + if (matches.length === 1) { + const lfgMessage = await (await getMessage(matches[0].channelId, matches[0].messageId)).edit({ + content: `Editing new LFG post for <@${matches[0].ownerId}>. Please reply with the requested information and watch as your LFG post gets edited!` + }); + const question = await message.send({ + content: "Please select an item to edit from the buttons below:", + components: [{ + type: 1, + components: editBtns + }] + }); + + activeBuilders.push({ + userId: matches[0].ownerId, + channelId: matches[0].channelId, + step: "edit_btn", + lfgMsg: lfgMessage, + questionMsg: question, + lastTouch: new Date(), + maxIdle: 60, + editing: true + }); + message.delete(); - }, 5000); + } + + // Found multiple, notify user + else if (matches.length) { + const deleteMsg = constantCmds.lfgEdit2; + const deepCloningFailedSoThisIsTheSolution = constantCmds.lfgEdit2.embed.fields[0].value; + matches.forEach(mt => { + deleteMsg.embed.fields[0].value += `[${mt.lfgUid}](https://discord.com/channels/${message.guildId}/${mt.channelId}/${mt.messageId})\n` + }); + + deleteMsg.embed.fields[0].value += "\nThis message will self descruct in 30 seconds." + + const m = await message.send(deleteMsg); + constantCmds.lfgEdit2.embed.fields[0].value = deepCloningFailedSoThisIsTheSolution; + setTimeout(() => { + m.delete(); + message.delete(); + }, 30000); + } + + // Found none, notify user you cannot edit other's lfgs + else { + const m = await message.send(constantCmds.lfgEdit1); + setTimeout(() => { + m.delete(); + message.delete(); + }, 5000); + } } } - - // User did not provide a Uid, find it automatically - else { - const matches = activeLFGPosts.filter(lfg => (message.authorId === lfg.ownerId && message.channelId === lfg.channelId)); - - // Found one, edit - if (matches.length === 1) { - const lfgMessage = await (await getMessage(matches[0].channelId, matches[0].messageId)).edit({ - content: `Editing new LFG post for <@${matches[0].ownerId}>. Please reply with the requested information and watch as your LFG post gets edited!` - }); - const question = await message.send({ - content: "Please select an item to edit from the buttons below:", - components: [{ - type: 1, - components: editBtns - }] - }); - - activeBuilders.push({ - userId: matches[0].ownerId, - channelId: matches[0].channelId, - step: "edit_btn", - lfgMsg: lfgMessage, - questionMsg: question, - lastTouch: new Date(), - maxIdle: 60, - editing: true - }); - - message.delete(); - } - - // Found multiple, notify user - else if (matches.length) { - const deleteMsg = constantCmds.lfgEdit2; - const deepCloningFailedSoThisIsTheSolution = constantCmds.lfgEdit2.embed.fields[0].value; - matches.forEach(mt => { - deleteMsg.embed.fields[0].value += `[${mt.lfgUid}](https://discord.com/channels/${message.guildId}/${mt.channelId}/${mt.messageId})\n` - }); - - deleteMsg.embed.fields[0].value += "\nThis message will self descruct in 30 seconds." - - const m = await message.send(deleteMsg); - constantCmds.lfgEdit2.embed.fields[0].value = deepCloningFailedSoThisIsTheSolution; - setTimeout(() => { - m.delete(); - message.delete(); - }, 30000); - } - - // Found none, notify user you cannot edit other's lfgs - else { - const m = await message.send(constantCmds.lfgEdit1); - setTimeout(() => { - m.delete(); - message.delete(); - }, 5000); - } + catch (e) { + log(LT.WARN, `LFG failed at step | edit | ${JSON.stringify(e)}`); } } } @@ -657,6 +686,9 @@ startBot({ interactionCreate: async (interact: Interaction) => { if (interact.type === DiscordInteractionTypes.MessageComponent) { if (interact.message && interact.data && (interact.data as ButtonData).customId && interact.member) { + log(LT.INFO, `Handling Button ${(interact.data as ButtonData).customId}`); + console.log(LT.LOG, `Button Data | ${JSON.stringify(interact)}`); + sendInteractionResponse(BigInt(interact.id), interact.token, { type: 6 }); @@ -720,7 +752,7 @@ startBot({ } case "active": { const member = await structures.createDiscordenoMember(interact.member, BigInt(interact.guildId)); - const message = await structures.createDiscordenoMessage(interact.message); + const message = await getMessage(BigInt(interact.channelId), BigInt(interact.message.id)); const embeds = message.embeds[0].fields || []; let results: JoinLeaveType = { @@ -766,7 +798,7 @@ startBot({ const nextComponents: Array = []; switch (action) { case "set_game": { - nextQuestion = "Please select a game from the list below. If your game is not listed, please type it out:"; + nextQuestion = lfgStepQuestions.set_game; const gameButtons: Array = Object.keys(LFGActivities).map(game => { return { diff --git a/src/constantCmds.ts b/src/constantCmds.ts index b0b7cfc..a351562 100644 --- a/src/constantCmds.ts +++ b/src/constantCmds.ts @@ -170,3 +170,14 @@ export const editBtns: ActionRow["components"] = [ style: DiscordButtonStyles.Primary } ]; + +export const lfgStepQuestions = { + "set_game": "Please select a game from the list below. If your game is not listed, please type it out:", + "set_activity_with_button": "Please select an Activity from the list below. Depending on the game selected, these may be categories you can use to drill down to a specific activity.\n\nIf your activity is not listed, please type it out:", + "set_activity_with_text": "Please type the activity name out:", + "set_activity_from_category": "Please select an Activity from the list below.\n\nIf your activity is not listed, please type it out:", + "set_player_cnt": "Please enter the max number of members for this activity:", + "set_time": "Please enter the time of the activity:\nRecommended format: `h:mm am/pm tz month/day`", + "set_desc": "Please enter a description for the activity. Enter `none` to skip:", + "set_done": "Finalizing, please wait. . ." +}; diff --git a/src/intervals.ts b/src/intervals.ts index ce1a7a2..8661a9f 100644 --- a/src/intervals.ts +++ b/src/intervals.ts @@ -41,17 +41,22 @@ const getRandomStatus = (): string => { const updateListStatistics = (botID: BigInt, serverCount: number): void => { config.botLists.forEach(async e => { if (e.enabled) { - log(LT.LOG, `Updating statistics for ${JSON.stringify(e)}`) - const tempHeaders = new Headers(); - tempHeaders.append(e.headers[0].header, e.headers[0].value); - tempHeaders.append("Content-Type", "application/json"); - // ?{} is a template used in config, just need to replace it with the real value - const response = await fetch(e.apiUrl.replace("?{bot_id}", botID.toString()), { - "method": 'POST', - "headers": tempHeaders, - "body": JSON.stringify(e.body).replace('"?{server_count}"', serverCount.toString()) // ?{server_count} needs the "" removed from around it aswell to make sure its sent as a number - }); - log(LT.INFO, `Posted server count to ${e.name}. Results: ${JSON.stringify(response)}`); + log(LT.LOG, `Updating statistics for ${JSON.stringify(e)}`); + try { + const tempHeaders = new Headers(); + tempHeaders.append(e.headers[0].header, e.headers[0].value); + tempHeaders.append("Content-Type", "application/json"); + // ?{} is a template used in config, just need to replace it with the real value + const response = await fetch(e.apiUrl.replace("?{bot_id}", botID.toString()), { + "method": 'POST', + "headers": tempHeaders, + "body": JSON.stringify(e.body).replace('"?{server_count}"', serverCount.toString()) // ?{server_count} needs the "" removed from around it aswell to make sure its sent as a number + }); + log(LT.INFO, `Posted server count to ${e.name}. Results: ${JSON.stringify(response)}`); + } + catch (e) { + log(LT.WARN, `Failed to post statistics to ${e.name} | ${JSON.stringify(e)}`); + } } }); }; @@ -64,16 +69,27 @@ const buildingTimeout = async (activeBuilders: Array): Promise { + log(LT.WARN, `Failed to clean up active builder | edit | ${activeBuilders[i].userId}-${activeBuilders[i].channelId} | ${JSON.stringify(e)}`); }); } else { - activeBuilders[i].lfgMsg.delete(); + activeBuilders[i].lfgMsg.delete().catch(e => { + log(LT.WARN, `Failed to clean up active builder | delete | ${activeBuilders[i].userId}-${activeBuilders[i].channelId} | ${JSON.stringify(e)}`); + }); + } + try { + const m = await sendMessage(activeBuilders[i].channelId, `<@${activeBuilders[i].userId}>, your LFG ${activeBuilders[i].editing ? "editing" : "creation"} has timed out. Please try again.`); + setTimeout(() => { + m.delete(); + }, 30000); + } + catch (e) { + log(LT.WARN, `Failed to clean up active builder | ${activeBuilders[i].userId}-${activeBuilders[i].channelId} | ${JSON.stringify(e)}`); + } + finally { + activeBuilders.splice(i, 1); + i--; } - const m = await sendMessage(activeBuilders[i].channelId, `<@${activeBuilders[i].userId}>, your LFG ${activeBuilders[i].editing ? "editing" : "creation"} has timed out. Please try again.`); - activeBuilders.splice(i, 1); - setTimeout(() => { - m.delete(); - }, 30000); - i--; } } } @@ -86,45 +102,66 @@ const lfgNotifier = async (activeLFGPosts: Array): Promise => { // Send notifications if (!activeLFGPosts[i].notified && activeLFGPosts[i].lfgTime < (now + tenMin)) { log(LT.INFO, `Notifying LFG ${activeLFGPosts[i].ownerId}-${activeLFGPosts[i].lfgUid}`); - const message = await getMessage(activeLFGPosts[i].channelId, activeLFGPosts[i].messageId); - const lfg = message.embeds[0].fields || []; - const lfgActivity = `${lfg[0].name.substr(0, lfg[0].name.length - 1)} - ${lfg[0].value}`; - const guildName = message.guild?.name || "unknown"; - const members = lfg[4].value; - let editMsg = ""; - await members.split("\n").forEach(async m => { - const [name, tmpId] = m.split(" - <@"); - const userId = BigInt(tmpId.substr(0, tmpId.length - 1)); - editMsg += `<@${userId}>, `; - await sendDirectMessage(userId, { - embed: { - title: `Hello ${name}! You ${lfgActivity} in ${guildName} starts in less than 10 minutes.`, - fields: [{ - name: "Please start grouping up with the other members of this activity:", - value: members - }] + try { + const message = await getMessage(activeLFGPosts[i].channelId, activeLFGPosts[i].messageId); + const lfg = message.embeds[0].fields || []; + const lfgActivity = `${lfg[0].name.substr(0, lfg[0].name.length - 1)} - ${lfg[0].value}`; + const guildName = message.guild?.name || "unknown"; + const members = lfg[4].value; + let editMsg = ""; + members.split("\n").forEach(async m => { + if (m !== "None") { + const [name, tmpId] = m.split(" - <@"); + const userId = BigInt(tmpId.substr(0, tmpId.length - 1)); + editMsg += `<@${userId}>, `; + await sendDirectMessage(userId, { + embed: { + title: `Hello ${name}! You event in ${guildName} starts in less than 10 minutes.`, + fields: [ + lfg[0], + { + name: "Please start grouping up with the other members of this activity:", + value: members + } + ] + } + }); } }); - }); - editMsg += `your ${lfgActivity} starts in less than 10 minutes.`; + editMsg += `your ${lfgActivity} starts in less than 10 minutes.`; - await message.edit({ - content: editMsg - }); + await message.edit({ + content: editMsg + }); - activeLFGPosts[i].notified = true; + activeLFGPosts[i].notified = true; + } + catch (err) { + log(LT.WARN, `Failed to find LFG ${activeLFGPosts[i].ownerId}-${activeLFGPosts[i].lfgUid} | ${JSON.stringify(err)}`); + + activeLFGPosts.splice(i, 1); + i--; + } } // Lock LFG from editing/Joining/Leaving if (!activeLFGPosts[i].locked && activeLFGPosts[i].lfgTime < now) { log(LT.INFO, `Locking LFG ${activeLFGPosts[i].ownerId}-${activeLFGPosts[i].lfgUid}`); - const message = await getMessage(activeLFGPosts[i].channelId, activeLFGPosts[i].messageId); + try { + const message = await getMessage(activeLFGPosts[i].channelId, activeLFGPosts[i].messageId); - await message.edit({ - components: [] - }); + await message.edit({ + components: [] + }); - activeLFGPosts[i].locked = true; + activeLFGPosts[i].locked = true; + } + catch (err) { + log(LT.WARN, `Failed to find LFG ${activeLFGPosts[i].ownerId}-${activeLFGPosts[i].lfgUid} | ${JSON.stringify(err)}`); + + activeLFGPosts.splice(i, 1); + i--; + } } // Delete old LFG post diff --git a/src/lfgHandlers.ts b/src/lfgHandlers.ts index 94fd7c8..2b653a2 100644 --- a/src/lfgHandlers.ts +++ b/src/lfgHandlers.ts @@ -1,11 +1,14 @@ import { - ActionRow, ButtonComponent, DiscordButtonStyles, EmbedField, DiscordenoMember + ActionRow, ButtonComponent, DiscordButtonStyles, EmbedField, DiscordenoMember, + + LT, log } from "../deps.ts"; import { JoinLeaveType } from "./lfgHandlers.d.ts"; import { BuildingLFG } from "./mod.d.ts"; import { LFGActivities } from "./games.ts"; -import { determineTZ } from "./timeUtils.ts" +import { determineTZ } from "./timeUtils.ts"; +import { lfgStepQuestions } from "./constantCmds.ts"; export const handleLFGStep = async (wipLFG: BuildingLFG, input: string): Promise => { const currentLFG = (wipLFG.lfgMsg.embeds[0] || { fields: undefined }).fields || [ @@ -47,10 +50,10 @@ export const handleLFGStep = async (wipLFG: BuildingLFG, input: string): Promise switch (wipLFG.step) { case "set_game": { - currentLFG[0].name = input; + currentLFG[0].name = input.substr(0, 254); if (Object.prototype.hasOwnProperty.call(LFGActivities, input)) { - nextQuestion = "Please select an Activity from the list below. Depending on the game selected, these may be categories you can use to drill down to a specific activity.\n\nIf your activity is not listed, please type it out:"; + nextQuestion = lfgStepQuestions.set_activity_with_button; let tempObj = {}; Object.entries(LFGActivities).some(e => { @@ -88,7 +91,7 @@ export const handleLFGStep = async (wipLFG: BuildingLFG, input: string): Promise } }); } else { - nextQuestion = "Please type the activity name out:"; + nextQuestion = lfgStepQuestions.set_activity_with_text; } wipLFG.step = "set_activity"; @@ -111,23 +114,23 @@ export const handleLFGStep = async (wipLFG: BuildingLFG, input: string): Promise }); currentLFG[0].name = `${game}:`; - currentLFG[0].value = input; + currentLFG[0].value = input.substr(0, 1023); if (typeof tempObj === "number") { // Activity currentLFG[4].name = `Members Joined: ${currentLFG[4].value === "None" ? 0 : currentLFG[4].value.split("\n").length}/${tempObj}`; - nextQuestion = wipLFG.editing ? "Finalizing, please wait. . ." : "Please enter the time of the activity:"; + nextQuestion = wipLFG.editing ? lfgStepQuestions.set_done : lfgStepQuestions.set_time; wipLFG.step = wipLFG.editing ? "done" : "set_time"; } else if (!tempObj) { // Custom - nextQuestion = "Please enter the max number of members for this activity:"; + nextQuestion = lfgStepQuestions.set_player_cnt; wipLFG.step = "set_player_cnt"; } else { // Category - nextQuestion = "Please select an Activity from the list below.\n\nIf your activity is not listed, please type it out:"; + nextQuestion = lfgStepQuestions.set_activity_from_category; currentLFG[0].name = game; @@ -187,16 +190,16 @@ export const handleLFGStep = async (wipLFG: BuildingLFG, input: string): Promise }); currentLFG[0].name = `${game}:`; - currentLFG[0].value = input; + currentLFG[0].value = input.substr(0, 1023); if (tempObj) { currentLFG[4].name = `Members Joined: ${currentLFG[4].value === "None" ? 0 : currentLFG[4].value.split("\n").length}/${tempObj}`; - nextQuestion = wipLFG.editing ? "Finalizing, please wait. . ." : "Please enter the time of the activity:"; + nextQuestion = wipLFG.editing ? lfgStepQuestions.set_done : lfgStepQuestions.set_time; wipLFG.step = wipLFG.editing ? "done" : "set_time"; } else { - nextQuestion = "Please enter the max number of members for this activity:"; + nextQuestion = lfgStepQuestions.set_player_cnt; wipLFG.step = "set_player_cnt"; } @@ -206,7 +209,7 @@ export const handleLFGStep = async (wipLFG: BuildingLFG, input: string): Promise if (parseInt(input)) { currentLFG[4].name = `Members Joined: ${currentLFG[4].value === "None" ? 0 : currentLFG[4].value.split("\n").length}/${parseInt(input)}`; - nextQuestion = wipLFG.editing ? "Finalizing, please wait. . ." : "Please enter the time of the activity:"; + nextQuestion = wipLFG.editing ? lfgStepQuestions.set_done : lfgStepQuestions.set_time; wipLFG.step = wipLFG.editing ? "done" : "set_time"; } else { @@ -227,13 +230,31 @@ export const handleLFGStep = async (wipLFG: BuildingLFG, input: string): Promise input.split(" ").forEach(c => { if (c.includes("/")) { lfgDate = c; - } else if (c.includes(":") || parseInt(c).toString() === c) { - lfgTime = c; } else if (c.toLowerCase() === "am" || c.toLowerCase() === "pm") { lfgPeriod = c.toLowerCase(); } else if (c.toLowerCase().includes("am") || c.toLowerCase().includes("pm")) { lfgTime = c.substr(0, c.length - 2); lfgPeriod = c.toLowerCase().includes("am") ? "am" : "pm"; + } else if (c.includes(":")) { + lfgTime = c; + } else if (parseInt(c).toString() === (c.replace(/^0+/, '') || "0")) { + if (c.length === 4) { + if (parseInt(c) >= 1300) { + lfgTime = (parseInt(c) - 1200).toString(); + lfgPeriod = "pm"; + } else if (parseInt(c) >= 1200) { + lfgTime = c; + lfgPeriod = "pm"; + } else { + lfgTime = c.startsWith("00") ? `12${c.substr(2)}` : c; + lfgPeriod = "am" + } + + const hourLen = lfgTime.length === 4 ? 2 : 1; + lfgTime = `${lfgTime.substr(0, hourLen)}:${lfgTime.substr(hourLen)}`; + } else { + lfgTime = c; + } } else { lfgTZ = determineTZ(c); } @@ -254,20 +275,26 @@ export const handleLFGStep = async (wipLFG: BuildingLFG, input: string): Promise lfgTZ = lfgTZ.toUpperCase(); lfgDate = `${lfgDate.split("/")[0]}/${lfgDate.split("/")[1]}/${today.getFullYear()}`; - const lfgDateTime = new Date(`${lfgTime} ${lfgPeriod} ${lfgTZ} ${lfgDate}`); + console.log(`${lfgTime} ${lfgPeriod} ${lfgTZ} ${lfgDate}`); + + const lfgDateTime = new Date(`${lfgTime} ${lfgPeriod} ${lfgTZ} ${lfgDate}`); lfgDate = `${lfgDate.split("/")[0]}/${lfgDate.split("/")[1]}`; const lfgDateStr = `[${lfgTime} ${lfgPeriod} ${lfgTZ} ${lfgDate}](https://groupup.eanm.dev/tz#${lfgDateTime.getTime()})`; currentLFG[1].name = "Start Time (Click for Conversion):"; - currentLFG[1].value = lfgDateStr; + currentLFG[1].value = lfgDateStr.substr(0, 1023); if (isNaN(lfgDateTime.getTime())) { - nextQuestion = `Input time "${input}" is invalid, please make sure you have the timezone set correctly.\n\nPlease enter the time of the activity:`; + nextQuestion = `Input time "${input}" is invalid, please make sure you have the timezone set correctly.\n\n${lfgStepQuestions.set_time}`; + + editFlag = false; + } else if (lfgDateTime.getTime() <= today.getTime()) { + nextQuestion = `Input time "${input}" is in the past, please make sure you are setting up the event to be in the future.\n\n${lfgStepQuestions.set_time}`; editFlag = false; } else { - nextQuestion = wipLFG.editing ? "Finalizing, please wait. . ." : "Please enter a description for the activity. Enter `none` to skip:"; + nextQuestion = wipLFG.editing ? lfgStepQuestions.set_done : lfgStepQuestions.set_desc; wipLFG.step = wipLFG.editing ? "done" : "set_desc"; } @@ -278,9 +305,9 @@ export const handleLFGStep = async (wipLFG: BuildingLFG, input: string): Promise input = currentLFG[0].value; } - currentLFG[3].value = input; + currentLFG[3].value = input.substr(0, 1023); - nextQuestion = "Finalizing, please wait. . ."; + nextQuestion = lfgStepQuestions.set_done; wipLFG.step = "done"; break; @@ -289,18 +316,23 @@ export const handleLFGStep = async (wipLFG: BuildingLFG, input: string): Promise break; } - if (editFlag) { - wipLFG.lfgMsg = await wipLFG.lfgMsg.edit({ - embed: { - fields: currentLFG - } + try { + if (editFlag) { + wipLFG.lfgMsg = await wipLFG.lfgMsg.edit({ + embed: { + fields: currentLFG + } + }); + } + + wipLFG.questionMsg = await wipLFG.questionMsg.edit({ + content: nextQuestion, + components: nextComponents }); } - - wipLFG.questionMsg = await wipLFG.questionMsg.edit({ - content: nextQuestion, - components: nextComponents - }); + catch (e) { + log(LT.WARN, `Failed to edit active builder | ${wipLFG.userId}-${wipLFG.channelId} | ${JSON.stringify(e)}`); + } return wipLFG; };