Skip to content
Merged
Show file tree
Hide file tree
Changes from 5 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
2 changes: 1 addition & 1 deletion .github/workflows/test.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ jobs:
uses: actions/checkout@v3
- uses: actions/setup-node@v3
with:
node-version: 16.18.1
node-version: 20.12.2

- name: Cache npm dependencies
uses: actions/cache@v3
Expand Down
2 changes: 1 addition & 1 deletion .nvmrc
Original file line number Diff line number Diff line change
@@ -1 +1 @@
16.18.1
20.12.2
2 changes: 1 addition & 1 deletion .vscode/settings.json
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
"**/dist": true
},
"editor.codeActionsOnSave": {
"source.fixAll.eslint": true
"source.fixAll.eslint": "always"
},
"deno.enable": false
}
4 changes: 2 additions & 2 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
FROM node:16.18.1-slim AS deps
FROM node:20.12.2-slim AS deps

WORKDIR /app

Expand All @@ -10,7 +10,7 @@ COPY src ./src
RUN yarn install --frozen-lockfile
RUN npm run build

FROM node:16.18.1-slim
FROM node:20.12.2-slim

WORKDIR /app

Expand Down
55 changes: 27 additions & 28 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,10 @@
"main": "index.js",
"type": "module",
"engines": {
"node": "16.18.1"
"node": "20.12.2"
},
"scripts": {
"dev": "cross-env TS_NODE_FILES=true TS_NODE_PROJECT=\"./tsconfig.json\" nodemon -r dotenv/config -x node --experimental-specifier-resolution=node --loader ts-node/esm ./src/index.ts",
"dev": "tsx watch -r dotenv/config ./src/index.ts",
"start": "node build/index.js",
"build": "tsc",
"lint": "eslint src && tsc --noEmit",
Expand All @@ -23,41 +23,40 @@
"author": "",
"license": "ISC",
"dependencies": {
"@mdn/browser-compat-data": "5.2.17",
"@sentry/node": "7.20.0",
"compare-versions": "4.1.3",
"@mdn/browser-compat-data": "5.5.49",
"@sentry/node": "8.27.0",
"compare-versions": "6.1.1",
"cross-env": "^7.0.3",
"date-fns": "2.28.0",
"discord.js": "13.8.1",
"dom-parser": "0.1.6",
"date-fns": "3.6.0",
"discord.js": "14.15.3",
"dom-parser": "1.1.5",
"domyno": "1.0.1",
"fuse.js": "6.6.2",
"html-entities": "2.3.3",
"fuse.js": "7.0.0",
"html-entities": "2.5.2",
"lodash-es": "4.17.21",
"mongoose": "6.4.6",
"mongoose": "8.5.4",
"node-cache": "5.1.2",
"node-fetch": "3.2.10",
"node-html-parser": "5.3.3",
"ts-node": "10.9.1",
"typescript": "4.7.4"
"node-fetch": "3.3.2",
"node-html-parser": "6.1.13",
"typescript": "5.5.4"
},
"devDependencies": {
"@sentry/types": "7.20.0",
"@types/dom-parser": "0.1.1",
"@sentry/types": "8.27.0",
"@types/dom-parser": "0.1.4",
"@types/html-entities": "1.3.4",
"@types/jest": "28.1.8",
"@types/jest": "29.5.12",
"@types/mongoose": "5.11.97",
"@types/node": "18.0.0",
"@types/node": "22.5.0",
"@types/node-fetch": "3.0.3",
"dotenv": "16.0.1",
"eslint-config-galex": "4.3.2",
"eslint": "8.28.0",
"husky": "8.0.1",
"jest": "28.1.3",
"lint-staged": "13.0.3",
"nodemon": "2.0.20",
"prettier": "2.7.1",
"ts-jest": "28.0.8"
"dotenv": "16.4.5",
"eslint": "8.57.0",
"eslint-config-galex": "4.5.2",
"husky": "9.1.5",
"jest": "29.7.0",
"lint-staged": "15.2.9",
"prettier": "3.3.3",
"ts-jest": "29.2.5",
"tsx": "^4.19.0"
},
"husky": {
"hooks": {
Expand Down
3 changes: 2 additions & 1 deletion src/types.d.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,13 @@
import type {
ChatInputApplicationCommandData,
ChatInputCommandInteraction,
Client,
CommandInteraction,
Guild,
} from 'discord.js';

export type CommandDataWithHandler = ChatInputApplicationCommandData & {
handler: (client: Client, interaction: CommandInteraction) => Promise<void>;
handler: (client: Client, interaction: ChatInputCommandInteraction) => Promise<void>;
onAttach?: (client: Client) => void;
guildValidate?: (guild: Guild) => boolean;
};
56 changes: 26 additions & 30 deletions src/v2/autorespond/thanks/createResponse.ts
Original file line number Diff line number Diff line change
@@ -1,30 +1,29 @@
import { MessageButton } from 'discord.js';
import { MessageActionRow, MessageSelectMenu } from 'discord.js';
import type { User, MessageOptions } from 'discord.js';
import type { EmbedField, Collection } from 'discord.js';
import { ButtonBuilder, MessageReplyOptions } from 'discord.js';
import { ActionRowBuilder, UserSelectMenuBuilder } from 'discord.js';
import { User, MessagePayload, ButtonStyle } from 'discord.js';
import type { EmbedField, Collection, MessageActionRowComponentBuilder } from 'discord.js';

import { clampLength } from '../../utils/clampStr.js';
import { createEmbed } from '../../utils/discordTools.js';

export function createResponse(
thankedUsers: Collection<string, User>,
authorId: string
): MessageOptions {
): MessageReplyOptions {
const title = `Point${thankedUsers.size === 1 ? '' : 's'} received!`;

const description = `<@!${authorId}> has given a point to ${
thankedUsers.size === 1
? `<@!${thankedUsers.first().id}>`
: 'the users mentioned below'
}!`;
const description = `<@!${authorId}> has given a point to ${thankedUsers.size === 1
? `<@!${thankedUsers.first().id}>`
: 'the users mentioned below'
}!`;

const fields: EmbedField[] =
thankedUsers.size > 1
? [...thankedUsers].map(([, u], i) => ({
inline: false,
name: `${(i + 1).toString()}.`,
value: `<@!${u.id}>`,
}))
inline: false,
name: `${(i + 1).toString()}.`,
value: `<@!${u.id}>`,
}))
: [];

const output = createEmbed({
Expand All @@ -39,23 +38,20 @@ export function createResponse(
return {
embeds: [output],
components: [
new MessageActionRow().addComponents(
new ActionRowBuilder<MessageActionRowComponentBuilder>().addComponents(
thankedUsers.size > 1
? new MessageSelectMenu()
.setCustomId(`thanks🤔${authorId}🤔select`)
.setPlaceholder('Accidentally Thank someone? Un-thank them here!')
.setMinValues(1)
.setOptions(
thankedUsers.map(user => ({
label: clampLength(user.username, 25),
value: user.id,
}))
)
: new MessageButton()
.setCustomId(`thanks🤔${authorId}🤔${thankedUsers.first().id}`)
.setStyle('SECONDARY')
.setLabel('This was an accident, UNDO!')
? new UserSelectMenuBuilder()
.setCustomId(`thanks🤔${authorId}🤔select`)
.setPlaceholder('Accidentally Thank someone? Un-thank them here!')
.setMinValues(1)
.setDefaultUsers(
...thankedUsers.keys()
)
: new ButtonBuilder()
.setCustomId(`thanks🤔${authorId}🤔${thankedUsers.first().id}`)
.setStyle(ButtonStyle.Secondary)
.setLabel('This was an accident, UNDO!')
),
],
};
}
}
8 changes: 3 additions & 5 deletions src/v2/autorespond/thanks/db_model.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,7 @@
import type { Document } from 'mongoose';
import mongoose from 'mongoose';
import { Schema, model } from 'mongoose';

const { model, Schema } = mongoose;

const schema = new Schema(
const schema = new Schema<ThanksInteractionType>(
{
guild: {
required: true,
Expand Down Expand Up @@ -34,7 +32,7 @@ export const ThanksInteraction = model<ThanksInteractionType>(
'thanksMessageInteraction',
schema
);
export type ThanksInteractionType = Document & {
export type ThanksInteractionType = {
guild: string;
thanker: string;
channel: string;
Expand Down
42 changes: 25 additions & 17 deletions src/v2/autorespond/thanks/index.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { MessageActionRow, MessageSelectMenu } from 'discord.js';
import type { Message, TextChannel } from 'discord.js';
import { ActionRowBuilder, ChannelType, EmbedBuilder, MessageActionRowComponentBuilder, StringSelectMenuBuilder, } from 'discord.js';
import { ComponentType, Message, TextChannel } from 'discord.js';
import type { Client } from 'discord.js';

import { POINT_LIMITER_IN_MINUTES } from '../../env.js';
Expand Down Expand Up @@ -41,7 +41,7 @@ const handleThanks = async (msg: Message): Promise<void> => {
const reply = await getReply(msg);
if (botId || (msg.mentions.users.size === 0 && !reply)) {
if (
['GUILD_PRIVATE_THREAD','GUILD_PUBLIC_THREAD'].includes(msg.channel.type)
[ChannelType.PrivateThread, ChannelType.PublicThread].includes(msg.channel.type)
) {
await handleThreadThanks(msg);
}
Expand Down Expand Up @@ -118,9 +118,8 @@ const handleThanks = async (msg: Message): Promise<void> => {
value: `<@!${u.id}>\n${diff} minute${diff === 1 ? '' : 's'}.`,
};
}),
footerText: `You can only give a point to a user every ${POINT_LIMITER_IN_MINUTES} minute${
Number.parseInt(POINT_LIMITER_IN_MINUTES) === 1 ? '' : 's'
}.`,
footerText: `You can only give a point to a user every ${POINT_LIMITER_IN_MINUTES} minute${Number.parseInt(POINT_LIMITER_IN_MINUTES) === 1 ? '' : 's'
}.`,
provider: 'spam',
title: 'Cooldown alert!',
}).embed,
Expand Down Expand Up @@ -149,7 +148,7 @@ const handleThanks = async (msg: Message): Promise<void> => {

function attachUndoThanksListener(client: Client): void {
client.on('interactionCreate', async interaction => {
if (!(interaction.isButton() || interaction.isSelectMenu())) {
if (!(interaction.isButton() || interaction.isStringSelectMenu())) {
return;
}
const id = interaction.customId;
Expand All @@ -170,7 +169,7 @@ function attachUndoThanksListener(client: Client): void {

await interaction.deferReply({ ephemeral: true });

const thanksInteraction: ThanksInteractionType =
const thanksInteraction =
await ThanksInteraction.findOne({
responseMsgId: msgId,
});
Expand Down Expand Up @@ -209,23 +208,32 @@ function attachUndoThanksListener(client: Client): void {
)) as TextChannel;
if (thanksInteraction.thankees.length === 0) {
textChannel.messages.delete(thanksInteraction.responseMsgId);
thanksInteraction.delete();
ThanksInteraction.deleteOne({ _id: thanksInteraction._id })
} else {
const oldMsg = await textChannel.messages.fetch(msgId);
oldMsg.embeds[0].fields = oldMsg.embeds[0].fields
.filter(item => !removeThankees.includes(item.value.slice(3, -1)))
.map((item, x) => ({ ...item, name: `${x + 1}` }));

const oldSelect = oldMsg.components[0].components[0] as MessageSelectMenu;
const updatedEmbeds = [
new EmbedBuilder(
oldMsg.embeds[0]
).setFields(
oldMsg.embeds[0].fields
.filter(item => !removeThankees.includes(item.value.slice(3, -1)))
.map((item, x) => ({ ...item, name: `${x + 1}` }))
),
...oldMsg.embeds.slice(1)
]


const oldSelect = oldMsg.components[0].components[0];
if (oldSelect.type !== ComponentType.StringSelect) throw new Error()
const nuOptions = oldSelect.options
.filter(item => !removeThankees.includes(item.value))
.map(({ label, value }) => ({ label, value }));

oldMsg.edit({
embeds: oldMsg.embeds,
embeds: updatedEmbeds,
components: [
new MessageActionRow().addComponents(
new MessageSelectMenu(oldSelect)
new ActionRowBuilder<MessageActionRowComponentBuilder>().addComponents(
new StringSelectMenuBuilder(oldSelect)
.setOptions(nuOptions)
.setMaxValues(nuOptions.length)
),
Expand Down
Loading
Loading