tldr: core, warn's skeleton

This commit is contained in:
Romain J 2020-06-05 00:29:14 +02:00
parent b5b7f0c7ef
commit 815709d68b
17 changed files with 328 additions and 106 deletions

View file

@ -8,6 +8,7 @@
<w>postgresql</w> <w>postgresql</w>
<w>socketstats</w> <w>socketstats</w>
<w>splt</w> <w>splt</w>
<w>systemd</w>
<w>tutux</w> <w>tutux</w>
<w>webhooks</w> <w>webhooks</w>
</words> </words>

View file

@ -3,10 +3,17 @@
<component name="ChangeListManager"> <component name="ChangeListManager">
<list default="true" id="c97c8a30-7573-4dcd-a0d4-5bf94b8ddbbd" name="5ed57ed9960f35191182a924 core" comment=""> <list default="true" id="c97c8a30-7573-4dcd-a0d4-5bf94b8ddbbd" name="5ed57ed9960f35191182a924 core" comment="">
<change beforePath="$PROJECT_DIR$/.idea/workspace.xml" beforeDir="false" afterPath="$PROJECT_DIR$/.idea/workspace.xml" afterDir="false" /> <change beforePath="$PROJECT_DIR$/.idea/workspace.xml" beforeDir="false" afterPath="$PROJECT_DIR$/.idea/workspace.xml" afterDir="false" />
<change beforePath="$PROJECT_DIR$/setup.cfg" beforeDir="false" afterPath="$PROJECT_DIR$/setup.cfg" afterDir="false" />
<change beforePath="$PROJECT_DIR$/tuxbot/__main__.py" beforeDir="false" afterPath="$PROJECT_DIR$/tuxbot/__main__.py" afterDir="false" /> <change beforePath="$PROJECT_DIR$/tuxbot/__main__.py" beforeDir="false" afterPath="$PROJECT_DIR$/tuxbot/__main__.py" afterDir="false" />
<change beforePath="$PROJECT_DIR$/tuxbot/cogs/images/__init__.py" beforeDir="false" afterPath="$PROJECT_DIR$/tuxbot/cogs/images/__init__.py" afterDir="false" />
<change beforePath="$PROJECT_DIR$/tuxbot/cogs/logs/__init__.py" beforeDir="false" afterPath="$PROJECT_DIR$/tuxbot/cogs/logs/__init__.py" afterDir="false" />
<change beforePath="$PROJECT_DIR$/tuxbot/cogs/network/__init__.py" beforeDir="false" afterPath="$PROJECT_DIR$/tuxbot/cogs/network/__init__.py" afterDir="false" />
<change beforePath="$PROJECT_DIR$/tuxbot/core/bot.py" beforeDir="false" afterPath="$PROJECT_DIR$/tuxbot/core/bot.py" afterDir="false" /> <change beforePath="$PROJECT_DIR$/tuxbot/core/bot.py" beforeDir="false" afterPath="$PROJECT_DIR$/tuxbot/core/bot.py" afterDir="false" />
<change beforePath="$PROJECT_DIR$/tuxbot/core/config.py" beforeDir="false" afterPath="$PROJECT_DIR$/tuxbot/core/config.py" afterDir="false" /> <change beforePath="$PROJECT_DIR$/tuxbot/core/config.py" beforeDir="false" afterPath="$PROJECT_DIR$/tuxbot/core/config.py" afterDir="false" />
<change beforePath="$PROJECT_DIR$/tuxbot/core/data_manager.py" beforeDir="false" afterPath="$PROJECT_DIR$/tuxbot/core/data_manager.py" afterDir="false" /> <change beforePath="$PROJECT_DIR$/tuxbot/core/data_manager.py" beforeDir="false" afterPath="$PROJECT_DIR$/tuxbot/core/data_manager.py" afterDir="false" />
<change beforePath="$PROJECT_DIR$/tuxbot/core/utils/functions/extra.py" beforeDir="false" afterPath="$PROJECT_DIR$/tuxbot/core/utils/functions/extra.py" afterDir="false" />
<change beforePath="$PROJECT_DIR$/tuxbot/logging.py" beforeDir="false" afterPath="$PROJECT_DIR$/tuxbot/logging.py" afterDir="false" />
<change beforePath="$PROJECT_DIR$/tuxbot/setup.py" beforeDir="false" afterPath="$PROJECT_DIR$/tuxbot/setup.py" afterDir="false" />
</list> </list>
<list id="a3abf5c0-7587-46e4-8f09-88e34a1ab8a4" name="5ed41911b012e33f68a07e7a i18n" comment="" /> <list id="a3abf5c0-7587-46e4-8f09-88e34a1ab8a4" name="5ed41911b012e33f68a07e7a i18n" comment="" />
<list id="6566fca1-2e90-48bb-9e74-dd3badbaca99" name="Default Changelist" comment="" /> <list id="6566fca1-2e90-48bb-9e74-dd3badbaca99" name="Default Changelist" comment="" />
@ -38,7 +45,7 @@
<property name="RunOnceActivity.OpenProjectViewOnStart" value="true" /> <property name="RunOnceActivity.OpenProjectViewOnStart" value="true" />
<property name="RunOnceActivity.ShowReadmeOnStart" value="true" /> <property name="RunOnceActivity.ShowReadmeOnStart" value="true" />
<property name="WebServerToolWindowFactoryState" value="false" /> <property name="WebServerToolWindowFactoryState" value="false" />
<property name="last_opened_file_path" value="$PROJECT_DIR$/tuxbot" /> <property name="last_opened_file_path" value="$PROJECT_DIR$/tuxbot/core" />
<property name="node.js.detected.package.eslint" value="true" /> <property name="node.js.detected.package.eslint" value="true" />
<property name="node.js.detected.package.tslint" value="true" /> <property name="node.js.detected.package.tslint" value="true" />
<property name="node.js.path.for.package.eslint" value="project" /> <property name="node.js.path.for.package.eslint" value="project" />
@ -49,6 +56,13 @@
<property name="tasks.open.task.update.state.enabled" value="false" /> <property name="tasks.open.task.update.state.enabled" value="false" />
</component> </component>
<component name="RecentsManager"> <component name="RecentsManager">
<key name="CopyFile.RECENT_KEYS">
<recent name="$PROJECT_DIR$/tuxbot/core" />
<recent name="$PROJECT_DIR$/tuxbot/cogs" />
<recent name="$PROJECT_DIR$/tuxbot" />
<recent name="$PROJECT_DIR$/tuxbot/cogs/network" />
<recent name="$PROJECT_DIR$" />
</key>
<key name="MoveFile.RECENT_KEYS"> <key name="MoveFile.RECENT_KEYS">
<recent name="$PROJECT_DIR$/tuxbot/cogs/network" /> <recent name="$PROJECT_DIR$/tuxbot/cogs/network" />
<recent name="$PROJECT_DIR$/tuxbot/cogs/logs" /> <recent name="$PROJECT_DIR$/tuxbot/cogs/logs" />
@ -56,13 +70,6 @@
<recent name="$PROJECT_DIR$/tuxbot/cogs" /> <recent name="$PROJECT_DIR$/tuxbot/cogs" />
<recent name="$PROJECT_DIR$/tuxbot/core" /> <recent name="$PROJECT_DIR$/tuxbot/core" />
</key> </key>
<key name="CopyFile.RECENT_KEYS">
<recent name="$PROJECT_DIR$/tuxbot" />
<recent name="$PROJECT_DIR$/tuxbot/cogs/network" />
<recent name="$PROJECT_DIR$" />
<recent name="$PROJECT_DIR$/tuxbot/cogs" />
<recent name="$PROJECT_DIR$/utils/locales" />
</key>
</component> </component>
<component name="SvnConfiguration"> <component name="SvnConfiguration">
<configuration /> <configuration />
@ -96,7 +103,6 @@
</task> </task>
<task id="5ed41911b012e33f68a07e7a" summary="i18n"> <task id="5ed41911b012e33f68a07e7a" summary="i18n">
<changelist id="a3abf5c0-7587-46e4-8f09-88e34a1ab8a4" name="5ed41911b012e33f68a07e7a i18n" comment="" /> <changelist id="a3abf5c0-7587-46e4-8f09-88e34a1ab8a4" name="5ed41911b012e33f68a07e7a i18n" comment="" />
<created>1591290805787</created>
<option name="issue" value="true" /> <option name="issue" value="true" />
<url>https://trello.com/c/vK0cBbF2/38-i18n</url> <url>https://trello.com/c/vK0cBbF2/38-i18n</url>
<option name="number" value="38" /> <option name="number" value="38" />
@ -108,7 +114,6 @@
</task> </task>
<task active="true" id="5ed57ed9960f35191182a924" summary="core"> <task active="true" id="5ed57ed9960f35191182a924" summary="core">
<changelist id="c97c8a30-7573-4dcd-a0d4-5bf94b8ddbbd" name="5ed57ed9960f35191182a924 core" comment="" /> <changelist id="c97c8a30-7573-4dcd-a0d4-5bf94b8ddbbd" name="5ed57ed9960f35191182a924 core" comment="" />
<created>1591290805787</created>
<option name="issue" value="true" /> <option name="issue" value="true" />
<url>https://trello.com/c/SafaMBht/40-core</url> <url>https://trello.com/c/SafaMBht/40-core</url>
<option name="number" value="40" /> <option name="number" value="40" />
@ -118,7 +123,7 @@
<workItem from="1591054878071" duration="1039000" /> <workItem from="1591054878071" duration="1039000" />
<workItem from="1591088657371" duration="4107000" /> <workItem from="1591088657371" duration="4107000" />
<workItem from="1591128560850" duration="40267000" /> <workItem from="1591128560850" duration="40267000" />
<workItem from="1591281151234" duration="9745000" /> <workItem from="1591281151234" duration="23336000" />
</task> </task>
<option name="localTasksCounter" value="2" /> <option name="localTasksCounter" value="2" />
<option name="createBranch" value="false" /> <option name="createBranch" value="false" />
@ -142,10 +147,10 @@
<option name="version" value="2" /> <option name="version" value="2" />
</component> </component>
<component name="WindowStateProjectService"> <component name="WindowStateProjectService">
<state x="2338" y="213" key="#com.intellij.execution.impl.EditConfigurationsDialog" timestamp="1589991158766"> <state x="2338" y="213" key="#com.intellij.execution.impl.EditConfigurationsDialog" timestamp="1591298885935">
<screen x="1920" y="0" width="1920" height="1080" /> <screen x="1920" y="0" width="1920" height="1080" />
</state> </state>
<state x="2338" y="213" key="#com.intellij.execution.impl.EditConfigurationsDialog/1920.0.1920.1080/0.29.1920.1051@1920.0.1920.1080" timestamp="1589991158766" /> <state x="2338" y="213" key="#com.intellij.execution.impl.EditConfigurationsDialog/1920.0.1920.1080/0.29.1920.1051@1920.0.1920.1080" timestamp="1591298885935" />
<state x="2616" y="357" width="521" height="396" key="#com.intellij.fileTypes.FileTypeChooser" timestamp="1589928148179"> <state x="2616" y="357" width="521" height="396" key="#com.intellij.fileTypes.FileTypeChooser" timestamp="1589928148179">
<screen x="1920" y="0" width="1920" height="1080" /> <screen x="1920" y="0" width="1920" height="1080" />
</state> </state>

