This commit is contained in:
Romain J 2020-02-04 18:47:11 +01:00
parent be1e6d24e4
commit cce7bb4093
13 changed files with 150 additions and 103 deletions

51
bot.py
View file

@ -1,5 +1,6 @@
import contextlib
import datetime
import json
import logging
import sys
from collections import deque, Counter
@ -8,14 +9,16 @@ from typing import List
import aiohttp
import discord
import git
import sqlalchemy
from discord.ext import commands
from utils.functions import Config
from utils.functions import Database
from utils.functions import Texts
from utils.functions import Version
from utils.functions import ContextPlus
from utils.models import metadata, database
description = """
Je suis TuxBot, le bot qui vit de l'OpenSource ! ;)
"""
@ -27,6 +30,7 @@ log = logging.getLogger(__name__)
l_extensions: List[str] = [
'cogs.Admin',
'cogs.API',
'cogs.Help',
'cogs.Logs',
# 'cogs.Monitoring',
@ -38,14 +42,16 @@ l_extensions: List[str] = [
async def _prefix_callable(bot, message: discord.message) -> list:
extras = [bot.cluster.get('Name') + '.', '.']
if message.guild is not None:
if str(message.guild.id) in bot.prefixes:
extras.extend(
bot.prefixes.get(str(message.guild.id), "prefixes").split(
bot.config.get("misc", "Separator")
)
)
try:
with open(f'./configs/guilds/{message.guild.id}.json', 'r') as f:
data = json.load(f)
custom_prefix = data['prefixes']
except FileNotFoundError:
custom_prefix = ['']
extras = [bot.cluster.get('Name') + '.']
extras.extend(custom_prefix)
return commands.when_mentioned_or(*extras)(bot, message)
@ -64,7 +70,6 @@ class TuxBot(commands.AutoShardedBot):
self.command_stats = Counter()
self.config = Config('./configs/config.cfg')
self.prefixes = Config('./configs/prefixes.cfg')
self.blacklist = Config('./configs/blacklist.cfg')
self.fallbacks = Config('./configs/fallbacks.cfg')
self.cluster = self.fallbacks.find('True', key='This', first=True)
@ -72,11 +77,14 @@ class TuxBot(commands.AutoShardedBot):
self.uptime: datetime = datetime.datetime.utcnow()
self._prev_events = deque(maxlen=10)
self.session = aiohttp.ClientSession(loop=self.loop)
self.database = Database(self.config)
self.database, self.metadata = database, metadata
self.engine = sqlalchemy.create_engine(str(self.database.url))
self.metadata.create_all(self.engine)
self.version = Version(*version, pre_release='rc2', build=build)
self.owner_ids = self.config.get('permissions', 'Owners').split(', ')
self.owner_id = int(self.owner_ids[0])
self.owners_id = [int(owner_id) for owner_id in self.config.get('permissions', 'Owners').split(', ')]
self.owner_id = int(self.owners_id[0])
for extension in l_extensions:
try:
@ -92,8 +100,16 @@ class TuxBot(commands.AutoShardedBot):
log.error(Texts().get("Failed to load extension : ")
+ extension, exc_info=e)
@property
def owner(self):
return self.get_user(self.owner_id)
@property
def owners(self):
return [self.get_user(owner_id) for owner_id in self.owners_id]
async def is_owner(self, user: discord.User) -> bool:
return str(user.id) in self.owner_ids
return user in self.owners
async def get_context(self, message, *, cls=None):
return await super().get_context(message, cls=cls or ContextPlus)
@ -156,13 +172,6 @@ class TuxBot(commands.AutoShardedBot):
print('-' * 60)
await self.change_presence(**presence)
self.owner = await self.fetch_user(
int(self.config.get('permissions', 'Owners').split(', ')[0])
)
for owner in self.config.get('permissions', 'Owners').split(', '):
self.owners.append(
await self.fetch_user(int(owner))
)
@staticmethod
async def on_resumed():

56
cogs/API.py Normal file
View file

@ -0,0 +1,56 @@
import logging
import discord
from aiohttp import web
from discord.ext import commands
from bot import TuxBot
log = logging.getLogger(__name__)
class API(commands.Cog):
def __init__(self, bot: TuxBot):
self.bot = bot
self.site = web.TCPSite
app = web.Application()
app.add_routes([web.get('/users/{user_id}', self.users)])
self.runner = web.AppRunner(app)
self.bot.loop.create_task(self.start_HTTPMonitoring_server())
async def start_HTTPMonitoring_server(self):
host = self.bot.config.get('API', 'Host')
port = self.bot.config.get('API', 'Port')
print(f"Starting API server on {host}:{port}")
await self.runner.setup()
self.site = web.TCPSite(self.runner, host, port)
await self.site.start()
async def users(self, request):
try:
user = await self.bot.fetch_user(request.match_info['user_id'])
except discord.NotFound:
return web.Response(status=404)
json = {
'id': user.id,
'username': user.name,
'discriminator': user.discriminator,
'avatar': user.avatar,
'default_avatar': user.default_avatar.value,
'bot': user.bot,
'system': user.system,
}
return web.json_response(
json
)
def setup(bot: TuxBot):
bot.add_cog(API(bot))

View file

@ -10,7 +10,7 @@ from discord.ext import commands
from bot import TuxBot
from utils import Texts
from utils.models import WarnModel
from utils import commandExtra, groupExtra
from utils import command_extra, group_extra
log = logging.getLogger(__name__)
@ -65,7 +65,7 @@ class Admin(commands.Cog):
###########################################################################
@groupExtra(name='say', invoke_without_command=True, category='text')
@group_extra(name='say', invoke_without_command=True, category='text')
async def _say(self, ctx: commands.Context, *, content: str):
if ctx.invoked_subcommand is None:
try:
@ -105,7 +105,7 @@ class Admin(commands.Cog):
###########################################################################
@commandExtra(name='ban', category='administration')
@command_extra(name='ban', category='administration')
async def _ban(self, ctx: commands.Context, user: discord.Member, *,
reason=""):
try:
@ -132,7 +132,7 @@ class Admin(commands.Cog):
###########################################################################
@commandExtra(name='kick', category='administration')
@command_extra(name='kick', category='administration')
async def _kick(self, ctx: commands.Context, user: discord.Member, *,
reason=""):
try:
@ -159,7 +159,7 @@ class Admin(commands.Cog):
###########################################################################
@commandExtra(name='clear', category='text')
@command_extra(name='clear', category='text')
async def _clear(self, ctx: commands.Context, count: int):
try:
await ctx.message.delete()
@ -169,7 +169,7 @@ class Admin(commands.Cog):
###########################################################################
@groupExtra(name='react', category='text')
@group_extra(name='react', category='text')
async def _react(self, ctx: commands.Context):
if ctx.invoked_subcommand is None:
await ctx.send_help('react')
@ -203,7 +203,7 @@ class Admin(commands.Cog):
###########################################################################
@groupExtra(name='delete', invoke_without_command=True, category='text')
@group_extra(name='delete', invoke_without_command=True, category='text')
async def _delete(self, ctx: commands.Context, message_id: int):
try:
await ctx.message.delete()
@ -229,12 +229,14 @@ class Admin(commands.Cog):
try:
message: discord.Message = await channel.fetch_message(
message_id)
message_id
)
await message.delete()
except (discord.errors.NotFound, discord.errors.Forbidden):
await ctx.send(
Texts('utils', ctx).get("Unable to find the message"),
delete_after=5)
delete_after=5
)
###########################################################################
@ -242,24 +244,18 @@ class Admin(commands.Cog):
member: discord.Member = False):
await ctx.trigger_typing()
week_ago = datetime.datetime.now() - datetime.timedelta(weeks=6)
if member:
warns = self.bot.database.session \
.query(WarnModel) \
.filter(WarnModel.user_id == member.id,
WarnModel.created_at > week_ago,
WarnModel.server_id == ctx.guild.id) \
.order_by(WarnModel.created_at.desc())
warns = WarnModel.objects.filter(
server_id=str(ctx.guild.id),
user_id=member.id
)
else:
warns = self.bot.database.session \
.query(WarnModel) \
.filter(WarnModel.created_at > week_ago,
WarnModel.server_id == ctx.guild.id) \
.order_by(WarnModel.created_at.desc())
warns = WarnModel.objects.filter(
server_id=str(ctx.guild.id)
)
warns_list = ''
for warn in warns:
for warn in await warns.all():
row_id = warn.id
user_id = warn.user_id
user = await self.bot.fetch_user(user_id)
@ -283,7 +279,7 @@ class Admin(commands.Cog):
self.bot.database.session.add(warn)
self.bot.database.session.commit()
@groupExtra(name='warn', aliases=['warns'], category='administration')
@group_extra(name='warn', aliases=['warns'], category='administration')
async def _warn(self, ctx: commands.Context):
await ctx.trigger_typing()
if ctx.invoked_subcommand is None:
@ -412,7 +408,7 @@ class Admin(commands.Cog):
###########################################################################
@commandExtra(name='language', aliases=['lang', 'langue', 'langage'], category='server')
@command_extra(name='language', aliases=['lang', 'langue', 'langage'], category='server')
async def _language(self, ctx: commands.Context, locale: str):
available = self.bot.database.session \
.query(LangModel.value) \
@ -443,7 +439,7 @@ class Admin(commands.Cog):
###########################################################################
@groupExtra(name='prefix', aliases=['prefixes'], category='server')
@group_extra(name='prefix', aliases=['prefixes'], category='server')
async def _prefix(self, ctx: commands.Context):
if ctx.invoked_subcommand is None:
await ctx.send_help('prefix')

