(core): fix commands, events & database.

This commit is contained in:
2026-08-26 13:27:20 +08:00
parent eaf05aebc3
commit eb5754d60a
8 changed files with 90 additions and 30 deletions
+2 -1
View File
@@ -1,4 +1,5 @@
import init from "./init";
import optin from "./optin"; import optin from "./optin";
import optout from "./optout"; import optout from "./optout";
export default [optin, optout]; export default [init, optin, optout];
+43
View File
@@ -0,0 +1,43 @@
import { Command, CommandBuilder, CommandClient, CommandInteraction, Constants, SlashCommand } from "athena-prime";
import config from "../config";
@SlashCommand(
new CommandBuilder('init', 'Event setup command.')
.setIntegrationTypes(Constants.ApplicationIntegrationType.GuildInstall)
.setContexts(Constants.InteractionContextType.Guild)
.setCommandType(Constants.ApplicationCommandType.ChatInput)
)
class InitCommand extends Command<CommandClient> {
users = ['1363132678022631428'];
async handleCommand(context: CommandClient<any, any>, interaction: CommandInteraction) {
await context.createMessage(interaction.channel.id, {
embed: {
color: 0xe77ed1,
title: 'Pet the Pond!',
description: `
There's a Pond that needs petting, and a leaderboard to show off your level of appreciation.
**How does it work?**
On any message sent by <@${config.identifiers.targetId}>, react with the <:pet:448912932340891670> emoji to receive a point.
**What do you get?**
You get appreciation and proof you appreciate Pond the most.
**What if I don't want to be involved?**
You can opt in & out using the \`/optin\` & \`/optout\` commands.
`,
footer: {
text: `Made by nxbat @ Archwing`,
icon_url: 'https://femboytrain.ing/nxbat-archwing'
}
}
});
await interaction.createMessage({ content: 'Done.', flags: Constants.MessageFlags.Ephemeral });
}
}
export default new InitCommand('init');
+6 -4
View File
@@ -1,5 +1,5 @@
import { Command, CommandBuilder, CommandClient, CommandInteraction, Constants, SlashCommand } from "athena-prime"; import { Command, CommandBuilder, CommandClient, CommandInteraction, Constants, SlashCommand } from "athena-prime";
import { setUserPrivacy } from "../utils"; import { getUser, setUserPrivacy } from "../utils";
@SlashCommand( @SlashCommand(
new CommandBuilder('optin', 'Opt into the Pet the Pond event.') new CommandBuilder('optin', 'Opt into the Pet the Pond event.')
@@ -11,11 +11,13 @@ class OptInCommand extends Command<CommandClient> {
cooldown = 5; cooldown = 5;
async handleCommand(context: CommandClient<any, any>, interaction: CommandInteraction) { async handleCommand(context: CommandClient<any, any>, interaction: CommandInteraction) {
await setUserPrivacy(interaction.member.id, { optin: true }); await interaction.defer(true);
const _user = await getUser(interaction.user.id);
await setUserPrivacy(_user.user_id, { optin: true });
await interaction.createMessage({ await interaction.createMessage({
content: "Successfully opted in. Interactions will be acknowledged.", content: "Successfully opted in. You'll receive points for your pets!",
flags: Constants.MessageFlags.Ephemeral
}); });
} }
} }
+6 -4
View File
@@ -1,5 +1,5 @@
import { Command, CommandBuilder, CommandClient, CommandInteraction, Constants, SlashCommand } from "athena-prime"; import { Command, CommandBuilder, CommandClient, CommandInteraction, Constants, SlashCommand } from "athena-prime";
import { setUserPrivacy } from "../utils"; import { getUser, setUserPrivacy } from "../utils";
@SlashCommand( @SlashCommand(
new CommandBuilder('optout', 'Opt out of the Pet the Pond event.') new CommandBuilder('optout', 'Opt out of the Pet the Pond event.')
@@ -11,11 +11,13 @@ class OptOutCommand extends Command<CommandClient> {
cooldown = 5; cooldown = 5;
async handleCommand(context: CommandClient<any, any>, interaction: CommandInteraction) { async handleCommand(context: CommandClient<any, any>, interaction: CommandInteraction) {
await setUserPrivacy(interaction.member.id, { optin: false }); await interaction.defer(true);
const _user = await getUser(interaction.user.id);
await setUserPrivacy(_user.user_id, { optin: false });
await interaction.createMessage({ await interaction.createMessage({
content: "Successfully opted out. Interactions will not be acknowledged.", content: "Successfully opted out. You won't receive any points for petting :<"
flags: Constants.MessageFlags.Ephemeral
}); });
} }
} }
+1 -1
View File
@@ -14,7 +14,7 @@ class MessageReactionAddEvent extends Event<CommandClient> {
const _user = await getUser(member.id); const _user = await getUser(member.id);
if (!_user.privacy.optin) return; if (!_user.privacy.optin) return;
await setUserXp(member.id, { current: _user.xp.current + 1 }); await setUserXp(_user.user_id, { current: _user.xp.current + 1 });
} }
} }
+2 -2
View File
@@ -12,9 +12,9 @@ class MessageReactionRemoveEvent extends Event<CommandClient> {
if (msg.author.id !== config.identifiers.targetId || emoji.id !== config.identifiers.emojiId) return; if (msg.author.id !== config.identifiers.targetId || emoji.id !== config.identifiers.emojiId) return;
const _user = await getUser(userId); const _user = await getUser(userId);
if (!_user.privacy.optin) return; if (!_user.privacy.optin || _user.xp.current <= 0) return;
await setUserXp(userId, { current: _user.xp.current - 1 }); await setUserXp(_user.user_id, { current: _user.xp.current - 1 });
} }
} }
+2 -2
View File
@@ -28,8 +28,8 @@ const client: CommandClient = new CommandClient({
}, },
}); });
commands.forEach(command => client.registerCommand(command)); commands.forEach(command => client.registerCommand(command, true));
events.forEach(event => client.registerEvent(event)); events.forEach(event => client.registerEvent(event, true));
// ---------- // ----------
+25 -13
View File
@@ -1,38 +1,50 @@
import postgres from "postgres"; import postgres from "postgres";
import { User } from "../types"; import { User } from "../types";
// ----------
const client = postgres(process.env.DATABASE_URL); const client = postgres(process.env.DATABASE_URL);
const getDefaultUser = (userId: string): User => ({ const getDefaultUser = (userId: string): User => ({
user_id: userId, user_id: userId,
privacy: { privacy: {
optin: true, optin: true,
}, },
xp: { xp: {
current: 0 current: 0
}, },
}); });
export async function getUser(userId: string): Promise<User> { export async function getUser(userId: string): Promise<User> {
const [user] = await client<{ user_id: string; data: User }[]>` let [user] = await client<{ user_id: string; data: User }[]>`
SELECT user_id, data
FROM users
WHERE user_id = ${userId}
`;
if (!user) {
const defaultUser = getDefaultUser(userId);
[user] = await client<{ user_id: string; data: User }[]>`
INSERT INTO users (user_id, data) INSERT INTO users (user_id, data)
VALUES (${userId}, ${JSON.stringify(getDefaultUser(userId))}::jsonb) VALUES (${userId}, ${client.json(defaultUser)})
ON CONFLICT (user_id) ON CONFLICT (user_id)
DO UPDATE SET user_id = EXCLUDED.user_id DO NOTHING
RETURNING user_id, data RETURNING user_id, data
`; `;
if (!user) {
[user] = await client<{ user_id: string; data: User }[]>`
SELECT user_id, data FROM users WHERE user_id = ${userId}
`;
}
}
return user.data; return user.data;
} }
export async function setUser(user: User): Promise<void> { export async function setUser(user: User): Promise<void> {
await client` await client`
INSERT INTO users (user_id, data) INSERT INTO users (user_id, data)
VALUES (${user.user_id}, ${JSON.stringify(user)}::jsonb) VALUES (${user.user_id}, ${client.json(user)})
ON CONFLICT (user_id) ON CONFLICT (user_id)
DO UPDATE SET data = EXCLUDED.data DO UPDATE SET data = EXCLUDED.data
`; `;
@@ -41,22 +53,22 @@ export async function setUser(user: User): Promise<void> {
export async function deleteUser(userId: string): Promise<void> { export async function deleteUser(userId: string): Promise<void> {
await client` await client`
DELETE FROM users DELETE FROM users
WHERE user_id = '${userId}' WHERE user_id = ${userId}
`; `;
} }
export async function setUserPrivacy(userId: string, privacy: User["privacy"]): Promise<void> { export async function setUserPrivacy(userId: string, privacy: User["privacy"]): Promise<void> {
await client` await client`
UPDATE users UPDATE users
SET data = jsonb_set(data, '{privacy}', ${JSON.stringify(privacy)}::jsonb) SET data = jsonb_set(data, '{privacy}', ${client.json(privacy)})
WHERE user_id = '${userId}' WHERE user_id = ${userId}
`; `;
} }
export async function setUserXp(userId: string, xp: User["xp"]): Promise<void> { export async function setUserXp(userId: string, xp: User["xp"]): Promise<void> {
await client` await client`
UPDATE users UPDATE users
SET data = jsonb_set(data, '{xp}', ${JSON.stringify(xp)}::jsonb) SET data = jsonb_set(data, '{xp}', ${client.json(xp)})
WHERE user_id = '${userId}' WHERE user_id = ${userId}
`; `;
} }