View file

@ -13,9 +13,11 @@ install_requires =
aiohttp==3.6.2 aiohttp==3.6.2
aiosqlite==0.13.0 aiosqlite==0.13.0
appdirs==1.4.4 appdirs==1.4.4
astunparse==1.6.3
async-timeout==3.0.1 async-timeout==3.0.1
asyncpg==0.20.1 asyncpg==0.20.1
attrs==19.3.0 attrs==19.3.0
braceexpand==0.1.5
cachetools==4.1.0 cachetools==4.1.0
certifi==2020.4.5.1 certifi==2020.4.5.1
chardet==3.0.4 chardet==3.0.4
@ -27,9 +29,11 @@ install_requires =
dnspython==1.16.0 dnspython==1.16.0
humanize==2.4.0 humanize==2.4.0
idna==2.9 idna==2.9
import-expression==1.1.3
ipinfo==3.0.0 ipinfo==3.0.0
ipwhois==1.1.0 ipwhois==1.1.0
iso8601==0.1.12 iso8601==0.1.12
jishaku==1.18.2.188
multidict==4.7.6 multidict==4.7.6
psutil==5.7.0 psutil==5.7.0
PyPika==0.37.7 PyPika==0.37.7
@ -40,6 +44,7 @@ install_requires =
typing-extensions==3.7.4.2 typing-extensions==3.7.4.2
urllib3==1.25.9 urllib3==1.25.9
websockets==8.1 websockets==8.1
wheel==0.34.2
yarl==1.4.2 yarl==1.4.2
[options.entry_points] [options.entry_points]

