refactor(cogs): prepare the env for help command
This commit is contained in:
parent
c71c976111
commit
fdf220cdfa
27 changed files with 452 additions and 261 deletions
7
.gitignore
vendored
7
.gitignore
vendored
|
@ -4,16 +4,15 @@ __pycache__/
|
|||
.env
|
||||
configs/config.cfg
|
||||
configs/prefixes.cfg
|
||||
configs/clusters.cfg
|
||||
configs/fallbacks.cfg
|
||||
.DS_Store
|
||||
private.py
|
||||
|
||||
#jetbrains
|
||||
.idea/
|
||||
|
||||
#other
|
||||
logs/tuxbot.log
|
||||
|
||||
# other
|
||||
*.logs
|
||||
|
||||
# Byte-compiled / optimized / DLL files
|
||||
__pycache__/
|
||||
|
|
36
bot.py
36
bot.py
|
@ -10,35 +10,35 @@ import discord
|
|||
import git
|
||||
from discord.ext import commands
|
||||
|
||||
from cogs.utils.config import Config
|
||||
from cogs.utils.database import Database
|
||||
from cogs.utils.lang import Texts
|
||||
from cogs.utils.version import Version
|
||||
from utils import Config
|
||||
from utils import Database
|
||||
from utils import Texts
|
||||
from utils import Version
|
||||
|
||||
description = """
|
||||
Je suis TuxBot, le bot qui vit de l'OpenSource ! ;)
|
||||
"""
|
||||
|
||||
build = git.Repo(search_parent_directories=True).head.object.hexsha
|
||||
version = (2, 1, 0)
|
||||
|
||||
log = logging.getLogger(__name__)
|
||||
|
||||
l_extensions: List[str] = [
|
||||
'cogs.admin',
|
||||
'cogs.basics',
|
||||
'cogs.fallback_manager',
|
||||
'cogs.logs',
|
||||
'cogs.poll',
|
||||
'cogs.user',
|
||||
'cogs.utility',
|
||||
'cogs.Admin',
|
||||
'cogs.Help',
|
||||
'cogs.Logs',
|
||||
'cogs.Monitoring',
|
||||
'cogs.Polls',
|
||||
'cogs.Useful',
|
||||
'cogs.User',
|
||||
'jishaku',
|
||||
]
|
||||
|
||||
|
||||
async def _prefix_callable(bot, message: discord.message) -> list:
|
||||
extras = [bot.cluster.get('Name')]
|
||||
extras = [bot.cluster.get('Name') + '.']
|
||||
if message.guild is not None:
|
||||
extras = []
|
||||
if str(message.guild.id) in bot.prefixes:
|
||||
extras.extend(
|
||||
bot.prefixes.get(str(message.guild.id), "prefixes").split(
|
||||
|
@ -70,10 +70,11 @@ class TuxBot(commands.AutoShardedBot):
|
|||
self.config = Config('./configs/config.cfg')
|
||||
self.prefixes = Config('./configs/prefixes.cfg')
|
||||
self.blacklist = Config('./configs/blacklist.cfg')
|
||||
self.clusters = Config('./configs/clusters.cfg')
|
||||
self.cluster = self.clusters.find('True', key='This', first=True)
|
||||
self.fallbacks = Config('./configs/fallbacks.cfg')
|
||||
self.cluster = self.fallbacks.find('True', key='This', first=True)
|
||||
|
||||
self.version = Version(10, 1, 0, pre_release='a5', build=build)
|
||||
self.version = Version(*version, pre_release='a5', build=build)
|
||||
self.owner = int
|
||||
|
||||
for extension in l_extensions:
|
||||
try:
|
||||
|
@ -149,6 +150,9 @@ 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])
|
||||
)
|
||||
|
||||
@staticmethod
|
||||
async def on_resumed():
|
||||
|
|
|
@ -1,17 +1,16 @@
|
|||
import asyncio
|
||||
import datetime
|
||||
import logging
|
||||
from typing import Union
|
||||
|
||||
import asyncio
|
||||
|
||||
import discord
|
||||
import humanize
|
||||
from discord.ext import commands
|
||||
|
||||
from bot import TuxBot
|
||||
from .utils.lang import Texts
|
||||
from .utils.extra import commandExtra, groupExtra
|
||||
from .utils.models import WarnModel, LangModel
|
||||
from utils import Texts
|
||||
from utils import WarnModel, LangModel
|
||||
from utils import commandExtra, groupExtra
|
||||
|
||||
log = logging.getLogger(__name__)
|
||||
|
||||
|
@ -20,6 +19,8 @@ class Admin(commands.Cog):
|
|||
|
||||
def __init__(self, bot: TuxBot):
|
||||
self.bot = bot
|
||||
self.icon = ":shield:"
|
||||
self.big_icon = "https://emojipedia-us.s3.dualstack.us-west-1.amazonaws.com/thumbs/160/twitter/233/shield_1f6e1.png"
|
||||
|
||||
async def cog_check(self, ctx: commands.Context) -> bool:
|
||||
permissions: discord.Permissions = ctx.channel.permissions_for(
|
220
cogs/Help.py
Normal file
220
cogs/Help.py
Normal file
|
@ -0,0 +1,220 @@
|
|||
# Created by romain at 04/01/2020
|
||||
|
||||
import logging
|
||||
|
||||
import discord
|
||||
from discord.ext import commands
|
||||
|
||||
from bot import TuxBot
|
||||
from utils import FieldPages
|
||||
from utils import commandsPlus
|
||||
|
||||
log = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class HelpCommand(commands.HelpCommand):
|
||||
def __init__(self, *args, **kwargs):
|
||||
super().__init__(*args, **kwargs)
|
||||
self.ignore_cogs = ["Monitoring", "Help", "Logs"]
|
||||
self.owner_cogs = []
|
||||
|
||||
def get_command_signature(self, command):
|
||||
return f"[{command.cog.qualified_name.upper()}] > {command.qualified_name}"
|
||||
|
||||
def common_command_formatting(self, emb, command):
|
||||
emb.title = self.get_command_signature(command)
|
||||
if command.cog_name != "Jishaku":
|
||||
emb.set_thumbnail(url=command.cog.big_icon)
|
||||
try:
|
||||
emb.description = f"{command.cog.qualified_name.lower()}_help " \
|
||||
f"{command.parent}_{command.name}_description"
|
||||
except:
|
||||
emb.description = f"{command.cog.qualified_name.lower()}_help " \
|
||||
f"{command.name}_description"
|
||||
usage = "help.command_help.usage"
|
||||
try:
|
||||
if command.parent:
|
||||
try:
|
||||
usg = f"{command.cog.qualified_name.lower()}_help " \
|
||||
f"{command.parent}_{command.name}_usage"
|
||||
except:
|
||||
usg = f"{command.cog.qualified_name.lower()}_help " \
|
||||
f"{command.name}_usage"
|
||||
else:
|
||||
usg = f"{command.cog.qualified_name.lower()}_help " \
|
||||
f"{command.name}_usage"
|
||||
|
||||
emb.add_field(name=usage,
|
||||
value=f"{self.context.prefix}{command.qualified_name} " + usg)
|
||||
except KeyError:
|
||||
emb.add_field(name=usage,
|
||||
value=f"{self.context.prefix}{command.qualified_name}")
|
||||
aliases = "`" + '`, `'.join(command.aliases) + "`"
|
||||
if aliases == "``":
|
||||
aliases = "help " \
|
||||
"help.command_help.no_aliases"
|
||||
|
||||
emb.add_field(name="help "
|
||||
"help.command_help.aliases",
|
||||
value=aliases)
|
||||
return emb
|
||||
|
||||
async def command_callback(self, ctx, *, command=None):
|
||||
await self.prepare_help_command(ctx, command)
|
||||
|
||||
if command is None:
|
||||
mapping = self.get_bot_mapping()
|
||||
return await self.send_bot_help(mapping)
|
||||
|
||||
cog = ctx.bot.get_cog(command.title())
|
||||
if cog is not None:
|
||||
return await self.send_cog_help(cog)
|
||||
|
||||
maybe_coro = discord.utils.maybe_coroutine
|
||||
|
||||
keys = command.split(' ')
|
||||
cmd = ctx.bot.all_commands.get(keys[0])
|
||||
if cmd is None:
|
||||
string = await maybe_coro(self.command_not_found,
|
||||
self.remove_mentions(keys[0]))
|
||||
return await self.send_error_message(string)
|
||||
|
||||
for key in keys[1:]:
|
||||
try:
|
||||
found = cmd.all_commands.get(key)
|
||||
except AttributeError:
|
||||
string = await maybe_coro(self.subcommand_not_found, cmd,
|
||||
self.remove_mentions(key))
|
||||
return await self.send_error_message(string)
|
||||
else:
|
||||
if found is None:
|
||||
string = await maybe_coro(self.subcommand_not_found,
|
||||
cmd,
|
||||
self.remove_mentions(key))
|
||||
return await self.send_error_message(string)
|
||||
cmd = found
|
||||
|
||||
if isinstance(cmd, commands.Group):
|
||||
return await self.send_group_help(cmd)
|
||||
else:
|
||||
return await self.send_command_help(cmd)
|
||||
|
||||
async def send_bot_help(self, mapping):
|
||||
owner = self.context.bot.owner
|
||||
emb = discord.Embed(color=discord.colour.Color.blue())
|
||||
emb.description = "help " \
|
||||
"help.main_page.description".format(owner)
|
||||
emb.set_author(icon_url=self.context.author.avatar_url,
|
||||
name=self.context.author)
|
||||
|
||||
cogs = ""
|
||||
for extension in self.context.bot.cogs.values():
|
||||
if self.context.author != owner and extension.qualified_name.upper() in self.owner_cogs:
|
||||
continue
|
||||
if self.context.author == owner and extension.qualified_name in self.ignore_cogs:
|
||||
continue
|
||||
if extension.qualified_name == "Jishaku":
|
||||
continue
|
||||
cogs += f"• {extension.icon} **{extension.qualified_name}**\n"
|
||||
|
||||
emb.add_field(name="help "
|
||||
"help.main_page.field_title.categories",
|
||||
value=cogs)
|
||||
|
||||
await self.context.send(embed=emb)
|
||||
|
||||
async def send_command_help(self, command):
|
||||
if command.cog_name in self.ignore_cogs:
|
||||
return await self.send_error_message(
|
||||
self.command_not_found(command.name))
|
||||
|
||||
if isinstance(command, commandsPlus):
|
||||
if command.name == "jishaku":
|
||||
pass
|
||||
|
||||
formatted = self.common_command_formatting(
|
||||
discord.Embed(color=discord.colour.Color.blue()), command)
|
||||
await self.context.send(embed=formatted)
|
||||
|
||||
async def send_group_help(self, group):
|
||||
if group.cog_name in self.ignore_cogs:
|
||||
return await self.send_error_message(
|
||||
self.command_not_found(group.name))
|
||||
|
||||
formatted = self.common_command_formatting(
|
||||
discord.Embed(color=discord.colour.Color.blue()), group)
|
||||
sub_cmd_list = ""
|
||||
for group_command in group.commands:
|
||||
try:
|
||||
sub_cmd_list += f"`╚╡` **{group_command.name}** - " \
|
||||
f"{group.cog.qualified_name.lower()}_help " \
|
||||
f"{group_command.parent}_{group_command.name}_brief\n"
|
||||
except Exception:
|
||||
sub_cmd_list += f"`╚╡` **{group_command.name}** - " \
|
||||
f"{group.cog.qualified_name.lower()}_help" \
|
||||
f"{group_command.name}_brief\n"
|
||||
subcommands = "help.command_help.subcommands"
|
||||
formatted.add_field(name=subcommands, value=sub_cmd_list,
|
||||
inline=False)
|
||||
await self.context.send(embed=formatted)
|
||||
|
||||
async def send_cog_help(self, cog):
|
||||
if (
|
||||
cog.qualified_name.upper() in self.owner_cogs
|
||||
and not await self.context.bot.is_owner(self.context.author)
|
||||
) or cog.qualified_name.upper() in self.ignore_cogs:
|
||||
return
|
||||
if cog.qualified_name == "Jishaku":
|
||||
return
|
||||
if cog.qualified_name in self.ignore_cogs:
|
||||
return
|
||||
|
||||
pages = {}
|
||||
for cmd in cog.get_commands():
|
||||
if not await self.context.bot.is_owner(
|
||||
self.context.author) and (
|
||||
cmd.hidden or cmd.category == "Hidden"):
|
||||
continue
|
||||
if cmd.category not in pages:
|
||||
pages[cmd.category] = "```asciidoc\n"
|
||||
cmd_brief = f"{cog.qualified_name.lower()}_help " \
|
||||
f"{cmd.name}_brief"
|
||||
pages[
|
||||
cmd.category] += f"{cmd.name}{' ' * int(17 - len(cmd.name))}:: {cmd_brief}\n"
|
||||
if isinstance(cmd, commands.Group):
|
||||
for group_command in cmd.commands:
|
||||
try:
|
||||
cmd_brief = f"{cog.qualified_name.lower()}_help " \
|
||||
f"{group_command.parent}_{group_command.name}_brief"
|
||||
except Exception:
|
||||
cmd_brief = f"{cog.qualified_name.lower()}_help " \
|
||||
f"{group_command.name}_brief"
|
||||
pages[
|
||||
cmd.category] += f"━ {group_command.name}{' ' * int(15 - len(group_command.name))}:: {cmd_brief}\n"
|
||||
for e in pages:
|
||||
pages[e] += "```"
|
||||
formatted = []
|
||||
for name, cont in pages.items():
|
||||
formatted.append((name, cont))
|
||||
footer_text = "help " \
|
||||
"help.category_page.footer_info".format(self.context.prefix)
|
||||
pages = FieldPages(self.context,
|
||||
embed_color=discord.colour.Color.blue(),
|
||||
entries=formatted,
|
||||
title=cog.qualified_name.upper(),
|
||||
thumbnail=cog.big_icon,
|
||||
footertext=footer_text,
|
||||
per_page=1)
|
||||
await pages.paginate()
|
||||
|
||||
def command_not_found(self, string):
|
||||
return 'No command called "{}" found.'.format(string)
|
||||
|
||||
|
||||
class Help(commands.Cog):
|
||||
def __init__(self, bot: TuxBot):
|
||||
bot.help_command = HelpCommand()
|
||||
|
||||
|
||||
def setup(bot: TuxBot):
|
||||
bot.add_cog(Help(bot))
|
|
@ -19,8 +19,8 @@ import psutil
|
|||
from discord.ext import commands, tasks
|
||||
|
||||
from bot import TuxBot
|
||||
from .utils import Texts
|
||||
from .utils.extra import commandExtra
|
||||
from utils import Texts
|
||||
from utils import commandExtra
|
||||
|
||||
log = logging.getLogger(__name__)
|
||||
|
|
@ -1,6 +1,6 @@
|
|||
from datetime import datetime
|
||||
import logging
|
||||
import urllib.request
|
||||
from datetime import datetime
|
||||
|
||||
import discord
|
||||
from aiohttp import web
|
||||
|
@ -30,11 +30,11 @@ class Monitoring(commands.Cog):
|
|||
|
||||
@tasks.loop(seconds=10.0)
|
||||
async def ping_clusters(self):
|
||||
for cluster in self.bot.clusters:
|
||||
for cluster in self.bot.fallbacks:
|
||||
if cluster == 'DEFAULT':
|
||||
pass
|
||||
else:
|
||||
cluster = self.bot.clusters[cluster]
|
||||
cluster = self.bot.fallbacks[cluster]
|
||||
if not cluster.get('This', False):
|
||||
host = cluster.get('Host')
|
||||
port = cluster.get('Port')
|
|
@ -7,10 +7,9 @@ from discord.ext import commands
|
|||
from yarl import URL
|
||||
|
||||
from bot import TuxBot
|
||||
from .utils.lang import Texts
|
||||
from .utils.models import PollModel, ResponsesModel
|
||||
from .utils.extra import groupExtra
|
||||
from .utils import emotes as utils_emotes
|
||||
from utils import PollModel, ResponsesModel
|
||||
from utils import Texts, emotes as utils_emotes
|
||||
from utils import groupExtra
|
||||
|
||||
log = logging.getLogger(__name__)
|
||||
|
||||
|
@ -19,6 +18,8 @@ class Polls(commands.Cog):
|
|||
|
||||
def __init__(self, bot: TuxBot):
|
||||
self.bot = bot
|
||||
self.icon = ":bar_chart:"
|
||||
self.big_icon = "https://emojipedia-us.s3.dualstack.us-west-1.amazonaws.com/thumbs/120/twitter/233/bar-chart_1f4ca.png:"
|
||||
|
||||
def get_poll(self, pld) -> Union[bool, PollModel]:
|
||||
if pld.user_id != self.bot.user.id:
|
||||
|
@ -76,7 +77,8 @@ class Polls(commands.Cog):
|
|||
await self.update_poll(poll.id)
|
||||
|
||||
@commands.Cog.listener()
|
||||
async def on_raw_reaction_remove(self, pld: discord.RawReactionActionEvent):
|
||||
async def on_raw_reaction_remove(self,
|
||||
pld: discord.RawReactionActionEvent):
|
||||
poll = self.get_poll(pld)
|
||||
|
||||
if poll:
|
||||
|
@ -156,8 +158,8 @@ class Polls(commands.Cog):
|
|||
content = json.loads(poll.content) \
|
||||
if isinstance(poll.content, str) \
|
||||
else poll.content
|
||||
raw_responses = self.bot.database.session\
|
||||
.query(ResponsesModel)\
|
||||
raw_responses = self.bot.database.session \
|
||||
.query(ResponsesModel) \
|
||||
.filter(ResponsesModel.poll_id == poll_id)
|
||||
responses = {}
|
||||
|
|
@ -1,26 +1,34 @@
|
|||
# Created by romain at 04/01/2020
|
||||
|
||||
import logging
|
||||
import os
|
||||
import pathlib
|
||||
import platform
|
||||
import re
|
||||
import socket
|
||||
import time
|
||||
from socket import AF_INET6
|
||||
|
||||
import aiohttp
|
||||
import discord
|
||||
import humanize
|
||||
import psutil
|
||||
from discord.ext import commands
|
||||
from tcp_latency import measure_latency
|
||||
|
||||
from bot import TuxBot
|
||||
from .utils.lang import Texts
|
||||
from .utils.extra import commandExtra
|
||||
from tcp_latency import measure_latency
|
||||
from utils import Texts
|
||||
from utils import commandExtra
|
||||
|
||||
log = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class Basics(commands.Cog):
|
||||
class Useful(commands.Cog):
|
||||
|
||||
def __init__(self, bot: TuxBot):
|
||||
self.bot = bot
|
||||
self.icon = ":toolbox:"
|
||||
self.big_icon = "https://emojipedia-us.s3.dualstack.us-west-1.amazonaws.com/thumbs/120/twitter/233/toolbox_1f9f0.png"
|
||||
|
||||
@staticmethod
|
||||
def _latest_commits():
|
||||
|
@ -30,6 +38,142 @@ class Basics(commands.Cog):
|
|||
|
||||
###########################################################################
|
||||
|
||||
@commandExtra(name='iplocalise', category='utility',
|
||||
description=Texts('commands').get('utility._iplocalise'))
|
||||
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
|
||||
|
||||
await ctx.trigger_typing()
|
||||
|
||||
try:
|
||||
if ip_type in ('v6', 'ipv6'):
|
||||
try:
|
||||
ip = socket.getaddrinfo(addr, None, AF_INET6)[1][4][0]
|
||||
except socket.gaierror:
|
||||
return await ctx.send(
|
||||
Texts('utility', ctx).get('ipv6 not available'))
|
||||
else:
|
||||
ip = socket.gethostbyname(addr)
|
||||
|
||||
async with self.bot.session.get(f"http://ip-api.com/json/{ip}") \
|
||||
as s:
|
||||
response: dict = await s.json()
|
||||
|
||||
if response.get('status') == 'success':
|
||||
e = discord.Embed(
|
||||
title=f"{Texts('utility', ctx).get('Information for')}"
|
||||
f" ``{addr}`` *`({response.get('query')})`*",
|
||||
color=0x5858d7
|
||||
)
|
||||
|
||||
e.add_field(
|
||||
name=Texts('utility', ctx).get('Belongs to :'),
|
||||
value=response.get('org', 'N/A'),
|
||||
inline=False
|
||||
)
|
||||
|
||||
e.add_field(
|
||||
name=Texts('utility', ctx).get('Is located at :'),
|
||||
value=response.get('city', 'N/A'),
|
||||
inline=True
|
||||
)
|
||||
|
||||
e.add_field(
|
||||
name="Region :",
|
||||
value=f"{response.get('regionName', 'N/A')} "
|
||||
f"({response.get('country', 'N/A')})",
|
||||
inline=True
|
||||
)
|
||||
|
||||
e.set_thumbnail(
|
||||
url=f"https://www.countryflags.io/"
|
||||
f"{response.get('countryCode')}/flat/64.png")
|
||||
|
||||
await ctx.send(embed=e)
|
||||
else:
|
||||
await ctx.send(
|
||||
content=f"{Texts('utility', ctx).get('info not available')}"
|
||||
f"``{response.get('query')}``")
|
||||
|
||||
except Exception:
|
||||
await ctx.send(
|
||||
f"{Texts('utility', ctx).get('Cannot connect to host')} {addr}"
|
||||
)
|
||||
|
||||
###########################################################################
|
||||
|
||||
@commandExtra(name='getheaders', category='utility',
|
||||
description=Texts('commands').get('utility._getheaders'))
|
||||
async def _getheaders(self, ctx: commands.Context, addr: str):
|
||||
if (addr.startswith('http') or addr.startswith('ftp')) is not True:
|
||||
addr = f"http://{addr}"
|
||||
|
||||
await ctx.trigger_typing()
|
||||
|
||||
try:
|
||||
async with self.bot.session.get(addr) as s:
|
||||
e = discord.Embed(
|
||||
title=f"{Texts('utility', ctx).get('Headers of')} {addr}",
|
||||
color=0xd75858
|
||||
)
|
||||
e.add_field(name="Status", value=s.status, inline=True)
|
||||
e.set_thumbnail(url=f"https://http.cat/{s.status}")
|
||||
|
||||
headers = dict(s.headers.items())
|
||||
headers.pop('Set-Cookie', headers)
|
||||
|
||||
for key, value in headers.items():
|
||||
e.add_field(name=key, value=value, inline=True)
|
||||
await ctx.send(embed=e)
|
||||
|
||||
except aiohttp.client_exceptions.ClientError:
|
||||
await ctx.send(
|
||||
f"{Texts('utility', ctx).get('Cannot connect to host')} {addr}"
|
||||
)
|
||||
|
||||
###########################################################################
|
||||
|
||||
@commandExtra(name='git', aliases=['sources', 'source', 'github'],
|
||||
category='utility',
|
||||
description=Texts('commands').get('utility._git'))
|
||||
async def _git(self, ctx):
|
||||
e = discord.Embed(
|
||||
title=Texts('utility', ctx).get('git repo'),
|
||||
description=Texts('utility', ctx).get('git text'),
|
||||
colour=0xE9D460
|
||||
)
|
||||
e.set_author(
|
||||
name='Gnous',
|
||||
icon_url="https://cdn.gnous.eu/logo1.png"
|
||||
)
|
||||
await ctx.send(embed=e)
|
||||
|
||||
###########################################################################
|
||||
|
||||
@commandExtra(name='quote', category='utility',
|
||||
description=Texts('commands').get('utility._quote'))
|
||||
async def _quote(self, ctx, message_id: discord.Message):
|
||||
e = discord.Embed(
|
||||
colour=message_id.author.colour,
|
||||
description=message_id.clean_content,
|
||||
timestamp=message_id.created_at
|
||||
)
|
||||
e.set_author(
|
||||
name=message_id.author.display_name,
|
||||
icon_url=message_id.author.avatar_url_as(format="jpg")
|
||||
)
|
||||
if len(message_id.attachments) >= 1:
|
||||
e.set_image(url=message_id.attachments[0].url)
|
||||
|
||||
e.add_field(name="**Original**",
|
||||
value=f"[Go!]({message_id.jump_url})")
|
||||
e.set_footer(text="#" + message_id.channel.name)
|
||||
|
||||
await ctx.send(embed=e)
|
||||
|
||||
###########################################################################
|
||||
|
||||
@commandExtra(name='ping', category='basics',
|
||||
description=Texts('commands').get('basics._ping'))
|
||||
async def _ping(self, ctx: commands.Context):
|
||||
|
@ -178,4 +322,4 @@ class Basics(commands.Cog):
|
|||
|
||||
|
||||
def setup(bot: TuxBot):
|
||||
bot.add_cog(Basics(bot))
|
||||
bot.add_cog(Useful(bot))
|
|
@ -3,9 +3,9 @@ import logging
|
|||
from discord.ext import commands
|
||||
|
||||
from bot import TuxBot
|
||||
from .utils.extra import groupExtra
|
||||
from .utils.lang import Texts
|
||||
from .utils.models import AliasesModel
|
||||
from utils import AliasesModel
|
||||
from utils import Texts
|
||||
from utils import groupExtra
|
||||
|
||||
log = logging.getLogger(__name__)
|
||||
|
||||
|
@ -14,6 +14,8 @@ class User(commands.Cog):
|
|||
|
||||
def __init__(self, bot: TuxBot):
|
||||
self.bot = bot
|
||||
self.icon = ":bust_in_silhouette:"
|
||||
self.big_icon = "https://emojipedia-us.s3.dualstack.us-west-1.amazonaws.com/thumbs/120/twitter/233/bust-in-silhouette_1f464.png"
|
||||
|
||||
###########################################################################
|
||||
|
160
cogs/utility.py
160
cogs/utility.py
|
@ -1,160 +0,0 @@
|
|||
import logging
|
||||
import re
|
||||
|
||||
import aiohttp
|
||||
import discord
|
||||
from discord.ext import commands
|
||||
from bot import TuxBot
|
||||
import socket
|
||||
from socket import AF_INET6
|
||||
|
||||
from .utils.lang import Texts
|
||||
from .utils.extra import commandExtra
|
||||
|
||||
log = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class Utility(commands.Cog):
|
||||
|
||||
def __init__(self, bot: TuxBot):
|
||||
self.bot = bot
|
||||
|
||||
###########################################################################
|
||||
|
||||
@commandExtra(name='iplocalise', category='utility',
|
||||
description=Texts('commands').get('utility._iplocalise'))
|
||||
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
|
||||
|
||||
await ctx.trigger_typing()
|
||||
|
||||
try:
|
||||
if ip_type in ('v6', 'ipv6'):
|
||||
try:
|
||||
ip = socket.getaddrinfo(addr, None, AF_INET6)[1][4][0]
|
||||
except socket.gaierror:
|
||||
return await ctx.send(
|
||||
Texts('utility', ctx).get('ipv6 not available'))
|
||||
else:
|
||||
ip = socket.gethostbyname(addr)
|
||||
|
||||
async with self.bot.session.get(f"http://ip-api.com/json/{ip}") \
|
||||
as s:
|
||||
response: dict = await s.json()
|
||||
|
||||
if response.get('status') == 'success':
|
||||
e = discord.Embed(
|
||||
title=f"{Texts('utility', ctx).get('Information for')}"
|
||||
f" ``{addr}`` *`({response.get('query')})`*",
|
||||
color=0x5858d7
|
||||
)
|
||||
|
||||
e.add_field(
|
||||
name=Texts('utility', ctx).get('Belongs to :'),
|
||||
value=response.get('org', 'N/A'),
|
||||
inline=False
|
||||
)
|
||||
|
||||
e.add_field(
|
||||
name=Texts('utility', ctx).get('Is located at :'),
|
||||
value=response.get('city', 'N/A'),
|
||||
inline=True
|
||||
)
|
||||
|
||||
e.add_field(
|
||||
name="Region :",
|
||||
value=f"{response.get('regionName', 'N/A')} "
|
||||
f"({response.get('country', 'N/A')})",
|
||||
inline=True
|
||||
)
|
||||
|
||||
e.set_thumbnail(
|
||||
url=f"https://www.countryflags.io/"
|
||||
f"{response.get('countryCode')}/flat/64.png")
|
||||
|
||||
await ctx.send(embed=e)
|
||||
else:
|
||||
await ctx.send(
|
||||
content=f"{Texts('utility', ctx).get('info not available')}"
|
||||
f"``{response.get('query')}``")
|
||||
|
||||
except Exception:
|
||||
await ctx.send(
|
||||
f"{Texts('utility', ctx).get('Cannot connect to host')} {addr}"
|
||||
)
|
||||
|
||||
###########################################################################
|
||||
|
||||
@commandExtra(name='getheaders', category='utility',
|
||||
description=Texts('commands').get('utility._getheaders'))
|
||||
async def _getheaders(self, ctx: commands.Context, addr: str):
|
||||
if (addr.startswith('http') or addr.startswith('ftp')) is not True:
|
||||
addr = f"http://{addr}"
|
||||
|
||||
await ctx.trigger_typing()
|
||||
|
||||
try:
|
||||
async with self.bot.session.get(addr) as s:
|
||||
e = discord.Embed(
|
||||
title=f"{Texts('utility', ctx).get('Headers of')} {addr}",
|
||||
color=0xd75858
|
||||
)
|
||||
e.add_field(name="Status", value=s.status, inline=True)
|
||||
e.set_thumbnail(url=f"https://http.cat/{s.status}")
|
||||
|
||||
headers = dict(s.headers.items())
|
||||
headers.pop('Set-Cookie', headers)
|
||||
|
||||
for key, value in headers.items():
|
||||
e.add_field(name=key, value=value, inline=True)
|
||||
await ctx.send(embed=e)
|
||||
|
||||
except aiohttp.client_exceptions.ClientError:
|
||||
await ctx.send(
|
||||
f"{Texts('utility', ctx).get('Cannot connect to host')} {addr}"
|
||||
)
|
||||
|
||||
###########################################################################
|
||||
|
||||
@commandExtra(name='git', aliases=['sources', 'source', 'github'],
|
||||
category='utility',
|
||||
description=Texts('commands').get('utility._git'))
|
||||
async def _git(self, ctx):
|
||||
e = discord.Embed(
|
||||
title=Texts('utility', ctx).get('git repo'),
|
||||
description=Texts('utility', ctx).get('git text'),
|
||||
colour=0xE9D460
|
||||
)
|
||||
e.set_author(
|
||||
name='Gnous',
|
||||
icon_url="https://cdn.gnous.eu/logo1.png"
|
||||
)
|
||||
await ctx.send(embed=e)
|
||||
|
||||
###########################################################################
|
||||
|
||||
@commandExtra(name='quote', category='utility',
|
||||
description=Texts('commands').get('utility._quote'))
|
||||
async def _quote(self, ctx, message_id: discord.Message):
|
||||
e = discord.Embed(
|
||||
colour=message_id.author.colour,
|
||||
description=message_id.clean_content,
|
||||
timestamp=message_id.created_at
|
||||
)
|
||||
e.set_author(
|
||||
name=message_id.author.display_name,
|
||||
icon_url=message_id.author.avatar_url_as(format="jpg")
|
||||
)
|
||||
if len(message_id.attachments) >= 1:
|
||||
e.set_image(url=message_id.attachments[0].url)
|
||||
|
||||
e.add_field(name="**Original**",
|
||||
value=f"[Go!]({message_id.jump_url})")
|
||||
e.set_footer(text="#" + message_id.channel.name)
|
||||
|
||||
await ctx.send(embed=e)
|
||||
|
||||
|
||||
def setup(bot: TuxBot):
|
||||
bot.add_cog(Utility(bot))
|
|
@ -1,3 +0,0 @@
|
|||
from .config import *
|
||||
from .lang import *
|
||||
from .version import *
|
|
@ -1,5 +1,5 @@
|
|||
[280805240977227776]
|
||||
prefixes = rm-srv01.
|
||||
prefixes = b1.
|
||||
|
||||
[303633056944881686]
|
||||
prefixes = b1.
|
||||
|
@ -14,4 +14,5 @@ prefixes = ba.
|
|||
prefixes = test.
|
||||
|
||||
[528679953399676938]
|
||||
prefixes = test.
|
||||
prefixes = test.
|
||||
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
from cogs.utils.models import *
|
||||
from cogs.utils.config import Config
|
||||
from cogs.utils.database import Database
|
||||
from utils import Config
|
||||
from utils import Database
|
||||
|
||||
database = Database(Config("./configs/config.cfg"))
|
||||
|
||||
|
|
9
utils/__init__.py
Executable file
9
utils/__init__.py
Executable file
|
@ -0,0 +1,9 @@
|
|||
from .database import Database
|
||||
from .models import *
|
||||
|
||||
from .config import *
|
||||
from .lang import *
|
||||
from .version import *
|
||||
|
||||
from .extra import *
|
||||
from .paginator import *
|
|
@ -1,6 +1,6 @@
|
|||
import gettext
|
||||
from .config import Config
|
||||
from cogs.utils.database import Database
|
||||
from utils import Database
|
||||
|
||||
from .models.lang import LangModel
|
||||
from discord.ext import commands
|
|
@ -2,20 +2,15 @@ import asyncio
|
|||
import discord
|
||||
from discord.ext.commands import Paginator as CommandPaginator
|
||||
|
||||
|
||||
class CannotPaginate(Exception):
|
||||
pass
|
||||
|
||||
|
||||
class Pages:
|
||||
"""Implements a paginator that queries the user for the
|
||||
pagination interface.
|
||||
|
||||
Pages are 1-index based, not 0-index based.
|
||||
|
||||
If the user does not reply within 2 minutes then the pagination
|
||||
interface exits automatically.
|
||||
|
||||
Parameters
|
||||
------------
|
||||
ctx: Context
|
||||
|
@ -26,7 +21,6 @@ class Pages:
|
|||
How many entries show up per page.
|
||||
show_entry_count: bool
|
||||
Whether to show an entry count in the footer.
|
||||
|
||||
Attributes
|
||||
-----------
|
||||
embed: discord.Embed
|
||||
|
@ -36,7 +30,6 @@ class Pages:
|
|||
permissions: discord.Permissions
|
||||
Our permissions for the channel.
|
||||
"""
|
||||
|
||||
def __init__(self, ctx, *, entries, per_page=12, show_entry_count=True):
|
||||
self.bot = ctx.bot
|
||||
self.entries = entries
|
||||
|
@ -52,13 +45,11 @@ class Pages:
|
|||
self.paginating = len(entries) > per_page
|
||||
self.show_entry_count = show_entry_count
|
||||
self.reaction_emojis = [
|
||||
('\N{BLACK LEFT-POINTING DOUBLE TRIANGLE WITH VERTICAL BAR}',
|
||||
self.first_page),
|
||||
('\N{BLACK LEFT-POINTING DOUBLE TRIANGLE WITH VERTICAL BAR}', self.first_page),
|
||||
('\N{BLACK LEFT-POINTING TRIANGLE}', self.previous_page),
|
||||
('\N{BLACK RIGHT-POINTING TRIANGLE}', self.next_page),
|
||||
('\N{BLACK RIGHT-POINTING DOUBLE TRIANGLE WITH VERTICAL BAR}',
|
||||
self.last_page),
|
||||
('\N{INPUT SYMBOL FOR NUMBERS}', self.numbered_page),
|
||||
('\N{BLACK RIGHT-POINTING DOUBLE TRIANGLE WITH VERTICAL BAR}', self.last_page),
|
||||
('\N{INPUT SYMBOL FOR NUMBERS}', self.numbered_page ),
|
||||
('\N{BLACK SQUARE FOR STOP}', self.stop_pages),
|
||||
('\N{INFORMATION SOURCE}', self.show_help),
|
||||
]
|
||||
|
@ -77,12 +68,10 @@ class Pages:
|
|||
if self.paginating:
|
||||
# verify we can actually use the pagination session
|
||||
if not self.permissions.add_reactions:
|
||||
raise CannotPaginate(
|
||||
'Bot does not have add reactions permission.')
|
||||
raise CannotPaginate('Bot does not have add reactions permission.')
|
||||
|
||||
if not self.permissions.read_message_history:
|
||||
raise CannotPaginate(
|
||||
'Bot does not have Read Message History permission.')
|
||||
raise CannotPaginate('Bot does not have Read Message History permission.')
|
||||
|
||||
def get_page(self, page):
|
||||
base = (page - 1) * self.per_page
|
||||
|
@ -97,8 +86,7 @@ class Pages:
|
|||
|
||||
def prepare_embed(self, entries, page, *, first=False):
|
||||
p = []
|
||||
for index, entry in enumerate(entries,
|
||||
1 + ((page - 1) * self.per_page)):
|
||||
for index, entry in enumerate(entries, 1 + ((page - 1) * self.per_page)):
|
||||
p.append(f'{index}. {entry}')
|
||||
|
||||
if self.maximum_pages > 1:
|
||||
|
@ -111,8 +99,7 @@ class Pages:
|
|||
|
||||
if self.paginating and first:
|
||||
p.append('')
|
||||
p.append(
|
||||
'Confused? React with \N{INFORMATION SOURCE} for more info.')
|
||||
p.append('Confused? React with \N{INFORMATION SOURCE} for more info.')
|
||||
|
||||
self.embed.description = '\n'.join(p)
|
||||
|
||||
|
@ -166,8 +153,7 @@ class Pages:
|
|||
async def numbered_page(self):
|
||||
"""lets you type a page number to go to"""
|
||||
to_delete = []
|
||||
to_delete.append(
|
||||
await self.channel.send('What page do you want to go to?'))
|
||||
to_delete.append(await self.channel.send('What page do you want to go to?'))
|
||||
|
||||
def message_check(m):
|
||||
return m.author == self.author and \
|
||||
|
@ -175,8 +161,7 @@ class Pages:
|
|||
m.content.isdigit()
|
||||
|
||||
try:
|
||||
msg = await self.bot.wait_for('message', check=message_check,
|
||||
timeout=30.0)
|
||||
msg = await self.bot.wait_for('message', check=message_check, timeout=30.0)
|
||||
except asyncio.TimeoutError:
|
||||
to_delete.append(await self.channel.send('Took too long.'))
|
||||
await asyncio.sleep(5)
|
||||
|
@ -186,8 +171,7 @@ class Pages:
|
|||
if page != 0 and page <= self.maximum_pages:
|
||||
await self.show_page(page)
|
||||
else:
|
||||
to_delete.append(await self.channel.send(
|
||||
f'Invalid page given. ({page}/{self.maximum_pages})'))
|
||||
to_delete.append(await self.channel.send(f'Invalid page given. ({page}/{self.maximum_pages})'))
|
||||
await asyncio.sleep(5)
|
||||
|
||||
try:
|
||||
|
@ -198,9 +182,8 @@ class Pages:
|
|||
async def show_help(self):
|
||||
"""shows this message"""
|
||||
messages = ['Welcome to the interactive paginator!\n']
|
||||
messages.append(
|
||||
'This interactively allows you to see pages of text by navigating with ' \
|
||||
'reactions. They are as follows:\n')
|
||||
messages.append('This interactively allows you to see pages of text by navigating with ' \
|
||||
'reactions. They are as follows:\n')
|
||||
|
||||
for (emoji, func) in self.reaction_emojis:
|
||||
messages.append(f'{emoji} {func.__doc__}')
|
||||
|
@ -208,8 +191,7 @@ class Pages:
|
|||
embed = self.embed.copy()
|
||||
embed.clear_fields()
|
||||
embed.description = '\n'.join(messages)
|
||||
embed.set_footer(
|
||||
text=f'We were on page {self.current_page} before this message.')
|
||||
embed.set_footer(text=f'We were on page {self.current_page} before this message.')
|
||||
await self.message.edit(content=None, embed=embed)
|
||||
|
||||
async def go_back_to_current_page():
|
||||
|
@ -248,9 +230,7 @@ class Pages:
|
|||
|
||||
while self.paginating:
|
||||
try:
|
||||
payload = await self.bot.wait_for('raw_reaction_add',
|
||||
check=self.react_check,
|
||||
timeout=120.0)
|
||||
payload = await self.bot.wait_for('raw_reaction_add', check=self.react_check, timeout=120.0)
|
||||
except asyncio.TimeoutError:
|
||||
self.paginating = False
|
||||
try:
|
||||
|
@ -261,15 +241,12 @@ class Pages:
|
|||
break
|
||||
|
||||
try:
|
||||
await self.message.remove_reaction(payload.emoji,
|
||||
discord.Object(
|
||||
id=payload.user_id))
|
||||
await self.message.remove_reaction(payload.emoji, discord.Object(id=payload.user_id))
|
||||
except:
|
||||
pass # can't remove it so don't bother doing so
|
||||
pass # can't remove it so don't bother doing so
|
||||
|
||||
await self.match()
|
||||
|
||||
|
||||
class FieldPages(Pages):
|
||||
"""Similar to Pages except entries should be a list of
|
||||
tuples having (key, value) to show as embed fields instead.
|
||||
|
@ -290,19 +267,15 @@ class FieldPages(Pages):
|
|||
|
||||
self.embed.set_footer(text=text)
|
||||
|
||||
|
||||
class TextPages(Pages):
|
||||
"""Uses a commands.Paginator internally to paginate some text."""
|
||||
|
||||
def __init__(self, ctx, text, *, prefix='```', suffix='```',
|
||||
max_size=2000):
|
||||
paginator = CommandPaginator(prefix=prefix, suffix=suffix,
|
||||
max_size=max_size - 200)
|
||||
def __init__(self, ctx, text, *, prefix='```', suffix='```', max_size=2000):
|
||||
paginator = CommandPaginator(prefix=prefix, suffix=suffix, max_size=max_size - 200)
|
||||
for line in text.split('\n'):
|
||||
paginator.add_line(line)
|
||||
|
||||
super().__init__(ctx, entries=paginator.pages, per_page=1,
|
||||
show_entry_count=False)
|
||||
super().__init__(ctx, entries=paginator.pages, per_page=1, show_entry_count=False)
|
||||
|
||||
def get_page(self, page):
|
||||
return self.entries[page - 1]
|
||||
|
@ -313,4 +286,4 @@ class TextPages(Pages):
|
|||
def get_content(self, entry, page, *, first=False):
|
||||
if self.maximum_pages > 1:
|
||||
return f'{entry}\nPage {page}/{self.maximum_pages}'
|
||||
return entry
|
||||
return entry
|
Loading…
Reference in a new issue