tldr: core, warn's skeleton
This commit is contained in:
parent
b5b7f0c7ef
commit
815709d68b
17 changed files with 328 additions and 106 deletions
|
@ -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>
|
||||||
|
|
|
@ -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>
|
||||||
|
|
|
@ -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]
|
||||||
|
|
|
@ -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
0
tuxbot/cogs/__init__.py
Normal 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))
|
||||||
|
|
|
@ -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)
|
||||||
|
|
||||||
|
|
|
@ -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))
|
||||||
|
|
6
tuxbot/cogs/warnings/__init__.py
Normal file
6
tuxbot/cogs/warnings/__init__.py
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
from .warnings import Warnings
|
||||||
|
from ...core.bot import Tux
|
||||||
|
|
||||||
|
|
||||||
|
def setup(bot: Tux):
|
||||||
|
bot.add_cog(Warnings(bot))
|
47
tuxbot/cogs/warnings/warnings.py
Normal file
47
tuxbot/cogs/warnings/warnings.py
Normal 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
|
|
@ -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
63
tuxbot/core/checks.py
Normal 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)
|
|
@ -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
|
||||||
|
|
|
@ -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"
|
||||||
|
|
|
@ -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)
|
|
||||||
|
|
|
@ -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)
|
||||||
|
|
|
@ -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:
|
||||||
|
|
Loading…
Reference in a new issue