View file

@ -16,7 +16,7 @@ from pip._vendor import distro
import tuxbot.logging import tuxbot.logging
from tuxbot.core import data_manager from tuxbot.core import data_manager
from tuxbot.core.bot import Tux from tuxbot.core.bot import Tux, ExitCodes
from tuxbot.core.utils.functions.cli import bordered from tuxbot.core.utils.functions.cli import bordered
from . import __version__ from . import __version__
@ -140,10 +140,10 @@ async def shutdown_handler(tux: Tux, signal_type, exit_code=None) -> NoReturn:
""" """
if signal_type: if signal_type:
log.info("%s received. Quitting...", signal_type) log.info("%s received. Quitting...", signal_type)
sys.exit(0) sys.exit(ExitCodes.SHUTDOWN)
elif exit_code is None: elif exit_code is None:
log.info("Shutting down from unhandled exception") log.info("Shutting down from unhandled exception")
tux.shutdown_code = 1 tux.shutdown_code = ExitCodes.CRITICAL
if exit_code is not None: if exit_code is not None:
tux.shutdown_code = exit_code tux.shutdown_code = exit_code
@ -161,7 +161,7 @@ async def shutdown_handler(tux: Tux, signal_type, exit_code=None) -> NoReturn:
await asyncio.gather(*pending, return_exceptions=True) await asyncio.gather(*pending, return_exceptions=True)
async def run_bot(tux: Tux, cli_flags: Namespace) -> None: async def run_bot(tux: Tux, cli_flags: Namespace, loop) -> None:
"""This run the bot. """This run the bot.
Parameters Parameters
@ -193,13 +193,14 @@ async def run_bot(tux: Tux, cli_flags: Namespace) -> None:
if not token: if not token:
log.critical("Token must be set if you want to login.") log.critical("Token must be set if you want to login.")
sys.exit(1) sys.exit(ExitCodes.CRITICAL)
try: try:
await tux.load_packages()
await tux.start(token, bot=True) await tux.start(token, bot=True)
except discord.LoginFailure: except discord.LoginFailure:
log.critical("This token appears to be valid.") log.critical("This token appears to be valid.")
sys.exit(1) sys.exit(ExitCodes.CRITICAL)
return None return None
@ -229,7 +230,7 @@ def main() -> NoReturn:
+ "No instance provided ! " + "No instance provided ! "
"You can use 'tuxbot -L' to list all available instances" "You can use 'tuxbot -L' to list all available instances"
+ Style.RESET_ALL) + Style.RESET_ALL)
sys.exit(1) sys.exit(ExitCodes.CRITICAL)
tux = Tux( tux = Tux(
cli_flags=cli_flags, cli_flags=cli_flags,
@ -237,8 +238,11 @@ def main() -> NoReturn:
dm_help=None dm_help=None
) )
loop.run_until_complete(run_bot(tux, cli_flags)) loop.run_until_complete(run_bot(tux, cli_flags, loop))
except KeyboardInterrupt: except KeyboardInterrupt:
print(Fore.RED
+ "Please use <prefix>quit instead of Ctrl+C to Shutdown!"
+ Style.RESET_ALL)
log.warning("Please use <prefix>quit instead of Ctrl+C to Shutdown!") log.warning("Please use <prefix>quit instead of Ctrl+C to Shutdown!")
log.error("Received KeyboardInterrupt") log.error("Received KeyboardInterrupt")
if tux is not None: if tux is not None:
@ -258,7 +262,7 @@ def main() -> NoReturn:
asyncio.set_event_loop(None) asyncio.set_event_loop(None)
loop.stop() loop.stop()
loop.close() loop.close()
exit_code = 1 if tux is None else tux.shutdown_code exit_code = ExitCodes.CRITICAL if tux is None else tux.shutdown_code
sys.exit(exit_code) sys.exit(exit_code)

