update(application|bot): add prefixes, blacklist,... confs and command processing

This commit is contained in:
Romain J 2019-09-09 22:40:17 +02:00
parent cb0b9a2681
commit 30e7906f3f
12 changed files with 92 additions and 61 deletions

1
.gitignore vendored
View file

@ -3,6 +3,7 @@ __pycache__/
*.pyc *.pyc
.env .env
config.py config.py
!cogs/utils/*
.DS_Store .DS_Store
private.py private.py

3
blacklist.json Normal file
View file

@ -0,0 +1,3 @@
[
589949234308972556
]

59
bot.py
View file

@ -2,13 +2,16 @@ import datetime
import logging import logging
import sys import sys
import traceback import traceback
from collections import deque
from typing import List
import aiohttp import aiohttp
import discord import discord
from discord.ext import commands from discord.ext import commands
import config import config
from cogs.utils.lang import _ from cogs.utils.config import Config
from cogs.utils.lang import gettext
description = """ description = """
Je suis TuxBot, le bot qui vit de l'OpenSource ! ;) Je suis TuxBot, le bot qui vit de l'OpenSource ! ;)
@ -18,16 +21,17 @@ log = logging.getLogger(__name__)
l_extensions = ( l_extensions = (
'cogs.admin', 'cogs.admin',
'cogs.basaics', 'cogs.basics',
'jishaku',
) )
async def _prefix_callable(bot, message): async def _prefix_callable(bot, message: discord.message) -> List:
base = [] if config.prefix is None else config.prefix extras = []
if message.guild is not None:
extras = bot.prefixes.get(str(message.guild.id), [])
# if message.guild is not None: return commands.when_mentioned_or(*extras)(bot, message)
# base.extend(bot.prefixes.get(message.guild.id))
return commands.when_mentioned_or(base)
class TuxBot(commands.AutoShardedBot): class TuxBot(commands.AutoShardedBot):
@ -40,40 +44,64 @@ class TuxBot(commands.AutoShardedBot):
self.uptime = datetime.datetime.utcnow() self.uptime = datetime.datetime.utcnow()
self.config = config self.config = config
self.prefixes = {} self._prev_events = deque(maxlen=10)
self.session = aiohttp.ClientSession(loop=self.loop) self.session = aiohttp.ClientSession(loop=self.loop)
self.prefixes = Config('prefixes.json')
self.blacklist = Config('blacklist.json')
for extension in l_extensions: for extension in l_extensions:
if extension not in unload: if extension not in unload:
try: try:
self.load_extension(extension) self.load_extension(extension)
except Exception as e: except Exception as e:
print(_("Failed to load extension : ") + extension, print(gettext("Failed to load extension : ") + extension,
file=sys.stderr) file=sys.stderr)
traceback.print_exc() log.error(gettext("Failed to load extension : ")
+ extension, exc_info=e)
async def on_socket_response(self, msg):
self._prev_events.append(msg)
async def on_command_error(self, ctx, error): async def on_command_error(self, ctx, error):
if isinstance(error, commands.NoPrivateMessage): if isinstance(error, commands.NoPrivateMessage):
await ctx.author.send( await ctx.author.send(
_('This command cannot be used in private messages.') gettext('This command cannot be used in private messages.')
) )
elif isinstance(error, commands.DisabledCommand): elif isinstance(error, commands.DisabledCommand):
await ctx.author.send( await ctx.author.send(
_('Sorry. This command is disabled and cannot be used.') gettext('Sorry. This command is disabled and cannot be used.')
) )
elif isinstance(error, commands.CommandInvokeError): elif isinstance(error, commands.CommandInvokeError):
print(_('In ') + f'{ctx.command.qualified_name}:', file=sys.stderr) print(gettext('In ') + f'{ctx.command.qualified_name}:',
file=sys.stderr)
traceback.print_tb(error.original.__traceback__) traceback.print_tb(error.original.__traceback__)
print(f'{error.original.__class__.__name__}: {error.original}', print(f'{error.original.__class__.__name__}: {error.original}',
file=sys.stderr) file=sys.stderr)
elif isinstance(error, commands.ArgumentParsingError): elif isinstance(error, commands.ArgumentParsingError):
await ctx.send(error) await ctx.send(error)
async def process_commands(self, message):
ctx = await self.get_context(message)
if ctx.command is None:
return
await self.invoke(ctx)
async def on_message(self, message):
if message.author.bot \
or message.author.id in self.blacklist \
or message.guild.id in self.blacklist:
return
await self.process_commands(message)
async def on_ready(self): async def on_ready(self):
if not hasattr(self, 'uptime'): if not hasattr(self, 'uptime'):
self.uptime = datetime.datetime.utcnow() self.uptime = datetime.datetime.utcnow()
print(_('Ready:') + f' {self.user} (ID: {self.user.id})') print(gettext('Ready:') + f' {self.user} (ID: {self.user.id})')
await self.change_presence(status=discord.Status.dnd, await self.change_presence(status=discord.Status.dnd,
activity=discord.Game( activity=discord.Game(
@ -90,7 +118,8 @@ class TuxBot(commands.AutoShardedBot):
webhook = discord.Webhook.partial(id=logs_webhook.get('id'), webhook = discord.Webhook.partial(id=logs_webhook.get('id'),
token=logs_webhook.get('token'), token=logs_webhook.get('token'),
adapter=discord.AsyncWebhookAdapter( adapter=discord.AsyncWebhookAdapter(
self.session)) self.session)
)
return webhook return webhook
async def close(self): async def close(self):

View file

@ -1,6 +1,5 @@
import platform import platform
import socket import socket
import subprocess
import discord import discord
from discord.ext import commands from discord.ext import commands
@ -10,33 +9,14 @@ from discord.http import Route
class Basics(commands.Cog): class Basics(commands.Cog):
"""Commandes générales.""" """Commandes générales."""
def __init__(self, bot): def __init__(self, bot: discord.ext.commands.AutoShardedBot):
self.bot = bot self.bot = bot
@commands.command() @commands.command()
async def ping(self, ctx): async def ping(self, ctx: discord.ext.commands.context.Context):
ping_res = str(subprocess.Popen(["/bin/ping", "-c1", "discordapp.com"], delta = await ctx.send(self.bot.latency * 1000)
stdout=subprocess.PIPE).stdout.read()) await ctx.send((delta.created_at-ctx.message.created_at)
formated_res = [item for item in ping_res.split() if 'time=' in item] .microseconds/1000)
result = str(formated_res[0])[5:]
if float(result) >= 200:
em = discord.Embed(title="Ping : " + str(result) + "ms",
description="... c'est quoi ce ping !",
colour=0xFF1111)
await ctx.send(embed=em)
elif float(result) > 100 < 200:
em = discord.Embed(title="Ping : " + str(result) + "ms",
description="Ca va, ça peut aller, mais j'ai "
"l'impression d'avoir 40 ans !",
colour=0xFFA500)
await ctx.send(embed=em)
else:
em = discord.Embed(title="Ping : " + str(result) + "ms",
description="Wow c'te vitesse de réaction, "
"je m'épate moi-même !",
colour=0x11FF11)
await ctx.send(embed=em)
"""---------------------------------------------------------------------""" """---------------------------------------------------------------------"""
@ -63,7 +43,7 @@ class Basics(commands.Cog):
text = open('texts/help.md').read().split("[split]") text = open('texts/help.md').read().split("[split]")
for txt in text: for txt in text:
em = discord.Embed(title='Commandes de TuxBot', description=txt, em = discord.Embed(title='Commandes de TuxBot', description=txt,
colour=0x89C4F9) colour=0x89C4F9)
await ctx.send(embed=em) await ctx.send(embed=em)

27
cogs/utils/config.py Normal file
View file

@ -0,0 +1,27 @@
import json
class Config:
__slots__ = ('name', '_db')
def __init__(self, name):
self.name = name
try:
with open(self.name, 'r') as f:
self._db = json.load(f)
except FileNotFoundError:
self._db = {}
def __contains__(self, item):
return item in self._db
def __getitem__(self, item):
return self._db[str(item)]
def get(self, key, *args):
"""Retrieves a config entry."""
return self._db.get(str(key), *args)
def all(self) -> dict:
return self._db

View file

@ -5,4 +5,4 @@ lang = gettext.translation('base', localedir='locales',
languages=[config.lang]) languages=[config.lang])
lang.install() lang.install()
_ = lang.gettext gettext = lang.gettext

View file

@ -66,7 +66,6 @@ class Config:
+ '\033[0m\n') + '\033[0m\n')
self.input('activity', empty=True) self.input('activity', empty=True)
self.input('prefix', empty=True)
def save(self): def save(self):
with open('config.py', 'w') as file: with open('config.py', 'w') as file:

View file

@ -20,7 +20,6 @@ texts = {
'misc': 'Autre', 'misc': 'Autre',
'activity': "Joue à ...", 'activity': "Joue à ...",
'prefix': "Prefixe (par defaut : @tuxbot)",
'end': "Configuration terminée, vous pouvez à tout moment la rectifier en modifiant le fichier config.py", 'end': "Configuration terminée, vous pouvez à tout moment la rectifier en modifiant le fichier config.py",
@ -47,7 +46,6 @@ texts = {
'misc': 'Misc', 'misc': 'Misc',
'activity': "Playing ...", 'activity': "Playing ...",
'prefix': "Prefix (default is @tuxbot)",
'end': "Configuration completed, you can fix it at any time by modifying the config.py file", 'end': "Configuration completed, you can fix it at any time by modifying the config.py file",

View file

@ -11,7 +11,7 @@ from cogs.utils.db import Table
try: try:
import config import config
from cogs.utils.lang import _ from cogs.utils.lang import gettext
except ModuleNotFoundError: except ModuleNotFoundError:
import first_run import first_run
@ -51,8 +51,8 @@ def run_bot(unload):
Table.create_pool(config.postgresql, command_timeout=60) Table.create_pool(config.postgresql, command_timeout=60)
) )
except socket.gaierror as e: except socket.gaierror as e:
click.echo(_('Could not set up PostgreSQL...'), file=sys.stderr) click.echo(gettext('Could not set up PostgreSQL...'), file=sys.stderr)
log.exception(_('Could not set up PostgreSQL...')) log.exception(gettext('Could not set up PostgreSQL...'))
return return
bot = TuxBot(unload) bot = TuxBot(unload)
@ -63,7 +63,7 @@ def run_bot(unload):
@click.group(invoke_without_command=True, options_metavar='[options]') @click.group(invoke_without_command=True, options_metavar='[options]')
@click.option('-u', '--unload', @click.option('-u', '--unload',
multiple=True, type=str, multiple=True, type=str,
help=_('Launch without loading the <TEXT> module')) help=gettext('Launch without loading the <TEXT> module'))
@click.pass_context @click.pass_context
def main(ctx, unload): def main(ctx, unload):
if ctx.invoked_subcommand is None: if ctx.invoked_subcommand is None:

View file

@ -1,12 +0,0 @@
[2019-09-08 22:58:46] [INFO ] discord.client: logging in using static token
[2019-09-08 22:58:47] [INFO ] discord.gateway: Shard ID 0 has sent the IDENTIFY payload.
[2019-09-08 22:58:47] [INFO ] discord.gateway: Shard ID 0 has connected to Gateway: ["gateway-prd-main-xfx5",{"micros":31802,"calls":["discord-sessions-prd-1-18",{"micros":26858,"calls":["start_session",{"micros":12548,"calls":["api-prd-main-6rfw",{"micros":8098,"calls":["get_user",{"micros":1942},"add_authorized_ip",{"micros":5},"get_guilds",{"micros":3036},"coros_wait",{"micros":3}]}]},"guilds_connect",{"micros":139,"calls":[]},"presence_connect",{"micros":1,"calls":[]}]}]}] (Session ID: 03fcb2e35ce477c42ae58e20259b5d68).
[2019-09-08 22:58:53] [INFO ] discord.state: Processed a chunk for 463 members in guild ID 280805240977227776.
[2019-09-08 22:58:54] [INFO ] discord.state: Processed a chunk for 807 members in guild ID 331981755177238530.
[2019-09-08 22:58:55] [INFO ] discord.state: Processed a chunk for 1000 members in guild ID 296698073177128962.
[2019-09-08 22:58:55] [INFO ] discord.state: Processed a chunk for 1000 members in guild ID 296698073177128962.
[2019-09-08 22:58:55] [INFO ] discord.state: Processed a chunk for 662 members in guild ID 296698073177128962.
[2019-09-08 23:03:12] [INFO ] discord.client: Cleaning up tasks.
[2019-09-08 23:03:12] [INFO ] discord.client: Cleaning up after 5 tasks.
[2019-09-08 23:03:12] [INFO ] discord.client: All tasks finished cancelling.
[2019-09-08 23:03:12] [INFO ] discord.client: Closing the event loop.

5
prefixes.json Normal file
View file

@ -0,0 +1,5 @@
{
"280805240977227776": [
"."
]
}

View file

@ -1,4 +1,5 @@
discord.py[voice] discord.py[voice]
jishaku
lxml lxml
click click
asyncpg>=0.12.0 asyncpg>=0.12.0