View file

@ -20,7 +20,7 @@ from discord.ext import commands, tasks
from bot import TuxBot
from utils import Texts
from utils import commandExtra
from utils import command_extra
log = logging.getLogger(__name__)
@ -243,7 +243,7 @@ class Logs(commands.Cog):
msg = f'{emoji} `[{dt:%Y-%m-%d %H:%M:%S}] {record.message}`'
await self.webhook.send(msg)
@commandExtra(name='commandstats', hidden=True, category='misc')
@command_extra(name='commandstats', hidden=True, category='misc')
@commands.is_owner()
async def _commandstats(self, ctx, limit=20):
counter = self.bot.command_stats
@ -258,7 +258,7 @@ class Logs(commands.Cog):
await ctx.send(f'```\n{output}\n```')
@commandExtra(name='socketstats', hidden=True, category='misc')
@command_extra(name='socketstats', hidden=True, category='misc')
@commands.is_owner()
async def _socketstats(self, ctx):
delta = datetime.datetime.utcnow() - self.bot.uptime
@ -268,7 +268,7 @@ class Logs(commands.Cog):
await ctx.send(
f'{total} socket events observed ({cpm:.2f}/minute):\n{self.bot.socket_stats}')
@commandExtra(name='uptime', category='misc')
@command_extra(name='uptime', category='misc')
async def _uptime(self, ctx):
uptime = humanize.naturaltime(
datetime.datetime.utcnow() - self.bot.uptime)