0
tuxbot/cogs/__init__.py Normal file
View file

View file

@ -1,5 +1,6 @@
from .images import Images from .images import Images
from ...core.bot import Tux
def setup(bot): def setup(bot: Tux):
bot.add_cog(Images(bot)) bot.add_cog(Images(bot))

View file

@ -3,9 +3,10 @@ import logging
from discord.ext import commands from discord.ext import commands
from .logs import Logs, GatewayHandler, on_error from .logs import Logs, GatewayHandler, on_error
from ...core.bot import Tux
def setup(bot): def setup(bot: Tux):
cog = Logs(bot) cog = Logs(bot)
bot.add_cog(cog) bot.add_cog(cog)

View file

@ -1,5 +1,6 @@
from .network import Network from .network import Network
from ...core.bot import Tux
def setup(bot): def setup(bot: Tux):
bot.add_cog(Network(bot)) bot.add_cog(Network(bot))

View file

@ -0,0 +1,6 @@
from .warnings import Warnings
from ...core.bot import Tux
def setup(bot: Tux):
bot.add_cog(Warnings(bot))

View file

@ -0,0 +1,47 @@
from typing import Union
import discord
from discord.ext import commands
from tuxbot.core import checks
from tuxbot.core.bot import Tux
class Warnings(commands.Cog, name="Warnings"):
def __init__(self, bot: Tux):
self.bot = bot
@commands.group(name='warn', alias=['warning'])
@commands.guild_only()
@checks.is_mod()
async def _warn(self, ctx: commands.Context):
pass
@_warn.command(name="add")
@commands.guild_only()
async def _warn_add(
self,
ctx: commands.Context,
member: Union[discord.User, discord.Member],
reason: str
):
pass
@_warn.command(name="delete", aliases=["del", "remove"])
@commands.guild_only()
async def action_del(
self,
ctx: commands.Context,
warn_id: int,
reason: str = ""
):
pass
@_warn.command(name="list", aliases=["all"])
@commands.guild_only()
async def action_del(
self,
ctx: commands.Context,
member: Union[discord.User, discord.Member] = None
):
pass

