Compare commits
9 Commits
138b7aab90
...
b5e63efb62
Author | SHA1 | Date | |
---|---|---|---|
b5e63efb62 | |||
43119b3422 | |||
323b7b3d11 | |||
6217203967 | |||
2524b6830f | |||
45d8721c5a | |||
5ee5944a78 | |||
e47bf9f451 | |||
10c807f611 |
15
.gitignore
vendored
15
.gitignore
vendored
@ -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/*
|
|
@ -26,6 +26,4 @@ Readme in progress...
|
|||||||
|
|
||||||
## TODO
|
## TODO
|
||||||
|
|
||||||
- [ ] corriger le problème de seuil
|
- [ ] update l'username (quand l'utilisateur en a un nouveau)
|
||||||
- [ ] changer la bet_value après un vote perdant (on se retrouve parfois avec un bet_value > points)
|
|
||||||
- [ ] update l'username (quand l'utilisateur en a un nouveau...) pareil pour l'avatar.......
|
|
||||||
|
301
database.py
301
database.py
@ -1,301 +0,0 @@
|
|||||||
from psycopg2.extensions import connection, cursor
|
|
||||||
|
|
||||||
|
|
||||||
async def user_exists(conn, user_id, guild_id):
|
|
||||||
cur = conn.cursor()
|
|
||||||
|
|
||||||
cur.execute("SELECT user_id FROM member WHERE user_id=%s AND guild_id=%s", (user_id, guild_id))
|
|
||||||
result = cur.fetchone()
|
|
||||||
|
|
||||||
cur.close()
|
|
||||||
|
|
||||||
return result is not None
|
|
||||||
|
|
||||||
|
|
||||||
async def insert_vote_options(conn, poll_id: str, vote_id: str, vote_option: str):
|
|
||||||
cur = conn.cursor()
|
|
||||||
|
|
||||||
cur.execute(
|
|
||||||
"INSERT INTO "
|
|
||||||
"vote (poll_id, vote_id, vote_option) "
|
|
||||||
"VALUES (%s, %s, %s)",
|
|
||||||
(poll_id, vote_id, vote_option)
|
|
||||||
)
|
|
||||||
|
|
||||||
conn.commit()
|
|
||||||
cur.close()
|
|
||||||
|
|
||||||
|
|
||||||
async def change_bet(conn: connection, user_id: str, guild_id: str, new_bet_amount: int):
|
|
||||||
cur: cursor = conn.cursor()
|
|
||||||
|
|
||||||
cur.execute("UPDATE member SET bet_value = %s WHERE user_id=%s AND guild_id=%s",
|
|
||||||
(new_bet_amount, user_id, guild_id))
|
|
||||||
|
|
||||||
conn.commit()
|
|
||||||
cur.close()
|
|
||||||
|
|
||||||
|
|
||||||
async def is_last_poll_created_opened(conn: connection, creator: str):
|
|
||||||
cur: cursor = conn.cursor()
|
|
||||||
|
|
||||||
cur.execute("select opened "
|
|
||||||
"from poll "
|
|
||||||
"where creator=%s "
|
|
||||||
"and opened=true",
|
|
||||||
(creator,)
|
|
||||||
)
|
|
||||||
result = cur.fetchone()
|
|
||||||
cur.close()
|
|
||||||
|
|
||||||
if result is not None:
|
|
||||||
return result[0]
|
|
||||||
return
|
|
||||||
|
|
||||||
|
|
||||||
async def close_poll(conn: connection, poll_id: str):
|
|
||||||
cur: cursor = conn.cursor()
|
|
||||||
|
|
||||||
cur.execute("UPDATE poll SET opened = false WHERE poll_id=%s",
|
|
||||||
(poll_id,))
|
|
||||||
|
|
||||||
conn.commit()
|
|
||||||
cur.close()
|
|
||||||
|
|
||||||
|
|
||||||
async def get_poll_id_opened(conn: connection, creator: str):
|
|
||||||
cur: cursor = conn.cursor()
|
|
||||||
|
|
||||||
cur.execute("select opened, poll_id, question "
|
|
||||||
"from poll "
|
|
||||||
"where creator=%s "
|
|
||||||
"and opened=true",
|
|
||||||
(creator,)
|
|
||||||
)
|
|
||||||
result = cur.fetchone()
|
|
||||||
cur.close()
|
|
||||||
|
|
||||||
return result
|
|
||||||
|
|
||||||
|
|
||||||
async def get_user_vote(conn: connection, user_id: str, poll_id: str):
|
|
||||||
cur: cursor = conn.cursor()
|
|
||||||
|
|
||||||
cur.execute(""
|
|
||||||
"SELECT vote_id "
|
|
||||||
"FROM vote_member "
|
|
||||||
"WHERE user_id=%s "
|
|
||||||
"AND poll_id=%s",
|
|
||||||
(user_id, poll_id)
|
|
||||||
)
|
|
||||||
|
|
||||||
result = cur.fetchone()
|
|
||||||
cur.close()
|
|
||||||
|
|
||||||
return result
|
|
||||||
|
|
||||||
|
|
||||||
async def get_user_by_id(conn: connection, user_id: str, guild_id: str):
|
|
||||||
cur: cursor = conn.cursor()
|
|
||||||
|
|
||||||
cur.execute(""
|
|
||||||
"SELECT username, points, bet_value "
|
|
||||||
"FROM member "
|
|
||||||
"WHERE user_id=%s "
|
|
||||||
"AND guild_id=%s",
|
|
||||||
(user_id, guild_id)
|
|
||||||
)
|
|
||||||
|
|
||||||
result = cur.fetchone()
|
|
||||||
cur.close()
|
|
||||||
|
|
||||||
return result
|
|
||||||
|
|
||||||
|
|
||||||
async def get_user_points(conn: connection, user_id: str, guild_id: str):
|
|
||||||
cur: cursor = conn.cursor()
|
|
||||||
|
|
||||||
cur.execute(""
|
|
||||||
"SELECT points "
|
|
||||||
"FROM member "
|
|
||||||
"WHERE user_id=%s "
|
|
||||||
"AND member.guild_id=%s",
|
|
||||||
(user_id, guild_id)
|
|
||||||
)
|
|
||||||
|
|
||||||
result = cur.fetchone()
|
|
||||||
cur.close()
|
|
||||||
|
|
||||||
if result is not None:
|
|
||||||
return result[0]
|
|
||||||
return
|
|
||||||
|
|
||||||
|
|
||||||
async def get_bet_value(conn: connection, user_id: str, guild_id: str):
|
|
||||||
cur: cursor = conn.cursor()
|
|
||||||
|
|
||||||
cur.execute(""
|
|
||||||
"SELECT bet_value "
|
|
||||||
"FROM member "
|
|
||||||
"WHERE user_id=%s "
|
|
||||||
"AND member.guild_id=%s",
|
|
||||||
(user_id, guild_id)
|
|
||||||
)
|
|
||||||
|
|
||||||
result = cur.fetchone()
|
|
||||||
cur.close()
|
|
||||||
|
|
||||||
if result is not None:
|
|
||||||
return result[0]
|
|
||||||
return
|
|
||||||
|
|
||||||
|
|
||||||
async def bet(conn, vote_id: str, poll_id: str, user_id: str, guild_id: str, bet_value: int):
|
|
||||||
cur = conn.cursor()
|
|
||||||
|
|
||||||
cur.execute(
|
|
||||||
"INSERT INTO "
|
|
||||||
"vote_member (user_id, poll_id, guild_id, vote_id, bet_value) "
|
|
||||||
"VALUES (%s, %s, %s, %s, %s)",
|
|
||||||
(user_id, poll_id, guild_id, vote_id, bet_value)
|
|
||||||
)
|
|
||||||
|
|
||||||
conn.commit()
|
|
||||||
cur.close()
|
|
||||||
|
|
||||||
|
|
||||||
async def get_bet_value_multipliers(conn: connection, poll_id: str):
|
|
||||||
cur = conn.cursor()
|
|
||||||
|
|
||||||
cur.execute("SELECT vote_id,(1 + (1 - (SUM(vote_member.bet_value) / total.sum))) "
|
|
||||||
"FROM vote_member "
|
|
||||||
"CROSS JOIN (SELECT SUM(bet_value) AS sum FROM vote_member WHERE poll_id=%s) AS total "
|
|
||||||
"WHERE poll_id=%s "
|
|
||||||
"GROUP BY vote_id, total.sum",
|
|
||||||
(poll_id, poll_id))
|
|
||||||
result = cur.fetchall()
|
|
||||||
|
|
||||||
return result
|
|
||||||
|
|
||||||
|
|
||||||
async def get_vote_id_by_vote_option_and_poll_id(conn: connection, vote_option: str, poll_id: str):
|
|
||||||
cur = conn.cursor()
|
|
||||||
|
|
||||||
cur.execute("SELECT vote_id FROM vote "
|
|
||||||
"WHERE vote_option=%s "
|
|
||||||
"AND poll_id=%s",
|
|
||||||
(vote_option, poll_id))
|
|
||||||
result = cur.fetchone()
|
|
||||||
|
|
||||||
if result is not None:
|
|
||||||
return result[0]
|
|
||||||
return
|
|
||||||
|
|
||||||
|
|
||||||
async def get_users_that_voted(conn: connection, vote_id: str):
|
|
||||||
cur = conn.cursor()
|
|
||||||
|
|
||||||
cur.execute("select user_id "
|
|
||||||
"from vote_member "
|
|
||||||
"where vote_id=%s",
|
|
||||||
(vote_id,))
|
|
||||||
results = cur.fetchall()
|
|
||||||
|
|
||||||
return results
|
|
||||||
|
|
||||||
|
|
||||||
async def guild_exists(conn, guild_id):
|
|
||||||
cur = conn.cursor()
|
|
||||||
|
|
||||||
cur.execute("SELECT guild_id FROM guild WHERE guild_id=%s", (guild_id,))
|
|
||||||
result = cur.fetchone()
|
|
||||||
|
|
||||||
cur.close()
|
|
||||||
|
|
||||||
return result is not None
|
|
||||||
|
|
||||||
|
|
||||||
async def insert_poll(conn, creator, poll_id, guild_id, question):
|
|
||||||
cur = conn.cursor()
|
|
||||||
|
|
||||||
cur.execute(
|
|
||||||
"INSERT INTO "
|
|
||||||
"poll (creator, poll_id, guild_id, question, opened) "
|
|
||||||
"VALUES (%s, %s, %s, %s, true)",
|
|
||||||
(creator, poll_id, guild_id, question)
|
|
||||||
)
|
|
||||||
|
|
||||||
conn.commit()
|
|
||||||
cur.close()
|
|
||||||
|
|
||||||
|
|
||||||
async def insert_guild(conn, guild_id):
|
|
||||||
cur = conn.cursor()
|
|
||||||
cur.execute(
|
|
||||||
"INSERT INTO "
|
|
||||||
"guild (guild_id) "
|
|
||||||
"VALUES (%s)",
|
|
||||||
(guild_id,)
|
|
||||||
)
|
|
||||||
|
|
||||||
conn.commit()
|
|
||||||
cur.close()
|
|
||||||
|
|
||||||
|
|
||||||
async def insert_user(conn, user_id, guild_id, username):
|
|
||||||
cur = conn.cursor()
|
|
||||||
|
|
||||||
cur.execute(
|
|
||||||
"INSERT INTO "
|
|
||||||
"member (user_id, guild_id, username) "
|
|
||||||
"VALUES (%s, %s, %s)",
|
|
||||||
(user_id, guild_id, username)
|
|
||||||
)
|
|
||||||
|
|
||||||
conn.commit()
|
|
||||||
cur.close()
|
|
||||||
|
|
||||||
|
|
||||||
async def get_users_and_bet_value_by_vote_id(conn: connection, vote_id: str):
|
|
||||||
cur = conn.cursor()
|
|
||||||
|
|
||||||
cur.execute("SELECT user_id, bet_value FROM vote_member "
|
|
||||||
"WHERE vote_id=%s",
|
|
||||||
(vote_id,)
|
|
||||||
)
|
|
||||||
result = cur.fetchall()
|
|
||||||
|
|
||||||
cur.close()
|
|
||||||
|
|
||||||
return result
|
|
||||||
|
|
||||||
|
|
||||||
async def add_user_points(conn: connection, user_id: str, bet_value: int):
|
|
||||||
cur = conn.cursor()
|
|
||||||
|
|
||||||
cur.execute(
|
|
||||||
"UPDATE member "
|
|
||||||
"SET points = points + %s "
|
|
||||||
"WHERE user_id=%s",
|
|
||||||
(bet_value, user_id)
|
|
||||||
)
|
|
||||||
|
|
||||||
conn.commit()
|
|
||||||
cur.close()
|
|
||||||
|
|
||||||
|
|
||||||
async def minus_user_points(conn: connection, user_id: str, bet_value: int):
|
|
||||||
try:
|
|
||||||
cur = conn.cursor()
|
|
||||||
|
|
||||||
cur.execute(
|
|
||||||
"UPDATE member "
|
|
||||||
"SET points = points - %s "
|
|
||||||
"WHERE user_id = %s AND points - %s >= 50",
|
|
||||||
(bet_value, user_id, bet_value)
|
|
||||||
)
|
|
||||||
|
|
||||||
conn.commit()
|
|
||||||
cur.close()
|
|
||||||
except Exception:
|
|
||||||
conn.rollback()
|
|
@ -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)
|
||||||
|
57
enums.py
57
enums.py
@ -1,57 +0,0 @@
|
|||||||
from enum import Enum
|
|
||||||
|
|
||||||
|
|
||||||
class OpCode(int, Enum):
|
|
||||||
DISPATCH = 0
|
|
||||||
HEARTBEAT = 1
|
|
||||||
IDENTIFY = 2
|
|
||||||
PRESENCE_UPDATE = 3
|
|
||||||
VOICE_STATE_UPDATE = 4
|
|
||||||
RESUME = 6
|
|
||||||
RECONNECT = 7
|
|
||||||
REQUEST_GUILD_MEMBERS = 8
|
|
||||||
INVALID_SESSION = 9
|
|
||||||
HELLO = 10
|
|
||||||
HEARTBEAT_ACK = 11
|
|
||||||
REQUEST_SOUNDBOARD_SOUNDS = 31
|
|
||||||
|
|
||||||
|
|
||||||
class MessageComponentType(str, Enum):
|
|
||||||
ACTION_ROW = 1
|
|
||||||
BUTTON = 2
|
|
||||||
STRING_SELECT = 3
|
|
||||||
TEXT_INPUT = 4
|
|
||||||
USER_SELECT = 5
|
|
||||||
ROLE_SELECT = 6
|
|
||||||
MENTIONNABLE_SELECT = 7
|
|
||||||
CHANNEL_SELECT = 8
|
|
||||||
MODAL = 9
|
|
||||||
|
|
||||||
|
|
||||||
class EventTitle(str, Enum):
|
|
||||||
INTERACTION_CREATE = "INTERACTION_CREATE"
|
|
||||||
MESSAGE_CREATE = "MESSAGE_CREATE"
|
|
||||||
GUILD_CREATE = "GUILD_CREATE"
|
|
||||||
READY = "READY"
|
|
||||||
|
|
||||||
|
|
||||||
class InteractionType(int, Enum):
|
|
||||||
PING = 1
|
|
||||||
APPLICATION_COMMAND = 2
|
|
||||||
MESSAGE_COMPONENT = 3
|
|
||||||
APPLICATION_COMMAND_AUTOCOMPLETE = 4
|
|
||||||
MODAL_SUBMIT = 5
|
|
||||||
|
|
||||||
|
|
||||||
class ApplicationCommand(int, Enum):
|
|
||||||
SUB_COMMAND = 1
|
|
||||||
SUB_COMMAND_GROUP = 2
|
|
||||||
STRING = 3
|
|
||||||
INTEGER = 4
|
|
||||||
BOOLEAN = 5
|
|
||||||
USER = 6
|
|
||||||
CHANNEL = 7
|
|
||||||
ROLE = 8
|
|
||||||
MENTIONABLE = 9
|
|
||||||
NUMBER = 10
|
|
||||||
ATTACHMENT = 11
|
|
598
main.py
598
main.py
@ -1,598 +0,0 @@
|
|||||||
import asyncio
|
|
||||||
import json
|
|
||||||
from typing import Any
|
|
||||||
from uuid import uuid4
|
|
||||||
|
|
||||||
import psycopg2
|
|
||||||
import requests
|
|
||||||
import websockets
|
|
||||||
|
|
||||||
from database import (user_exists, insert_user, guild_exists, insert_guild,
|
|
||||||
insert_poll, insert_vote_options, bet, get_user_vote, change_bet,
|
|
||||||
is_last_poll_created_opened, get_poll_id_opened, close_poll, get_bet_value,
|
|
||||||
get_bet_value_multipliers, get_vote_id_by_vote_option_and_poll_id,
|
|
||||||
get_users_and_bet_value_by_vote_id, add_user_points, minus_user_points, get_user_points,
|
|
||||||
get_user_by_id)
|
|
||||||
from enums import OpCode, EventTitle, InteractionType, ApplicationCommand
|
|
||||||
|
|
||||||
with open('configuration.json', 'r') as file:
|
|
||||||
CONFIG = json.load(file)
|
|
||||||
|
|
||||||
APPLICATION_ID: int = CONFIG["APPLICATION_ID"]
|
|
||||||
GATEWAY_URL: str = "wss://gateway.discord.gg/?v=10&encoding=json"
|
|
||||||
API_URL: str = "https://discord.com/api/v10"
|
|
||||||
TOKEN: str = CONFIG["TOKEN"]
|
|
||||||
|
|
||||||
try:
|
|
||||||
conn = psycopg2.connect(
|
|
||||||
database=CONFIG["DB_NAME"],
|
|
||||||
user=CONFIG["DB_USER"],
|
|
||||||
password=CONFIG["DB_PASSWORD"],
|
|
||||||
host=CONFIG["DB_ADDRESS"],
|
|
||||||
port=CONFIG["DB_PORT"]
|
|
||||||
)
|
|
||||||
except Exception as e:
|
|
||||||
raise e
|
|
||||||
|
|
||||||
|
|
||||||
async def create_command():
|
|
||||||
bodies = [
|
|
||||||
{
|
|
||||||
"name": "poll",
|
|
||||||
"type": ApplicationCommand.SUB_COMMAND,
|
|
||||||
"description": "Des votes sur lesquels gamble !",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "bet",
|
|
||||||
"type": ApplicationCommand.SUB_COMMAND,
|
|
||||||
"description": "Pour pouvoir planifier le prochain pari !",
|
|
||||||
"options": [
|
|
||||||
{
|
|
||||||
"name": "somme",
|
|
||||||
"required": True,
|
|
||||||
"min_value": 0,
|
|
||||||
"description": "La somme du prochain pari",
|
|
||||||
"type": ApplicationCommand.INTEGER
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "close",
|
|
||||||
"type": ApplicationCommand.SUB_COMMAND,
|
|
||||||
"description": "Pour clôturer un sondage",
|
|
||||||
"options": [
|
|
||||||
{
|
|
||||||
"name": "option",
|
|
||||||
"description": "L'issue du sondage",
|
|
||||||
"required": True,
|
|
||||||
"type": ApplicationCommand.STRING
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "profil",
|
|
||||||
"type": ApplicationCommand.SUB_COMMAND,
|
|
||||||
"description": "Afficher des informations sur un utilisateur",
|
|
||||||
"options": [
|
|
||||||
{
|
|
||||||
"name": "user",
|
|
||||||
"description": "La personne concernée",
|
|
||||||
"required": False,
|
|
||||||
"type": ApplicationCommand.USER
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
]
|
|
||||||
|
|
||||||
for body in bodies:
|
|
||||||
requests.post(f"{API_URL}/applications/{APPLICATION_ID}/commands", json=body,
|
|
||||||
headers={"Authorization": f"Bot {TOKEN}"})
|
|
||||||
|
|
||||||
|
|
||||||
async def init_commands():
|
|
||||||
res = requests.get(f"{API_URL}/applications/{APPLICATION_ID}/commands",
|
|
||||||
headers={"Authorization": f"Bot {TOKEN}"})
|
|
||||||
commands = json.loads(res.content)
|
|
||||||
for command in commands:
|
|
||||||
response = requests.delete(f"{API_URL}/applications/{APPLICATION_ID}/commands/{command['id']}",
|
|
||||||
headers={"Authorization": f"Bot {TOKEN}"})
|
|
||||||
if response.status_code == 204:
|
|
||||||
print("Suppression des commandes: Supprimé avec succès !")
|
|
||||||
else:
|
|
||||||
print("Suppression des commandes: Une erreur est survenue")
|
|
||||||
await create_command()
|
|
||||||
|
|
||||||
|
|
||||||
async def create_poll(guild_id: str, creator_id: str, poll_created_id: str, interaction_id: str,
|
|
||||||
interaction_token: str,
|
|
||||||
components: list[dict]):
|
|
||||||
question = next(
|
|
||||||
(comp["components"][0]["value"] for comp in components if comp["components"][0]["custom_id"] == "label"),
|
|
||||||
"Question du poll"
|
|
||||||
)
|
|
||||||
|
|
||||||
vote_options = ""
|
|
||||||
buttons = []
|
|
||||||
vote_text_mem = [] # mémoire pour détecter les doublons
|
|
||||||
for index, comp in enumerate(components):
|
|
||||||
if "vote" in comp["components"][0]["custom_id"] and comp["components"][0]["value"] != "":
|
|
||||||
vote_text = comp["components"][0]["value"]
|
|
||||||
if vote_text not in vote_text_mem:
|
|
||||||
vote_text_mem.append(vote_text)
|
|
||||||
vote_options += f"Option {index}: {vote_text}\n"
|
|
||||||
buttons.append({
|
|
||||||
"type": 2,
|
|
||||||
"label": vote_text,
|
|
||||||
"style": 1,
|
|
||||||
"custom_id": f"{poll_created_id}_{vote_text}_{index}"
|
|
||||||
})
|
|
||||||
|
|
||||||
action_rows = [{"type": 1, "components": buttons[i:i + 5]} for i in range(0, len(buttons), 5)]
|
|
||||||
|
|
||||||
body = {
|
|
||||||
"type": 4,
|
|
||||||
"data": {
|
|
||||||
"embeds": [
|
|
||||||
{
|
|
||||||
"title": "Les paris sont ouverts !",
|
|
||||||
"description": "Vous pouvez parier vos points, ils ne passeront pas en dessous de 50.",
|
|
||||||
"color": 5613215
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"title": f"Sondage: {question}",
|
|
||||||
"description": vote_options,
|
|
||||||
"color": 16775222
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"components": action_rows
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
res = requests.post(
|
|
||||||
f"{API_URL}/interactions/{interaction_id}/{interaction_token}/callback",
|
|
||||||
json=body,
|
|
||||||
headers={"Authorization": f"Bot {TOKEN}"}
|
|
||||||
)
|
|
||||||
|
|
||||||
if res.status_code == 400:
|
|
||||||
print(res.json())
|
|
||||||
else:
|
|
||||||
await insert_poll(conn=conn, creator=creator_id, poll_id=poll_created_id, guild_id=guild_id,
|
|
||||||
question=question)
|
|
||||||
for option in buttons:
|
|
||||||
await insert_vote_options(conn=conn, poll_id=poll_created_id, vote_id=option["custom_id"],
|
|
||||||
vote_option=option["label"])
|
|
||||||
|
|
||||||
|
|
||||||
async def identify(websocket):
|
|
||||||
payload: dict = {
|
|
||||||
"op": OpCode.IDENTIFY,
|
|
||||||
"d": {
|
|
||||||
"token": TOKEN,
|
|
||||||
"properties": {
|
|
||||||
"os": "linux",
|
|
||||||
"browser": "gambling",
|
|
||||||
"device": "gambling"
|
|
||||||
},
|
|
||||||
"presence": {
|
|
||||||
"activities": [{
|
|
||||||
"name": "son argent flamber",
|
|
||||||
"type": 3,
|
|
||||||
}],
|
|
||||||
"status": "dnd",
|
|
||||||
"since": 91879201,
|
|
||||||
"afk": False
|
|
||||||
},
|
|
||||||
"intents": 36871,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
await websocket.send(json.dumps(payload))
|
|
||||||
|
|
||||||
|
|
||||||
async def create_poll_form(interaction_id: str, interaction_token: str, guild_id: str, user_id: str, username: str):
|
|
||||||
poll_id = uuid4()
|
|
||||||
if not await guild_exists(conn=conn, guild_id=guild_id):
|
|
||||||
await insert_guild(conn=conn, guild_id=guild_id)
|
|
||||||
if not await user_exists(conn=conn, user_id=user_id, guild_id=guild_id):
|
|
||||||
await insert_user(conn=conn, user_id=user_id, guild_id=guild_id, username=username)
|
|
||||||
if not await is_last_poll_created_opened(conn=conn, creator=user_id):
|
|
||||||
body = {
|
|
||||||
"type": 9,
|
|
||||||
"data": {
|
|
||||||
"title": "Créer un vote",
|
|
||||||
"custom_id": str(poll_id),
|
|
||||||
"components": [
|
|
||||||
{
|
|
||||||
"type": 1,
|
|
||||||
"components": [
|
|
||||||
{
|
|
||||||
"type": 4,
|
|
||||||
"custom_id": "label",
|
|
||||||
"label": "Question du vote",
|
|
||||||
"placeholder": "Shy aime-t-il les robots?",
|
|
||||||
"style": 1,
|
|
||||||
"min_length": 1,
|
|
||||||
"required": True
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"type": 1,
|
|
||||||
"components": [
|
|
||||||
{
|
|
||||||
"type": 4,
|
|
||||||
"custom_id": "vote1",
|
|
||||||
"label": "Première option",
|
|
||||||
"placeholder": "Oui",
|
|
||||||
"style": 1,
|
|
||||||
"min_length": 1,
|
|
||||||
"required": True
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"type": 1,
|
|
||||||
"components": [
|
|
||||||
{
|
|
||||||
"type": 4,
|
|
||||||
"custom_id": "vote2",
|
|
||||||
"label": "Deuxième option",
|
|
||||||
"placeholder": "Non",
|
|
||||||
"style": 1,
|
|
||||||
"min_length": 1,
|
|
||||||
"required": False
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"type": 1,
|
|
||||||
"components": [
|
|
||||||
{
|
|
||||||
"type": 4,
|
|
||||||
"custom_id": "vote3",
|
|
||||||
"label": "Troisième option",
|
|
||||||
"placeholder": "Peut-être",
|
|
||||||
"style": 1,
|
|
||||||
"min_length": 1,
|
|
||||||
"required": False
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"type": 1,
|
|
||||||
"components": [
|
|
||||||
{
|
|
||||||
"type": 4,
|
|
||||||
"custom_id": "vote4",
|
|
||||||
"label": "Quatrième option",
|
|
||||||
"placeholder": "Pas du tout",
|
|
||||||
"style": 1,
|
|
||||||
"min_length": 1,
|
|
||||||
"required": False
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else:
|
|
||||||
body = {
|
|
||||||
"type": 4,
|
|
||||||
"data": {
|
|
||||||
"content": f"<@{user_id}>, il faut d'abord clôturer ton sondage avant de pouvoir en créer un nouveau. "
|
|
||||||
f"(commande: **/close**)",
|
|
||||||
"flags": 64
|
|
||||||
}
|
|
||||||
}
|
|
||||||
res = requests.post(f"{API_URL}/interactions/{interaction_id}/{interaction_token}/callback", json=body,
|
|
||||||
headers={"Authorization": f"Bot {TOKEN}"})
|
|
||||||
if res.status_code == 400:
|
|
||||||
print(res.json())
|
|
||||||
else:
|
|
||||||
print(res)
|
|
||||||
|
|
||||||
|
|
||||||
async def heartbeat(websocket, interval):
|
|
||||||
while True:
|
|
||||||
await asyncio.sleep(interval / 1000)
|
|
||||||
try:
|
|
||||||
await websocket.send(json.dumps({"op": OpCode.HEARTBEAT, "d": None}))
|
|
||||||
except websockets.exceptions.ConnectionClosed:
|
|
||||||
print("WebSocket fermé")
|
|
||||||
break
|
|
||||||
except Exception as e:
|
|
||||||
print(f"Erreur lors du heartbeat : {e}")
|
|
||||||
break
|
|
||||||
|
|
||||||
|
|
||||||
async def vote_confirmation(interaction_id: str, interaction_token: str, custom_id: str, user_id: str,
|
|
||||||
guild_id: str, username: str):
|
|
||||||
user_vote = await get_user_vote(conn=conn, user_id=user_id, poll_id=custom_id.split("_")[0])
|
|
||||||
if user_vote is not None:
|
|
||||||
body = {
|
|
||||||
"type": 4,
|
|
||||||
"data": {
|
|
||||||
"content": f"<@{user_id}>, tu as déjà voté pour **{user_vote[0].split('_')[1]}**",
|
|
||||||
"flags": 64
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else:
|
|
||||||
if not await user_exists(conn=conn, user_id=user_id, guild_id=guild_id):
|
|
||||||
if not await guild_exists(conn=conn, guild_id=guild_id):
|
|
||||||
await insert_guild(conn=conn, guild_id=guild_id)
|
|
||||||
await insert_user(conn=conn, user_id=user_id, guild_id=guild_id, username=username)
|
|
||||||
bet_value = await get_bet_value(conn=conn, user_id=user_id, guild_id=guild_id)
|
|
||||||
await bet(conn=conn, guild_id=guild_id, user_id=user_id, vote_id=custom_id,
|
|
||||||
poll_id=custom_id.split("_")[0], bet_value=bet_value)
|
|
||||||
await minus_user_points(conn=conn, user_id=user_id, bet_value=bet_value)
|
|
||||||
body = {
|
|
||||||
"type": 4,
|
|
||||||
"data": {
|
|
||||||
"content": f"<@{user_id}>, tu as misé {bet_value} sur l'option **{custom_id.split('_')[1]}** ! 🎉",
|
|
||||||
"flags": 64
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
res = requests.post(
|
|
||||||
f"{API_URL}/interactions/{interaction_id}/{interaction_token}/callback",
|
|
||||||
json=body,
|
|
||||||
headers={"Authorization": f"Bot {TOKEN}", "Content-Type": "application/json"}
|
|
||||||
)
|
|
||||||
if res.status_code == 400:
|
|
||||||
print(res.json())
|
|
||||||
else:
|
|
||||||
print(res)
|
|
||||||
|
|
||||||
|
|
||||||
async def close_poll_cmd(guild_id: str, user_id: str, interaction_id: str, issue: str, interaction_token: str,
|
|
||||||
username: str):
|
|
||||||
if not await guild_exists(conn=conn, guild_id=guild_id):
|
|
||||||
await insert_guild(conn=conn, guild_id=guild_id)
|
|
||||||
if not await user_exists(conn=conn, user_id=user_id, guild_id=guild_id):
|
|
||||||
await insert_user(conn=conn, user_id=user_id, guild_id=guild_id, username=username)
|
|
||||||
poll: tuple = await get_poll_id_opened(conn=conn, creator=user_id)
|
|
||||||
if poll is not None:
|
|
||||||
winner_id = await get_vote_id_by_vote_option_and_poll_id(conn=conn, vote_option=issue, poll_id=poll[1])
|
|
||||||
if winner_id is not None:
|
|
||||||
winner_cote = None
|
|
||||||
values = await get_bet_value_multipliers(conn=conn, poll_id=poll[1])
|
|
||||||
for value in values:
|
|
||||||
vote_id = value[0]
|
|
||||||
users_with_bet_values = await get_users_and_bet_value_by_vote_id(conn=conn, vote_id=vote_id)
|
|
||||||
if vote_id == winner_id:
|
|
||||||
winner_cote = value[1]
|
|
||||||
for user_with_bet_value in users_with_bet_values:
|
|
||||||
print(int(user_with_bet_value[1] * winner_cote))
|
|
||||||
await add_user_points(conn=conn,
|
|
||||||
user_id=user_with_bet_value[0],
|
|
||||||
bet_value=int(user_with_bet_value[1] * winner_cote))
|
|
||||||
await close_poll(conn=conn, poll_id=poll[1])
|
|
||||||
if winner_cote is not None:
|
|
||||||
out = (round(winner_cote, 2) - 1) * 100
|
|
||||||
else:
|
|
||||||
out = 0.0
|
|
||||||
body = {
|
|
||||||
"type": 4,
|
|
||||||
"data": {
|
|
||||||
"content": f'@everyone le sondage **{poll[2]}** est terminé ! L\'issue gagnante est **{issue}** '
|
|
||||||
f'avec une côte de {out}%'
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else:
|
|
||||||
body = {
|
|
||||||
"type": 4,
|
|
||||||
"data": {
|
|
||||||
"content": f"<@{user_id}>, L'option **{issue}** n'existe pas.",
|
|
||||||
"flags": 64
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else:
|
|
||||||
body = {
|
|
||||||
"type": 4,
|
|
||||||
"data": {
|
|
||||||
"content": f"<@{user_id}>, tu n'as actuellement aucun sondage en cours.",
|
|
||||||
"flags": 64
|
|
||||||
}
|
|
||||||
}
|
|
||||||
res = requests.post(f"{API_URL}/interactions/{interaction_id}/{interaction_token}/callback", json=body,
|
|
||||||
headers={"Authorization": f"Bot {TOKEN}"})
|
|
||||||
if res.status_code == 400:
|
|
||||||
print(res.json())
|
|
||||||
else:
|
|
||||||
print(res)
|
|
||||||
|
|
||||||
|
|
||||||
async def get_event(response: Any):
|
|
||||||
match response["t"]:
|
|
||||||
# case EventTitle.MESSAGE_CREATE:
|
|
||||||
case EventTitle.INTERACTION_CREATE:
|
|
||||||
if response["d"]["type"] == InteractionType.MODAL_SUBMIT:
|
|
||||||
await create_poll(
|
|
||||||
guild_id=response["d"]["guild"]["id"],
|
|
||||||
creator_id=response["d"]["member"]["user"]["id"],
|
|
||||||
poll_created_id=response["d"]["data"]["custom_id"],
|
|
||||||
interaction_id=response["d"]["id"],
|
|
||||||
interaction_token=response["d"]["token"],
|
|
||||||
components=response["d"]["data"]["components"]
|
|
||||||
)
|
|
||||||
elif response["d"]["type"] == InteractionType.MESSAGE_COMPONENT:
|
|
||||||
custom_id = response["d"]["data"]["custom_id"]
|
|
||||||
user_id = response["d"]["member"]["user"]["id"]
|
|
||||||
await vote_confirmation(interaction_id=response["d"]["id"],
|
|
||||||
interaction_token=response["d"]["token"],
|
|
||||||
custom_id=custom_id,
|
|
||||||
user_id=user_id,
|
|
||||||
guild_id=response["d"]["guild"]["id"],
|
|
||||||
username=response["d"]["member"]["user"]["username"])
|
|
||||||
elif (response["d"]["type"] == InteractionType.APPLICATION_COMMAND and
|
|
||||||
response["d"]["data"]["name"] == 'poll'):
|
|
||||||
await create_poll_form(interaction_id=response["d"]["id"],
|
|
||||||
user_id=response["d"]["member"]["user"]["id"],
|
|
||||||
interaction_token=response["d"]["token"],
|
|
||||||
guild_id=response["d"]["guild_id"],
|
|
||||||
username=response["d"]["member"]["user"]["username"])
|
|
||||||
elif (response["d"]["type"] == InteractionType.APPLICATION_COMMAND and
|
|
||||||
response["d"]["data"]["name"] == 'close'):
|
|
||||||
await close_poll_cmd(guild_id=response["d"]["guild_id"],
|
|
||||||
user_id=response["d"]["member"]["user"]["id"],
|
|
||||||
interaction_id=response["d"]["id"],
|
|
||||||
interaction_token=response["d"]["token"],
|
|
||||||
issue=response["d"]["data"]["options"][0]["value"],
|
|
||||||
username=response["d"]["member"]["user"]["username"])
|
|
||||||
elif (response["d"]["type"] == InteractionType.APPLICATION_COMMAND and
|
|
||||||
response["d"]["data"]["name"] == 'bet'):
|
|
||||||
command_option: int = response["d"]["data"]["options"][0]["value"]
|
|
||||||
await change_bet_cmd(guild_id=response["d"]["guild_id"],
|
|
||||||
command_option=command_option,
|
|
||||||
user_id=response["d"]["member"]["user"]["id"],
|
|
||||||
username=response["d"]["member"]["user"]["username"],
|
|
||||||
interaction_id=response["d"]["id"],
|
|
||||||
interaction_token=response["d"]["token"])
|
|
||||||
elif (response["d"]["type"] == InteractionType.APPLICATION_COMMAND and
|
|
||||||
response["d"]["data"]["name"] == 'profil'):
|
|
||||||
command_option: str = ''
|
|
||||||
user_avatar: str = ''
|
|
||||||
username: str = ''
|
|
||||||
try:
|
|
||||||
command_option = response["d"]["data"]["options"][0]["value"]
|
|
||||||
user_avatar = response["d"]["data"]["resolved"]["users"][str(command_option)]["avatar"]
|
|
||||||
username = response["d"]["data"]["resolved"]["users"][str(command_option)]["username"]
|
|
||||||
except Exception as e:
|
|
||||||
pass
|
|
||||||
if command_option == '':
|
|
||||||
command_option = response["d"]["member"]["user"]["id"]
|
|
||||||
if user_avatar == '':
|
|
||||||
user_avatar = response["d"]["member"]["user"]["avatar"]
|
|
||||||
username = response["d"]["member"]["user"]["username"]
|
|
||||||
await show_user_profile(guild_id=response["d"]["guild_id"],
|
|
||||||
interaction_id=response["d"]["id"],
|
|
||||||
interaction_token=response["d"]["token"],
|
|
||||||
avatar=user_avatar,
|
|
||||||
concerned_user_id=command_option,
|
|
||||||
username=username)
|
|
||||||
|
|
||||||
case _:
|
|
||||||
print(response)
|
|
||||||
|
|
||||||
|
|
||||||
async def show_user_profile(guild_id: str, interaction_id: str, interaction_token: str,
|
|
||||||
concerned_user_id: str, avatar: str, username: str):
|
|
||||||
if not await guild_exists(conn=conn, guild_id=guild_id):
|
|
||||||
await insert_guild(conn=conn, guild_id=guild_id)
|
|
||||||
if not await user_exists(conn=conn, user_id=concerned_user_id, guild_id=guild_id):
|
|
||||||
await insert_user(conn=conn, user_id=concerned_user_id, guild_id=guild_id, username=username)
|
|
||||||
|
|
||||||
concerned_user = await get_user_by_id(conn=conn, user_id=concerned_user_id, guild_id=guild_id)
|
|
||||||
body = {
|
|
||||||
"type": 4,
|
|
||||||
"data": {
|
|
||||||
"embeds": [
|
|
||||||
{
|
|
||||||
"title": f"Profil de {concerned_user[0]}",
|
|
||||||
"description": f"Solde : {concerned_user[1]}\n"
|
|
||||||
f"Valeur du prochain pari: {concerned_user[2]}",
|
|
||||||
"image": {
|
|
||||||
"url": f"https://cdn.discordapp.com/avatars/{concerned_user_id}/{avatar}"
|
|
||||||
},
|
|
||||||
"color": 11141375
|
|
||||||
}
|
|
||||||
],
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
res = requests.post(f"{API_URL}/interactions/{interaction_id}/{interaction_token}/callback", json=body,
|
|
||||||
headers={"Authorization": f"Bot {TOKEN}"})
|
|
||||||
if res.status_code == 400:
|
|
||||||
print(res.json())
|
|
||||||
else:
|
|
||||||
print(res)
|
|
||||||
|
|
||||||
|
|
||||||
async def change_bet_cmd(guild_id: str, command_option: int, user_id: str, username: str,
|
|
||||||
interaction_id: str, interaction_token: str):
|
|
||||||
if not await guild_exists(conn=conn, guild_id=guild_id):
|
|
||||||
await insert_user(conn=conn, guild_id=guild_id, user_id=user_id, username=username)
|
|
||||||
if not await user_exists(conn=conn, user_id=user_id, guild_id=guild_id):
|
|
||||||
await insert_guild(conn=conn, guild_id=guild_id)
|
|
||||||
|
|
||||||
if await get_user_points(conn=conn, user_id=user_id, guild_id=guild_id) >= command_option:
|
|
||||||
await change_bet(conn=conn, guild_id=guild_id, user_id=user_id, new_bet_amount=command_option)
|
|
||||||
body = {
|
|
||||||
"type": 4,
|
|
||||||
"data": {
|
|
||||||
"content": f"<@{user_id}>, ton prochain pari vaudra **{command_option}**.",
|
|
||||||
"flags": 64
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else:
|
|
||||||
body = {
|
|
||||||
"type": 4,
|
|
||||||
"data": {
|
|
||||||
"content": f"<@{user_id}>, solde insuffisant !",
|
|
||||||
"flags": 64
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
res = requests.post(f"{API_URL}/interactions/{interaction_id}/{interaction_token}/callback", json=body,
|
|
||||||
headers={"Authorization": f"Bot {TOKEN}"})
|
|
||||||
if res.status_code == 400:
|
|
||||||
print(res.json())
|
|
||||||
else:
|
|
||||||
print(res)
|
|
||||||
|
|
||||||
|
|
||||||
async def connect():
|
|
||||||
while True:
|
|
||||||
try:
|
|
||||||
async with websockets.connect(GATEWAY_URL) as websocket:
|
|
||||||
response = json.loads(await websocket.recv())
|
|
||||||
heartbeat_interval = response["d"]["heartbeat_interval"]
|
|
||||||
|
|
||||||
heartbeat_task = asyncio.create_task(heartbeat(websocket, heartbeat_interval))
|
|
||||||
await identify(websocket)
|
|
||||||
|
|
||||||
while True:
|
|
||||||
try:
|
|
||||||
response = json.loads(await websocket.recv())
|
|
||||||
op = response.get("op")
|
|
||||||
|
|
||||||
match op:
|
|
||||||
case OpCode.DISPATCH:
|
|
||||||
await get_event(response)
|
|
||||||
case OpCode.RECONNECT:
|
|
||||||
print("Reconnexion demandée...")
|
|
||||||
break
|
|
||||||
case OpCode.INVALID_SESSION:
|
|
||||||
print("Session invalide, réidentification...")
|
|
||||||
await asyncio.sleep(1)
|
|
||||||
await identify(websocket)
|
|
||||||
case _:
|
|
||||||
pass
|
|
||||||
|
|
||||||
except websockets.exceptions.ConnectionClosed as e:
|
|
||||||
print(f"Connexion fermée : {e}")
|
|
||||||
break
|
|
||||||
except Exception as e:
|
|
||||||
print(f"Erreur dans le loop principal : {e}")
|
|
||||||
break
|
|
||||||
|
|
||||||
heartbeat_task.cancel()
|
|
||||||
try:
|
|
||||||
await heartbeat_task
|
|
||||||
except asyncio.CancelledError:
|
|
||||||
pass
|
|
||||||
|
|
||||||
except Exception as e:
|
|
||||||
print(f"Erreur de connexion WebSocket : {e}")
|
|
||||||
|
|
||||||
print("Tentative de reconnexion dans 5 secondes...")
|
|
||||||
await asyncio.sleep(5)
|
|
||||||
|
|
||||||
|
|
||||||
async def main():
|
|
||||||
gateway_connect = asyncio.create_task(connect())
|
|
||||||
# await init_commands()
|
|
||||||
await gateway_connect
|
|
||||||
|
|
||||||
|
|
||||||
asyncio.run(main())
|
|
18
package.json
Normal file
18
package.json
Normal 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"
|
||||||
|
}
|
||||||
|
}
|
BIN
requirements.txt
BIN
requirements.txt
Binary file not shown.
45
src/constants.js
Normal file
45
src/constants.js
Normal 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
|
190
src/database.js
Normal file
190
src/database.js
Normal file
@ -0,0 +1,190 @@
|
|||||||
|
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 userExistsInDB(userId, guildId) {
|
||||||
|
const response = await DATABASE_CLIENT.query(
|
||||||
|
"SELECT user_id FROM member WHERE user_id=$1 AND guild_id=$2",
|
||||||
|
[userId, guildId]
|
||||||
|
);
|
||||||
|
return response.rows.length > 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
async function findPollCreatedByUserAndOpened(userId) {
|
||||||
|
const response = await DATABASE_CLIENT.query(
|
||||||
|
"SELECT poll_id, question FROM poll WHERE creator=$1 and opened=true",
|
||||||
|
[userId]
|
||||||
|
);
|
||||||
|
return response.rows[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
async function findVoteIdByVoteOptionAndPollId(voteOption, pollId) {
|
||||||
|
const response = await DATABASE_CLIENT.query(
|
||||||
|
"SELECT vote_id FROM vote WHERE vote_option=$1 AND poll_id=$2",
|
||||||
|
[voteOption, pollId]
|
||||||
|
);
|
||||||
|
return response.rows[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
async function findUserPoints(userId, guildId) {
|
||||||
|
const response = await DATABASE_CLIENT.query(
|
||||||
|
"SELECT points FROM member WHERE user_id=$1 AND guild_id=$2",
|
||||||
|
[userId, guildId]
|
||||||
|
);
|
||||||
|
return response.rows[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
async function changeNextBetValueForUser(userId, guildId, amount) {
|
||||||
|
await DATABASE_CLIENT.query(
|
||||||
|
"UPDATE member SET bet_value=$1 WHERE user_id=$2 AND guild_id=$3",
|
||||||
|
[amount, userId, guildId]
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
async function findBetValueMultiplierForPoll(pollId) {
|
||||||
|
const response = await DATABASE_CLIENT.query(
|
||||||
|
"SELECT vote_id, (1 + (1 - (SUM(vote_member.bet_value) / total.sum))) AS cote " +
|
||||||
|
"FROM vote_member " +
|
||||||
|
"CROSS JOIN (SELECT SUM(bet_value) " +
|
||||||
|
"AS sum FROM vote_member WHERE poll_id=$1) " +
|
||||||
|
"AS total " +
|
||||||
|
"WHERE poll_id=$1 " +
|
||||||
|
"GROUP BY vote_id, total.sum",
|
||||||
|
[pollId]
|
||||||
|
);
|
||||||
|
return response.rows;
|
||||||
|
}
|
||||||
|
|
||||||
|
async function findUsersAndBetValueByVoteId(voteId) {
|
||||||
|
const response = await DATABASE_CLIENT.query(
|
||||||
|
"SELECT user_id, bet_value FROM vote_member WHERE vote_id=$1",
|
||||||
|
[voteId]
|
||||||
|
);
|
||||||
|
return response.rows;
|
||||||
|
}
|
||||||
|
|
||||||
|
async function addPointsToUser(userId, betValue) {
|
||||||
|
await DATABASE_CLIENT.query(
|
||||||
|
"UPDATE member SET points = points + $1 WHERE user_id = $2",
|
||||||
|
[betValue, userId]
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
async function closePoll(pollId) {
|
||||||
|
await DATABASE_CLIENT.query(
|
||||||
|
"UPDATE poll SET opened = false WHERE poll_id=$1",
|
||||||
|
[pollId]
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
async function findUserById(userId, guildId) {
|
||||||
|
const response = await DATABASE_CLIENT.query(
|
||||||
|
"SELECT username, points, bet_value FROM member WHERE user_id=$1 AND guild_id=$2",
|
||||||
|
[userId, guildId]
|
||||||
|
);
|
||||||
|
return response.rows[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
async function isLastPollCreatedByUserOpen(userId) {
|
||||||
|
const response = await DATABASE_CLIENT.query(
|
||||||
|
"SELECT opened FROM poll WHERE creator=$1 AND opened=true",
|
||||||
|
[userId]
|
||||||
|
);
|
||||||
|
return !response.rows.length > 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
async function findUserVoteForPoll(userId, pollId) {
|
||||||
|
const response = await DATABASE_CLIENT.query(
|
||||||
|
"SELECT vote_id FROM vote_member WHERE user_id=$1 AND poll_id=$2",
|
||||||
|
[userId, pollId]
|
||||||
|
);
|
||||||
|
return response.rows[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
async function findBetValueForUser(userId, guildId) {
|
||||||
|
const response = await DATABASE_CLIENT.query(
|
||||||
|
"SELECT bet_value FROM member WHERE user_id=$1 AND member.guild_id=$2",
|
||||||
|
[userId, guildId]
|
||||||
|
);
|
||||||
|
return response.rows[0].bet_value;
|
||||||
|
}
|
||||||
|
|
||||||
|
async function substractUserPoints(userId, betValue) {
|
||||||
|
await DATABASE_CLIENT.query(
|
||||||
|
"UPDATE member SET points = points - $1 WHERE user_id = $2 AND points - $1 >= 50",
|
||||||
|
betValue, userId
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
async function bet(userId, pollId, guildId, voteId, betValue) {
|
||||||
|
await DATABASE_CLIENT.query(
|
||||||
|
"INSERT INTO vote_member (user_id, poll_id, guild_id, vote_id, bet_value) VALUES ($1, $2, $3, $4, $5)",
|
||||||
|
[userId, pollId, guildId, voteId, betValue]
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
async function insertVoteOptions(pollId, voteId, voteOption) {
|
||||||
|
await DATABASE_CLIENT.query(
|
||||||
|
"INSERT INTO vote (poll_id, vote_id, vote_option) VALUES ($1, $2, $3)",
|
||||||
|
[pollId, voteId, voteOption]
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
async function insertUserIntoDB(userId, guildId, username) {
|
||||||
|
await DATABASE_CLIENT.query(
|
||||||
|
"INSERT INTO member (user_id, guild_id, username) VALUES ($1, $2, $3)",
|
||||||
|
[userId, guildId, username]
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
async function guildExistsInDB(guildId) {
|
||||||
|
const response = await DATABASE_CLIENT.query(
|
||||||
|
"SELECT guild_id FROM guild WHERE guild_id=$1",
|
||||||
|
[guildId]
|
||||||
|
);
|
||||||
|
return response.rows.length > 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
async function insertGuildIntoDB(guildId) {
|
||||||
|
await DATABASE_CLIENT.query(
|
||||||
|
"INSERT INTO guild (guild_id) VALUES ($1)",
|
||||||
|
[guildId]
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
exports.DATABASE_CLIENT = DATABASE_CLIENT;
|
||||||
|
exports.userExistsInDB = userExistsInDB;
|
||||||
|
exports.insertPollIntoDB = insertPollIntoDB;
|
||||||
|
exports.guildExistsInDB = guildExistsInDB;
|
||||||
|
exports.insertGuildIntoDB = insertGuildIntoDB;
|
||||||
|
exports.insertUserIntoDB = insertUserIntoDB;
|
||||||
|
exports.isLastPollCreatedByUserOpen = isLastPollCreatedByUserOpen;
|
||||||
|
exports.findPollCreatedByUserAndOpened = findPollCreatedByUserAndOpened;
|
||||||
|
exports.findUserById = findUserById;
|
||||||
|
exports.findUserVoteForPoll = findUserVoteForPoll;
|
||||||
|
exports.findBetValueForUser = findBetValueForUser;
|
||||||
|
exports.bet = bet;
|
||||||
|
exports.substractUserPoints = substractUserPoints;
|
||||||
|
exports.insertVoteOptions = insertVoteOptions;
|
||||||
|
exports.findVoteIdByVoteOptionAndPollId = findVoteIdByVoteOptionAndPollId;
|
||||||
|
exports.findBetValueMultiplierForPoll = findBetValueMultiplierForPoll;
|
||||||
|
exports.findUsersAndBetValueByVoteId = findUsersAndBetValueByVoteId;
|
||||||
|
exports.addPointsToUser = addPointsToUser;
|
||||||
|
exports.closePoll = closePoll;
|
||||||
|
exports.findUserPoints = findUserPoints;
|
||||||
|
exports.changeNextBetValueForUser = changeNextBetValueForUser;
|
13
src/deploy-commands.js
Normal file
13
src/deploy-commands.js
Normal 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);
|
289
src/main.js
Normal file
289
src/main.js
Normal file
@ -0,0 +1,289 @@
|
|||||||
|
const {
|
||||||
|
Client,
|
||||||
|
Events,
|
||||||
|
GatewayIntentBits,
|
||||||
|
ModalBuilder,
|
||||||
|
TextInputBuilder,
|
||||||
|
ActionRowBuilder,
|
||||||
|
EmbedBuilder,
|
||||||
|
Colors, ButtonBuilder
|
||||||
|
} = require('discord.js');
|
||||||
|
const {
|
||||||
|
DATABASE_CLIENT,
|
||||||
|
insertPollIntoDB,
|
||||||
|
guildExistsInDB,
|
||||||
|
insertGuildIntoDB,
|
||||||
|
userExistsInDB,
|
||||||
|
insertUserIntoDB,
|
||||||
|
isLastPollCreatedByUserOpen,
|
||||||
|
findPollCreatedByUserAndOpened,
|
||||||
|
findUserById,
|
||||||
|
findUserVoteForPoll,
|
||||||
|
findBetValueForUser,
|
||||||
|
bet,
|
||||||
|
insertVoteOptions,
|
||||||
|
findVoteIdByVoteOptionAndPollId,
|
||||||
|
findBetValueMultiplierForPoll,
|
||||||
|
findUsersAndBetValueByVoteId,
|
||||||
|
addPointsToUser,
|
||||||
|
closePoll,
|
||||||
|
findUserPoints,
|
||||||
|
changeNextBetValueForUser
|
||||||
|
} = require('./database');
|
||||||
|
const {TOKEN} = require('../config.json');
|
||||||
|
const {v4: uuidv4} = require('uuid');
|
||||||
|
const {POLL_COMMAND_NAME, PROFIL_COMMAND_NAME, BET_COMMAND_NAME, CLOSE_COMMAND_NAME} = require("./constants");
|
||||||
|
const {ButtonStyle, ActivityType} = require("discord-api-types/v10");
|
||||||
|
const {MessageFlags} = 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}`);
|
||||||
|
client.user.setPresence({
|
||||||
|
status: "dnd",
|
||||||
|
activities: [
|
||||||
|
{
|
||||||
|
name: "son argent flamber",
|
||||||
|
type: ActivityType.Watching,
|
||||||
|
}
|
||||||
|
]
|
||||||
|
})
|
||||||
|
await DATABASE_CLIENT.connect();
|
||||||
|
});
|
||||||
|
|
||||||
|
client.on(Events.InteractionCreate, async interaction => {
|
||||||
|
await createGuildAndUserIfNecessary(interaction.guildId, interaction.user);
|
||||||
|
if (interaction.isCommand()) {
|
||||||
|
const {commandName} = interaction;
|
||||||
|
switch (commandName) {
|
||||||
|
case POLL_COMMAND_NAME: {
|
||||||
|
if (await isLastPollCreatedByUserOpen(interaction.user.id)) {
|
||||||
|
await interaction.showModal(buildPollModal());
|
||||||
|
} else {
|
||||||
|
await interaction.reply({
|
||||||
|
flags: MessageFlags.Ephemeral,
|
||||||
|
content: `${interaction.user.username}, il faut d'abord clôturer ton sondage avant de pouvoir en créer un nouveau. (commande: **/close**)`
|
||||||
|
})
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case CLOSE_COMMAND_NAME: {
|
||||||
|
const actualOpenedPollCreatedByUser = await findPollCreatedByUserAndOpened(interaction.user.id);
|
||||||
|
|
||||||
|
if (!actualOpenedPollCreatedByUser) {
|
||||||
|
await interaction.reply({
|
||||||
|
flags: MessageFlags.Ephemeral,
|
||||||
|
content: `${interaction.user.username}, tu n'as actuellement aucun sondage en cours.`
|
||||||
|
});
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
const optionSendedByUser = interaction.options.data[0].value;
|
||||||
|
let winnerVoteId = await findVoteIdByVoteOptionAndPollId(optionSendedByUser, actualOpenedPollCreatedByUser.poll_id);
|
||||||
|
|
||||||
|
if (!winnerVoteId) {
|
||||||
|
await interaction.reply({
|
||||||
|
flags: MessageFlags.Ephemeral,
|
||||||
|
content: `${interaction.user.username}, L'option **${optionSendedByUser}** n'existe pas.`
|
||||||
|
});
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
winnerVoteId = winnerVoteId.vote_id;
|
||||||
|
|
||||||
|
const voteIdsWithMultipliers = await findBetValueMultiplierForPoll(actualOpenedPollCreatedByUser.poll_id);
|
||||||
|
let winnerCote;
|
||||||
|
|
||||||
|
for (const voteIdWithMultiplier of voteIdsWithMultipliers) {
|
||||||
|
const usersThatVotedActualVoteId = await findUsersAndBetValueByVoteId(voteIdWithMultiplier.vote_id);
|
||||||
|
|
||||||
|
if (voteIdWithMultiplier.vote_id === winnerVoteId) {
|
||||||
|
winnerCote = Number.parseFloat(voteIdWithMultiplier.cote);
|
||||||
|
for (const user of usersThatVotedActualVoteId) {
|
||||||
|
const gain = Math.round(user.bet_value * winnerCote);
|
||||||
|
await addPointsToUser(user.user_id, gain);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
await closePoll(actualOpenedPollCreatedByUser.poll_id);
|
||||||
|
|
||||||
|
const out = winnerCote ? ((Math.round(winnerCote * 100) / 100 - 1) * 100) : 0;
|
||||||
|
|
||||||
|
await interaction.reply({
|
||||||
|
content: `@everyone le sondage **${actualOpenedPollCreatedByUser.question}** est terminé ! L'issue gagnante est **${optionSendedByUser}** avec une côte de ${out.toFixed(2)}%`
|
||||||
|
});
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case PROFIL_COMMAND_NAME: {
|
||||||
|
let concernedUser;
|
||||||
|
if (interaction.options.data.length) {
|
||||||
|
concernedUser = interaction.options.data[0].user;
|
||||||
|
if (!await userExistsInDB(concernedUser.id, interaction.guildId)) {
|
||||||
|
await insertUserIntoDB(concernedUser.id, interaction.guildId, concernedUser.username);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
concernedUser = interaction.user;
|
||||||
|
}
|
||||||
|
const userFetched = await findUserById(concernedUser.id, interaction.guildId);
|
||||||
|
|
||||||
|
const profilEmbed = new EmbedBuilder()
|
||||||
|
.setTitle(`Profil de ${concernedUser.username}`)
|
||||||
|
.setThumbnail(`https://cdn.discordapp.com/avatars/${concernedUser.id}/${concernedUser.avatar}`)
|
||||||
|
.setFooter({text: 'https://guams.fr', iconURL: 'https://guams.fr/icon.webp'})
|
||||||
|
.addFields(
|
||||||
|
{name: 'Solde du compte', value: `${userFetched.points}`, inline: true},
|
||||||
|
{name: 'Valeur du prochain pari', value: `${userFetched.bet_value}`, inline: true})
|
||||||
|
.setTimestamp()
|
||||||
|
.setColor(Colors.Aqua);
|
||||||
|
await interaction.reply({embeds: [profilEmbed]});
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case BET_COMMAND_NAME: {
|
||||||
|
const amountForNextBet = interaction.options.data[0].value;
|
||||||
|
const senderPoints = await findUserPoints(interaction.user.id, interaction.guildId);
|
||||||
|
if (Number.parseInt(senderPoints.points) >= amountForNextBet) {
|
||||||
|
await changeNextBetValueForUser(interaction.user.id, interaction.guildId, amountForNextBet);
|
||||||
|
await interaction.reply({
|
||||||
|
flags: MessageFlags.Ephemeral,
|
||||||
|
content: `${interaction.user.username}, ton prochain pari vaudra **${amountForNextBet}**`
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
await interaction.reply({
|
||||||
|
flags: MessageFlags.Ephemeral,
|
||||||
|
content: `${interaction.user.username}, solde insuffisant !`
|
||||||
|
});
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default: {
|
||||||
|
console.log(`Commande [${commandName}] inconnue`);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} 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)
|
||||||
|
.setFooter({text: 'https://guams.fr', iconURL: 'https://guams.fr/icon.webp'});
|
||||||
|
|
||||||
|
await insertPollIntoDB(sender.id, interaction.customId, guildFromWhereUserSendedInteraction.id, pollQuestionObj.value);
|
||||||
|
for (let i = 0; i < voteOptions.length; i++) {
|
||||||
|
await insertVoteOptions(interaction.customId, `${interaction.customId}_${voteOptions[i]}_${i + 1}`, voteOptions[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
await interaction.reply({embeds: [introEmbed, pollEmbed], components: [buttons]});
|
||||||
|
} else if (interaction.isMessageComponent()) {
|
||||||
|
const userVote = await findUserVoteForPoll(interaction.user.id, interaction.customId.split("_")[0])
|
||||||
|
if (userVote) {
|
||||||
|
await interaction.reply({
|
||||||
|
flags: MessageFlags.Ephemeral,
|
||||||
|
content: `${interaction.user.username}, tu as déjà voté pour **${userVote.vote_id.split("_")[1]}**`
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
const userBetValue = await findBetValueForUser(interaction.user.id, interaction.guildId);
|
||||||
|
await bet(interaction.user.id, interaction.customId.split("_")[0], interaction.guildId, interaction.customId, userBetValue)
|
||||||
|
await interaction.reply({
|
||||||
|
flags: MessageFlags.Ephemeral,
|
||||||
|
content: `${interaction.user.username}, tu as misé ${userBetValue} sur l'option **${interaction.customId.split("_")[1]}** ! 🎉`
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
async function createGuildAndUserIfNecessary(guildId, user) {
|
||||||
|
if (!await guildExistsInDB(guildId)) {
|
||||||
|
insertGuildIntoDB(guildId);
|
||||||
|
}
|
||||||
|
if (!await userExistsInDB(user.id, guildId)) {
|
||||||
|
insertUserIntoDB(user.id, guildId, user.username);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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);
|
Loading…
Reference in New Issue
Block a user