View file

@ -10,7 +10,7 @@ from bot import TuxBot
from utils import PollModel, ResponsesModel
from utils import Texts
from utils.functions import emotes as utils_emotes
from utils import groupExtra
from utils import group_extra
log = logging.getLogger(__name__)
@ -205,7 +205,7 @@ class Poll(commands.Cog):
poll.content = json.dumps(content)
self.bot.database.session.commit()
@groupExtra(name='poll', aliases=['sondage'], category='poll')
@group_extra(name='poll', aliases=['sondage'], category='poll')
async def _poll(self, ctx: commands.Context):
if ctx.invoked_subcommand is None:
await ctx.send_help('poll')

View file

@ -23,7 +23,7 @@ from tcp_latency import measure_latency
from bot import TuxBot
from utils import Texts
from utils import commandExtra, groupExtra
from utils import command_extra, group_extra
log = logging.getLogger(__name__)
@ -86,7 +86,7 @@ class Useful(commands.Cog):
###########################################################################
@commandExtra(name='iplocalise', category='network')
@command_extra(name='iplocalise', category='network')
async def _iplocalise(self, ctx: commands.Context, addr, ip_type=''):
addr = re.sub(r'http(s?)://', '', addr)
addr = addr[:-1] if addr.endswith('/') else addr
@ -150,7 +150,7 @@ class Useful(commands.Cog):
###########################################################################
@commandExtra(name='getheaders', category='network')
@command_extra(name='getheaders', category='network')
async def _getheaders(self, ctx: commands.Context, addr: str):
if (addr.startswith('http') or addr.startswith('ftp')) is not True:
addr = f"http://{addr}"
@ -180,7 +180,7 @@ class Useful(commands.Cog):
###########################################################################
@commandExtra(name='git', aliases=['sources', 'source', 'github'], category='misc')
@command_extra(name='git', aliases=['sources', 'source', 'github'], category='misc')
async def _git(self, ctx):
e = discord.Embed(
title=Texts('useful', ctx).get('git repo'),
@ -195,7 +195,7 @@ class Useful(commands.Cog):
###########################################################################
@commandExtra(name='quote', category='misc')
@command_extra(name='quote', category='misc')
async def _quote(self, ctx, message_id: discord.Message):
e = discord.Embed(
colour=message_id.author.colour,
@ -217,7 +217,7 @@ class Useful(commands.Cog):
###########################################################################
@commandExtra(name='ping', category='network')
@command_extra(name='ping', category='network')
async def _ping(self, ctx: commands.Context):
start = time.perf_counter()
await ctx.trigger_typing()
@ -235,7 +235,7 @@ class Useful(commands.Cog):
###########################################################################
@commandExtra(name='info', aliases=['about'], category='misc')
@command_extra(name='info', aliases=['about'], category='misc')
async def _info(self, ctx: commands.Context):
proc = psutil.Process()
total, python = self.fetch_info()
@ -318,7 +318,7 @@ class Useful(commands.Cog):
###########################################################################
@commandExtra(name='credits', aliases=['contributors', 'authors'], category='misc')
@command_extra(name='credits', aliases=['contributors', 'authors'], category='misc')
async def _credits(self, ctx: commands.Context):
e = discord.Embed(
title=Texts('useful', ctx).get('Contributors'),
@ -342,7 +342,7 @@ class Useful(commands.Cog):
await ctx.send(embed=e)
###########################################################################
@groupExtra(name='cb', aliases=['cc'], category='misc')
@group_extra(name='cb', aliases=['cc'], category='misc')
@commands.cooldown(1, 5, type=commands.BucketType.user)
async def _cb(self, ctx: commands.Context):
if ctx.invoked_subcommand is None:

View file

@ -5,7 +5,7 @@ from discord.ext import commands
from bot import TuxBot
from utils import AliasesModel
from utils import Texts
from utils import groupExtra
from utils import group_extra
log = logging.getLogger(__name__)
@ -19,7 +19,7 @@ class User(commands.Cog):
###########################################################################
@groupExtra(name='alias', aliases=['aliases'], category='alias')
@group_extra(name='alias', aliases=['aliases'], category='alias')
async def _alias(self, ctx: commands.Context):
if ctx.invoked_subcommand is None:
await ctx.send_help('alias')

View file

@ -18,3 +18,7 @@ Token =
[misc]
Separator =
[API]
Host =
Port =

View file

@ -1,5 +0,0 @@
{
"default": "fr",
"available": ["en", "fr"],
"280805240977227776": "fr"
}

View file

@ -1,18 +0,0 @@
[280805240977227776]
prefixes = b1.
[303633056944881686]
prefixes = b1.
[373881878471770112]
prefixes = b1.
[336642139381301249]
prefixes = ba.
[274247231534792704]
prefixes = test.
[528679953399676938]
prefixes = test.

View file

@ -15,21 +15,18 @@ class GroupPlus(commands.Group):
class ContextPlus(commands.Context):
async def send(self, **kwargs):
async def send(self, content=None, **kwargs):
config = Config('./configs/config.cfg')
content = kwargs.pop('content')
content = content.replace(config.get("bot", "Token"), 'Whoops! leaked token')
content = content.replace(config.get("webhook", "Token"), 'Whoops! leaked token')
kwargs['content'] = content
return await super().send(**kwargs)
return await super().send(content, **kwargs)
def commandExtra(*args, **kwargs):
def command_extra(*args, **kwargs):
return commands.command(*args, **kwargs, cls=CommandsPlus)
def groupExtra(*args, **kwargs):
def group_extra(*args, **kwargs):
return commands.group(*args, **kwargs, cls=GroupPlus)

View file

@ -19,11 +19,16 @@ class Texts:
self.locale = lang
@staticmethod
def get_locale(ctx):
with open('./configs/langs.json') as f:
def get_locale(ctx: commands.Context):
lang = 'fr'
if ctx is not None:
try:
with open(f'./configs/guilds/{ctx.guild.id}.json', 'r') as f:
data = json.load(f)
if ctx is not None:
return data.get(str(ctx.guild.id), data['default'])
else:
return data['default']
lang = data['lang']
except FileNotFoundError:
pass
return lang

View file

@ -10,6 +10,9 @@ postgresql = 'postgresql://{}:{}@{}/{}'.format(
database = databases.Database(postgresql)
metadata = sqlalchemy.MetaData()
engine = sqlalchemy.create_engine(str(database.url))
metadata.create_all(engine)
from .warn import WarnModel
from .poll import PollModel, ResponsesModel
from .alias import AliasesModel