mirror of
https://github.com/ahmadk953/poixpixel-discord-bot.git
synced 2025-04-01 01:04:16 +00:00
Fixes and Improvements
This commit is contained in:
parent
4c5a8d2e66
commit
82f354db1c
12 changed files with 137 additions and 105 deletions
|
@ -99,7 +99,7 @@ export default [
|
|||
"no-var": "error",
|
||||
"object-curly-spacing": ["error", "always"],
|
||||
"prefer-const": "error",
|
||||
quotes: ["warning", "single"],
|
||||
quotes: ["warn", "single"],
|
||||
semi: ["error", "always"],
|
||||
"space-before-blocks": "error",
|
||||
|
||||
|
|
|
@ -30,5 +30,5 @@
|
|||
"tsx": "^4.19.2",
|
||||
"typescript": "^5.7.2"
|
||||
},
|
||||
"packageManager": "yarn@4.5.2"
|
||||
"packageManager": "yarn@4.5.3"
|
||||
}
|
||||
|
|
|
@ -1,22 +1,29 @@
|
|||
import { SlashCommandBuilder, CommandInteraction, EmbedBuilder } from "discord.js";
|
||||
import { getAllMembers } from "../util/db.js";
|
||||
import {
|
||||
SlashCommandBuilder,
|
||||
CommandInteraction,
|
||||
EmbedBuilder,
|
||||
} from 'discord.js';
|
||||
import { getAllMembers } from '../util/db.js';
|
||||
|
||||
interface Command {
|
||||
data: Omit<SlashCommandBuilder, "addSubcommand" | "addSubcommandGroup">;
|
||||
data: Omit<SlashCommandBuilder, 'addSubcommand' | 'addSubcommandGroup'>;
|
||||
execute: (interaction: CommandInteraction) => Promise<void>;
|
||||
}
|
||||
|
||||
const command: Command = {
|
||||
data: new SlashCommandBuilder()
|
||||
.setName("members")
|
||||
.setDescription("Lists all non-bot members of the server"),
|
||||
.setName('members')
|
||||
.setDescription('Lists all non-bot members of the server'),
|
||||
execute: async (interaction) => {
|
||||
const members = await getAllMembers();
|
||||
const memberList = members.map(m => `**${m.discordUsername}** (${m.discordId})`).join("\n");
|
||||
const memberList = members
|
||||
.map((m) => `**${m.discordUsername}** (${m.discordId})`)
|
||||
.join('\n');
|
||||
const membersEmbed = new EmbedBuilder()
|
||||
.setTitle("Members")
|
||||
.setTitle('Members')
|
||||
.setDescription(memberList)
|
||||
.setColor(0x0099ff);
|
||||
.setColor(0x0099ff)
|
||||
.addFields({ name: 'Total Members', value: members.length.toString() });
|
||||
await interaction.reply({ embeds: [membersEmbed] });
|
||||
},
|
||||
};
|
||||
|
|
|
@ -1,14 +1,14 @@
|
|||
import { SlashCommandBuilder, CommandInteraction } from "discord.js";
|
||||
import { SlashCommandBuilder, CommandInteraction } from 'discord.js';
|
||||
|
||||
interface Command {
|
||||
data: Omit<SlashCommandBuilder, "addSubcommand" | "addSubcommandGroup">;
|
||||
data: Omit<SlashCommandBuilder, 'addSubcommand' | 'addSubcommandGroup'>;
|
||||
execute: (interaction: CommandInteraction) => Promise<void>;
|
||||
}
|
||||
|
||||
const command: Command = {
|
||||
data: new SlashCommandBuilder()
|
||||
.setName("ping")
|
||||
.setDescription("Check the latency from you to the bot"),
|
||||
.setName('ping')
|
||||
.setDescription('Check the latency from you to the bot'),
|
||||
execute: async (interaction) => {
|
||||
await interaction.reply(`Pong! Latency: ${Date.now() - interaction.createdTimestamp}ms`);
|
||||
},
|
||||
|
|
|
@ -2,107 +2,107 @@ import {
|
|||
SlashCommandBuilder,
|
||||
CommandInteraction,
|
||||
EmbedBuilder,
|
||||
} from "discord.js";
|
||||
} from 'discord.js';
|
||||
|
||||
interface Command {
|
||||
data: Omit<SlashCommandBuilder, "addSubcommand" | "addSubcommandGroup">;
|
||||
data: Omit<SlashCommandBuilder, 'addSubcommand' | 'addSubcommandGroup'>;
|
||||
execute: (interaction: CommandInteraction) => Promise<void>;
|
||||
}
|
||||
|
||||
const rulesEmbed = new EmbedBuilder()
|
||||
.setColor(0x0099ff)
|
||||
.setTitle("Server Rules")
|
||||
.setTitle('Server Rules')
|
||||
.setAuthor({
|
||||
name: "Poixixel",
|
||||
name: 'Poixixel',
|
||||
iconURL:
|
||||
"https://cdn.discordapp.com/avatars/1052017329376071781/922947c726d7866d313744186c42ef49.webp",
|
||||
'https://cdn.discordapp.com/avatars/1052017329376071781/922947c726d7866d313744186c42ef49.webp',
|
||||
})
|
||||
.setDescription(
|
||||
"These are the rules for the server. Please read and follow them carefully."
|
||||
'These are the rules for the server. Please read and follow them carefully.'
|
||||
)
|
||||
.addFields(
|
||||
{
|
||||
name: "**Rule #1: Be respectful**",
|
||||
name: '**Rule #1: Be respectful**',
|
||||
value:
|
||||
"Treat everyone with kindness. No harassment, bullying, hate speech, or toxic behavior.",
|
||||
'Treat everyone with kindness. No harassment, bullying, hate speech, or toxic behavior.',
|
||||
},
|
||||
{
|
||||
name: "**Rule #2: Keep it Family-Friendly**",
|
||||
name: '**Rule #2: Keep it Family-Friendly**',
|
||||
value:
|
||||
"No explicit content, including NSFW images, language, or discussions. This is a safe space for everyone.",
|
||||
'No explicit content, including NSFW images, language, or discussions. This is a safe space for everyone.',
|
||||
},
|
||||
{
|
||||
name: "**Rule #3: Use Common Sense**",
|
||||
name: '**Rule #3: Use Common Sense**',
|
||||
value:
|
||||
"Think before you act or post. If something seems questionable, it’s probably best not to do it.",
|
||||
'Think before you act or post. If something seems questionable, it’s probably best not to do it.',
|
||||
},
|
||||
{
|
||||
name: "**Rule #4: No Spamming**",
|
||||
name: '**Rule #4: No Spamming**',
|
||||
value:
|
||||
"Avoid excessive messages, emoji use, or CAPS LOCK. Keep the chat clean and readable.",
|
||||
'Avoid excessive messages, emoji use, or CAPS LOCK. Keep the chat clean and readable.',
|
||||
},
|
||||
{
|
||||
name: "**Rule #5: No Raiding**",
|
||||
name: '**Rule #5: No Raiding**',
|
||||
value:
|
||||
"Do not disrupt the server or other servers with spam, unwanted content, or malicious behavior.",
|
||||
'Do not disrupt the server or other servers with spam, unwanted content, or malicious behavior.',
|
||||
},
|
||||
{
|
||||
name: "**Rule #6: No Self-Promotion**",
|
||||
name: '**Rule #6: No Self-Promotion**',
|
||||
value:
|
||||
"Do not advertise your own content or other servers without permission from staff.",
|
||||
'Do not advertise your own content or other servers without permission from staff.',
|
||||
},
|
||||
{
|
||||
name: "**Rule #7: No Impersonation**",
|
||||
name: '**Rule #7: No Impersonation**',
|
||||
value:
|
||||
"Do not pretend to be someone else, including staff or other members.",
|
||||
'Do not pretend to be someone else, including staff or other members.',
|
||||
},
|
||||
{
|
||||
name: "**Rule #8: No Violence**",
|
||||
name: '**Rule #8: No Violence**',
|
||||
value:
|
||||
"Do not post or share content that is offensive, harmful, or contains violent or dangerous content.",
|
||||
'Do not post or share content that is offensive, harmful, or contains violent or dangerous content.',
|
||||
},
|
||||
{
|
||||
name: "**Rule #9: No Doxxing or Sharing Personal Information**",
|
||||
name: '**Rule #9: No Doxxing or Sharing Personal Information**',
|
||||
value:
|
||||
"Protect your privacy and the privacy of others. Do not share personal details.",
|
||||
'Protect your privacy and the privacy of others. Do not share personal details.',
|
||||
},
|
||||
{
|
||||
name: "**Rule #10: No Ping Abuse**",
|
||||
name: '**Rule #10: No Ping Abuse**',
|
||||
value:
|
||||
"Do not ping staff members unless it's absolutely necessary. Use pings responsibly for all members.",
|
||||
'Do not ping staff members unless it\'s absolutely necessary. Use pings responsibly for all members.',
|
||||
},
|
||||
{
|
||||
name: "**Rule #11: Use Appropriate Channels**",
|
||||
name: '**Rule #11: Use Appropriate Channels**',
|
||||
value:
|
||||
"Post content in the right channels. Off-topic content may be moved or deleted.",
|
||||
'Post content in the right channels. Off-topic content may be moved or deleted.',
|
||||
},
|
||||
{
|
||||
name: "**Rule #12: Follow Discord's ToS and Community Guidelines**",
|
||||
name: '**Rule #12: Follow Discord\'s ToS and Community Guidelines**',
|
||||
value:
|
||||
"All members must adhere to Discord’s Terms of Service and Community Guidelines.",
|
||||
'All members must adhere to Discord’s Terms of Service and Community Guidelines.',
|
||||
},
|
||||
{
|
||||
name: "**Rule #13: Moderator Discretion**",
|
||||
name: '**Rule #13: Moderator Discretion**',
|
||||
value:
|
||||
"Moderators reserve the right to moderate at their discretion. If you feel mistreated, please create a support ticket.",
|
||||
'Moderators reserve the right to moderate at their discretion. If you feel mistreated, please create a support ticket.',
|
||||
},
|
||||
{
|
||||
name: "**Disclaimer:**",
|
||||
name: '**Disclaimer:**',
|
||||
value:
|
||||
"**These rules may be updated at any time. It is your responsibility to review them regularly. Moderators and admins have the authority to enforce these rules and take appropriate action.**",
|
||||
'**These rules may be updated at any time. It is your responsibility to review them regularly. Moderators and admins have the authority to enforce these rules and take appropriate action.**',
|
||||
}
|
||||
)
|
||||
.setTimestamp()
|
||||
.setFooter({
|
||||
text: "Sent by the Poixpixel Bot",
|
||||
text: 'Sent by the Poixpixel Bot',
|
||||
iconURL:
|
||||
"https://cdn.discordapp.com/avatars/1052017329376071781/922947c726d7866d313744186c42ef49.webp",
|
||||
'https://cdn.discordapp.com/avatars/1052017329376071781/922947c726d7866d313744186c42ef49.webp',
|
||||
});
|
||||
|
||||
const command: Command = {
|
||||
data: new SlashCommandBuilder()
|
||||
.setName("rules")
|
||||
.setDescription("Sends the server rules"),
|
||||
.setName('rules')
|
||||
.setDescription('Sends the server rules'),
|
||||
execute: async (interaction) => {
|
||||
await interaction.reply({ embeds: [rulesEmbed] });
|
||||
},
|
||||
|
|
|
@ -1,17 +1,17 @@
|
|||
import { SlashCommandBuilder, CommandInteraction } from "discord.js";
|
||||
import { SlashCommandBuilder, CommandInteraction } from 'discord.js';
|
||||
|
||||
interface Command {
|
||||
data: Omit<SlashCommandBuilder, "addSubcommand" | "addSubcommandGroup">;
|
||||
data: Omit<SlashCommandBuilder, 'addSubcommand' | 'addSubcommandGroup'>;
|
||||
execute: (interaction: CommandInteraction) => Promise<void>;
|
||||
}
|
||||
|
||||
const command: Command = {
|
||||
data: new SlashCommandBuilder()
|
||||
.setName("server")
|
||||
.setDescription("Provides information about the server."),
|
||||
.setName('server')
|
||||
.setDescription('Provides information about the server.'),
|
||||
execute: async (interaction) => {
|
||||
await interaction.reply(
|
||||
`The server ${interaction?.guild?.name} has ${interaction?.guild?.memberCount} members and was created on ${interaction?.guild?.createdAt}. It is ${new Date().getFullYear() - interaction?.guild?.createdAt?.getFullYear()!} years old.`
|
||||
`The server ${interaction!.guild!.name} has ${interaction!.guild!.memberCount} members and was created on ${interaction!.guild!.createdAt}. It is ${new Date().getFullYear() - interaction!.guild!.createdAt.getFullYear()!} years old.`
|
||||
);
|
||||
},
|
||||
};
|
||||
|
|
|
@ -2,23 +2,24 @@ import {
|
|||
SlashCommandBuilder,
|
||||
CommandInteraction,
|
||||
GuildMember,
|
||||
} from "discord.js";
|
||||
} from 'discord.js';
|
||||
|
||||
interface Command {
|
||||
data: Omit<SlashCommandBuilder, "addSubcommand" | "addSubcommandGroup">;
|
||||
data: Omit<SlashCommandBuilder, 'addSubcommand' | 'addSubcommandGroup'>;
|
||||
execute: (interaction: CommandInteraction) => Promise<void>;
|
||||
}
|
||||
|
||||
const command: Command = {
|
||||
data: new SlashCommandBuilder()
|
||||
.setName("user")
|
||||
.setDescription("Provides information about the user."),
|
||||
.setName('user')
|
||||
.setDescription('Provides information about the user.'),
|
||||
execute: async (interaction) => {
|
||||
if (interaction.member instanceof GuildMember) {
|
||||
await interaction.reply(
|
||||
`This command was run by ${interaction.user.username}, who joined this server on ${interaction.member.joinedAt}.`
|
||||
);
|
||||
} else {
|
||||
}
|
||||
else {
|
||||
await interaction.reply(
|
||||
`This command was run by ${interaction.user.username}.`
|
||||
);
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
import { integer, pgTable, varchar } from "drizzle-orm/pg-core";
|
||||
import { integer, pgTable, varchar } from 'drizzle-orm/pg-core';
|
||||
|
||||
export const memberTable = pgTable("members", {
|
||||
export const memberTable = pgTable('members', {
|
||||
id: integer().primaryKey().generatedAlwaysAsIdentity(),
|
||||
discordId: varchar("discord_id").notNull().unique(),
|
||||
discordUsername: varchar("discord_username").notNull(),
|
||||
discordId: varchar('discord_id').notNull().unique(),
|
||||
discordUsername: varchar('discord_username').notNull(),
|
||||
});
|
||||
|
|
|
@ -1,11 +1,11 @@
|
|||
import fs from "node:fs";
|
||||
import path from "node:path";
|
||||
import { Client, Collection, Events, GatewayIntentBits } from "discord.js";
|
||||
import fs from 'node:fs';
|
||||
import path from 'node:path';
|
||||
import { Client, Collection, Events, GatewayIntentBits } from 'discord.js';
|
||||
|
||||
import { deployCommands } from "./util/deployCommand.js";
|
||||
import { getAllMembers, setMembers } from "./util/db.js";
|
||||
import { deployCommands } from './util/deployCommand.js';
|
||||
import { removeMember, setMembers } from './util/db.js';
|
||||
|
||||
const config = JSON.parse(fs.readFileSync("./config.json", "utf8"));
|
||||
const config = JSON.parse(fs.readFileSync('./config.json', 'utf8'));
|
||||
const { token, guildId } = config;
|
||||
|
||||
const client: any = new Client({
|
||||
|
@ -16,35 +16,38 @@ client.commands = new Collection();
|
|||
try {
|
||||
const __dirname = path.resolve();
|
||||
|
||||
const commandsPath = path.join(__dirname, "/target/commands/");
|
||||
const commandsPath = path.join(__dirname, '/target/commands/');
|
||||
const commandFiles = fs
|
||||
.readdirSync(commandsPath)
|
||||
.filter((file) => file.endsWith(".js"));
|
||||
.filter((file) => file.endsWith('.js'));
|
||||
|
||||
for (const file of commandFiles) {
|
||||
const filePath = path.join("file://", commandsPath, file);
|
||||
const filePath = path.join('file://', commandsPath, file);
|
||||
const commandModule = await import(filePath);
|
||||
const command = commandModule.default;
|
||||
|
||||
if (
|
||||
command instanceof Object &&
|
||||
"data" in command &&
|
||||
"execute" in command
|
||||
'data' in command &&
|
||||
'execute' in command
|
||||
) {
|
||||
client.commands.set(command.data.name, command);
|
||||
} else {
|
||||
}
|
||||
else {
|
||||
console.log(
|
||||
`[WARNING] The command at ${filePath} is missing a required "data" or "execute" property.`
|
||||
);
|
||||
}
|
||||
}
|
||||
} catch (error: any) {
|
||||
}
|
||||
catch (error: any) {
|
||||
console.log(`Error while getting commands up: ${error}`);
|
||||
}
|
||||
|
||||
try {
|
||||
await deployCommands();
|
||||
} catch (error: any) {
|
||||
}
|
||||
catch (error: any) {
|
||||
console.log(`Error while registering commands: ${error}`);
|
||||
}
|
||||
|
||||
|
@ -70,20 +73,34 @@ client.on(Events.InteractionCreate, async (interaction: any) => {
|
|||
|
||||
try {
|
||||
await command.execute(interaction);
|
||||
} catch (error) {
|
||||
}
|
||||
catch (error) {
|
||||
console.error(error);
|
||||
if (interaction.replied || interaction.deferred) {
|
||||
await interaction.followUp({
|
||||
content: "There was an error while executing this command!",
|
||||
content: 'There was an error while executing this command!',
|
||||
ephemeral: true,
|
||||
});
|
||||
} else {
|
||||
}
|
||||
else {
|
||||
await interaction.reply({
|
||||
content: "There was an error while executing this command!",
|
||||
content: 'There was an error while executing this command!',
|
||||
ephemeral: true,
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
client.on(Events.GuildMemberAdd, async () => {
|
||||
const guild = await client.guilds.fetch(guildId);
|
||||
const members = await guild.members.fetch();
|
||||
const nonBotMembers = members.filter((member: any) => !member.user.bot);
|
||||
|
||||
await setMembers(nonBotMembers);
|
||||
});
|
||||
|
||||
client.on(Events.GuildMemberRemove, async (member: any) => {
|
||||
await removeMember(member.user.id);
|
||||
});
|
||||
|
||||
client.login(token);
|
||||
|
|
|
@ -1,12 +1,12 @@
|
|||
import fs from "node:fs";
|
||||
import pkg from "pg";
|
||||
import { drizzle } from "drizzle-orm/node-postgres";
|
||||
import { memberTable } from "../db/schema.js";
|
||||
import { eq } from "drizzle-orm";
|
||||
import fs from 'node:fs';
|
||||
import pkg from 'pg';
|
||||
import { drizzle } from 'drizzle-orm/node-postgres';
|
||||
import { memberTable } from '../db/schema.js';
|
||||
import { eq } from 'drizzle-orm';
|
||||
|
||||
const { Pool } = pkg;
|
||||
const config = JSON.parse(fs.readFileSync("./config.json", "utf8"));
|
||||
const { dbConnectionString, guildId } = config;
|
||||
const config = JSON.parse(fs.readFileSync('./config.json', 'utf8'));
|
||||
const { dbConnectionString } = config;
|
||||
|
||||
const dbPool = new Pool({
|
||||
connectionString: dbConnectionString,
|
||||
|
@ -29,7 +29,8 @@ export async function setMembers(nonBotMembers: any) {
|
|||
.update(memberTable)
|
||||
.set({ discordUsername: member.user.username })
|
||||
.where(eq(memberTable.discordId, member.user.id));
|
||||
} else {
|
||||
}
|
||||
else {
|
||||
const members: typeof memberTable.$inferInsert = {
|
||||
discordId: member.user.id,
|
||||
discordUsername: member.user.username,
|
||||
|
@ -38,3 +39,7 @@ export async function setMembers(nonBotMembers: any) {
|
|||
}
|
||||
});
|
||||
}
|
||||
|
||||
export async function removeMember(discordId: string) {
|
||||
await db.delete(memberTable).where(eq(memberTable.discordId, discordId));
|
||||
}
|
||||
|
|
|
@ -1,17 +1,17 @@
|
|||
import { REST, Routes } from "discord.js";
|
||||
import fs from "fs";
|
||||
import path from "path";
|
||||
import { REST, Routes } from 'discord.js';
|
||||
import fs from 'fs';
|
||||
import path from 'path';
|
||||
|
||||
const config = JSON.parse(fs.readFileSync("./config.json", "utf8"));
|
||||
const config = JSON.parse(fs.readFileSync('./config.json', 'utf8'));
|
||||
const { token, clientId, guildId } = config;
|
||||
|
||||
const __dirname = path.resolve();
|
||||
const commandsPath = path.join(__dirname, "target", "commands");
|
||||
const commandsPath = path.join(__dirname, 'target', 'commands');
|
||||
const commandFiles = fs
|
||||
.readdirSync(commandsPath)
|
||||
.filter((file) => file.endsWith(".js"));
|
||||
.filter((file) => file.endsWith('.js'));
|
||||
|
||||
const rest = new REST({ version: "9" }).setToken(token);
|
||||
const rest = new REST({ version: '9' }).setToken(token);
|
||||
|
||||
export const deployCommands = async () => {
|
||||
try {
|
||||
|
@ -20,13 +20,14 @@ export const deployCommands = async () => {
|
|||
);
|
||||
|
||||
const commands = commandFiles.map(async (file) => {
|
||||
const filePath = path.join("file://", commandsPath, file);
|
||||
const filePath = path.join('file://', commandsPath, file);
|
||||
const commandModule = await import(filePath);
|
||||
const command = commandModule.default;
|
||||
|
||||
if (command instanceof Object && "data" in command) {
|
||||
if (command instanceof Object && 'data' in command) {
|
||||
return command.data.toJSON();
|
||||
} else {
|
||||
}
|
||||
else {
|
||||
console.log(
|
||||
`[WARNING] The command at ${filePath} is missing a required "data" property.`
|
||||
);
|
||||
|
@ -46,7 +47,8 @@ export const deployCommands = async () => {
|
|||
console.log(
|
||||
`Successfully reloaded ${data.length} application (/) commands.`
|
||||
);
|
||||
} catch (error) {
|
||||
}
|
||||
catch (error) {
|
||||
console.error(error);
|
||||
}
|
||||
};
|
||||
|
|
|
@ -11,8 +11,8 @@
|
|||
// "disableReferencedProjectLoad": true, /* Reduce the number of projects loaded automatically by TypeScript. */
|
||||
|
||||
/* Language and Environment */
|
||||
"target": "es2017", /* Set the JavaScript language version for emitted JavaScript and include compatible library declarations. */
|
||||
// "lib": [], /* Specify a set of bundled library declaration files that describe the target runtime environment. */
|
||||
"target": "es2022", /* Set the JavaScript language version for emitted JavaScript and include compatible library declarations. */
|
||||
"lib": ["ES2022"], /* Specify a set of bundled library declaration files that describe the target runtime environment. */
|
||||
// "jsx": "preserve", /* Specify what JSX code is generated. */
|
||||
// "experimentalDecorators": true, /* Enable experimental support for legacy experimental decorators. */
|
||||
// "emitDecoratorMetadata": true, /* Emit design-type metadata for decorated declarations in source files. */
|
||||
|
|
Loading…
Add table
Reference in a new issue