This commit is contained in:
guams 2025-06-28 16:13:36 +02:00
parent 138b7aab90
commit 10c807f611
7 changed files with 235 additions and 12 deletions

15
.gitignore vendored
View File

@ -1,11 +1,4 @@
# Default ignored files node_modules
/shelf/ package-lock.json
/workspace.xml config.json
# Editor-based HTTP Client requests .idea
/httpRequests/
# Datasource local storage ignored files
/dataSources/
/dataSources.local.xml
configuration.json
.idea/
.venv/*

View File

@ -35,7 +35,7 @@ CREATE TABLE member
user_id VARCHAR(255), user_id VARCHAR(255),
guild_id VARCHAR(255), guild_id VARCHAR(255),
username VARCHAR(255), username VARCHAR(255),
points bigint DEFAULT 50, points bigint DEFAULT 50 NOT NULL CHECK (points >= 50),
bet_value bigint DEFAULT 50, bet_value bigint DEFAULT 50,
PRIMARY KEY (user_id), PRIMARY KEY (user_id),
FOREIGN KEY (guild_id) REFERENCES guild (guild_id) FOREIGN KEY (guild_id) REFERENCES guild (guild_id)

18
package.json Normal file
View File

@ -0,0 +1,18 @@
{
"name": "gambling-bot",
"version": "1.0.0",
"description": "a simple gambling discord bot",
"license": "ISC",
"author": "",
"type": "commonjs",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"dependencies": {
"discord-api-types": "^0.38.13",
"discord.js": "^14.21.0",
"pg": "^8.16.3",
"uuid": "^11.1.0"
}
}

45
src/constants.js Normal file
View File

@ -0,0 +1,45 @@
const {SlashCommandBuilder} = require("discord.js");
const POLL_COMMAND_NAME = 'poll';
const BET_COMMAND_NAME = 'bet';
const CLOSE_COMMAND_NAME = 'close';
const PROFIL_COMMAND_NAME = 'profil';
const POLL_COMMAND = new SlashCommandBuilder()
.setName("poll")
.setDescription("Des votes sur lesquels gamble");
const BET_COMMAND = new SlashCommandBuilder()
.setName("bet")
.setDescription("Pour pouvoir planifier le prochain pari !")
.addNumberOption(option => option
.setName("somme")
.setDescription("La somme du prochain pari")
.setRequired(true)
.setMinValue(0));
const CLOSE_COMMAND = new SlashCommandBuilder()
.setName("close")
.setDescription("Pour clôturer un sondage")
.addStringOption(option => option
.setName("option")
.setDescription("L'issue du sondage")
.setRequired(true));
const PROFIL_COMMAND = new SlashCommandBuilder()
.setName("profil")
.setDescription("Afficher des informations sur un utilisateur")
.addUserOption(option => option
.setName("user")
.setDescription("La personne concernée")
.setRequired(false));
exports.POLL_COMMAND_NAME = POLL_COMMAND_NAME
exports.BET_COMMAND_NAME = BET_COMMAND_NAME
exports.CLOSE_COMMAND_NAME = CLOSE_COMMAND_NAME
exports.PROFIL_COMMAND_NAME = PROFIL_COMMAND_NAME
exports.POLL_COMMAND = POLL_COMMAND
exports.BET_COMMAND = BET_COMMAND
exports.CLOSE_COMMAND = CLOSE_COMMAND
exports.PROFIL_COMMAND = PROFIL_COMMAND

25
src/database.js Normal file
View File

@ -0,0 +1,25 @@
const { Client } = require('pg');
const {DB_NAME, DB_USER, DB_PASSWORD, DB_ADDRESS, DB_PORT} = require('../config.json');
const DATABASE_CLIENT = new Client({
user: DB_USER,
password: DB_PASSWORD,
host: DB_ADDRESS,
port: DB_PORT,
database: DB_NAME,
});
async function userExists() {
const res = await DATABASE_CLIENT.query("SELECT * FROM member");
return res.rows;
}
async function insertPollIntoDB(creatorId, pollId, guildId, questionLabel) {
const response = await DATABASE_CLIENT.query("INSERT INTO poll(creator, poll_id, guild_id, question, opened) VALUES ($1, $2, $3, $4, true)", [creatorId, pollId, guildId, questionLabel])
return response.rows;
}
exports.DATABASE_CLIENT = DATABASE_CLIENT;
exports.userExists = userExists;
exports.insertPollIntoDB = insertPollIntoDB;

13
src/deploy-commands.js Normal file
View File

@ -0,0 +1,13 @@
const {POLL_COMMAND, BET_COMMAND, CLOSE_COMMAND, PROFIL_COMMAND} = require("./constants")
const {TOKEN, APPLICATION_ID} = require('../config.json')
const {REST} = require("discord.js");
const { Routes } = require('discord-api-types/v10');
const commands = [POLL_COMMAND, BET_COMMAND, CLOSE_COMMAND, PROFIL_COMMAND].map(command => command.toJSON());
const rest = new REST({version: '10'}).setToken(TOKEN);
console.log(commands)
rest.put(Routes.applicationCommands(APPLICATION_ID), { body: commands })
.then(() => console.log('Successfully registered application commands.'))
.catch(console.error);

129
src/main.js Normal file
View File

@ -0,0 +1,129 @@
const {
Client,
Events,
GatewayIntentBits,
ModalBuilder,
TextInputBuilder,
ActionRowBuilder,
EmbedBuilder,
Colors, ButtonBuilder
} = require('discord.js');
const {DATABASE_CLIENT, insertPollIntoDB} = require('./database');
const {TOKEN} = require('../config.json');
const {v4: uuidv4} = require('uuid');
const {POLL_COMMAND_NAME} = require("./constants");
const {ButtonStyle} = require("discord-api-types/v10");
const client = new Client({intents: [GatewayIntentBits.Guilds]});
client.once(Events.ClientReady, async readyClient => {
console.log(`Ready! Logged in as ${readyClient.user.tag}`);
await DATABASE_CLIENT.connect();
});
client.on(Events.InteractionCreate, async interaction => {
if (interaction.isCommand()) {
const {commandName} = interaction;
if (commandName === POLL_COMMAND_NAME) {
await interaction.showModal(buildPollModal());
}
} else if (interaction.isModalSubmit()) {
const pollToCreate = interaction.components;
const sender = interaction.user;
const guildFromWhereUserSendedInteraction = interaction.member.guild;
const pollQuestionObj = pollToCreate[0].components[0];
let voteOptions = [
pollToCreate[1].components[0].value,
pollToCreate[2].components[0].value,
pollToCreate[3].components[0].value,
pollToCreate[4].components[0].value
];
voteOptions = [...new Set(voteOptions)].filter(voteOption => voteOption !== '');
const introEmbed = new EmbedBuilder()
.setTitle("Les paris sont ouverts !")
.setDescription("Vous pouvez parier vos points, ils ne passeront pas en dessous de 50")
.setColor(Colors.Aqua);
const buttons = new ActionRowBuilder();
let pollDesc = '';
voteOptions.forEach((voteOption, index) => {
buttons.addComponents(new ButtonBuilder()
.setCustomId(`${interaction.customId}_${voteOption}_${index + 1}`)
.setLabel(voteOption)
.setStyle(ButtonStyle.Primary));
pollDesc += `Option ${index + 1}: ${voteOption}\n`
});
const pollEmbed = new EmbedBuilder()
.setTitle(`Sondage: ${pollQuestionObj.value}`)
.setDescription(pollDesc)
.setColor(Colors.Green);
insertPollIntoDB(sender.id, interaction.customId, guildFromWhereUserSendedInteraction.id, pollQuestionObj.value);
await interaction.reply({embeds: [introEmbed, pollEmbed], components: [buttons]});
}
});
function buildPollModal() {
const pollId = uuidv4();
const pollModal = new ModalBuilder()
.setTitle("Créer un vote")
.setCustomId(pollId)
const questionRow = new ActionRowBuilder().addComponents(
new TextInputBuilder()
.setCustomId("label")
.setLabel("Question du vote")
.setPlaceholder("Shy aime-t-il les robots?")
.setStyle(1)
.setMinLength(1)
.setRequired(true)
);
const firstOption = new ActionRowBuilder().addComponents(
new TextInputBuilder()
.setCustomId("vote1")
.setLabel("Première option")
.setPlaceholder("Oui")
.setStyle(1)
.setMinLength(1)
.setRequired(true)
);
const secondOption = new ActionRowBuilder().addComponents(
new TextInputBuilder()
.setCustomId("vote2")
.setLabel("Deuxième option")
.setPlaceholder("Non")
.setStyle(1)
.setMinLength(1)
.setRequired(false)
);
const thirdOption = new ActionRowBuilder().addComponents(
new TextInputBuilder()
.setCustomId("vote3")
.setLabel("Troisième option")
.setPlaceholder("Peut-être")
.setStyle(1)
.setMinLength(1)
.setRequired(false)
);
const fourthOption = new ActionRowBuilder().addComponents(
new TextInputBuilder()
.setCustomId("vote4")
.setLabel("Quatrième option")
.setPlaceholder("Pas du tout")
.setStyle(1)
.setMinLength(1)
.setRequired(false)
);
return pollModal.addComponents(questionRow, firstOption, secondOption, thirdOption, fourthOption);
}
client.login(TOKEN);