pnp-scheduler/source/Discord/Commands/Playdates.ts

215 lines
No EOL
7.9 KiB
TypeScript

import {
SlashCommandBuilder,
Interaction,
CommandInteraction,
AutocompleteInteraction,
GuildMember,
EmbedBuilder, MessageFlags, ChatInputCommandInteraction, ModalSubmitFields, time, User
} from "discord.js";
import {AutocompleteCommand, ChatInteractionCommand, Command} from "./Command";
import {Container} from "../../Container/Container";
import {GroupRepository} from "../../Repositories/GroupRepository";
import {GroupSelection} from "../CommandPartials/GroupSelection";
import {setFlagsFromString} from "node:v8";
import {UserError} from "../UserError";
import Playdate from "../../Database/tables/Playdate";
import {PlaydateModel} from "../../Models/PlaydateModel";
import {PlaydateRepository} from "../../Repositories/PlaydateRepository";
import {GroupModel} from "../../Models/GroupModel";
import playdate from "../../Database/tables/Playdate";
export class PlaydatesCommand implements Command, AutocompleteCommand, ChatInteractionCommand {
static REGEX = [
]
definition(): SlashCommandBuilder {
// @ts-ignore
return new SlashCommandBuilder()
.setName("playdates")
.setDescription("Manage your playdates")
.addSubcommand((subcommand) => subcommand
.setName("create")
.setDescription("Creates a new playdate")
.addIntegerOption(GroupSelection.createOptionSetup())
.addStringOption((option) => option
.setName("from")
.setDescription("Defines the start date & time. Format: YYYY-MM-DD HH:mm")
)
.addStringOption((option) => option
.setName("to")
.setDescription("Defines the end date & time. Format: YYYY-MM-DD HH:mm")
)
.addAttachmentOption((option) => option
.setName("calendar-entry")
.setDescription("Optional, you can upload a iCal file and the from and to-values are read from it.")
)
)
.addSubcommand((subcommand) => subcommand
.setName("list")
.setDescription("Lists all playdates")
.addIntegerOption(GroupSelection.createOptionSetup())
)
.addSubcommand((subcommand) => subcommand
.setName("remove")
.setDescription("Removes a playdate")
.addIntegerOption(GroupSelection.createOptionSetup())
.addIntegerOption((option) => option
.setName("playdate")
.setDescription("Selects a playdate")
.setRequired(true)
.setAutocomplete(true)
)
);
}
async execute(interaction: ChatInputCommandInteraction): Promise<void> {
const group = GroupSelection.getGroup(interaction);
switch (interaction.options.getSubcommand()) {
case "create":
await this.create(interaction, group);
break;
case "remove":
await this.delete(interaction, group);
break;
case "list":
await this.list(interaction, group);
break;
default:
throw new UserError("This subcommand is not yet implemented.");
}
}
async create(interaction: CommandInteraction, group: GroupModel): Promise<void> {
const fromDate = Date.parse(<string>interaction.options.get("from")?.value ?? '');
const toDate = Date.parse(<string>interaction.options.get("to")?.value ?? '');
if (isNaN(fromDate)) {
throw new UserError("No date or invalid date format for the from parameter.");
}
if (isNaN(toDate)) {
throw new UserError("No date or invalid date format for the to parameter.");
}
if (fromDate > toDate) {
throw new UserError("The to-date can't be earlier than the from-date");
}
const playdateRepo = Container.get<PlaydateRepository>(PlaydateRepository.name);
const collidingTimes = playdateRepo.findPlaydatesInRange(fromDate, toDate, group);
if (collidingTimes.length > 0) {
throw new UserError("The playdate collides with another playdate. Please either remove the old one or choose a different time.")
}
const playdate: Partial<PlaydateModel> = {
group: group,
from_time: new Date(fromDate),
to_time: new Date(toDate),
}
const id = playdateRepo.create(playdate);
const embed = new EmbedBuilder()
.setTitle("Created a play-date.")
.setDescription(":white_check_mark: Your playdate has been created! You and your group get notified, when its time.")
.setFields({
name: "Created playdate",
value: `${time(new Date(fromDate),'F')} - ${time(new Date(toDate), 'F')}`,
})
.setFooter({
text: `Group: ${group.name}`
})
await interaction.reply({
embeds: [
embed
],
flags: MessageFlags.Ephemeral,
})
}
async handleAutocomplete(interaction: AutocompleteInteraction): Promise<void> {
const option = interaction.options.getFocused(true);
if (option.name == "group") {
await GroupSelection.handleAutocomplete(interaction);
return;
}
if (option.name != 'playdate') {
return;
}
const group = GroupSelection.getGroup(interaction);
const playdates = Container.get<PlaydateRepository>(PlaydateRepository.name).findFromGroup(group);
await interaction.respond(
playdates.map(playdate => {
return {
name: `${playdate.from_time.toLocaleString()} - ${playdate.to_time.toLocaleString()}`,
value: playdate.id
}
})
)
}
private async list(interaction: ChatInputCommandInteraction, group: GroupModel) {
const playdates = Container.get<PlaydateRepository>(PlaydateRepository.name).findFromGroup(group);
const embed = new EmbedBuilder()
.setTitle("The next playdates:")
.setFields(
playdates.map((playdate) =>
{
return {
name: `${time(playdate.from_time, 'F')} - ${time(playdate.to_time, 'F')}`,
value: `${time(playdate.from_time, 'R')}`
}
})
)
.setFooter({
text: `Group: ${group.name}`
})
await interaction.reply({
embeds: [
embed
],
flags: MessageFlags.Ephemeral,
})
}
private async delete(interaction: ChatInputCommandInteraction, group: GroupModel): Promise<void> {
const playdateId = interaction.options.getInteger("playdate", true)
const repo = Container.get<PlaydateRepository>(PlaydateRepository.name);
const selected = repo.getById(playdateId);
if (!selected) {
throw new UserError("No playdate found");
}
if (selected.group?.id != group.id) {
throw new UserError("No playdate found");
}
repo.delete(playdateId);
const embed = new EmbedBuilder()
.setTitle("Playdate deleted")
.setDescription(
`:x: Deleted \`${selected.from_time.toLocaleString()} - ${selected.to_time.toLocaleString()}\``
)
.setFooter({
text: `Group: ${group.name}`
})
await interaction.reply({
embeds: [
embed
],
flags: MessageFlags.Ephemeral,
})
}
}