diff --git a/.gitignore b/.gitignore index e9cdb23..56669db 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,5 @@ +package-lock.json + # Database /data diff --git a/src/db.ts b/src/db.ts index d3fdbc6..e397a37 100644 --- a/src/db.ts +++ b/src/db.ts @@ -86,7 +86,6 @@ export interface Proposal { totalVotes: number; polls: number; created: DateTime; - used: boolean; } interface InternalProposal { @@ -100,7 +99,6 @@ interface InternalProposal { totalVotes: number; polls: number; created: ISODate; - used: boolean; } // -- Poll Database -- @@ -190,7 +188,8 @@ export interface Jam { start: DateTime; end: DateTime; resultChannelID: string | null; - eventID: string | null; + /** ID of the scheduled event. Only available during the jam. */ + scheduledEventID: string | null; //pollID: string | null; } @@ -200,7 +199,7 @@ interface InternalJam { start: ISODate; end: ISODate; resultChannelID: string | null; - eventID: string | null; + scheduledEventID: string | null; //pollID: string | null; } diff --git a/src/interactions/autocompleters/CodingJamsAutocomplete.ts b/src/interactions/autocompleters/CodingJamsAutocomplete.ts index 4f6e61e..96d3846 100644 --- a/src/interactions/autocompleters/CodingJamsAutocomplete.ts +++ b/src/interactions/autocompleters/CodingJamsAutocomplete.ts @@ -1,6 +1,5 @@ import { AutocompleteInteraction } from "discord.js"; -import { jamDb, pollDb, proposalID, userID } from "../../db.js"; -import { unusedProposals } from "../../util/coding-jams/managePoll.js"; +import { jamDb, pollDb, proposalDb, proposalID, userID } from "../../db.js"; import { autocompleteISODuration, autocompleteISOTime } from "../../util/misc/autocomplete.js"; import { Autocompleter } from "../interactionClasses.js"; @@ -40,7 +39,7 @@ class CodingJamsAutocompleter extends Autocompleter { const proposalNameAutocompletion = async () => await interaction.respond( - unusedProposals() + proposalDb .array() .filter((k) => k.title.toLowerCase().includes(value)) .slice(0, 25) diff --git a/src/interactions/modals/ProposalModal.ts b/src/interactions/modals/ProposalModal.ts index 8bb1075..d247433 100644 --- a/src/interactions/modals/ProposalModal.ts +++ b/src/interactions/modals/ProposalModal.ts @@ -53,7 +53,6 @@ class ProposalModal extends Modal { totalVotes: 0, polls: 0, created: DateTime.now(), - used: false, }; proposalDb.set(String(proposalDb.autonum), proposal); @@ -73,7 +72,6 @@ class ProposalModal extends Modal { totalVotes: oldProposal.totalVotes, polls: oldProposal.polls, created: oldProposal.created, - used: oldProposal.used, }; proposalDb.update(key, proposal); diff --git a/src/interactions/selectMenus/PollSelectMenu.ts b/src/interactions/selectMenus/PollSelectMenu.ts index 27ff741..d223839 100644 --- a/src/interactions/selectMenus/PollSelectMenu.ts +++ b/src/interactions/selectMenus/PollSelectMenu.ts @@ -1,12 +1,7 @@ import { bold, GuildMember, StringSelectMenuInteraction } from "discord.js"; import { pollDb, proposalDb } from "../../db.js"; import { logger } from "../../logger.js"; -import { - pollEmbed, - pollSelectMenus, - sortBySelectionType, - unusedProposals, -} from "../../util/coding-jams/managePoll.js"; +import { pollEmbed, pollSelectMenus, sortBySelectionType } from "../../util/coding-jams/managePoll.js"; import { getFromEnmap } from "../../util/misc/enmap.js"; import { SelectMenu } from "../interactionClasses.js"; @@ -30,9 +25,6 @@ class PollSelectMenu extends SelectMenu { if (type === "include" || type === "exclude") { if (values.includes("-")) values = []; - - const unused = unusedProposals(); - if (type === "include") { if (values.length > poll.numProposals) { await interaction.reply({ @@ -43,10 +35,10 @@ class PollSelectMenu extends SelectMenu { } poll.include = values; } else if (type === "exclude") { - if (unused.size - values.length < poll.numProposals) { + if (proposalDb.size - values.length < poll.numProposals) { await interaction.reply({ content: `You can't exclude ${values.length} proposals because then only ${ - unused.size - values.length + proposalDb.size - values.length } proposals are left, which is less than the required amount of ${ poll.numProposals } proposals. No proposals were used.`, @@ -57,7 +49,7 @@ class PollSelectMenu extends SelectMenu { poll.exclude = values; } - const sorted = sortBySelectionType(unused, poll.selectionType); + const sorted = sortBySelectionType(proposalDb, poll.selectionType); poll.proposals = poll.include.slice(0); // copy the array const numExtra = poll.numProposals - poll.proposals.length; diff --git a/src/util/coding-jams/jamEvents.ts b/src/util/coding-jams/jamEvents.ts index 7e3e0ad..93248b8 100644 --- a/src/util/coding-jams/jamEvents.ts +++ b/src/util/coding-jams/jamEvents.ts @@ -25,7 +25,9 @@ export async function createScheduledEventEvent(channel: TextChannel, jamID: str entityMetadata: { location: "Here!" }, }; - channel.guild.scheduledEvents.create(options); + const event = await channel.guild.scheduledEvents.create(options); + jam.scheduledEventID = event.id; + jamDb.set(jamID, jam); const embed = new EmbedBuilder() .setTitle(`${proposal.title} coming up!`) @@ -34,7 +36,7 @@ export async function createScheduledEventEvent(channel: TextChannel, jamID: str jam.start )}! That's ${discordRelativeTimestamp( jam.start - )}! Make sure your calender is free :) I hope you can make it!\nThe current end is planned for ${discordTimestamp( + )}! Make sure your calender is free :) I hope you can make it!\nCurrently the end is planned for ${discordTimestamp( jam.end )}. That would be ${durationToReadable(jam.end.diff(jam.start))}.` ) @@ -96,6 +98,8 @@ export async function endEvent(channel: TextChannel, jamID: string) { const jamRole = channel.guild.roles.cache.find((v) => v.name === config.jamRoleName) || channel.guild.roles.everyone; channel.send({ embeds: [addEmbedFooter(embed)], content: jamRole.toString() }); + + proposalDb.delete(jam.proposal); } export async function halftimeEvent(channel: TextChannel, jamID: string) { diff --git a/src/util/coding-jams/manageJams.ts b/src/util/coding-jams/manageJams.ts index 70ef154..469a58b 100644 --- a/src/util/coding-jams/manageJams.ts +++ b/src/util/coding-jams/manageJams.ts @@ -1,8 +1,9 @@ -import { CommandInteraction, EmbedBuilder } from "discord.js"; +import { CommandInteraction, EmbedBuilder, TextChannel } from "discord.js"; import { DateTime } from "luxon"; import { Jam, jamDb, JamEvent, jamEventsDb, proposalDb } from "../../db.js"; import { addEmbedFooter } from "../misc/embeds.js"; import { discordRelativeTimestamp, discordTimestamp, durationToReadable, isInFuture } from "../misc/time.js"; +import { config } from "../../config.js"; const hoursBeforeEvent = 2; @@ -29,16 +30,8 @@ export async function newJam( const proposal = proposalDb.get(proposalID)!; - if (proposal.used) { - interaction.editReply({ - content: `The proposal "${proposal.title}" has already been used for a jam. You can't use it again.`, - }); - return; - } - const end = start.plus(proposal.duration); - proposal.used = true; proposalDb.set(proposalID, proposal); const jam: Jam = { @@ -47,7 +40,7 @@ export async function newJam( resultChannelID: null, start: start, end: end, - eventID: null, + scheduledEventID: null, }; const id = String(jamDb.autonum); @@ -105,8 +98,22 @@ export async function editJam(interaction: CommandInteraction, jam: Jam, jamKey: events.forEach((e) => jamEventsDb.set(String(jamEventsDb.autonum), e)); - if (jam.eventID) { - interaction.guild?.scheduledEvents.edit(jam.eventID, { scheduledEndTime: end.toISO()! }); + if (jam.scheduledEventID) + interaction.guild?.scheduledEvents.edit(jam.scheduledEventID, { scheduledEndTime: end.toISO()! }); + + if (jam.start < DateTime.now()) { + const proposal = proposalDb.get(jam.proposal)!; + + const embed = new EmbedBuilder() + .setTitle(`More time to finish!`) + .setDescription( + `The ${proposal.title} jam has been extended to the ${discordTimestamp(jam.end)}. That's ${discordRelativeTimestamp(jam.end)}! Happy jamming :)` + ); + + const channel = (await interaction.client.channels.fetch(config.jamChannelId)) as TextChannel; + const jamRole = + channel.guild.roles.cache.find((v) => v.name === config.jamRoleName) || channel.guild.roles.everyone; + await channel.send({ embeds: [addEmbedFooter(embed)], content: jamRole.toString() }); } interaction.reply({ embeds: [jamEmbed(jam, jamKey, "(edit)")], ephemeral: true }); @@ -120,12 +127,9 @@ export async function deleteJam(interaction: CommandInteraction, jam: Jam, jamKe jamDb.delete(jamKey); const proposal = proposalDb.get(jam.proposal)!; - proposal.used = false; proposalDb.set(jam.proposal, proposal); - if (jam.eventID) { - interaction.guild?.scheduledEvents.delete(jam.eventID); - } + if (jam.scheduledEventID) interaction.guild?.scheduledEvents.delete(jam.scheduledEventID); for (const key of jamEventsDb.filter((e) => e.jamID === jamKey).keyArray()) { jamEventsDb.delete(key); diff --git a/src/util/coding-jams/managePoll.ts b/src/util/coding-jams/managePoll.ts index e243ad8..6c62c9a 100644 --- a/src/util/coding-jams/managePoll.ts +++ b/src/util/coding-jams/managePoll.ts @@ -24,9 +24,7 @@ export async function newPoll( return; } - const unused = unusedProposals(); - - if (unused.size < 2) { + if (proposalDb.size < 2) { interaction.reply({ content: "There simply aren't enough proposals to create a poll...", ephemeral: true, @@ -36,12 +34,12 @@ export async function newPoll( // check numVotes and numProposals if (numVotes > numProposals) numVotes = numProposals; - if (unused.size < numProposals) { - numProposals = unused.size; - numVotes = unused.size; + if (proposalDb.size < numProposals) { + numProposals = proposalDb.size; + numVotes = proposalDb.size; } - const sorted = sortBySelectionType(unused, selectionType); + const sorted = sortBySelectionType(proposalDb, selectionType); const proposals = sorted.slice(0, numProposals); const poll: Poll = { @@ -108,7 +106,7 @@ export async function editPoll(interaction: CommandInteraction, poll: Poll, poll }); } - const sorted = sortBySelectionType(unusedProposals(), poll.selectionType); + const sorted = sortBySelectionType(proposalDb, poll.selectionType); await interaction.reply({ embeds: [pollEmbed(poll, pollKey, "(edit)")], @@ -268,7 +266,3 @@ export function pollSelectMenus( ), ]; } - -export function unusedProposals() { - return proposalDb.filter((v) => v.used === false); -}