mirror of
https://github.com/Burn-E99/GroupUp.git
synced 2026-01-06 19:37:54 -05:00
V0.1.0 - Initial
This is the first release of Group Up. Expect errors and poor input parsing for time.
Documentation is coming soon™️
This commit is contained in:
172
src/constantCmds.ts
Normal file
172
src/constantCmds.ts
Normal file
@ -0,0 +1,172 @@
|
||||
import {
|
||||
DiscordButtonStyles, ActionRow
|
||||
} from "../deps.ts";
|
||||
|
||||
import config from "../config.ts";
|
||||
|
||||
export const constantCmds = {
|
||||
help: {
|
||||
embed: {
|
||||
title: `${config.name} Help`,
|
||||
fields: [
|
||||
{
|
||||
name: "All commands must have the bot's prefix before them.",
|
||||
value: `Default is \`${config.prefix}\`, send <@847256159123013722> to change it.`
|
||||
},
|
||||
{
|
||||
name: "LFG Commands",
|
||||
value: `
|
||||
\`lfg help\` - More detailed help for the LFG commands
|
||||
\`lfg create\` - Create a new LFG post
|
||||
\`lfg edit\` - Edit an existing LFG post
|
||||
\`lfg delete\` - Delete an existing LFG post
|
||||
`
|
||||
},
|
||||
{
|
||||
name: "Utility Commands",
|
||||
value: `
|
||||
\`info\` - Information about the bot
|
||||
\`ping\` - Pings the bot to check its connection
|
||||
\`report [TEXT]\` - Report an issue to the developer
|
||||
\`version\` - Prints the bot's current version
|
||||
`
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
lfgHelp: {
|
||||
embed: {
|
||||
title: `${config.name} LFG Help`,
|
||||
fields: [
|
||||
{
|
||||
name: "All commands must have the bot's prefix before them.",
|
||||
value: `Default is \`${config.prefix}\`, send <@847256159123013722> to change it.`
|
||||
},
|
||||
{
|
||||
name: "lfg create",
|
||||
value: `
|
||||
\`lfg create\`, alternatively \`lfg c\`, will walk you through creating a new LFG post. Simply follow the prompts and the bot will walk you through building a new LFG.
|
||||
|
||||
Make sure you run this command in the channel you wish the LFG post to be created in.
|
||||
`,
|
||||
inline: true
|
||||
},
|
||||
{
|
||||
name: "lfg edit",
|
||||
value: `
|
||||
\`lfg edit [id?]\`, alternatively \`lfg e [id?]\`, will walk you through editing an existing LFG. Like \`lfg create\`, the bot will walk you through editing it.
|
||||
|
||||
Simply run \`lfg edit\` in the channel where the LFG post lives.
|
||||
If you only have one LFG in this channel, the editing process will begin.
|
||||
If you have more than one LFG in this channel, the bot will ask you to specify the LFG post using a two character id.
|
||||
`,
|
||||
inline: true
|
||||
},
|
||||
{
|
||||
name: "lfg delete",
|
||||
value: `
|
||||
\`lfg delete [id?]\`, alternatively \`lfg d [id?]\`, will delete an existing LFG. You only can delete LFG posts that you own.
|
||||
|
||||
Simply run \`lfg delete\` in the channel where the LFG post lives.
|
||||
If you only have one LFG in this channel, the LFG will be deleted.
|
||||
If you have more than one LFG in this channel, the bot will ask you to specify the LFG post using a two character id.
|
||||
`,
|
||||
inline: true
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
info: {
|
||||
embed: {
|
||||
fields: [
|
||||
{
|
||||
name: "Group Up, the LFG bot",
|
||||
value: `Group Up is developed by Ean AKA Burn_E99.
|
||||
Want to check out my source code? Check it out [here](https://github.com/Burn-E99/GroupUp).
|
||||
Need help with this bot? Join my support server [here](https://discord.gg/peHASXMZYv).`
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
version: {
|
||||
embed: {
|
||||
title: `My current version is ${config.version}`
|
||||
}
|
||||
},
|
||||
report: {
|
||||
embed: {
|
||||
fields: [
|
||||
{
|
||||
name: "Failed command has been reported to my developer.",
|
||||
value: "For more in depth support, and information about planned maintenance, please join the support server [here](https://discord.gg/peHASXMZYv)."
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
lfgDelete1: {
|
||||
embed: {
|
||||
fields: [
|
||||
{
|
||||
name: "Could not find any LFGs to delete.",
|
||||
value: "Make sure you are the owner of the LFG and are running this command in the same channel as the LFG"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
lfgDelete2: {
|
||||
embed: {
|
||||
fields: [
|
||||
{
|
||||
name: `Multiple LFGs found, please run this command again with the two character ID of the LFG you wish to delete.\n\nExample: \`${config.prefix}lfg delete XX\``,
|
||||
value: "Click on the two character IDs below to view the LFG:\n"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
lfgDelete3: {
|
||||
embed: {
|
||||
title: "LFG deleted."
|
||||
}
|
||||
},
|
||||
lfgEdit1: {
|
||||
embed: {
|
||||
fields: [
|
||||
{
|
||||
name: "Could not find any LFGs to edit.",
|
||||
value: "Make sure you are the owner of the LFG and are running this command in the same channel as the LFG"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
lfgEdit2: {
|
||||
embed: {
|
||||
fields: [
|
||||
{
|
||||
name: `Multiple LFGs found, please run this command again with the two character ID of the LFG you wish to edit.\n\nExample: \`${config.prefix}lfg edit XX\``,
|
||||
value: "Click on the two character IDs below to view the LFG:\n"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
export const editBtns: ActionRow["components"] = [
|
||||
{
|
||||
type: 2,
|
||||
label: "Change Game/Activity",
|
||||
customId: `editing@set_game`,
|
||||
style: DiscordButtonStyles.Primary
|
||||
},
|
||||
{
|
||||
type: 2,
|
||||
label: "Change Time",
|
||||
customId: `editing@set_time`,
|
||||
style: DiscordButtonStyles.Primary
|
||||
},
|
||||
{
|
||||
type: 2,
|
||||
label: "Change Description",
|
||||
customId: `editing@set_desc`,
|
||||
style: DiscordButtonStyles.Primary
|
||||
}
|
||||
];
|
||||
43
src/games.ts
Normal file
43
src/games.ts
Normal file
@ -0,0 +1,43 @@
|
||||
export const LFGActivities = {
|
||||
"Destiny 2": {
|
||||
"Raids": {
|
||||
"Vault of Glass": 6,
|
||||
"Deep Stone Crypt": 6,
|
||||
"Garden of Salvation": 6,
|
||||
"Last Wish": 6
|
||||
},
|
||||
"Dungeons": {
|
||||
"Prophecy": 3,
|
||||
"Pit of Heresy": 3,
|
||||
"Shattered Throne": 3
|
||||
},
|
||||
"Crucible": {
|
||||
"Iron Banner": 6,
|
||||
"Quickplay": 6,
|
||||
"Competitive": 3,
|
||||
"Trials of Osiris": 3,
|
||||
"Private Match": 12
|
||||
},
|
||||
"Gambit": {
|
||||
"Classic": 4,
|
||||
"Private Match": 8
|
||||
},
|
||||
"Exotic Missions": {
|
||||
"Presage": 3,
|
||||
"Harbinger": 3
|
||||
},
|
||||
"Nightfall": 3,
|
||||
"Miscellaneous": {
|
||||
"Override": 6,
|
||||
"Expunge": 3,
|
||||
"Battlegrounds": 3,
|
||||
"Wrathborn Hunt": 3,
|
||||
"Empire Hunt": 3,
|
||||
"Nightmare Hunt": 3
|
||||
}
|
||||
},
|
||||
"Among Us": {
|
||||
"Vanilla": 10,
|
||||
"Modded": 10
|
||||
}
|
||||
};
|
||||
146
src/intervals.ts
Normal file
146
src/intervals.ts
Normal file
@ -0,0 +1,146 @@
|
||||
import {
|
||||
// Discordeno deps
|
||||
cache,
|
||||
sendMessage, getMessage, deleteMessage, sendDirectMessage,
|
||||
|
||||
// Log4Deno deps
|
||||
LT, log
|
||||
} from "../deps.ts";
|
||||
|
||||
import { BuildingLFG, ActiveLFG } from "./mod.d.ts";
|
||||
|
||||
import config from "../config.ts";
|
||||
|
||||
// getRandomStatus() returns status as string
|
||||
// Gets a new random status for the bot
|
||||
const getRandomStatus = (): string => {
|
||||
let status = "";
|
||||
switch (Math.floor((Math.random() * 5) + 1)) {
|
||||
case 1:
|
||||
status = `${config.prefix}help for commands`;
|
||||
break;
|
||||
case 2:
|
||||
status = `Running V${config.version}`;
|
||||
break;
|
||||
case 3:
|
||||
status = `${config.prefix}info to learn more`;
|
||||
break;
|
||||
case 4:
|
||||
status = "Mention me to check my prefix!";
|
||||
break;
|
||||
default:
|
||||
status = `Running LFGs in ${cache.guilds.size} servers`;
|
||||
break;
|
||||
}
|
||||
|
||||
return status;
|
||||
};
|
||||
|
||||
// updateListStatistics(bot ID, current guild count) returns nothing
|
||||
// Sends the current server count to all bot list sites we are listed on
|
||||
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)}`);
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
const buildingTimeout = async (activeBuilders: Array<BuildingLFG>): Promise<void> => {
|
||||
const currentTime = new Date().getTime();
|
||||
for (let i = 0; i < activeBuilders.length; i++) {
|
||||
if (activeBuilders[i].lastTouch.getTime() + (activeBuilders[i].maxIdle * 1000) < currentTime) {
|
||||
activeBuilders[i].questionMsg.delete();
|
||||
if (activeBuilders[i].editing) {
|
||||
activeBuilders[i].lfgMsg.edit({
|
||||
content: ""
|
||||
});
|
||||
} else {
|
||||
activeBuilders[i].lfgMsg.delete();
|
||||
}
|
||||
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--;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const lfgNotifier = async (activeLFGPosts: Array<ActiveLFG>): Promise<void> => {
|
||||
log(LT.INFO, "Checking for LFG posts to notify/delete/lock")
|
||||
const tenMin = 10 * 60 * 1000;
|
||||
const now = new Date().getTime();
|
||||
for (let i = 0; i < activeLFGPosts.length; i++) {
|
||||
// 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
|
||||
}]
|
||||
}
|
||||
});
|
||||
});
|
||||
editMsg += `your ${lfgActivity} starts in less than 10 minutes.`;
|
||||
|
||||
await message.edit({
|
||||
content: editMsg
|
||||
});
|
||||
|
||||
activeLFGPosts[i].notified = true;
|
||||
}
|
||||
|
||||
// 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);
|
||||
|
||||
await message.edit({
|
||||
components: []
|
||||
});
|
||||
|
||||
activeLFGPosts[i].locked = true;
|
||||
}
|
||||
|
||||
// Delete old LFG post
|
||||
if (activeLFGPosts[i].lfgTime < (now - tenMin)) {
|
||||
log(LT.INFO, `Deleting LFG ${activeLFGPosts[i].ownerId}-${activeLFGPosts[i].lfgUid}`);
|
||||
await deleteMessage(activeLFGPosts[i].channelId, activeLFGPosts[i].messageId, "LFG post expired").catch(e => {
|
||||
log(LT.WARN, `Failed to delete LFG ${activeLFGPosts[i].ownerId}-${activeLFGPosts[i].lfgUid} | ${JSON.stringify(e)}`);
|
||||
});
|
||||
activeLFGPosts.splice(i, 1);
|
||||
i--;
|
||||
}
|
||||
}
|
||||
|
||||
localStorage.setItem("activeLFGPosts", JSON.stringify(activeLFGPosts, (_key, value) =>
|
||||
typeof value === "bigint" ? value.toString() + "n" : value
|
||||
));
|
||||
}
|
||||
|
||||
export default { getRandomStatus, updateListStatistics, buildingTimeout, lfgNotifier };
|
||||
9
src/lfgHandlers.d.ts
vendored
Normal file
9
src/lfgHandlers.d.ts
vendored
Normal file
@ -0,0 +1,9 @@
|
||||
import {
|
||||
EmbedField
|
||||
} from "../deps.ts";
|
||||
|
||||
export type JoinLeaveType = {
|
||||
embed: EmbedField[],
|
||||
success: boolean,
|
||||
full: boolean
|
||||
}
|
||||
401
src/lfgHandlers.ts
Normal file
401
src/lfgHandlers.ts
Normal file
@ -0,0 +1,401 @@
|
||||
import {
|
||||
ActionRow, ButtonComponent, DiscordButtonStyles, EmbedField, DiscordenoMember
|
||||
} 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"
|
||||
|
||||
export const handleLFGStep = async (wipLFG: BuildingLFG, input: string): Promise<BuildingLFG> => {
|
||||
const currentLFG = (wipLFG.lfgMsg.embeds[0] || { fields: undefined }).fields || [
|
||||
{
|
||||
name: ". . .",
|
||||
value: ". . .",
|
||||
inline: true
|
||||
},
|
||||
{
|
||||
name: "Start Time:",
|
||||
value: ". . .",
|
||||
inline: true
|
||||
},
|
||||
{
|
||||
name: "Add to Calendar:",
|
||||
value: "Coming Soon:tm:",
|
||||
inline: true
|
||||
},
|
||||
{
|
||||
name: "Description:",
|
||||
value: ". . .",
|
||||
inline: false
|
||||
},
|
||||
{
|
||||
name: `Members Joined: 0/?`,
|
||||
value: "None",
|
||||
inline: true
|
||||
},
|
||||
{
|
||||
name: "Alternates:",
|
||||
value: "None",
|
||||
inline: true
|
||||
}
|
||||
];
|
||||
|
||||
let nextQuestion = "";
|
||||
const nextComponents: Array<ActionRow> = [];
|
||||
let editFlag = true;
|
||||
|
||||
switch (wipLFG.step) {
|
||||
case "set_game": {
|
||||
currentLFG[0].name = input;
|
||||
|
||||
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:";
|
||||
|
||||
let tempObj = {};
|
||||
Object.entries(LFGActivities).some(e => {
|
||||
if (e[0] === input) {
|
||||
tempObj = e[1];
|
||||
return true;
|
||||
}
|
||||
});
|
||||
|
||||
const activityButtons: Array<ButtonComponent> = Object.keys(tempObj).map(activity => {
|
||||
return {
|
||||
type: 2,
|
||||
label: activity,
|
||||
customId: `building@set_activity#${activity}`,
|
||||
style: DiscordButtonStyles.Primary
|
||||
};
|
||||
});
|
||||
|
||||
const temp: Array<ActionRow["components"]> = [];
|
||||
|
||||
activityButtons.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) {
|
||||
nextComponents.push({
|
||||
type: 1,
|
||||
components: btns
|
||||
});
|
||||
}
|
||||
});
|
||||
} else {
|
||||
nextQuestion = "Please type the activity name out:";
|
||||
}
|
||||
|
||||
wipLFG.step = "set_activity";
|
||||
break;
|
||||
}
|
||||
case "set_activity": {
|
||||
const game = currentLFG[0].name;
|
||||
|
||||
let tempObj;
|
||||
Object.entries(LFGActivities).some(e => {
|
||||
if (e[0] === game) {
|
||||
Object.entries(e[1]).some(f => {
|
||||
if (f[0] === input) {
|
||||
tempObj = f[1];
|
||||
return true;
|
||||
}
|
||||
});
|
||||
return true;
|
||||
}
|
||||
});
|
||||
|
||||
currentLFG[0].name = `${game}:`;
|
||||
currentLFG[0].value = input;
|
||||
|
||||
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:";
|
||||
|
||||
wipLFG.step = wipLFG.editing ? "done" : "set_time";
|
||||
} else if (!tempObj) {
|
||||
// Custom
|
||||
nextQuestion = "Please enter the max number of members for this activity:";
|
||||
|
||||
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:";
|
||||
|
||||
currentLFG[0].name = game;
|
||||
|
||||
const activityButtons: Array<ButtonComponent> = Object.keys(tempObj).map(activity => {
|
||||
return {
|
||||
type: 2,
|
||||
label: activity,
|
||||
customId: `building@set_activity_from_category#${activity}`,
|
||||
style: DiscordButtonStyles.Primary
|
||||
};
|
||||
});
|
||||
|
||||
const temp: Array<ActionRow["components"]> = [];
|
||||
|
||||
activityButtons.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) {
|
||||
nextComponents.push({
|
||||
type: 1,
|
||||
components: btns
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
wipLFG.step = "set_activity_from_category";
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
case "set_activity_from_category": {
|
||||
const game = currentLFG[0].name;
|
||||
const category = currentLFG[0].value;
|
||||
|
||||
let tempObj;
|
||||
Object.entries(LFGActivities).some(e => {
|
||||
if (e[0] === game) {
|
||||
Object.entries(e[1]).some(f => {
|
||||
if (f[0] === category) {
|
||||
Object.entries(f[1]).some(g => {
|
||||
if (g[0] === input) {
|
||||
tempObj = g[1];
|
||||
return true;
|
||||
}
|
||||
});
|
||||
return true;
|
||||
}
|
||||
});
|
||||
return true;
|
||||
}
|
||||
});
|
||||
|
||||
currentLFG[0].name = `${game}:`;
|
||||
currentLFG[0].value = input;
|
||||
|
||||
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:";
|
||||
|
||||
wipLFG.step = wipLFG.editing ? "done" : "set_time";
|
||||
} else {
|
||||
nextQuestion = "Please enter the max number of members for this activity:";
|
||||
|
||||
wipLFG.step = "set_player_cnt";
|
||||
}
|
||||
break;
|
||||
}
|
||||
case "set_player_cnt": {
|
||||
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:";
|
||||
|
||||
wipLFG.step = wipLFG.editing ? "done" : "set_time";
|
||||
} else {
|
||||
editFlag = false;
|
||||
|
||||
nextQuestion = `Input max members "${input}" is invalid, please make sure you are only entering a number.\n\nPlease enter the max number of members for this activity:`
|
||||
}
|
||||
break;
|
||||
}
|
||||
case "set_time": {
|
||||
const today = new Date();
|
||||
|
||||
let lfgDate = `${today.getMonth() + 1}/${today.getDate()}`,
|
||||
lfgTime = "",
|
||||
lfgTZ = "",
|
||||
lfgPeriod = "";
|
||||
|
||||
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 {
|
||||
lfgTZ = determineTZ(c);
|
||||
}
|
||||
});
|
||||
|
||||
if (!lfgTZ) {
|
||||
lfgTZ = determineTZ("ET");
|
||||
}
|
||||
|
||||
if (!lfgTime.includes(":")) {
|
||||
lfgTime += ":00";
|
||||
}
|
||||
|
||||
if (!lfgPeriod) {
|
||||
lfgPeriod = parseInt(lfgTime.split(":")[0]) >= 12 ? "pm" : "am";
|
||||
}
|
||||
lfgPeriod = lfgPeriod.toUpperCase();
|
||||
lfgTZ = lfgTZ.toUpperCase();
|
||||
|
||||
lfgDate = `${lfgDate.split("/")[0]}/${lfgDate.split("/")[1]}/${today.getFullYear()}`;
|
||||
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;
|
||||
|
||||
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:`;
|
||||
|
||||
editFlag = false;
|
||||
} else {
|
||||
nextQuestion = wipLFG.editing ? "Finalizing, please wait. . ." : "Please enter a description for the activity. Enter `none` to skip:";
|
||||
|
||||
wipLFG.step = wipLFG.editing ? "done" : "set_desc";
|
||||
}
|
||||
break;
|
||||
}
|
||||
case "set_desc":{
|
||||
if (input === "none") {
|
||||
input = currentLFG[0].value;
|
||||
}
|
||||
|
||||
currentLFG[3].value = input;
|
||||
|
||||
nextQuestion = "Finalizing, please wait. . .";
|
||||
|
||||
wipLFG.step = "done";
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
if (editFlag) {
|
||||
wipLFG.lfgMsg = await wipLFG.lfgMsg.edit({
|
||||
embed: {
|
||||
fields: currentLFG
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
wipLFG.questionMsg = await wipLFG.questionMsg.edit({
|
||||
content: nextQuestion,
|
||||
components: nextComponents
|
||||
});
|
||||
|
||||
return wipLFG;
|
||||
};
|
||||
|
||||
export const handleMemberJoin = (lfg: EmbedField[], member: DiscordenoMember, alternate: boolean): JoinLeaveType => {
|
||||
let success = false;
|
||||
|
||||
const userStr = `${member.username} - <@${member.id}>`;
|
||||
|
||||
const tempMembers = lfg[4].name.split(":")[1].split("/");
|
||||
let currentMembers = parseInt(tempMembers[0]);
|
||||
const maxMembers = parseInt(tempMembers[1]);
|
||||
|
||||
if (alternate && !lfg[5].value.includes(member.id.toString())) {
|
||||
if (lfg[4].value.includes(member.id.toString())) {
|
||||
const tempArr = lfg[4].value.split("\n");
|
||||
const memberIdx = tempArr.findIndex(m => m.includes(member.id.toString()));
|
||||
tempArr.splice(memberIdx, 1)
|
||||
lfg[4].value = tempArr.join("\n") || "None";
|
||||
|
||||
if (currentMembers) {
|
||||
currentMembers--;
|
||||
}
|
||||
lfg[4].name = `Members Joined: ${currentMembers}/${maxMembers}`;
|
||||
}
|
||||
|
||||
if (lfg[5].value === "None") {
|
||||
lfg[5].value = userStr;
|
||||
} else {
|
||||
lfg[5].value += `\n${userStr}`;
|
||||
}
|
||||
|
||||
success = true;
|
||||
} else if (!alternate &¤tMembers < maxMembers && !lfg[4].value.includes(member.id.toString())) {
|
||||
if (lfg[5].value.includes(member.id.toString())) {
|
||||
const tempArr = lfg[5].value.split("\n");
|
||||
const memberIdx = tempArr.findIndex(m => m.includes(member.id.toString()));
|
||||
tempArr.splice(memberIdx, 1)
|
||||
lfg[5].value = tempArr.join("\n") || "None";
|
||||
}
|
||||
|
||||
if (lfg[4].value === "None") {
|
||||
lfg[4].value = userStr;
|
||||
} else {
|
||||
lfg[4].value += `\n${userStr}`;
|
||||
}
|
||||
currentMembers++;
|
||||
|
||||
lfg[4].name = `Members Joined: ${currentMembers}/${maxMembers}`;
|
||||
|
||||
success = true;
|
||||
}
|
||||
|
||||
return {
|
||||
embed: lfg,
|
||||
success: success,
|
||||
full: currentMembers === maxMembers
|
||||
};
|
||||
};
|
||||
|
||||
export const handleMemberLeave = (lfg: EmbedField[], member: DiscordenoMember): JoinLeaveType => {
|
||||
let success = false;
|
||||
|
||||
const memberId = member.id.toString();
|
||||
|
||||
const tempMembers = lfg[4].name.split(":")[1].split("/");
|
||||
let currentMembers = parseInt(tempMembers[0]);
|
||||
const maxMembers = parseInt(tempMembers[1]);
|
||||
|
||||
if (lfg[4].value.includes(memberId)) {
|
||||
const tempArr = lfg[4].value.split("\n");
|
||||
const memberIdx = tempArr.findIndex(m => m.includes(memberId));
|
||||
tempArr.splice(memberIdx, 1);
|
||||
lfg[4].value = tempArr.join("\n") || "None";
|
||||
|
||||
if (currentMembers) {
|
||||
currentMembers--;
|
||||
}
|
||||
lfg[4].name = `Members Joined: ${currentMembers}/${maxMembers}`;
|
||||
|
||||
success = true;
|
||||
}
|
||||
|
||||
if (lfg[5].value.includes(memberId)) {
|
||||
const tempArr = lfg[5].value.split("\n");
|
||||
const memberIdx = tempArr.findIndex(m => m.includes(memberId));
|
||||
tempArr.splice(memberIdx, 1);
|
||||
lfg[5].value = tempArr.join("\n") || "None";
|
||||
|
||||
success = true;
|
||||
}
|
||||
|
||||
return {
|
||||
embed: lfg,
|
||||
success: success,
|
||||
full: currentMembers === maxMembers
|
||||
};
|
||||
};
|
||||
37
src/mod.d.ts
vendored
Normal file
37
src/mod.d.ts
vendored
Normal file
@ -0,0 +1,37 @@
|
||||
import {
|
||||
DiscordenoMessage
|
||||
} from "../deps.ts";
|
||||
|
||||
export type BuildingLFG = {
|
||||
userId: bigint,
|
||||
channelId: bigint,
|
||||
step: string,
|
||||
lfgMsg: DiscordenoMessage,
|
||||
questionMsg: DiscordenoMessage,
|
||||
lastTouch: Date,
|
||||
maxIdle: number,
|
||||
editing: boolean
|
||||
}
|
||||
|
||||
export type ActiveLFG = {
|
||||
messageId: bigint,
|
||||
channelId: bigint,
|
||||
ownerId: bigint,
|
||||
lfgUid: string,
|
||||
lfgTime: number,
|
||||
notified: boolean,
|
||||
locked: boolean
|
||||
}
|
||||
|
||||
export type GuildPrefixes = {
|
||||
guildId: bigint,
|
||||
prefix: string
|
||||
}
|
||||
|
||||
// TEMP
|
||||
export interface ButtonData {
|
||||
/** with the value you defined for this component */
|
||||
customId: string;
|
||||
/** The type of this component */
|
||||
componentType: 2;
|
||||
}
|
||||
16
src/timeUtils.ts
Normal file
16
src/timeUtils.ts
Normal file
@ -0,0 +1,16 @@
|
||||
export const determineTZ = (tz: string): string => {
|
||||
tz = tz.toUpperCase();
|
||||
|
||||
if (tz === "ET" || tz === "CT" || tz === "MT" || tz === "PT") {
|
||||
const today = new Date();
|
||||
const jan = new Date(today.getFullYear(), 0, 1);
|
||||
const jul = new Date(today.getFullYear(), 6, 1);
|
||||
if (today.getTimezoneOffset() < Math.max(jan.getTimezoneOffset(), jul.getTimezoneOffset())) {
|
||||
tz = `${tz.substr(0, 1)}DT`;
|
||||
} else {
|
||||
tz = `${tz.substr(0, 1)}ST`;
|
||||
}
|
||||
}
|
||||
|
||||
return tz;
|
||||
};
|
||||
Reference in New Issue
Block a user