mirror of https://github.com/stijndcl/didier
Compare commits
No commits in common. "7bbe4db26d7db185e507676f6fadf2ad7056df51" and "34fe8a0feb6b7f558ae6954e6de417d4f77ef3bc" have entirely different histories.
7bbe4db26d
...
34fe8a0feb
|
|
@ -1,11 +1,14 @@
|
||||||
|
files/status.txt
|
||||||
|
files/readyMessage.txt
|
||||||
|
files/client.txt
|
||||||
files/lastTasks.json
|
files/lastTasks.json
|
||||||
files/c4.json
|
files/c4.json
|
||||||
files/hangman.json
|
files/hangman.json
|
||||||
files/stats.json
|
files/stats.json
|
||||||
files/lost.json
|
files/lost.json
|
||||||
files/locked.json
|
files/locked.json
|
||||||
|
files/database.json
|
||||||
files/ufora_notifications.json
|
files/ufora_notifications.json
|
||||||
.idea/
|
.idea/
|
||||||
__pycache__
|
__pycache__
|
||||||
.env
|
.env
|
||||||
/venv/
|
|
||||||
|
|
@ -1,82 +0,0 @@
|
||||||
from discord.ext import ipc
|
|
||||||
from functions.database import custom_commands
|
|
||||||
import json
|
|
||||||
from quart import Quart, jsonify, request
|
|
||||||
from quart_cors import cors
|
|
||||||
from time import time
|
|
||||||
|
|
||||||
|
|
||||||
app = Quart(__name__)
|
|
||||||
# TODO allow_origin=re.compile(r"http://localhost:.*")
|
|
||||||
# needs higher Python & Quart version
|
|
||||||
app = cors(app, allow_origin="*")
|
|
||||||
app.config.from_object(__name__)
|
|
||||||
|
|
||||||
|
|
||||||
ipc_client = ipc.Client(secret_key="SOME_SECRET_KEY")
|
|
||||||
|
|
||||||
|
|
||||||
@app.route("/ping", methods=["GET"])
|
|
||||||
async def ping():
|
|
||||||
"""
|
|
||||||
Send a ping request, monitors bot latency, endpoint time, and PSQL latency
|
|
||||||
"""
|
|
||||||
latency = await ipc_client.request("get_bot_latency")
|
|
||||||
|
|
||||||
return jsonify({"bot_latency": latency, "response_sent": time()})
|
|
||||||
|
|
||||||
|
|
||||||
@app.route("/dm", methods=["POST"])
|
|
||||||
async def send_dm():
|
|
||||||
"""
|
|
||||||
Send a DM to the given user
|
|
||||||
"""
|
|
||||||
data = json.loads((await request.body).decode('UTF-8'))
|
|
||||||
|
|
||||||
dm = await ipc_client.request(
|
|
||||||
"send_dm",
|
|
||||||
user=int(data["userid"]),
|
|
||||||
message=data.get("message")
|
|
||||||
)
|
|
||||||
|
|
||||||
return jsonify({"response": dm})
|
|
||||||
|
|
||||||
|
|
||||||
@app.route("/custom", methods=["GET"])
|
|
||||||
async def get_all_custom_commands():
|
|
||||||
"""
|
|
||||||
Return a list of all custom commands in the bot
|
|
||||||
"""
|
|
||||||
commands = custom_commands.get_all()
|
|
||||||
|
|
||||||
return jsonify(commands)
|
|
||||||
|
|
||||||
|
|
||||||
@app.route("/custom/<command_id>")
|
|
||||||
async def get_custom_command(command_id):
|
|
||||||
try:
|
|
||||||
command_id = int(command_id)
|
|
||||||
except ValueError:
|
|
||||||
# Id is not an int
|
|
||||||
return unprocessable_entity("Parameter id was not a valid integer.")
|
|
||||||
|
|
||||||
command = custom_commands.get_by_id(command_id)
|
|
||||||
|
|
||||||
if command is None:
|
|
||||||
return page_not_found("")
|
|
||||||
|
|
||||||
return jsonify(command)
|
|
||||||
|
|
||||||
|
|
||||||
@app.errorhandler(404)
|
|
||||||
def page_not_found(e):
|
|
||||||
return jsonify({"error": "No resource could be found matching the given URL."}), 404
|
|
||||||
|
|
||||||
|
|
||||||
@app.errorhandler(422)
|
|
||||||
def unprocessable_entity(e):
|
|
||||||
return jsonify({"error": e}), 422
|
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
|
||||||
app.run()
|
|
||||||
|
|
@ -5,7 +5,6 @@ from discord.ext import commands
|
||||||
from functions import checks, easterEggResponses
|
from functions import checks, easterEggResponses
|
||||||
from functions.database import stats, muttn, custom_commands, commands as command_stats
|
from functions.database import stats, muttn, custom_commands, commands as command_stats
|
||||||
import pytz
|
import pytz
|
||||||
from settings import READY_MESSAGE, SANDBOX, STATUS_MESSAGE
|
|
||||||
import time
|
import time
|
||||||
import traceback
|
import traceback
|
||||||
|
|
||||||
|
|
@ -31,13 +30,20 @@ class Events(commands.Cog):
|
||||||
"""
|
"""
|
||||||
Function called when the bot is ready & done leading.
|
Function called when the bot is ready & done leading.
|
||||||
"""
|
"""
|
||||||
# Set status
|
# Change status
|
||||||
await self.client.change_presence(status=discord.Status.online, activity=discord.Game(STATUS_MESSAGE))
|
with open("files/status.txt", "r") as statusFile:
|
||||||
|
status = statusFile.readline()
|
||||||
|
|
||||||
print(READY_MESSAGE)
|
await self.client.change_presence(status=discord.Status.online, activity=discord.Game(str(status)))
|
||||||
|
|
||||||
|
# Print a message in the terminal to show that he's ready
|
||||||
|
with open("files/readyMessage.txt", "r") as readyFile:
|
||||||
|
readyMessage = readyFile.readline()
|
||||||
|
|
||||||
|
print(readyMessage)
|
||||||
|
|
||||||
# Add constants to the client as a botvar
|
# Add constants to the client as a botvar
|
||||||
self.client.constants = constants.Live if SANDBOX else constants.Zandbak
|
self.client.constants = constants.Live if "zandbak" not in readyMessage else constants.Zandbak
|
||||||
|
|
||||||
@commands.Cog.listener()
|
@commands.Cog.listener()
|
||||||
async def on_message(self, message):
|
async def on_message(self, message):
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
from data.menus import paginatedLeaderboard
|
from data import paginatedLeaderboard
|
||||||
from decorators import help
|
from decorators import help
|
||||||
import discord
|
import discord
|
||||||
from discord.ext import commands
|
from discord.ext import commands
|
||||||
|
|
|
||||||
26
cogs/ipc.py
26
cogs/ipc.py
|
|
@ -1,26 +0,0 @@
|
||||||
from discord.ext import commands, ipc
|
|
||||||
|
|
||||||
|
|
||||||
class IPC(commands.Cog):
|
|
||||||
def __init__(self, client):
|
|
||||||
self.client = client
|
|
||||||
|
|
||||||
@ipc.server.route()
|
|
||||||
async def send_dm(self, data):
|
|
||||||
print("got here")
|
|
||||||
user = self.client.get_user(data.user)
|
|
||||||
await user.send(data.message)
|
|
||||||
print("sent")
|
|
||||||
return True
|
|
||||||
|
|
||||||
@ipc.server.route()
|
|
||||||
async def get_bot_latency(self, data):
|
|
||||||
"""
|
|
||||||
Get Didier's latency
|
|
||||||
"""
|
|
||||||
|
|
||||||
return self.client.latency * 1000
|
|
||||||
|
|
||||||
|
|
||||||
def setup(client):
|
|
||||||
client.add_cog(IPC(client))
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
from data.menus import paginatedLeaderboard
|
from data import paginatedLeaderboard
|
||||||
from decorators import help
|
from decorators import help
|
||||||
import discord
|
import discord
|
||||||
from discord.ext import commands
|
from discord.ext import commands
|
||||||
|
|
|
||||||
|
|
@ -5,10 +5,11 @@ from discord.ext import commands
|
||||||
from enums.help_categories import Category
|
from enums.help_categories import Category
|
||||||
from functions import checks, config, timeFormatters
|
from functions import checks, config, timeFormatters
|
||||||
from functions.database import memes, githubs, twitch, dadjoke
|
from functions.database import memes, githubs, twitch, dadjoke
|
||||||
from functions.database.custom_commands import add_command, add_alias
|
|
||||||
import json
|
import json
|
||||||
import os
|
import os
|
||||||
|
|
||||||
|
from functions.database.custom_commands import is_name_free, add_command, add_alias
|
||||||
|
|
||||||
|
|
||||||
class ModCommands(commands.Cog):
|
class ModCommands(commands.Cog):
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,30 +0,0 @@
|
||||||
from discord.ext import commands
|
|
||||||
from data.menus import custom_commands
|
|
||||||
from decorators import help
|
|
||||||
from enums.help_categories import Category
|
|
||||||
from functions.database.custom_commands import get_all
|
|
||||||
from functions.stringFormatters import capitalize
|
|
||||||
|
|
||||||
|
|
||||||
class Other(commands.Cog):
|
|
||||||
def __init__(self, client):
|
|
||||||
self.client = client
|
|
||||||
|
|
||||||
# Don't allow any commands to work when locked
|
|
||||||
def cog_check(self, ctx):
|
|
||||||
return not self.client.locked
|
|
||||||
|
|
||||||
@commands.command(name="Custom")
|
|
||||||
@help.Category(category=Category.Didier)
|
|
||||||
async def list_custom(self, ctx):
|
|
||||||
"""
|
|
||||||
Get a list of all custom commands
|
|
||||||
"""
|
|
||||||
all_commands = get_all()
|
|
||||||
formatted = list(sorted(map(lambda x: capitalize(x["name"]), all_commands)))
|
|
||||||
src = custom_commands.CommandsList(formatted)
|
|
||||||
await custom_commands.Pages(source=src, clear_reactions_after=True).start(ctx)
|
|
||||||
|
|
||||||
|
|
||||||
def setup(client):
|
|
||||||
client.add_cog(Other(client))
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
from converters.numbers import Abbreviated
|
from converters.numbers import Abbreviated
|
||||||
from data.menus import storePages
|
from data import storePages
|
||||||
from decorators import help
|
from decorators import help
|
||||||
import discord
|
import discord
|
||||||
from discord.ext import commands
|
from discord.ext import commands
|
||||||
|
|
|
||||||
|
|
@ -246,7 +246,7 @@ class Tasks(commands.Cog):
|
||||||
Task that checks for new Ufora announcements every few minutes
|
Task that checks for new Ufora announcements every few minutes
|
||||||
"""
|
"""
|
||||||
# Don't run this when testing
|
# Don't run this when testing
|
||||||
if self.client.user.id != int(constants.didierId):
|
if self.client.user.id == int(constants.coolerDidierId):
|
||||||
return
|
return
|
||||||
|
|
||||||
# Get new notifications
|
# Get new notifications
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,5 @@
|
||||||
from data.menus import paginatedLeaderboard
|
from data import paginatedLeaderboard
|
||||||
|
import datetime
|
||||||
from decorators import help
|
from decorators import help
|
||||||
import discord
|
import discord
|
||||||
from discord.ext import commands, menus
|
from discord.ext import commands, menus
|
||||||
|
|
|
||||||
|
|
@ -15,8 +15,8 @@ class Translate(commands.Cog):
|
||||||
def cog_check(self, ctx):
|
def cog_check(self, ctx):
|
||||||
return not self.client.locked
|
return not self.client.locked
|
||||||
|
|
||||||
@commands.command(name="Translate", aliases=["Tl", "Trans"], usage="[Tekst] [Van]* [Naar]*")
|
# @commands.command(name="Translate", aliases=["Tl", "Trans"], usage="[Tekst] [Van]* [Naar]*")
|
||||||
@help.Category(Category.Words)
|
# @help.Category(Category.Words)
|
||||||
async def translate(self, ctx, query=None, to="nl", fr="auto"):
|
async def translate(self, ctx, query=None, to="nl", fr="auto"):
|
||||||
if query is None:
|
if query is None:
|
||||||
return await ctx.send("Controleer je argumenten.")
|
return await ctx.send("Controleer je argumenten.")
|
||||||
|
|
@ -39,11 +39,9 @@ class Translate(commands.Cog):
|
||||||
embed.set_author(name="Didier Translate")
|
embed.set_author(name="Didier Translate")
|
||||||
|
|
||||||
if fr == "auto":
|
if fr == "auto":
|
||||||
language = translation.src
|
language = translation.extra_data["original-language"]
|
||||||
embed.add_field(name="Gedetecteerde taal", value=tc(LANGUAGES[language]))
|
embed.add_field(name="Gedetecteerde taal", value=tc(LANGUAGES[language]))
|
||||||
|
embed.add_field(name="Zekerheid", value="{}%".format(translation.extra_data["confidence"] * 100))
|
||||||
if translation.extra_data["confidence"] is not None:
|
|
||||||
embed.add_field(name="Zekerheid", value="{}%".format(translation.extra_data["confidence"] * 100))
|
|
||||||
|
|
||||||
embed.add_field(name="Origineel ({})".format(translation.src.upper()), value=query, inline=False)
|
embed.add_field(name="Origineel ({})".format(translation.src.upper()), value=query, inline=False)
|
||||||
embed.add_field(name="Vertaling ({})".format(to.upper()), value=translation.text)
|
embed.add_field(name="Vertaling ({})".format(to.upper()), value=translation.text)
|
||||||
|
|
|
||||||
|
|
@ -1,21 +0,0 @@
|
||||||
import discord
|
|
||||||
from discord.ext import menus
|
|
||||||
|
|
||||||
|
|
||||||
class CommandsList(menus.ListPageSource):
|
|
||||||
def __init__(self, data, colour=discord.Colour.blue()):
|
|
||||||
super().__init__(data, per_page=15)
|
|
||||||
self.colour = colour
|
|
||||||
|
|
||||||
async def format_page(self, menu: menus.MenuPages, entries):
|
|
||||||
embed = discord.Embed(colour=self.colour)
|
|
||||||
embed.set_author(name="Custom Commands")
|
|
||||||
embed.description = "\n".join(entries)
|
|
||||||
embed.set_footer(text="{}/{}".format(menu.current_page + 1, self.get_max_pages()))
|
|
||||||
|
|
||||||
return embed
|
|
||||||
|
|
||||||
|
|
||||||
class Pages(menus.MenuPages):
|
|
||||||
def __init__(self, source, clear_reactions_after, timeout=30.0):
|
|
||||||
super().__init__(source, timeout=timeout, delete_message_after=True, clear_reactions_after=clear_reactions_after)
|
|
||||||
36
didier.py
36
didier.py
|
|
@ -1,19 +1,33 @@
|
||||||
import discord
|
import discord
|
||||||
|
from discord.ext import commands
|
||||||
from dotenv import load_dotenv
|
from dotenv import load_dotenv
|
||||||
from functions.prefixes import get_prefix
|
from functions.prefixes import get_prefix
|
||||||
from settings import TOKEN
|
import os
|
||||||
from startup.didier import Didier
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
|
||||||
load_dotenv(verbose=True)
|
|
||||||
|
|
||||||
# Configure intents (1.5.0)
|
load_dotenv(verbose=True)
|
||||||
intents = discord.Intents.default()
|
|
||||||
intents.members = True
|
|
||||||
|
|
||||||
client = Didier(command_prefix=get_prefix, case_insensitive=True, intents=intents)
|
|
||||||
|
|
||||||
if client.ipc is not None:
|
# Configure intents (1.5.0)
|
||||||
client.ipc.start()
|
intents = discord.Intents.default()
|
||||||
|
intents.members = True
|
||||||
|
|
||||||
client.run(TOKEN)
|
client = commands.Bot(command_prefix=get_prefix, case_insensitive=True, intents=intents)
|
||||||
|
|
||||||
|
# Remove default help because it sucks & I made my own
|
||||||
|
client.remove_command("help")
|
||||||
|
|
||||||
|
# Load utils first so it can be used in other places & it's not None
|
||||||
|
client.load_extension("cogs.utils")
|
||||||
|
client.load_extension("cogs.failedchecks")
|
||||||
|
client.load_extension("cogs.events")
|
||||||
|
|
||||||
|
# Load all remaining cogs
|
||||||
|
for file in os.listdir("./cogs"):
|
||||||
|
if file.endswith(".py") and not (file.startswith(("utils", "failedchecks", "events"),)):
|
||||||
|
client.load_extension("cogs.{}".format(file[:-3]))
|
||||||
|
|
||||||
|
# Get the token out of the file & run the bot
|
||||||
|
with open("files/client.txt", "r") as fp:
|
||||||
|
token = fp.readline()
|
||||||
|
client.run(token)
|
||||||
|
|
|
||||||
15
faq.md
15
faq.md
|
|
@ -1,14 +1,5 @@
|
||||||
# FAQ
|
# FAQ
|
||||||
Answers to Frequently Asked Questions and solutions to issues that may arise.
|
Answers to Frequently Asked Questions.
|
||||||
|
|
||||||
## Issues installing dotenv
|
### Table of Contents
|
||||||
|
A list of all questions (in order) so you can easily find what you're looking for.
|
||||||
The name of this package is `python-dotenv`, as listed in `requirements.txt`. The _name_ of the package, however, is just `dotenv`. This confuses PyCharm, which will tell you that you don't have `dotenv` installed as it can't link those two together. You can just click `ignore this requirement` if you don't like the warning.
|
|
||||||
|
|
||||||
## Issues installing psycopg2
|
|
||||||
|
|
||||||
The `psychopg2` and `psychopg2-binary` packages might cause you some headaches when trying to install them, especially when using PyCharm to install dependencies. The reason for this is because these are `PSQL` packages, and as a result they require you to have `PSQL` installed on your system to function properly.
|
|
||||||
|
|
||||||
## Package is not listed in project requirements
|
|
||||||
|
|
||||||
This is the exact same case as [Issues installing dotenv](#issues-installing-dotenv), and occurs for packages such as `Quart`. The names of the modules differ from the name used to install it from `pip`. Once again, you can ignore this message.
|
|
||||||
|
|
|
||||||
|
|
@ -1,5 +0,0 @@
|
||||||
{
|
|
||||||
"guessed": [],
|
|
||||||
"guesses": 0,
|
|
||||||
"word": ""
|
|
||||||
}
|
|
||||||
|
|
@ -1,9 +0,0 @@
|
||||||
{
|
|
||||||
"interest": 0,
|
|
||||||
"lost": 0,
|
|
||||||
"poke": 0,
|
|
||||||
"prison": 0,
|
|
||||||
"birthdays": 0,
|
|
||||||
"channels": 0,
|
|
||||||
"remind": 0
|
|
||||||
}
|
|
||||||
|
|
@ -1,4 +0,0 @@
|
||||||
{
|
|
||||||
"locked": false,
|
|
||||||
"until": -1
|
|
||||||
}
|
|
||||||
|
|
@ -1,4 +0,0 @@
|
||||||
{
|
|
||||||
"lost": 0,
|
|
||||||
"today": 0
|
|
||||||
}
|
|
||||||
|
|
@ -1,19 +0,0 @@
|
||||||
{
|
|
||||||
"cf": {
|
|
||||||
"h": 0,
|
|
||||||
"t": 0
|
|
||||||
},
|
|
||||||
"dice": {
|
|
||||||
"2": 0,
|
|
||||||
"5": 0,
|
|
||||||
"3": 0,
|
|
||||||
"6": 0,
|
|
||||||
"1": 0,
|
|
||||||
"4": 0
|
|
||||||
},
|
|
||||||
"rob": {
|
|
||||||
"robs_success": 0,
|
|
||||||
"robs_failed": 0,
|
|
||||||
"bail_paid": 0.0
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,12 +0,0 @@
|
||||||
{
|
|
||||||
"Algoritmen en Datastructuren 2": [],
|
|
||||||
"Communicatienetwerken": [],
|
|
||||||
"Computerarchitectuur": [],
|
|
||||||
"Functioneel Programmeren": [],
|
|
||||||
"Multimedia": [],
|
|
||||||
"Software Engineering Lab 1": [],
|
|
||||||
"Statistiek en Probabiliteit": [],
|
|
||||||
"Systeemprogrammeren": [],
|
|
||||||
"Webdevelopment": [],
|
|
||||||
"Wetenschappelijk Rekenen": []
|
|
||||||
}
|
|
||||||
|
|
@ -33,7 +33,6 @@
|
||||||
"config": "Past constanten in het config bestand aan.",
|
"config": "Past constanten in het config bestand aan.",
|
||||||
"corona": "Coronatracker voor [Land].\nIndien je geen land opgeeft is dit standaard België.\nCorona Global voor wereldwijde cijfers.",
|
"corona": "Coronatracker voor [Land].\nIndien je geen land opgeeft is dit standaard België.\nCorona Global voor wereldwijde cijfers.",
|
||||||
"corona vaccinations": "Vaccinatiecijfers voor België.",
|
"corona vaccinations": "Vaccinatiecijfers voor België.",
|
||||||
"custom": "Geeft een lijst van custom commands. Didier > Dyno confirmed once more.",
|
|
||||||
"dadjoke": "Didier vertelt een dad joke.",
|
"dadjoke": "Didier vertelt een dad joke.",
|
||||||
"define": "Geeft de definitie van [Woord] zoals het in de Urban Dictionary staat.\nZoektermen met spaties moeten **niet** tussen aanhalingstekens staan.",
|
"define": "Geeft de definitie van [Woord] zoals het in de Urban Dictionary staat.\nZoektermen met spaties moeten **niet** tussen aanhalingstekens staan.",
|
||||||
"detect": "Didier probeert de taal van [Tekst] te detecteren.",
|
"detect": "Didier probeert de taal van [Tekst] te detecteren.",
|
||||||
|
|
|
||||||
|
|
@ -127,55 +127,3 @@ def add_alias(command: str, alias: str):
|
||||||
|
|
||||||
cursor.execute("INSERT INTO custom_command_aliases(command, alias) VALUES(%s, %s)", (command_id, alias,))
|
cursor.execute("INSERT INTO custom_command_aliases(command, alias) VALUES(%s, %s)", (command_id, alias,))
|
||||||
connection.commit()
|
connection.commit()
|
||||||
|
|
||||||
|
|
||||||
def get_all():
|
|
||||||
"""
|
|
||||||
Return a list of all registered custom commands
|
|
||||||
"""
|
|
||||||
connection = utils.connect()
|
|
||||||
cursor = connection.cursor()
|
|
||||||
|
|
||||||
cursor.execute("SELECT * FROM custom_commands")
|
|
||||||
commands = cursor.fetchall()
|
|
||||||
ret = []
|
|
||||||
|
|
||||||
# Create a list of all entries
|
|
||||||
for command in commands:
|
|
||||||
dic = {"id": command[0], "name": command[1], "response": command[2]}
|
|
||||||
|
|
||||||
# Find and add aliases
|
|
||||||
cursor.execute("SELECT id, alias FROM custom_command_aliases WHERE command = %s", (command[0],))
|
|
||||||
aliases = cursor.fetchall()
|
|
||||||
|
|
||||||
if aliases:
|
|
||||||
dic["aliases"] = list(map(lambda x: {"id": x[0], "alias": x[1]}, aliases))
|
|
||||||
|
|
||||||
ret.append(dic)
|
|
||||||
|
|
||||||
return ret
|
|
||||||
|
|
||||||
|
|
||||||
def get_by_id(command_id: int):
|
|
||||||
"""
|
|
||||||
Return a command that matches a given id
|
|
||||||
"""
|
|
||||||
connection = utils.connect()
|
|
||||||
cursor = connection.cursor()
|
|
||||||
|
|
||||||
cursor.execute("SELECT * FROM custom_commands WHERE id = %s", (command_id,))
|
|
||||||
command = cursor.fetchone()
|
|
||||||
|
|
||||||
# Nothing found
|
|
||||||
if not command:
|
|
||||||
return None
|
|
||||||
|
|
||||||
dic = {"id": command[0], "name": command[1], "response": command[2]}
|
|
||||||
|
|
||||||
cursor.execute("SELECT id, alias FROM custom_command_aliases WHERE command = %s", (command_id,))
|
|
||||||
aliases = cursor.fetchall()
|
|
||||||
|
|
||||||
if aliases:
|
|
||||||
dic["aliases"] = list(map(lambda x: {"id": x[0], "alias": x[1]}, aliases))
|
|
||||||
|
|
||||||
return dic
|
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,6 @@
|
||||||
import psycopg2
|
import psycopg2
|
||||||
from settings import DB_HOST, DB_NAME, DB_USERNAME, DB_PASSWORD
|
import json
|
||||||
|
import os
|
||||||
|
|
||||||
|
|
||||||
connection = None
|
connection = None
|
||||||
|
|
@ -16,11 +17,15 @@ def connect():
|
||||||
def create_connection():
|
def create_connection():
|
||||||
global connection
|
global connection
|
||||||
|
|
||||||
|
dir_path = os.path.dirname(os.path.realpath(__file__))
|
||||||
|
with open(os.path.join(dir_path, "../../files/database.json"), "r") as fp:
|
||||||
|
db = json.load(fp)
|
||||||
|
|
||||||
connection = psycopg2.connect(
|
connection = psycopg2.connect(
|
||||||
host=DB_HOST,
|
host=db["host"],
|
||||||
database=DB_NAME,
|
database=db["database"],
|
||||||
user=DB_USERNAME,
|
user=db["username"],
|
||||||
password=DB_PASSWORD
|
password=db["password"]
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
37
ignored.md
37
ignored.md
|
|
@ -2,7 +2,28 @@
|
||||||
|
|
||||||
A list of all ignored files with copy-pastable templates. Useful for when you want to work on commands that use these, for obvious reasons. Every file has a copy-pastable template to make it easy for you to use.
|
A list of all ignored files with copy-pastable templates. Useful for when you want to work on commands that use these, for obvious reasons. Every file has a copy-pastable template to make it easy for you to use.
|
||||||
|
|
||||||
These are usually files which would be overkill to make a PSQL table for. Other possibilities are files that are never edited, but should be different on every machine.
|
These are usually files which would be overkill to make a PSQL table for. Other possibilities are files that are never edited, but should be different on every machine (Discord token, status message, ...).
|
||||||
|
|
||||||
|
### files/client.txt
|
||||||
|
|
||||||
|
Contains the application's token to connect to Discord. You can create your own bot & put it's token in this file to run & test Didier code.
|
||||||
|
|
||||||
|
token_goes_here
|
||||||
|
|
||||||
|
### files/database.json
|
||||||
|
|
||||||
|
Contains the credentials needed to connect to the PSQL database. This is ignored so that I don't have to leak my IP address, but also so that you can set up a local database to mess around without affecting the Live one or having to change any code.
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"username": "username",
|
||||||
|
"password": "password",
|
||||||
|
"host": "host_address",
|
||||||
|
"database": "database_name"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
When connecting to a local PSQL database, `host` should be `"localhost"`.
|
||||||
|
|
||||||
### files/hangman.json
|
### files/hangman.json
|
||||||
|
|
||||||
|
|
@ -43,6 +64,14 @@ Contains a boolean indicating whether or not the server is currently locked, and
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
### files/readyMessage.txt
|
||||||
|
|
||||||
|
Contains the message printed in your terminal when Didier is ready.
|
||||||
|
|
||||||
|
I'M READY I'M READY I'M READY I'M READY
|
||||||
|
|
||||||
|
In case you were wondering: yes, this is a Spongebob reference.
|
||||||
|
|
||||||
### files/stats.json
|
### files/stats.json
|
||||||
|
|
||||||
Contains the stats to track for gambling games. Weren't made as a PSQL table because they would be too long (and every game is different).
|
Contains the stats to track for gambling games. Weren't made as a PSQL table because they would be too long (and every game is different).
|
||||||
|
|
@ -69,6 +98,12 @@ Contains the stats to track for gambling games. Weren't made as a PSQL table bec
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
### files/status.txt
|
||||||
|
|
||||||
|
Contains Didier's status message for when he logs in. Keep in mind that his activity is set to `Playing `. This was first used in Didier V1 to show whether or not he was in sandbox mode.
|
||||||
|
|
||||||
|
with your Didier Dinks.
|
||||||
|
|
||||||
### files/ufora_notifications.json
|
### files/ufora_notifications.json
|
||||||
|
|
||||||
Stores ID's of all received Ufora notifications.
|
Stores ID's of all received Ufora notifications.
|
||||||
|
|
|
||||||
|
|
@ -51,16 +51,13 @@ When creating a new Didier command, you can add it to a `Category` by adding a d
|
||||||
|
|
||||||
```python
|
```python
|
||||||
from decorators import help
|
from decorators import help
|
||||||
from discord.ext import commands
|
|
||||||
from enums.help_categories import Category
|
from enums.help_categories import Category
|
||||||
from functions import checks
|
|
||||||
|
|
||||||
@commands.command(name="Command Name", aliases=["Cn"])
|
@commands.command(name="Command Name", aliases=["Cn"])
|
||||||
@commands.check(checks.allowedChannels)
|
@commands.check(checks.allowedChannels)
|
||||||
@help.Category(Category.Currency)
|
@help.Category(Category.Currency)
|
||||||
async def command_name(self, ctx):
|
async def command_name(self, ctx):
|
||||||
# Command code
|
# Command code
|
||||||
await ctx.send("Command response")
|
|
||||||
```
|
```
|
||||||
|
|
||||||
This allows commands across multiple Cogs to be classified under the same category in the help page.
|
This allows commands across multiple Cogs to be classified under the same category in the help page.
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,6 @@
|
||||||
python-dotenv==0.14.0
|
python-dotenv==0.14.0
|
||||||
beautifulsoup4==4.9.1
|
beautifulsoup4==4.9.1
|
||||||
discord.py==1.7.3
|
discord.py==1.7.0
|
||||||
git+https://github.com/Rapptz/discord-ext-menus@master
|
|
||||||
discord-ext-ipc==2.0.0
|
|
||||||
psycopg2==2.8.5
|
psycopg2==2.8.5
|
||||||
psycopg2-binary==2.8.5
|
psycopg2-binary==2.8.5
|
||||||
python-dateutil==2.6.1
|
python-dateutil==2.6.1
|
||||||
|
|
@ -12,6 +10,4 @@ requests-unixsocket==0.1.5
|
||||||
tabulate==0.8.7
|
tabulate==0.8.7
|
||||||
yarl==1.4.2
|
yarl==1.4.2
|
||||||
feedparser==6.0.2
|
feedparser==6.0.2
|
||||||
googletrans==4.0.0rc1
|
googletrans==3.0.0
|
||||||
quart==0.6.15
|
|
||||||
Quart-CORS==0.1.3
|
|
||||||
33
settings.py
33
settings.py
|
|
@ -1,33 +0,0 @@
|
||||||
from dotenv import load_dotenv
|
|
||||||
import os
|
|
||||||
|
|
||||||
|
|
||||||
load_dotenv()
|
|
||||||
|
|
||||||
|
|
||||||
def _to_bool(value: str) -> bool:
|
|
||||||
"""
|
|
||||||
Env variables are strings so this converts them to booleans
|
|
||||||
"""
|
|
||||||
return value.lower() in ["true", "1", "y", "yes"]
|
|
||||||
|
|
||||||
|
|
||||||
# Sandbox or live
|
|
||||||
SANDBOX = _to_bool(os.getenv("SANDBOX", "true"))
|
|
||||||
|
|
||||||
# Tokens & API keys
|
|
||||||
URBANDICTIONARY = os.getenv("URBANDICTIONARY", "")
|
|
||||||
IMGFLIP_NAME = os.getenv("IMGFLIPNAME", "")
|
|
||||||
IMGFLIP_PASSWORD = os.getenv("IMGFLIPPASSWORD", "")
|
|
||||||
|
|
||||||
# Database credentials
|
|
||||||
DB_USERNAME = os.getenv("DBUSERNAME", "")
|
|
||||||
DB_PASSWORD = os.getenv("DBPASSWORD", "")
|
|
||||||
DB_HOST = os.getenv("DBHOST", "")
|
|
||||||
DB_NAME = os.getenv("DBNAME", "")
|
|
||||||
|
|
||||||
# Discord-related
|
|
||||||
TOKEN = os.getenv("TOKEN", "")
|
|
||||||
HOST_IPC = _to_bool(os.getenv("HOSTIPC", "false"))
|
|
||||||
READY_MESSAGE = os.getenv("READYMESSAGE", "I'M READY I'M READY I'M READY I'M READY") # Yes, this is a Spongebob reference
|
|
||||||
STATUS_MESSAGE = os.getenv("STATUSMESSAGE", "with your Didier Dinks.")
|
|
||||||
|
|
@ -1,46 +0,0 @@
|
||||||
from discord.ext import commands, ipc
|
|
||||||
from settings import HOST_IPC
|
|
||||||
from startup.init_files import check_all
|
|
||||||
import os
|
|
||||||
|
|
||||||
|
|
||||||
class Didier(commands.Bot):
|
|
||||||
"""
|
|
||||||
Main Bot class for Didier
|
|
||||||
"""
|
|
||||||
def __init__(self, *args, **kwargs):
|
|
||||||
super().__init__(*args, **kwargs)
|
|
||||||
|
|
||||||
self._host_ipc = HOST_IPC
|
|
||||||
|
|
||||||
# IPC Server
|
|
||||||
# TODO secret key
|
|
||||||
self.ipc = ipc.Server(self, secret_key="SOME_SECRET_KEY") if self._host_ipc else None
|
|
||||||
|
|
||||||
# Cogs that should be loaded before the others
|
|
||||||
self._preload = ("ipc", "utils", "failedchecks", "events",)
|
|
||||||
|
|
||||||
# Remove default help command
|
|
||||||
self.remove_command("help")
|
|
||||||
|
|
||||||
# Load all extensions
|
|
||||||
self.init_extensions()
|
|
||||||
|
|
||||||
# Check missing files
|
|
||||||
check_all()
|
|
||||||
|
|
||||||
def init_extensions(self):
|
|
||||||
# Load initial extensions
|
|
||||||
for ext in self._preload:
|
|
||||||
self.load_extension(f"cogs.{ext}")
|
|
||||||
|
|
||||||
# Load all remaining cogs
|
|
||||||
for file in os.listdir("./cogs"):
|
|
||||||
if file.endswith(".py") and not (file.startswith(self._preload)):
|
|
||||||
self.load_extension("cogs.{}".format(file[:-3]))
|
|
||||||
|
|
||||||
async def on_ipc_ready(self):
|
|
||||||
print("IPC server is ready.")
|
|
||||||
|
|
||||||
async def on_ipc_error(self, endpoint, error):
|
|
||||||
print(endpoint, "raised", error)
|
|
||||||
|
|
@ -1,13 +0,0 @@
|
||||||
import json
|
|
||||||
from os import path
|
|
||||||
|
|
||||||
|
|
||||||
def check_all():
|
|
||||||
files = ["hangman", "lastTasks", "locked", "lost", "stats", "ufora_notifications"]
|
|
||||||
|
|
||||||
for f in files:
|
|
||||||
if not path.isfile(path.join(f"files/{f}.json")):
|
|
||||||
with open(f"files/{f}.json", "w+") as new_file, open(f"files/default/{f}.json", "r") as default:
|
|
||||||
content = json.load(default)
|
|
||||||
json.dump(content, new_file)
|
|
||||||
print(f"Created missing file: files/{f}.json")
|
|
||||||
Loading…
Reference in New Issue