View file

@ -1,15 +1,19 @@
import asyncio
import datetime
import logging import logging
from pathlib import Path import sys
from typing import List from typing import List, Union
import discord import discord
from colorama import Fore, Style, init from colorama import Fore, Style, init
from discord.ext import commands from discord.ext import commands
from . import Config from . import Config
from .data_manager import logs_data_path
from .utils.functions.cli import bordered from .utils.functions.cli import bordered
from . import __version__ from . import __version__
from .utils.functions.extra import ContextPlus
log = logging.getLogger("tuxbot") log = logging.getLogger("tuxbot")
init() init()
@ -22,24 +26,30 @@ NAME = r"""
|_| \__,_/_/\_\_.__/ \___/ \__| |_.__/ \___/ \__| |_| \__,_/_/\_\_.__/ \___/ \__| |_.__/ \___/ \__|
""" """
l_extensions: List[str] = [ packages: List[str] = [
"jishaku" "jishaku",
"tuxbot.cogs.warnings"
] ]
class Tux(commands.AutoShardedBot): class Tux(commands.AutoShardedBot):
def __init__(self, *args, cli_flags=None, bot_dir: Path = Path.cwd(), **kwargs): _loading: asyncio.Task
def __init__(self, *args, cli_flags=None, **kwargs):
# by default, if the bot shutdown without any intervention, # by default, if the bot shutdown without any intervention,
# it's a crash # it's a crash
self.shutdown_code = 1 self.shutdown_code = ExitCodes.CRITICAL
self.cli_flags = cli_flags self.cli_flags = cli_flags
self.instance_name = self.cli_flags.instance_name self.instance_name = self.cli_flags.instance_name
self.last_exception = None self.last_exception = None
self.logs = logs_data_path(self.instance_name)
self.config = Config(self.instance_name) self.config = Config(self.instance_name)
async def _prefixes(bot, message) -> List[str]: async def _prefixes(bot, message) -> List[str]:
prefixes = self.config.get_prefixes(message.guild) prefixes = self.config('core').get('prefixes')
prefixes.extend(self.config.get_prefixes(message.guild))
if self.config('core').get('mentionable'): if self.config('core').get('mentionable'):
return commands.when_mentioned_or(*prefixes)(bot, message) return commands.when_mentioned_or(*prefixes)(bot, message)
@ -51,18 +61,38 @@ class Tux(commands.AutoShardedBot):
if "owner_ids" in kwargs: if "owner_ids" in kwargs:
kwargs["owner_ids"] = set(kwargs["owner_ids"]) kwargs["owner_ids"] = set(kwargs["owner_ids"])
else: else:
kwargs["owner_ids"] = self.config.owner_ids() kwargs["owner_ids"] = self.config.owners_id()
message_cache_size = 100_000 message_cache_size = 100_000
kwargs["max_messages"] = message_cache_size kwargs["max_messages"] = message_cache_size
self.max_messages = message_cache_size self.max_messages = message_cache_size
self.uptime = None self.uptime = None
self.main_dir = bot_dir self._app_owners_fetched = False # to prevent abusive API calls
super().__init__(*args, help_command=None, **kwargs) super().__init__(*args, help_command=None, **kwargs)
async def load_packages(self):
if packages:
print("Loading packages...")
for package in packages:
try:
self.load_extension(package)
except Exception as e:
print(Fore.RED
+ f"Failed to load package {package}"
+ Style.RESET_ALL
+ f" check "
f"{str((self.logs / 'tuxbot.log').resolve())} "
f"for more details")
log.exception(
f"Failed to load package {package}",
exc_info=e
)
async def on_ready(self): async def on_ready(self):
self.uptime = datetime.datetime.now()
INFO = { INFO = {
'title': "INFO", 'title': "INFO",
'rows': [ 'rows': [
@ -81,7 +111,7 @@ class Tux(commands.AutoShardedBot):
'title': "COGS", 'title': "COGS",
'rows': [] 'rows': []
} }
for extension in l_extensions: for extension in packages:
COGS['rows'].append( COGS['rows'].append(
f"[{'X' if extension in self.extensions else ' '}] {extension}" f"[{'X' if extension in self.extensions else ' '}] {extension}"
) )
@ -91,3 +121,84 @@ class Tux(commands.AutoShardedBot):
print(bordered(INFO, COGS)) print(bordered(INFO, COGS))
print(f"\n{'=' * 118}\n\n") print(f"\n{'=' * 118}\n\n")
async def is_owner(self, user: Union[discord.User, discord.Member]) -> bool:
"""Determines if the user is a bot owner.
Parameters
----------
user: Union[discord.User, discord.Member]
Returns
-------
bool
"""
if user.id in self.config.owners_id():
return True
owner = False
if not self._app_owners_fetched:
app = await self.application_info()
if app.team:
ids = [m.id for m in app.team.members]
self.config.update('core', 'owners_id', ids)
owner = user.id in ids
self._app_owners_fetched = True
return owner
async def get_context(self, message: discord.Message, *, cls=None):
return await super().get_context(message, cls=ContextPlus)
async def process_commands(self, message: discord.Message):
"""Check for blacklists.
"""
if message.author.bot:
return
if message.guild.id in self.config.get_blacklist('guild') \
or message.channel.id in self.config.get_blacklist('channel') \
or message.author.id in self.config.get_blacklist('user'):
return
ctx = await self.get_context(message)
if ctx is None or ctx.valid is False:
self.dispatch("message_without_command", message)
else:
await self.invoke(ctx)
async def on_message(self, message: discord.Message):
await self.process_commands(message)
async def logout(self):
"""Disconnect from Discord and closes all actives connections.
Todo: add postgresql logout here
"""
await super().logout()
async def shutdown(self, *, restart: bool = False):
"""Gracefully quit.
Parameters
----------
restart:bool
If `True`, systemd or the launcher gonna see custom exit code
and reboot.
"""
if not restart:
self.shutdown_code = ExitCodes.SHUTDOWN
else:
self.shutdown_code = ExitCodes.RESTART
await self.logout()
sys.exit(self.shutdown_code)
class ExitCodes:
CRITICAL = 1
SHUTDOWN = 0
RESTART = 42

63
tuxbot/core/checks.py Normal file
View file

@ -0,0 +1,63 @@
from typing import Awaitable, Dict
import discord
from discord.ext import commands
from discord.ext.commands import (
bot_has_permissions,
has_permissions,
is_owner,
)
from tuxbot.core.utils.functions.extra import ContextPlus
__all__ = [
"bot_has_permissions",
"has_permissions",
"is_owner",
"is_mod",
"is_admin",
"check_permissions",
"guild_owner_or_permissions",
]
def is_mod():
async def pred(ctx):
if await ctx.bot.is_owner(ctx.author):
return True
permissions: discord.Permissions = ctx.channel.permissions_for(ctx.author)
return permissions.manage_messages
return commands.check(pred)
def is_admin():
async def pred(ctx):
if await ctx.bot.is_owner(ctx.author):
return True
permissions: discord.Permissions = ctx.channel.permissions_for(ctx.author)
return permissions.administrator
return commands.check(pred)
async def check_permissions(ctx: "ContextPlus", **perms: Dict[str, bool]):
if await ctx.bot.is_owner(ctx.author):
return True
elif not perms:
return False
resolved = ctx.channel.permissions_for(ctx.author)
return all(
getattr(resolved, name, None) == value for name, value in perms.items()
)
def guild_owner_or_permissions(**perms: Dict[str, bool]):
async def pred(ctx):
if ctx.author is ctx.guild.owner:
return True
return await check_permissions(ctx, **perms)
return commands.check(pred)

View file

@ -3,7 +3,7 @@ import logging
__all__ = ["Config"] __all__ = ["Config"]
from typing import List, Dict from typing import List, Dict, Union
import discord import discord
@ -39,8 +39,8 @@ class Config:
def __call__(self, item): def __call__(self, item):
return self.__getitem__(item) return self.__getitem__(item)
def owner_ids(self) -> List[int]: def owners_id(self) -> List[int]:
return self.__getitem__('core').get('owner_ids') return self.__getitem__('core').get('owners_id')
def token(self) -> str: def token(self) -> str:
return self.__getitem__('core').get('token') return self.__getitem__('core').get('token')
@ -53,3 +53,29 @@ class Config:
.get('prefixes', []) .get('prefixes', [])
return prefixes return prefixes
def get_blacklist(self, key: str) -> List[Union[str, int]]:
core = self.__getitem__('core')
blacklist = core \
.get('blacklist', {}) \
.get(key, [])
return blacklist
def update(self, cog_name, item, value) -> dict:
datas = self.__getitem__(cog_name)
path = data_path(self._cog_instance)
datas[item] = value
if cog_name != 'core':
path = path / 'cogs' / cog_name
else:
path /= 'core'
settings_file = path / 'settings.json'
with settings_file.open('w') as f:
json.dump(datas, f, indent=4)
return datas

View file

@ -69,3 +69,18 @@ def cog_data_path(instance_name: str, cog_name: str) -> Path:
Generated path for cog's configs. Generated path for cog's configs.
""" """
return data_path(instance_name) / "data" / instance_name / "cogs" / cog_name return data_path(instance_name) / "data" / instance_name / "cogs" / cog_name
def logs_data_path(instance_name: str) -> Path:
"""Return Path for logs.
Parameters
----------
instance_name:str
Returns
-------
Path
Generated path for logs files.
"""
return data_path(instance_name) / "data" / instance_name / "logs"

View file

@ -1,48 +1,11 @@
import ast
import asyncio import asyncio
import json
import os
import discord import discord
from discord.ext import commands, flags from discord.ext import commands, flags
from configs.bot.protected import protected
from configs.bot.settings import prefixes
class ContextPlus(commands.Context): class ContextPlus(commands.Context):
async def send(self, content=None, *args, **kwargs): async def send(self, content=None, *args, **kwargs):
if content is not None:
for value in protected:
content = content.replace(
str(value),
'[Deleted]'
)
if kwargs.get('content') is not None:
for value in protected:
kwargs['content'] = kwargs['content'].replace(
str(value),
'[Deleted]'
)
if kwargs.get('embeds') is not None and len(kwargs.get('embeds')) > 0:
for i, embed in enumerate(kwargs.get('embeds')):
embed = str(kwargs.get('embed').to_dict())
for value in protected:
embed = embed.replace(str(value), '[Deleted]')
kwargs['embeds'][i] = discord.Embed.from_dict(
ast.literal_eval(embed)
)
if kwargs.get('embed') is not None:
embed = str(kwargs.get('embed').to_dict())
for value in protected:
embed = embed.replace(str(value), '[Deleted]')
kwargs['embed'] = discord.Embed.from_dict(
ast.literal_eval(embed)
)
if (hasattr(self.command, 'deletable') and self.command.deletable) \ if (hasattr(self.command, 'deletable') and self.command.deletable) \
and kwargs.pop('deletable', True): and kwargs.pop('deletable', True):
message = await super().send(content, *args, **kwargs) message = await super().send(content, *args, **kwargs)
@ -86,29 +49,3 @@ class GroupPlus(flags.FlagGroup):
def group_extra(*args, **kwargs): def group_extra(*args, **kwargs):
return commands.group(*args, **kwargs, cls=GroupPlus) return commands.group(*args, **kwargs, cls=GroupPlus)
async def get_prefix(bot, message):
custom_prefix = prefixes
if message.guild:
path = f"configs/guilds/{str(message.guild.id)}.json"
if os.path.exists(path):
with open(path) as f:
datas = json.load(f)
custom_prefix = datas["Prefix"]
return commands.when_mentioned_or(*custom_prefix)(bot, message)
def get_owners() -> list:
with open("configs/bot/whitelist.json") as f:
datas = json.load(f)
return datas['owners']
def get_blacklist() -> dict:
with open("configs/bot/blacklist.json") as f:
return json.load(f)

View file

@ -17,6 +17,7 @@ def init_logging(level: int, location: pathlib.Path) -> None:
location:Path location:Path
Where to store logs. Where to store logs.
""" """
dpy_logger = logging.getLogger("discord") dpy_logger = logging.getLogger("discord")
dpy_logger.setLevel(logging.WARN) dpy_logger.setLevel(logging.WARN)
dpy_logger_file = location / 'discord.log' dpy_logger_file = location / 'discord.log'
@ -39,10 +40,7 @@ def init_logging(level: int, location: pathlib.Path) -> None:
maxBytes=MAX_BYTES, backupCount=MAX_OLD_LOGS maxBytes=MAX_BYTES, backupCount=MAX_OLD_LOGS
) )
dpy_logger.addHandler(dpy_handler)
base_logger.addHandler(base_handler)
stdout_handler = logging.StreamHandler(sys.stdout) stdout_handler = logging.StreamHandler(sys.stdout)
stdout_handler.setFormatter(formatter) stdout_handler.setFormatter(formatter)
base_logger.addHandler(stdout_handler) dpy_logger.addHandler(dpy_handler)
dpy_logger.addHandler(stdout_handler) base_logger.addHandler(base_handler)

View file

@ -292,6 +292,7 @@ def finish_setup(data_dir: Path) -> NoReturn:
'prefixes': prefixes, 'prefixes': prefixes,
'mentionable': mentionable, 'mentionable': mentionable,
'owners_id': owners_id, 'owners_id': owners_id,
'locale': "en-US"
} }
with core_file.open("w") as fs: with core_file.open("w") as fs: