mirror of
https://github.com/thedrewen/protojx-manager.git
synced 2026-03-21 09:48:56 +01:00
Compare commits
9 Commits
v1.0.0-bet
...
v1.0.0
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
e9565a9552 | ||
| 0504e8262d | |||
| 978d21a120 | |||
| 9cadfb2734 | |||
| 5b3167bf14 | |||
| 7f9468bc99 | |||
| 86a7429711 | |||
| 43b7bdd8b4 | |||
| 58ecaf3c4c |
19
.env.example
19
.env.example
@@ -1,5 +1,18 @@
|
|||||||
TOKEN=
|
# Discord Bot Configuration
|
||||||
CLIENT_ID=
|
TOKEN=your_discord_bot_token_here
|
||||||
|
CLIENT_ID=your_discord_client_id_here
|
||||||
|
|
||||||
|
# Custom Emojis
|
||||||
EMOJI_STATUS_ONLINE=<a:online:1432684754276323431>
|
EMOJI_STATUS_ONLINE=<a:online:1432684754276323431>
|
||||||
EMOJI_STATUS_OFFLINE=<a:offline:1432684900175183882>
|
EMOJI_STATUS_OFFLINE=<a:offline:1432684900175183882>
|
||||||
|
|
||||||
|
# Database Configuration
|
||||||
|
DB_HOST=localhost
|
||||||
|
DB_PORT=5432
|
||||||
|
DB_USERNAME=postgres
|
||||||
|
DB_PASSWORD=your_database_password_here
|
||||||
|
DB_DATABASE=protojx_manager
|
||||||
|
DB_LOGGING=false
|
||||||
|
|
||||||
|
# Environment
|
||||||
|
NODE_ENV=development
|
||||||
@@ -9,8 +9,9 @@ A status bot and other features for protojx.
|
|||||||
| Description | Status |
|
| Description | Status |
|
||||||
|-------------|--------|
|
|-------------|--------|
|
||||||
| /status command | 🌐 |
|
| /status command | 🌐 |
|
||||||
| Number of services down in the bot's status. | ✅ |
|
| Number of services down in the bot's status. | 🌐 |
|
||||||
| Notification system in case of downtime. | ➖ |
|
| Notification system in case of downtime. | ➖ |
|
||||||
|
| Ability to create persistent status messages that update automatically. | ➖ |
|
||||||
| Deployment workflow on Raspberry Pi. | ➖ |
|
| Deployment workflow on Raspberry Pi. | ➖ |
|
||||||
|
|
||||||
- 🌐 -> In production
|
- 🌐 -> In production
|
||||||
@@ -92,4 +93,4 @@ npm run start
|
|||||||
```
|
```
|
||||||
|
|
||||||
---
|
---
|
||||||
**Note**: This template is based on community best practices and has been customized for Discord bot development.
|
**Note**: This template is based on community best practices and has been customized for Discord bot development.
|
||||||
|
|||||||
1511
package-lock.json
generated
1511
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@@ -24,6 +24,7 @@
|
|||||||
},
|
},
|
||||||
"homepage": "https://github.com/Under-scape/discordbot-ts-template#readme",
|
"homepage": "https://github.com/Under-scape/discordbot-ts-template#readme",
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
|
"@types/node": "^24.9.2",
|
||||||
"typescript": "^5.9.2"
|
"typescript": "^5.9.2"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
@@ -31,6 +32,9 @@
|
|||||||
"cron": "^4.3.3",
|
"cron": "^4.3.3",
|
||||||
"discord.js": "^14.24.1",
|
"discord.js": "^14.24.1",
|
||||||
"dotenv": "^17.2.2",
|
"dotenv": "^17.2.2",
|
||||||
"ping": "^1.0.0"
|
"pg": "^8.16.3",
|
||||||
|
"ping": "^1.0.0",
|
||||||
|
"reflect-metadata": "^0.2.2",
|
||||||
|
"typeorm": "^0.3.27"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
import { ApplicationIntegrationType, ChatInputCommandInteraction, CommandInteraction, InteractionContextType, SlashCommandBuilder } from "discord.js";
|
import { ApplicationIntegrationType, ButtonInteraction, ButtonStyle, ChatInputCommandInteraction, CommandInteraction, ComponentType, ContainerBuilder, InteractionContextType, MessageFlags, SlashCommandBuilder } from "discord.js";
|
||||||
|
import { CommandDefinition } from "../../type";
|
||||||
|
|
||||||
export default {
|
const cmd : CommandDefinition = {
|
||||||
data: new SlashCommandBuilder()
|
data: new SlashCommandBuilder()
|
||||||
.setName('ping')
|
.setName('ping')
|
||||||
.setDescription('Pong again!')
|
.setDescription('Pong again!')
|
||||||
@@ -14,6 +15,35 @@ export default {
|
|||||||
InteractionContextType.PrivateChannel
|
InteractionContextType.PrivateChannel
|
||||||
),
|
),
|
||||||
async execute(interaction : ChatInputCommandInteraction) {
|
async execute(interaction : ChatInputCommandInteraction) {
|
||||||
await interaction.reply(`🏓 Latency is ${Date.now() - interaction.createdTimestamp}ms. API Latency : ${interaction.client.ws.ping}ms`);
|
|
||||||
}
|
const container = new ContainerBuilder()
|
||||||
}
|
.addTextDisplayComponents((textDisplay) => textDisplay.setContent(`🏓 Latency is ${Date.now() - interaction.createdTimestamp}ms. API Latency : ${interaction.client.ws.ping}ms`))
|
||||||
|
.addSeparatorComponents((s) => s)
|
||||||
|
.addSectionComponents((section) =>
|
||||||
|
section
|
||||||
|
.addTextDisplayComponents((textDisplay) =>
|
||||||
|
textDisplay
|
||||||
|
.setContent('Oh, that\'s a beautiful button!')
|
||||||
|
)
|
||||||
|
.setButtonAccessory((button) =>
|
||||||
|
button
|
||||||
|
.setCustomId('testClick')
|
||||||
|
.setLabel('Click Me !')
|
||||||
|
.setStyle(ButtonStyle.Success)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
// await interaction.reply();
|
||||||
|
await interaction.reply({
|
||||||
|
components: [container],
|
||||||
|
flags: MessageFlags.IsComponentsV2
|
||||||
|
})
|
||||||
|
},
|
||||||
|
buttons: [
|
||||||
|
{id: 'testClick', handle: (interaction : ButtonInteraction) => {
|
||||||
|
interaction.reply({content: 'Ho !', flags: [MessageFlags.Ephemeral]})
|
||||||
|
}}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
export default cmd;
|
||||||
@@ -1,8 +1,9 @@
|
|||||||
import { ApplicationIntegrationType, ChatInputCommandInteraction, CommandInteraction, EmbedBuilder, InteractionContextType, SlashCommandBuilder } from "discord.js";
|
import { ApplicationIntegrationType, ChatInputCommandInteraction, CommandInteraction, EmbedBuilder, InteractionContextType, SlashCommandBuilder } from "discord.js";
|
||||||
import ping from "ping";
|
import ping from "ping";
|
||||||
import statusService from "../../services/status.service";
|
import statusService from "../../services/status.service";
|
||||||
|
import { CommandDefinition } from "../../type";
|
||||||
|
|
||||||
export default {
|
const cmd : CommandDefinition = {
|
||||||
data: new SlashCommandBuilder()
|
data: new SlashCommandBuilder()
|
||||||
.setName('status')
|
.setName('status')
|
||||||
.setDescription('Give statut of servers.')
|
.setDescription('Give statut of servers.')
|
||||||
@@ -30,4 +31,6 @@ export default {
|
|||||||
|
|
||||||
await interaction.editReply({embeds: [embed]});
|
await interaction.editReply({embeds: [embed]});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export default cmd;
|
||||||
19
src/data-source.ts
Normal file
19
src/data-source.ts
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
import "reflect-metadata"
|
||||||
|
import { DataSource } from "typeorm"
|
||||||
|
import { configDotenv } from "dotenv"
|
||||||
|
|
||||||
|
configDotenv()
|
||||||
|
|
||||||
|
export const AppDataSource = new DataSource({
|
||||||
|
type: "postgres",
|
||||||
|
host: process.env.DB_HOST || "localhost",
|
||||||
|
port: parseInt(process.env.DB_PORT || "5432"),
|
||||||
|
username: process.env.DB_USERNAME || "postgres",
|
||||||
|
password: process.env.DB_PASSWORD,
|
||||||
|
database: process.env.DB_DATABASE,
|
||||||
|
synchronize: process.env.NODE_ENV !== "production", // false en production
|
||||||
|
logging: process.env.DB_LOGGING === "true",
|
||||||
|
entities: ["./entity/**/*.js"],
|
||||||
|
migrations: ["./migration/**/*.js"],
|
||||||
|
subscribers: ["./subscriber/**/*.js"],
|
||||||
|
})
|
||||||
13
src/entity/Guilds.ts
Normal file
13
src/entity/Guilds.ts
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
import { Column, Entity, PrimaryGeneratedColumn } from "typeorm";
|
||||||
|
|
||||||
|
@Entity()
|
||||||
|
export class Guild {
|
||||||
|
@PrimaryGeneratedColumn()
|
||||||
|
id: number;
|
||||||
|
|
||||||
|
@Column()
|
||||||
|
guild_id: string;
|
||||||
|
|
||||||
|
@Column()
|
||||||
|
persistent_message_id: string;
|
||||||
|
}
|
||||||
38
src/index.ts
38
src/index.ts
@@ -1,11 +1,21 @@
|
|||||||
import { Client, Collection, Events, GatewayIntentBits, MessageFlags } from "discord.js";
|
import { ButtonInteraction, ChatInputCommandInteraction, Client, Collection, Events, GatewayIntentBits, MessageFlags, SlashCommandBuilder } from "discord.js";
|
||||||
import { configDotenv } from "dotenv";
|
import { configDotenv } from "dotenv";
|
||||||
import path from "path";
|
import path from "path";
|
||||||
import fs from "fs";
|
import fs from "fs";
|
||||||
import statusService from "./services/status.service";
|
import statusService from "./services/status.service";
|
||||||
|
|
||||||
|
import "reflect-metadata";
|
||||||
|
import { AppDataSource } from "./data-source";
|
||||||
|
import { CommandDefinition } from "./type";
|
||||||
|
|
||||||
configDotenv();
|
configDotenv();
|
||||||
|
|
||||||
|
AppDataSource.initialize()
|
||||||
|
.then(() => {
|
||||||
|
console.log("Data Source initialized !")
|
||||||
|
})
|
||||||
|
.catch((error) => console.log(error));
|
||||||
|
|
||||||
const client = new Client({
|
const client = new Client({
|
||||||
intents: [
|
intents: [
|
||||||
GatewayIntentBits.Guilds,
|
GatewayIntentBits.Guilds,
|
||||||
@@ -15,8 +25,7 @@ const client = new Client({
|
|||||||
]
|
]
|
||||||
});
|
});
|
||||||
|
|
||||||
// @ts-expect-error
|
const commands = new Collection<string, CommandDefinition>();
|
||||||
client.commands = new Collection();
|
|
||||||
|
|
||||||
const foldersPath = path.join(__dirname, 'commands');
|
const foldersPath = path.join(__dirname, 'commands');
|
||||||
const commandFolders = fs.readdirSync(foldersPath);
|
const commandFolders = fs.readdirSync(foldersPath);
|
||||||
@@ -29,8 +38,7 @@ for (const folder of commandFolders) {
|
|||||||
const command = require(filePath);
|
const command = require(filePath);
|
||||||
const commandModule = command.default || command;
|
const commandModule = command.default || command;
|
||||||
if ('data' in commandModule && 'execute' in commandModule) {
|
if ('data' in commandModule && 'execute' in commandModule) {
|
||||||
// @ts-expect-error
|
commands.set(commandModule.data.name, commandModule);
|
||||||
client.commands.set(commandModule.data.name, commandModule);
|
|
||||||
} else {
|
} else {
|
||||||
console.log(`[WARNING] The command at ${filePath} is missing a required "data" or "execute" property.`);
|
console.log(`[WARNING] The command at ${filePath} is missing a required "data" or "execute" property.`);
|
||||||
}
|
}
|
||||||
@@ -38,10 +46,26 @@ for (const folder of commandFolders) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
client.on(Events.InteractionCreate, async interaction => {
|
client.on(Events.InteractionCreate, async interaction => {
|
||||||
|
|
||||||
|
if(interaction.isButton()) {
|
||||||
|
|
||||||
|
const id = interaction.customId;
|
||||||
|
|
||||||
|
commands.forEach((value, key) => {
|
||||||
|
if(value.buttons) {
|
||||||
|
const button = value.buttons.filter((b) => b.id == id);
|
||||||
|
if(button.length == 1) {
|
||||||
|
button[0]?.handle(interaction);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (!interaction.isChatInputCommand()) return;
|
if (!interaction.isChatInputCommand()) return;
|
||||||
|
|
||||||
// @ts-expect-error
|
const command = commands.get(interaction.commandName);
|
||||||
const command = interaction.client.commands.get(interaction.commandName);
|
|
||||||
|
|
||||||
if (!command) {
|
if (!command) {
|
||||||
console.error(`No command matching ${interaction.commandName} was found.`);
|
console.error(`No command matching ${interaction.commandName} was found.`);
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
import ping from "ping";
|
import ping from "ping";
|
||||||
import * as cron from 'cron';
|
import * as cron from 'cron';
|
||||||
import { ActivityType, Client } from "discord.js";
|
import { ActivityType, Client } from "discord.js";
|
||||||
|
import { Host } from "../type";
|
||||||
|
|
||||||
export class StatusService {
|
export class StatusService {
|
||||||
|
|
||||||
|
|||||||
3
src/type.d.ts
vendored
3
src/type.d.ts
vendored
@@ -1 +1,2 @@
|
|||||||
type Host = { host: string, name: string, alive: boolean, type: 'ping' | 'website' };
|
export type Host = { host: string, name: string, alive: boolean, type: 'ping' | 'website' };
|
||||||
|
export type CommandDefinition = { data: SlashCommandBuilder, execute: (interaction: ChatInputCommandInteraction) => void, buttons?: { id: string, handle: (interaction: ButtonInteraction) => void}[]};
|
||||||
@@ -24,7 +24,8 @@
|
|||||||
"experimentalDecorators": true,
|
"experimentalDecorators": true,
|
||||||
"emitDecoratorMetadata": true,
|
"emitDecoratorMetadata": true,
|
||||||
"removeComments": false,
|
"removeComments": false,
|
||||||
"preserveConstEnums": true
|
"preserveConstEnums": true,
|
||||||
|
"strictPropertyInitialization": false
|
||||||
},
|
},
|
||||||
"include": [
|
"include": [
|
||||||
"src/**/*"
|
"src/**/*"
|
||||||
|
|||||||
Reference in New Issue
Block a user