first commit
This commit is contained in:
parent
7eac932a4e
commit
04645ec639
76 changed files with 792 additions and 4532 deletions
31
.github/issue_template.md
vendored
31
.github/issue_template.md
vendored
|
@ -1,31 +0,0 @@
|
|||
---
|
||||
name: Bug report
|
||||
about: Create a report to help us improve
|
||||
title: ''
|
||||
labels: bug
|
||||
assignees: ''
|
||||
|
||||
---
|
||||
|
||||
**Describe the bug**
|
||||
A clear and concise description of what the bug is.
|
||||
|
||||
**To Reproduce**
|
||||
Steps to reproduce the behavior:
|
||||
1. Go to '...'
|
||||
2. Launch bot
|
||||
3. Type command '...'
|
||||
4. See error
|
||||
|
||||
**Expected behavior**
|
||||
A clear and concise description of what you expected to happen.
|
||||
|
||||
**Screenshots**
|
||||
If applicable, add screenshots to help explain your problem.
|
||||
|
||||
**Desktop (please complete the following information):**
|
||||
- OS: [e.g. Debian]
|
||||
- Python Version [e.g. 3.7.4]
|
||||
|
||||
**Additional context**
|
||||
Add any other context about the problem here.
|
136
.gitignore
vendored
136
.gitignore
vendored
|
@ -1,146 +1,12 @@
|
|||
#Python
|
||||
__pycache__/
|
||||
*.pyc
|
||||
.env
|
||||
configs/config.cfg
|
||||
configs/prefixes.cfg
|
||||
configs/fallbacks.cfg
|
||||
.DS_Store
|
||||
private.py
|
||||
|
||||
#jetbrains
|
||||
.idea/
|
||||
|
||||
# other
|
||||
logs/tuxbot.log
|
||||
utils/images/tmp/*
|
||||
|
||||
# Byte-compiled / optimized / DLL files
|
||||
__pycache__/
|
||||
*.py[cod]
|
||||
*$py.class
|
||||
|
||||
# C extensions
|
||||
*.so
|
||||
|
||||
# Distribution / packaging
|
||||
.Python
|
||||
build/
|
||||
develop-eggs/
|
||||
dist/
|
||||
downloads/
|
||||
eggs/
|
||||
.eggs/
|
||||
lib/
|
||||
lib64/
|
||||
parts/
|
||||
sdist/
|
||||
var/
|
||||
wheels/
|
||||
pip-wheel-metadata/
|
||||
share/python-wheels/
|
||||
*.egg-info/
|
||||
.installed.cfg
|
||||
*.egg
|
||||
MANIFEST
|
||||
|
||||
# PyInstaller
|
||||
# Usually these files are written by a python script from a template
|
||||
# before PyInstaller builds the exe, so as to inject date/other infos into it.
|
||||
*.manifest
|
||||
*.spec
|
||||
|
||||
# Installer logs
|
||||
pip-log.txt
|
||||
pip-delete-this-directory.txt
|
||||
|
||||
# Unit test / coverage reports
|
||||
htmlcov/
|
||||
.tox/
|
||||
.nox/
|
||||
.coverage
|
||||
.coverage.*
|
||||
.cache
|
||||
nosetests.xml
|
||||
coverage.xml
|
||||
*.cover
|
||||
*.py,cover
|
||||
.hypothesis/
|
||||
.pytest_cache/
|
||||
|
||||
# Translations
|
||||
*.mo
|
||||
*.pot
|
||||
|
||||
# Django stuff:
|
||||
*.log
|
||||
local_settings.py
|
||||
db.sqlite3
|
||||
db.sqlite3-journal
|
||||
|
||||
# Flask stuff:
|
||||
instance/
|
||||
.webassets-cache
|
||||
|
||||
# Scrapy stuff:
|
||||
.scrapy
|
||||
|
||||
# Sphinx documentation
|
||||
docs/_build/
|
||||
|
||||
# PyBuilder
|
||||
target/
|
||||
|
||||
# Jupyter Notebook
|
||||
.ipynb_checkpoints
|
||||
|
||||
# IPython
|
||||
profile_default/
|
||||
ipython_config.py
|
||||
|
||||
# pyenv
|
||||
.python-version
|
||||
|
||||
# pipenv
|
||||
# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
|
||||
# However, in case of collaboration, if having platform-specific dependencies or dependencies
|
||||
# having no cross-platform support, pipenv may install dependencies that don't work, or not
|
||||
# install all needed dependencies.
|
||||
#Pipfile.lock
|
||||
|
||||
# PEP 582; used by e.g. github.com/David-OConnor/pyflow
|
||||
__pypackages__/
|
||||
|
||||
# Celery stuff
|
||||
celerybeat-schedule
|
||||
celerybeat.pid
|
||||
|
||||
# SageMath parsed files
|
||||
*.sage.py
|
||||
|
||||
# Environments
|
||||
.env
|
||||
.venv
|
||||
env/
|
||||
venv/
|
||||
ENV/
|
||||
env.bak/
|
||||
venv.bak/
|
||||
|
||||
# Spyder project settings
|
||||
.spyderproject
|
||||
.spyproject
|
||||
|
||||
# Rope project settings
|
||||
.ropeproject
|
||||
|
||||
# mkdocs documentation
|
||||
/site
|
||||
|
||||
# mypy
|
||||
.mypy_cache/
|
||||
.dmypy.json
|
||||
dmypy.json
|
||||
|
||||
# Pyre type checker
|
||||
.pyre/
|
||||
settings.py
|
6
.idea/discord.xml
Normal file
6
.idea/discord.xml
Normal file
|
@ -0,0 +1,6 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="DiscordProjectSettings">
|
||||
<option name="show" value="true" />
|
||||
</component>
|
||||
</project>
|
15
.idea/inspectionProfiles/Project_Default.xml
Normal file
15
.idea/inspectionProfiles/Project_Default.xml
Normal file
|
@ -0,0 +1,15 @@
|
|||
<component name="InspectionProjectProfileManager">
|
||||
<profile version="1.0">
|
||||
<option name="myName" value="Project Default" />
|
||||
<inspection_tool class="PyPackageRequirementsInspection" enabled="true" level="WARNING" enabled_by_default="true">
|
||||
<option name="ignoredPackages">
|
||||
<value>
|
||||
<list size="2">
|
||||
<item index="0" class="java.lang.String" itemvalue="discord" />
|
||||
<item index="1" class="java.lang.String" itemvalue="tortoise" />
|
||||
</list>
|
||||
</value>
|
||||
</option>
|
||||
</inspection_tool>
|
||||
</profile>
|
||||
</component>
|
6
.idea/inspectionProfiles/profiles_settings.xml
Normal file
6
.idea/inspectionProfiles/profiles_settings.xml
Normal file
|
@ -0,0 +1,6 @@
|
|||
<component name="InspectionProjectProfileManager">
|
||||
<settings>
|
||||
<option name="USE_PROJECT_PROFILE" value="false" />
|
||||
<version value="1.0" />
|
||||
</settings>
|
||||
</component>
|
7
.idea/misc.xml
Normal file
7
.idea/misc.xml
Normal file
|
@ -0,0 +1,7 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="JavaScriptSettings">
|
||||
<option name="languageLevel" value="ES6" />
|
||||
</component>
|
||||
<component name="ProjectRootManager" version="2" project-jdk-name="Python 3.8 (tuxbot-bot-rewrite)" project-jdk-type="Python SDK" />
|
||||
</project>
|
8
.idea/modules.xml
Normal file
8
.idea/modules.xml
Normal file
|
@ -0,0 +1,8 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="ProjectModuleManager">
|
||||
<modules>
|
||||
<module fileurl="file://$PROJECT_DIR$/.idea/tuxbot-bot-rewrite.iml" filepath="$PROJECT_DIR$/.idea/tuxbot-bot-rewrite.iml" />
|
||||
</modules>
|
||||
</component>
|
||||
</project>
|
10
.idea/tuxbot-bot-rewrite.iml
Normal file
10
.idea/tuxbot-bot-rewrite.iml
Normal file
|
@ -0,0 +1,10 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<module type="PYTHON_MODULE" version="4">
|
||||
<component name="NewModuleRootManager">
|
||||
<content url="file://$MODULE_DIR$">
|
||||
<excludeFolder url="file://$MODULE_DIR$/venv" />
|
||||
</content>
|
||||
<orderEntry type="inheritedJdk" />
|
||||
<orderEntry type="sourceFolder" forTests="false" />
|
||||
</component>
|
||||
</module>
|
11
.idea/vcs.xml
Normal file
11
.idea/vcs.xml
Normal file
|
@ -0,0 +1,11 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="CommitMessageInspectionProfile">
|
||||
<profile version="1.0">
|
||||
<inspection_tool class="GrazieCommit" enabled="true" level="TYPO" enabled_by_default="true" />
|
||||
</profile>
|
||||
</component>
|
||||
<component name="VcsDirectoryMappings">
|
||||
<mapping directory="$PROJECT_DIR$" vcs="Git" />
|
||||
</component>
|
||||
</project>
|
199
.idea/workspace.xml
Normal file
199
.idea/workspace.xml
Normal file
|
@ -0,0 +1,199 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="ChangeListManager">
|
||||
<list default="true" id="6566fca1-2e90-48bb-9e74-dd3badbaca99" name="Default Changelist" comment="">
|
||||
<change beforePath="$PROJECT_DIR$/.github/issue_template.md" beforeDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/.gitignore" beforeDir="false" afterPath="$PROJECT_DIR$/.gitignore" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/LICENSE" beforeDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/README.md" beforeDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/bot.py" beforeDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/cogs/API.py" beforeDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/cogs/Admin.py" beforeDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/cogs/Help.py" beforeDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/cogs/Logs.py" beforeDir="false" afterPath="$PROJECT_DIR$/cogs/Logs.py" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/cogs/Monitoring.py" beforeDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/cogs/Poll.py" beforeDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/cogs/Useful.py" beforeDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/cogs/User.py" beforeDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/configs/blacklist.cfg" beforeDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/configs/config.cfg.example" beforeDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/configs/fallbacks.cfg.example" beforeDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/configs/prefixes.cfg" beforeDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/database.py" beforeDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/generate_locales.sh" beforeDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/requirements.txt" beforeDir="false" afterPath="$PROJECT_DIR$/requirements.txt" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/todo" beforeDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/utils/__init__.py" beforeDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/utils/fonts/credit_card.ttf" beforeDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/utils/functions/__init__.py" beforeDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/utils/functions/config.py" beforeDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/utils/functions/database.py" beforeDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/utils/functions/emotes.py" beforeDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/utils/functions/extra.py" beforeDir="false" afterPath="$PROJECT_DIR$/utils/functions/extra.py" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/utils/functions/lang.py" beforeDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/utils/functions/paginator.py" beforeDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/utils/functions/version.py" beforeDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/utils/images/blank_credit_card.png" beforeDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/utils/images/gnous.png" beforeDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/utils/locales/en/LC_MESSAGES/admin.po" beforeDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/utils/locales/en/LC_MESSAGES/admin_help.po" beforeDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/utils/locales/en/LC_MESSAGES/base.po" beforeDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/utils/locales/en/LC_MESSAGES/help.po" beforeDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/utils/locales/en/LC_MESSAGES/logs.po" beforeDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/utils/locales/en/LC_MESSAGES/poll.po" beforeDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/utils/locales/en/LC_MESSAGES/poll_help.po" beforeDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/utils/locales/en/LC_MESSAGES/useful.po" beforeDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/utils/locales/en/LC_MESSAGES/useful_help.po" beforeDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/utils/locales/en/LC_MESSAGES/user.po" beforeDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/utils/locales/en/LC_MESSAGES/user_help.po" beforeDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/utils/locales/en/LC_MESSAGES/utils.po" beforeDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/utils/locales/fr/LC_MESSAGES/admin.po" beforeDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/utils/locales/fr/LC_MESSAGES/admin_help.po" beforeDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/utils/locales/fr/LC_MESSAGES/base.po" beforeDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/utils/locales/fr/LC_MESSAGES/help.po" beforeDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/utils/locales/fr/LC_MESSAGES/logs.po" beforeDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/utils/locales/fr/LC_MESSAGES/logs_help.po" beforeDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/utils/locales/fr/LC_MESSAGES/poll.po" beforeDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/utils/locales/fr/LC_MESSAGES/poll_help.po" beforeDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/utils/locales/fr/LC_MESSAGES/useful.po" beforeDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/utils/locales/fr/LC_MESSAGES/useful_help.po" beforeDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/utils/locales/fr/LC_MESSAGES/user.po" beforeDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/utils/locales/fr/LC_MESSAGES/user_help.po" beforeDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/utils/locales/fr/LC_MESSAGES/utils.po" beforeDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/utils/models/__init__.py" beforeDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/utils/models/alias.py" beforeDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/utils/models/poll.py" beforeDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/utils/models/warn.py" beforeDir="false" />
|
||||
</list>
|
||||
<option name="SHOW_DIALOG" value="false" />
|
||||
<option name="HIGHLIGHT_CONFLICTS" value="true" />
|
||||
<option name="HIGHLIGHT_NON_ACTIVE_CHANGELIST" value="false" />
|
||||
<option name="LAST_RESOLUTION" value="IGNORE" />
|
||||
</component>
|
||||
<component name="FileTemplateManagerImpl">
|
||||
<option name="RECENT_TEMPLATES">
|
||||
<list>
|
||||
<option value="package.json" />
|
||||
</list>
|
||||
</option>
|
||||
</component>
|
||||
<component name="Git.Settings">
|
||||
<option name="RECENT_GIT_ROOT_PATH" value="$PROJECT_DIR$" />
|
||||
</component>
|
||||
<component name="ProjectId" id="1c8uTCADTYzyrek4IjGPAZUYsa9" />
|
||||
<component name="ProjectLevelVcsManager" settingsEditedManually="true">
|
||||
<ConfirmationsSetting value="1" id="Add" />
|
||||
</component>
|
||||
<component name="ProjectViewState">
|
||||
<option name="hideEmptyMiddlePackages" value="true" />
|
||||
<option name="showLibraryContents" value="true" />
|
||||
<option name="showMembers" value="true" />
|
||||
</component>
|
||||
<component name="PropertiesComponent">
|
||||
<property name="RunOnceActivity.OpenProjectViewOnStart" value="true" />
|
||||
<property name="RunOnceActivity.ShowReadmeOnStart" value="true" />
|
||||
<property name="WebServerToolWindowFactoryState" value="false" />
|
||||
<property name="last_opened_file_path" value="$PROJECT_DIR$/configs/bot" />
|
||||
<property name="node.js.detected.package.eslint" 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.tslint" value="project" />
|
||||
<property name="node.js.selected.package.eslint" value="(autodetect)" />
|
||||
<property name="node.js.selected.package.tslint" value="(autodetect)" />
|
||||
<property name="settings.editor.selected.configurable" value="reference.settingsdialog.IDE.editor.colors" />
|
||||
</component>
|
||||
<component name="RecentsManager">
|
||||
<key name="CopyFile.RECENT_KEYS">
|
||||
<recent name="$PROJECT_DIR$/configs/bot" />
|
||||
<recent name="$PROJECT_DIR$/cogs" />
|
||||
</key>
|
||||
<key name="MoveFile.RECENT_KEYS">
|
||||
<recent name="$PROJECT_DIR$/cogs" />
|
||||
</key>
|
||||
</component>
|
||||
<component name="SvnConfiguration">
|
||||
<configuration />
|
||||
</component>
|
||||
<component name="TaskManager">
|
||||
<task active="true" id="Default" summary="Default task">
|
||||
<changelist id="6566fca1-2e90-48bb-9e74-dd3badbaca99" name="Default Changelist" comment="" />
|
||||
<created>1589922546510</created>
|
||||
<option name="number" value="Default" />
|
||||
<option name="presentableId" value="Default" />
|
||||
<updated>1589991138014</updated>
|
||||
<workItem from="1589922559463" duration="2090000" />
|
||||
<workItem from="1589925987600" duration="7107000" />
|
||||
<workItem from="1589991138257" duration="2797000" />
|
||||
<workItem from="1590020744819" duration="3432000" />
|
||||
<workItem from="1590065919217" duration="8090000" />
|
||||
<workItem from="1590152430112" duration="7500000" />
|
||||
<workItem from="1590268542625" duration="3535000" />
|
||||
<workItem from="1590273830049" duration="1288000" />
|
||||
</task>
|
||||
<option name="localTasksCounter" value="2" />
|
||||
<option name="createBranch" value="false" />
|
||||
<option name="commitChanges" value="false" />
|
||||
<servers />
|
||||
</component>
|
||||
<component name="TypeScriptGeneratedFilesManager">
|
||||
<option name="version" value="2" />
|
||||
</component>
|
||||
<component name="WindowStateProjectService">
|
||||
<state x="2338" y="213" key="#com.intellij.execution.impl.EditConfigurationsDialog" timestamp="1589991158766">
|
||||
<screen x="1920" y="0" width="1920" height="1080" />
|
||||
</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="2616" y="357" width="521" height="396" key="#com.intellij.fileTypes.FileTypeChooser" timestamp="1589928148179">
|
||||
<screen x="1920" y="0" width="1920" height="1080" />
|
||||
</state>
|
||||
<state x="2616" y="357" width="521" height="396" key="#com.intellij.fileTypes.FileTypeChooser/1920.0.1920.1080/0.29.1920.1051@1920.0.1920.1080" timestamp="1589928148179" />
|
||||
<state x="2613" y="304" width="528" height="502" key="#com.intellij.refactoring.safeDelete.UnsafeUsagesDialog" timestamp="1590160080814">
|
||||
<screen x="1920" y="0" width="1920" height="1080" />
|
||||
</state>
|
||||
<state x="2613" y="304" width="528" height="502" key="#com.intellij.refactoring.safeDelete.UnsafeUsagesDialog/1920.0.1920.1080/0.29.1920.1051@1920.0.1920.1080" timestamp="1590160080814" />
|
||||
<state x="2663" y="313" width="428" height="484" key="FileChooserDialogImpl" timestamp="1590152666732">
|
||||
<screen x="1920" y="0" width="1920" height="1080" />
|
||||
</state>
|
||||
<state x="2663" y="313" width="428" height="484" key="FileChooserDialogImpl/1920.0.1920.1080/0.29.1920.1051@1920.0.1920.1080" timestamp="1590152666732" />
|
||||
<state x="2666" y="239" width="421" height="633" key="RollbackChangesDialog" timestamp="1589983513390">
|
||||
<screen x="1920" y="0" width="1920" height="1080" />
|
||||
</state>
|
||||
<state x="2666" y="239" width="421" height="633" key="RollbackChangesDialog/1920.0.1920.1080/0.29.1920.1051@1920.0.1920.1080" timestamp="1589983513390" />
|
||||
<state x="2669" y="310" key="SettingsEditor" timestamp="1589983575542">
|
||||
<screen x="1920" y="0" width="1920" height="1080" />
|
||||
</state>
|
||||
<state x="2669" y="310" key="SettingsEditor/1920.0.1920.1080/0.29.1920.1051@1920.0.1920.1080" timestamp="1589983575542" />
|
||||
<state x="2656" y="388" key="SimpleOpenTaskDialog" timestamp="1589983150588">
|
||||
<screen x="1920" y="0" width="1920" height="1080" />
|
||||
</state>
|
||||
<state x="2656" y="388" key="SimpleOpenTaskDialog/1920.0.1920.1080/0.29.1920.1051@1920.0.1920.1080" timestamp="1589983150588" />
|
||||
<state x="2727" y="471" width="299" height="169" key="VCS.ChangelistChooser" timestamp="1589983445998">
|
||||
<screen x="1920" y="0" width="1920" height="1080" />
|
||||
</state>
|
||||
<state x="2727" y="471" width="299" height="169" key="VCS.ChangelistChooser/1920.0.1920.1080/0.29.1920.1051@1920.0.1920.1080" timestamp="1589983445998" />
|
||||
<state x="2475" y="291" width="804" height="528" key="Vcs.Push.Dialog.v2" timestamp="1589983676744">
|
||||
<screen x="1920" y="0" width="1920" height="1080" />
|
||||
</state>
|
||||
<state x="2475" y="291" width="804" height="528" key="Vcs.Push.Dialog.v2/1920.0.1920.1080/0.29.1920.1051@1920.0.1920.1080" timestamp="1589983676744" />
|
||||
<state x="2440" y="156" width="873" height="799" key="com.intellij.openapi.editor.actions.MultiplePasteAction$ClipboardContentChooser" timestamp="1590155739870">
|
||||
<screen x="1920" y="0" width="1920" height="1080" />
|
||||
</state>
|
||||
<state x="2440" y="156" width="873" height="799" key="com.intellij.openapi.editor.actions.MultiplePasteAction$ClipboardContentChooser/1920.0.1920.1080/0.29.1920.1051@1920.0.1920.1080" timestamp="1590155739870" />
|
||||
<state x="2584" y="164" width="592" height="783" key="find.popup" timestamp="1589983672115">
|
||||
<screen x="1920" y="0" width="1920" height="1080" />
|
||||
</state>
|
||||
<state x="2584" y="164" width="592" height="783" key="find.popup/1920.0.1920.1080/0.29.1920.1051@1920.0.1920.1080" timestamp="1589983672115" />
|
||||
<state width="600" height="428" key="javadoc.popup" timestamp="1589983663541">
|
||||
<screen x="1920" y="0" width="1920" height="1080" />
|
||||
</state>
|
||||
<state width="600" height="428" key="javadoc.popup/1920.0.1920.1080/0.29.1920.1051@1920.0.1920.1080" timestamp="1589983663541" />
|
||||
<state x="2527" y="274" width="700" height="530" key="recent.locations.popup" timestamp="1589983638293">
|
||||
<screen x="1920" y="0" width="1920" height="1080" />
|
||||
</state>
|
||||
<state x="2527" y="274" width="700" height="530" key="recent.locations.popup/1920.0.1920.1080/0.29.1920.1051@1920.0.1920.1080" timestamp="1589983638292" />
|
||||
<state x="2543" y="261" width="672" height="678" key="search.everywhere.popup" timestamp="1589983695298">
|
||||
<screen x="1920" y="0" width="1920" height="1080" />
|
||||
</state>
|
||||
<state x="2543" y="261" width="672" height="678" key="search.everywhere.popup/1920.0.1920.1080/0.29.1920.1051@1920.0.1920.1080" timestamp="1589983695298" />
|
||||
</component>
|
||||
</project>
|
437
LICENSE
437
LICENSE
|
@ -1,437 +0,0 @@
|
|||
Attribution-NonCommercial-ShareAlike 4.0 International
|
||||
|
||||
=======================================================================
|
||||
|
||||
Creative Commons Corporation ("Creative Commons") is not a law firm and
|
||||
does not provide legal services or legal advice. Distribution of
|
||||
Creative Commons public licenses does not create a lawyer-client or
|
||||
other relationship. Creative Commons makes its licenses and related
|
||||
information available on an "as-is" basis. Creative Commons gives no
|
||||
warranties regarding its licenses, any material licensed under their
|
||||
terms and conditions, or any related information. Creative Commons
|
||||
disclaims all liability for damages resulting from their use to the
|
||||
fullest extent possible.
|
||||
|
||||
Using Creative Commons Public Licenses
|
||||
|
||||
Creative Commons public licenses provide a standard set of terms and
|
||||
conditions that creators and other rights holders may use to share
|
||||
original works of authorship and other material subject to copyright
|
||||
and certain other rights specified in the public license below. The
|
||||
following considerations are for informational purposes only, are not
|
||||
exhaustive, and do not form part of our licenses.
|
||||
|
||||
Considerations for licensors: Our public licenses are
|
||||
intended for use by those authorized to give the public
|
||||
permission to use material in ways otherwise restricted by
|
||||
copyright and certain other rights. Our licenses are
|
||||
irrevocable. Licensors should read and understand the terms
|
||||
and conditions of the license they choose before applying it.
|
||||
Licensors should also secure all rights necessary before
|
||||
applying our licenses so that the public can reuse the
|
||||
material as expected. Licensors should clearly mark any
|
||||
material not subject to the license. This includes other CC-
|
||||
licensed material, or material used under an exception or
|
||||
limitation to copyright. More considerations for licensors:
|
||||
wiki.creativecommons.org/Considerations_for_licensors
|
||||
|
||||
Considerations for the public: By using one of our public
|
||||
licenses, a licensor grants the public permission to use the
|
||||
licensed material under specified terms and conditions. If
|
||||
the licensor's permission is not necessary for any reason--for
|
||||
example, because of any applicable exception or limitation to
|
||||
copyright--then that use is not regulated by the license. Our
|
||||
licenses grant only permissions under copyright and certain
|
||||
other rights that a licensor has authority to grant. Use of
|
||||
the licensed material may still be restricted for other
|
||||
reasons, including because others have copyright or other
|
||||
rights in the material. A licensor may make special requests,
|
||||
such as asking that all changes be marked or described.
|
||||
Although not required by our licenses, you are encouraged to
|
||||
respect those requests where reasonable. More_considerations
|
||||
for the public:
|
||||
wiki.creativecommons.org/Considerations_for_licensees
|
||||
|
||||
=======================================================================
|
||||
|
||||
Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International
|
||||
Public License
|
||||
|
||||
By exercising the Licensed Rights (defined below), You accept and agree
|
||||
to be bound by the terms and conditions of this Creative Commons
|
||||
Attribution-NonCommercial-ShareAlike 4.0 International Public License
|
||||
("Public License"). To the extent this Public License may be
|
||||
interpreted as a contract, You are granted the Licensed Rights in
|
||||
consideration of Your acceptance of these terms and conditions, and the
|
||||
Licensor grants You such rights in consideration of benefits the
|
||||
Licensor receives from making the Licensed Material available under
|
||||
these terms and conditions.
|
||||
|
||||
|
||||
Section 1 -- Definitions.
|
||||
|
||||
a. Adapted Material means material subject to Copyright and Similar
|
||||
Rights that is derived from or based upon the Licensed Material
|
||||
and in which the Licensed Material is translated, altered,
|
||||
arranged, transformed, or otherwise modified in a manner requiring
|
||||
permission under the Copyright and Similar Rights held by the
|
||||
Licensor. For purposes of this Public License, where the Licensed
|
||||
Material is a musical work, performance, or sound recording,
|
||||
Adapted Material is always produced where the Licensed Material is
|
||||
synched in timed relation with a moving image.
|
||||
|
||||
b. Adapter's License means the license You apply to Your Copyright
|
||||
and Similar Rights in Your contributions to Adapted Material in
|
||||
accordance with the terms and conditions of this Public License.
|
||||
|
||||
c. BY-NC-SA Compatible License means a license listed at
|
||||
creativecommons.org/compatiblelicenses, approved by Creative
|
||||
Commons as essentially the equivalent of this Public License.
|
||||
|
||||
d. Copyright and Similar Rights means copyright and/or similar rights
|
||||
closely related to copyright including, without limitation,
|
||||
performance, broadcast, sound recording, and Sui Generis Database
|
||||
Rights, without regard to how the rights are labeled or
|
||||
categorized. For purposes of this Public License, the rights
|
||||
specified in Section 2(b)(1)-(2) are not Copyright and Similar
|
||||
Rights.
|
||||
|
||||
e. Effective Technological Measures means those measures that, in the
|
||||
absence of proper authority, may not be circumvented under laws
|
||||
fulfilling obligations under Article 11 of the WIPO Copyright
|
||||
Treaty adopted on December 20, 1996, and/or similar international
|
||||
agreements.
|
||||
|
||||
f. Exceptions and Limitations means fair use, fair dealing, and/or
|
||||
any other exception or limitation to Copyright and Similar Rights
|
||||
that applies to Your use of the Licensed Material.
|
||||
|
||||
g. License Elements means the license attributes listed in the name
|
||||
of a Creative Commons Public License. The License Elements of this
|
||||
Public License are Attribution, NonCommercial, and ShareAlike.
|
||||
|
||||
h. Licensed Material means the artistic or literary work, database,
|
||||
or other material to which the Licensor applied this Public
|
||||
License.
|
||||
|
||||
i. Licensed Rights means the rights granted to You subject to the
|
||||
terms and conditions of this Public License, which are limited to
|
||||
all Copyright and Similar Rights that apply to Your use of the
|
||||
Licensed Material and that the Licensor has authority to license.
|
||||
|
||||
j. Licensor means the individual(s) or entity(ies) granting rights
|
||||
under this Public License.
|
||||
|
||||
k. NonCommercial means not primarily intended for or directed towards
|
||||
commercial advantage or monetary compensation. For purposes of
|
||||
this Public License, the exchange of the Licensed Material for
|
||||
other material subject to Copyright and Similar Rights by digital
|
||||
file-sharing or similar means is NonCommercial provided there is
|
||||
no payment of monetary compensation in connection with the
|
||||
exchange.
|
||||
|
||||
l. Share means to provide material to the public by any means or
|
||||
process that requires permission under the Licensed Rights, such
|
||||
as reproduction, public display, public performance, distribution,
|
||||
dissemination, communication, or importation, and to make material
|
||||
available to the public including in ways that members of the
|
||||
public may access the material from a place and at a time
|
||||
individually chosen by them.
|
||||
|
||||
m. Sui Generis Database Rights means rights other than copyright
|
||||
resulting from Directive 96/9/EC of the European Parliament and of
|
||||
the Council of 11 March 1996 on the legal protection of databases,
|
||||
as amended and/or succeeded, as well as other essentially
|
||||
equivalent rights anywhere in the world.
|
||||
|
||||
n. You means the individual or entity exercising the Licensed Rights
|
||||
under this Public License. Your has a corresponding meaning.
|
||||
|
||||
|
||||
Section 2 -- Scope.
|
||||
|
||||
a. License grant.
|
||||
|
||||
1. Subject to the terms and conditions of this Public License,
|
||||
the Licensor hereby grants You a worldwide, royalty-free,
|
||||
non-sublicensable, non-exclusive, irrevocable license to
|
||||
exercise the Licensed Rights in the Licensed Material to:
|
||||
|
||||
a. reproduce and Share the Licensed Material, in whole or
|
||||
in part, for NonCommercial purposes only; and
|
||||
|
||||
b. produce, reproduce, and Share Adapted Material for
|
||||
NonCommercial purposes only.
|
||||
|
||||
2. Exceptions and Limitations. For the avoidance of doubt, where
|
||||
Exceptions and Limitations apply to Your use, this Public
|
||||
License does not apply, and You do not need to comply with
|
||||
its terms and conditions.
|
||||
|
||||
3. Term. The term of this Public License is specified in Section
|
||||
6(a).
|
||||
|
||||
4. Media and formats; technical modifications allowed. The
|
||||
Licensor authorizes You to exercise the Licensed Rights in
|
||||
all media and formats whether now known or hereafter created,
|
||||
and to make technical modifications necessary to do so. The
|
||||
Licensor waives and/or agrees not to assert any right or
|
||||
authority to forbid You from making technical modifications
|
||||
necessary to exercise the Licensed Rights, including
|
||||
technical modifications necessary to circumvent Effective
|
||||
Technological Measures. For purposes of this Public License,
|
||||
simply making modifications authorized by this Section 2(a)
|
||||
(4) never produces Adapted Material.
|
||||
|
||||
5. Downstream recipients.
|
||||
|
||||
a. Offer from the Licensor -- Licensed Material. Every
|
||||
recipient of the Licensed Material automatically
|
||||
receives an offer from the Licensor to exercise the
|
||||
Licensed Rights under the terms and conditions of this
|
||||
Public License.
|
||||
|
||||
b. Additional offer from the Licensor -- Adapted Material.
|
||||
Every recipient of Adapted Material from You
|
||||
automatically receives an offer from the Licensor to
|
||||
exercise the Licensed Rights in the Adapted Material
|
||||
under the conditions of the Adapter's License You apply.
|
||||
|
||||
c. No downstream restrictions. You may not offer or impose
|
||||
any additional or different terms or conditions on, or
|
||||
apply any Effective Technological Measures to, the
|
||||
Licensed Material if doing so restricts exercise of the
|
||||
Licensed Rights by any recipient of the Licensed
|
||||
Material.
|
||||
|
||||
6. No endorsement. Nothing in this Public License constitutes or
|
||||
may be construed as permission to assert or imply that You
|
||||
are, or that Your use of the Licensed Material is, connected
|
||||
with, or sponsored, endorsed, or granted official status by,
|
||||
the Licensor or others designated to receive attribution as
|
||||
provided in Section 3(a)(1)(A)(i).
|
||||
|
||||
b. Other rights.
|
||||
|
||||
1. Moral rights, such as the right of integrity, are not
|
||||
licensed under this Public License, nor are publicity,
|
||||
privacy, and/or other similar personality rights; however, to
|
||||
the extent possible, the Licensor waives and/or agrees not to
|
||||
assert any such rights held by the Licensor to the limited
|
||||
extent necessary to allow You to exercise the Licensed
|
||||
Rights, but not otherwise.
|
||||
|
||||
2. Patent and trademark rights are not licensed under this
|
||||
Public License.
|
||||
|
||||
3. To the extent possible, the Licensor waives any right to
|
||||
collect royalties from You for the exercise of the Licensed
|
||||
Rights, whether directly or through a collecting society
|
||||
under any voluntary or waivable statutory or compulsory
|
||||
licensing scheme. In all other cases the Licensor expressly
|
||||
reserves any right to collect such royalties, including when
|
||||
the Licensed Material is used other than for NonCommercial
|
||||
purposes.
|
||||
|
||||
|
||||
Section 3 -- License Conditions.
|
||||
|
||||
Your exercise of the Licensed Rights is expressly made subject to the
|
||||
following conditions.
|
||||
|
||||
a. Attribution.
|
||||
|
||||
1. If You Share the Licensed Material (including in modified
|
||||
form), You must:
|
||||
|
||||
a. retain the following if it is supplied by the Licensor
|
||||
with the Licensed Material:
|
||||
|
||||
i. identification of the creator(s) of the Licensed
|
||||
Material and any others designated to receive
|
||||
attribution, in any reasonable manner requested by
|
||||
the Licensor (including by pseudonym if
|
||||
designated);
|
||||
|
||||
ii. a copyright notice;
|
||||
|
||||
iii. a notice that refers to this Public License;
|
||||
|
||||
iv. a notice that refers to the disclaimer of
|
||||
warranties;
|
||||
|
||||
v. a URI or hyperlink to the Licensed Material to the
|
||||
extent reasonably practicable;
|
||||
|
||||
b. indicate if You modified the Licensed Material and
|
||||
retain an indication of any previous modifications; and
|
||||
|
||||
c. indicate the Licensed Material is licensed under this
|
||||
Public License, and include the text of, or the URI or
|
||||
hyperlink to, this Public License.
|
||||
|
||||
2. You may satisfy the conditions in Section 3(a)(1) in any
|
||||
reasonable manner based on the medium, means, and context in
|
||||
which You Share the Licensed Material. For example, it may be
|
||||
reasonable to satisfy the conditions by providing a URI or
|
||||
hyperlink to a resource that includes the required
|
||||
information.
|
||||
3. If requested by the Licensor, You must remove any of the
|
||||
information required by Section 3(a)(1)(A) to the extent
|
||||
reasonably practicable.
|
||||
|
||||
b. ShareAlike.
|
||||
|
||||
In addition to the conditions in Section 3(a), if You Share
|
||||
Adapted Material You produce, the following conditions also apply.
|
||||
|
||||
1. The Adapter's License You apply must be a Creative Commons
|
||||
license with the same License Elements, this version or
|
||||
later, or a BY-NC-SA Compatible License.
|
||||
|
||||
2. You must include the text of, or the URI or hyperlink to, the
|
||||
Adapter's License You apply. You may satisfy this condition
|
||||
in any reasonable manner based on the medium, means, and
|
||||
context in which You Share Adapted Material.
|
||||
|
||||
3. You may not offer or impose any additional or different terms
|
||||
or conditions on, or apply any Effective Technological
|
||||
Measures to, Adapted Material that restrict exercise of the
|
||||
rights granted under the Adapter's License You apply.
|
||||
|
||||
|
||||
Section 4 -- Sui Generis Database Rights.
|
||||
|
||||
Where the Licensed Rights include Sui Generis Database Rights that
|
||||
apply to Your use of the Licensed Material:
|
||||
|
||||
a. for the avoidance of doubt, Section 2(a)(1) grants You the right
|
||||
to extract, reuse, reproduce, and Share all or a substantial
|
||||
portion of the contents of the database for NonCommercial purposes
|
||||
only;
|
||||
|
||||
b. if You include all or a substantial portion of the database
|
||||
contents in a database in which You have Sui Generis Database
|
||||
Rights, then the database in which You have Sui Generis Database
|
||||
Rights (but not its individual contents) is Adapted Material,
|
||||
including for purposes of Section 3(b); and
|
||||
|
||||
c. You must comply with the conditions in Section 3(a) if You Share
|
||||
all or a substantial portion of the contents of the database.
|
||||
|
||||
For the avoidance of doubt, this Section 4 supplements and does not
|
||||
replace Your obligations under this Public License where the Licensed
|
||||
Rights include other Copyright and Similar Rights.
|
||||
|
||||
|
||||
Section 5 -- Disclaimer of Warranties and Limitation of Liability.
|
||||
|
||||
a. UNLESS OTHERWISE SEPARATELY UNDERTAKEN BY THE LICENSOR, TO THE
|
||||
EXTENT POSSIBLE, THE LICENSOR OFFERS THE LICENSED MATERIAL AS-IS
|
||||
AND AS-AVAILABLE, AND MAKES NO REPRESENTATIONS OR WARRANTIES OF
|
||||
ANY KIND CONCERNING THE LICENSED MATERIAL, WHETHER EXPRESS,
|
||||
IMPLIED, STATUTORY, OR OTHER. THIS INCLUDES, WITHOUT LIMITATION,
|
||||
WARRANTIES OF TITLE, MERCHANTABILITY, FITNESS FOR A PARTICULAR
|
||||
PURPOSE, NON-INFRINGEMENT, ABSENCE OF LATENT OR OTHER DEFECTS,
|
||||
ACCURACY, OR THE PRESENCE OR ABSENCE OF ERRORS, WHETHER OR NOT
|
||||
KNOWN OR DISCOVERABLE. WHERE DISCLAIMERS OF WARRANTIES ARE NOT
|
||||
ALLOWED IN FULL OR IN PART, THIS DISCLAIMER MAY NOT APPLY TO YOU.
|
||||
|
||||
b. TO THE EXTENT POSSIBLE, IN NO EVENT WILL THE LICENSOR BE LIABLE
|
||||
TO YOU ON ANY LEGAL THEORY (INCLUDING, WITHOUT LIMITATION,
|
||||
NEGLIGENCE) OR OTHERWISE FOR ANY DIRECT, SPECIAL, INDIRECT,
|
||||
INCIDENTAL, CONSEQUENTIAL, PUNITIVE, EXEMPLARY, OR OTHER LOSSES,
|
||||
COSTS, EXPENSES, OR DAMAGES ARISING OUT OF THIS PUBLIC LICENSE OR
|
||||
USE OF THE LICENSED MATERIAL, EVEN IF THE LICENSOR HAS BEEN
|
||||
ADVISED OF THE POSSIBILITY OF SUCH LOSSES, COSTS, EXPENSES, OR
|
||||
DAMAGES. WHERE A LIMITATION OF LIABILITY IS NOT ALLOWED IN FULL OR
|
||||
IN PART, THIS LIMITATION MAY NOT APPLY TO YOU.
|
||||
|
||||
c. The disclaimer of warranties and limitation of liability provided
|
||||
above shall be interpreted in a manner that, to the extent
|
||||
possible, most closely approximates an absolute disclaimer and
|
||||
waiver of all liability.
|
||||
|
||||
|
||||
Section 6 -- Term and Termination.
|
||||
|
||||
a. This Public License applies for the term of the Copyright and
|
||||
Similar Rights licensed here. However, if You fail to comply with
|
||||
this Public License, then Your rights under this Public License
|
||||
terminate automatically.
|
||||
|
||||
b. Where Your right to use the Licensed Material has terminated under
|
||||
Section 6(a), it reinstates:
|
||||
|
||||
1. automatically as of the date the violation is cured, provided
|
||||
it is cured within 30 days of Your discovery of the
|
||||
violation; or
|
||||
|
||||
2. upon express reinstatement by the Licensor.
|
||||
|
||||
For the avoidance of doubt, this Section 6(b) does not affect any
|
||||
right the Licensor may have to seek remedies for Your violations
|
||||
of this Public License.
|
||||
|
||||
c. For the avoidance of doubt, the Licensor may also offer the
|
||||
Licensed Material under separate terms or conditions or stop
|
||||
distributing the Licensed Material at any time; however, doing so
|
||||
will not terminate this Public License.
|
||||
|
||||
d. Sections 1, 5, 6, 7, and 8 survive termination of this Public
|
||||
License.
|
||||
|
||||
|
||||
Section 7 -- Other Terms and Conditions.
|
||||
|
||||
a. The Licensor shall not be bound by any additional or different
|
||||
terms or conditions communicated by You unless expressly agreed.
|
||||
|
||||
b. Any arrangements, understandings, or agreements regarding the
|
||||
Licensed Material not stated herein are separate from and
|
||||
independent of the terms and conditions of this Public License.
|
||||
|
||||
|
||||
Section 8 -- Interpretation.
|
||||
|
||||
a. For the avoidance of doubt, this Public License does not, and
|
||||
shall not be interpreted to, reduce, limit, restrict, or impose
|
||||
conditions on any use of the Licensed Material that could lawfully
|
||||
be made without permission under this Public License.
|
||||
|
||||
b. To the extent possible, if any provision of this Public License is
|
||||
deemed unenforceable, it shall be automatically reformed to the
|
||||
minimum extent necessary to make it enforceable. If the provision
|
||||
cannot be reformed, it shall be severed from this Public License
|
||||
without affecting the enforceability of the remaining terms and
|
||||
conditions.
|
||||
|
||||
c. No term or condition of this Public License will be waived and no
|
||||
failure to comply consented to unless expressly agreed to by the
|
||||
Licensor.
|
||||
|
||||
d. Nothing in this Public License constitutes or may be interpreted
|
||||
as a limitation upon, or waiver of, any privileges and immunities
|
||||
that apply to the Licensor or You, including from the legal
|
||||
processes of any jurisdiction or authority.
|
||||
|
||||
=======================================================================
|
||||
|
||||
Creative Commons is not a party to its public
|
||||
licenses. Notwithstanding, Creative Commons may elect to apply one of
|
||||
its public licenses to material it publishes and in those instances
|
||||
will be considered the “Licensor.” The text of the Creative Commons
|
||||
public licenses is dedicated to the public domain under the CC0 Public
|
||||
Domain Dedication. Except for the limited purpose of indicating that
|
||||
material is shared under a Creative Commons public license or as
|
||||
otherwise permitted by the Creative Commons policies published at
|
||||
creativecommons.org/policies, Creative Commons does not authorize the
|
||||
use of the trademark "Creative Commons" or any other trademark or logo
|
||||
of Creative Commons without its prior written consent including,
|
||||
without limitation, in connection with any unauthorized modifications
|
||||
to any of its public licenses or any other arrangements,
|
||||
understandings, or agreements concerning use of licensed material. For
|
||||
the avoidance of doubt, this paragraph does not form part of the
|
||||
public licenses.
|
||||
|
||||
Creative Commons may be contacted at creativecommons.org.
|
86
README.md
86
README.md
|
@ -1,86 +0,0 @@
|
|||
# News
|
||||
|
||||
- [ ] i18n for messages
|
||||
- [x] Custom prefixes
|
||||
- [ ] Better help command
|
||||
- [ ] Alias system for commands (e.g. `.alias .ci show .cs`)
|
||||
- [x] Migrate MySQL to postgresql
|
||||
- [x] Prepare bot for python 3.8 and discord.py 1.3.0
|
||||
- [ ] Create launcher
|
||||
- [ ] Create documentation
|
||||
|
||||
## Launcher requirements :
|
||||
|
||||
- [ ] Can install the bot
|
||||
- [ ] Can launch the bot
|
||||
- [ ] Can propose updates
|
||||
|
||||
## New commands :
|
||||
|
||||
- [x] `.sondage --anonyme <...>` (create à sondage with the possibility of answering anonymously)
|
||||
- [ ] `.sondage --edit <id>` (edit a sondage if we are the author or an admin)
|
||||
|
||||
## Documentation:
|
||||
- [ ] How to use ?
|
||||
- [ ] How to add more commands ?
|
||||
|
||||
## Ultimate :
|
||||
|
||||
- [ ] Send email or Telegram's message when something is wrong on the bot
|
||||
- [ ] Create skynet (group of multiple commands about sky (planes, meteo, AI,...))
|
||||
|
||||
---
|
||||
|
||||
# Cogs.admin commands
|
||||
|
||||
- [x] upload `removed`, cause : `never used`
|
||||
- [x] ban
|
||||
- [x] kick
|
||||
- [x] clear
|
||||
- [x] say
|
||||
- [x] sayto `removed`, now : `say to`
|
||||
- [x] sayto_dm `removed`, now : `say to`
|
||||
- [x] editsay `removed`, now : `say edit`
|
||||
- [x] addreaction `renamed`, now `react add`
|
||||
- [x] delete
|
||||
- [x] deletefrom `removed`, now `delete (from|to|in)`
|
||||
- [x] embed `removed`, cause : `never used`
|
||||
- [x] warn `new command`
|
||||
|
||||
---
|
||||
|
||||
# Cogs.basics commands
|
||||
- [x] ping
|
||||
- [x] info
|
||||
- [ ] help
|
||||
- [x] credits `new command`
|
||||
|
||||
---
|
||||
|
||||
# Cogs.ci commands `canceled until the frontend development`
|
||||
- [ ] ci (help?)
|
||||
- [ ] ci show
|
||||
- [ ] ci register
|
||||
- [ ] ci delete
|
||||
- [ ] ci update
|
||||
- [ ] ci setconfig
|
||||
- [ ] ci setos
|
||||
- [ ] ci setcountry
|
||||
- [ ] ci online_edit `renamed`, cause : `website down`
|
||||
- [ ] ci list
|
||||
|
||||
---
|
||||
|
||||
# Cogs.utility commands
|
||||
- [ ] clock `removed` ?
|
||||
- [ ] clock * `removed` ?
|
||||
- [ ] ytdiscover `removed` ?
|
||||
- [x] iplocalise
|
||||
- [x] getheaders
|
||||
- [x] git
|
||||
- [x] quote
|
||||
|
||||
---
|
||||
|
||||
# Cogs.sondage commands `(renamed as cogs.poll)` `canceled until the frontend development`
|
||||
- [ ] sondage (help?)
|
151
app.py
Normal file
151
app.py
Normal file
|
@ -0,0 +1,151 @@
|
|||
import contextlib
|
||||
import datetime
|
||||
import logging
|
||||
from collections import Counter
|
||||
from typing import List
|
||||
|
||||
import aiohttp
|
||||
import discord
|
||||
from discord.ext import commands
|
||||
from tortoise import Tortoise
|
||||
|
||||
from configs.bot import settings
|
||||
from utils.functions.extra import ContextPlus, get_prefix, \
|
||||
get_owners, get_blacklist
|
||||
|
||||
log = logging.getLogger(__name__)
|
||||
|
||||
l_extensions: List[str] = [
|
||||
"jishaku",
|
||||
"cogs.Logs",
|
||||
"cogs.Images",
|
||||
]
|
||||
|
||||
|
||||
class TuxBot(commands.AutoShardedBot):
|
||||
logs_channels: dict
|
||||
session: aiohttp.ClientSession
|
||||
command_stats: Counter = Counter()
|
||||
socket_stats: Counter = Counter()
|
||||
|
||||
def __init__(self):
|
||||
self.uptime = datetime.datetime.utcnow()
|
||||
self.config = settings
|
||||
super().__init__(
|
||||
command_prefix=get_prefix,
|
||||
case_insensitive=True
|
||||
)
|
||||
|
||||
self.logs_channels = {
|
||||
"dm": self.config.logs["dm"],
|
||||
"mentions": self.config.logs["mentions"],
|
||||
"guilds": self.config.logs["guilds"],
|
||||
"errors": self.config.logs["errors"],
|
||||
}
|
||||
|
||||
print("\n"*2)
|
||||
|
||||
for extension in l_extensions:
|
||||
try:
|
||||
self.load_extension(extension)
|
||||
print(f"{extension} loaded !")
|
||||
except Exception as e:
|
||||
print(f"{type(e).__name__}: {e}")
|
||||
|
||||
print("\n"*2)
|
||||
|
||||
async def is_owner(self, user: discord.User):
|
||||
return user.id in get_owners()
|
||||
|
||||
async def on_ready(self):
|
||||
print(f"Connected !\n"
|
||||
f"\n"
|
||||
f"==> info: bot username {self.user}\n"
|
||||
f" info: bot id {self.user.id}\n"
|
||||
f" info: bot prefix {self.command_prefix}\n"
|
||||
f"==> info: guild count {len(self.guilds)}\n"
|
||||
f" info: member count {len(list(self.get_all_members()))}\n"
|
||||
f" info: channel count {len(list(self.get_all_channels()))}")
|
||||
|
||||
print(f"\n{'='*118}\n\n")
|
||||
|
||||
@staticmethod
|
||||
async def on_resumed():
|
||||
print("resumed...")
|
||||
|
||||
async def get_context(self, message: discord.Message, *, cls=None):
|
||||
return await super().get_context(message, cls=ContextPlus)
|
||||
|
||||
async def on_message(self, message: discord.Message):
|
||||
if message.author.bot:
|
||||
return
|
||||
|
||||
if message.author.id in get_blacklist()['users'] \
|
||||
or message.channel.id in get_blacklist()['channels'] \
|
||||
or (message.channel.guild
|
||||
and message.channel.guild.id in get_blacklist()['guilds']):
|
||||
return
|
||||
|
||||
try:
|
||||
await self.process_commands(message)
|
||||
except Exception as e:
|
||||
print(f"{type(e).__name__}: {e}")
|
||||
|
||||
async def bot_logout(self):
|
||||
await super().logout()
|
||||
await self.session.close()
|
||||
|
||||
async def bot_start(self):
|
||||
self.session = aiohttp.ClientSession(loop=self.loop)
|
||||
await self.login(self.config.token, bot=True)
|
||||
await self.connect()
|
||||
|
||||
def run(self):
|
||||
loop = self.loop
|
||||
|
||||
loop.run_until_complete(Tortoise.init(
|
||||
db_url=self.config.postgresql,
|
||||
modules={
|
||||
"models": [
|
||||
"models.__init__"
|
||||
]
|
||||
}
|
||||
))
|
||||
loop.run_until_complete(Tortoise.generate_schemas())
|
||||
|
||||
try:
|
||||
loop.run_until_complete(self.bot_start())
|
||||
except KeyboardInterrupt:
|
||||
loop.run_until_complete(self.bot_logout())
|
||||
|
||||
|
||||
@contextlib.contextmanager
|
||||
def setup_logging():
|
||||
logging.getLogger('discord').setLevel(logging.INFO)
|
||||
logging.getLogger('discord.http').setLevel(logging.WARNING)
|
||||
|
||||
logger = logging.getLogger()
|
||||
logger.setLevel(logging.INFO)
|
||||
|
||||
try:
|
||||
handler = logging.FileHandler(filename='logs/tuxbot.log',
|
||||
encoding='utf-8', mode='w')
|
||||
fmt = logging.Formatter('[{levelname:<7}] [{asctime}]'
|
||||
' {name}: {message}',
|
||||
'%Y-%m-%d %H:%M:%S', style='{')
|
||||
|
||||
handler.setFormatter(fmt)
|
||||
logger.addHandler(handler)
|
||||
|
||||
yield
|
||||
finally:
|
||||
handlers = logger.handlers[:]
|
||||
for handler in handlers:
|
||||
handler.close()
|
||||
logger.removeHandler(handler)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
tutux = TuxBot()
|
||||
with setup_logging():
|
||||
tutux.run()
|
250
bot.py
250
bot.py
|
@ -1,250 +0,0 @@
|
|||
import contextlib
|
||||
import datetime
|
||||
import json
|
||||
import logging
|
||||
import sys
|
||||
from collections import deque, Counter
|
||||
from typing import List
|
||||
|
||||
import aiohttp
|
||||
import discord
|
||||
import git
|
||||
import sqlalchemy
|
||||
from discord.ext import commands
|
||||
|
||||
from utils.functions import Config
|
||||
from utils.functions import Texts
|
||||
from utils.functions import Version
|
||||
from utils.functions import ContextPlus
|
||||
|
||||
from utils.models import metadata, database
|
||||
|
||||
description = """
|
||||
Je suis TuxBot, le bot qui vit de l'OpenSource ! ;)
|
||||
"""
|
||||
|
||||
build = git.Repo(search_parent_directories=True).head.object.hexsha
|
||||
version = (2, 0, 0)
|
||||
|
||||
log = logging.getLogger(__name__)
|
||||
|
||||
l_extensions: List[str] = [
|
||||
'cogs.Admin',
|
||||
'cogs.API',
|
||||
'cogs.Help',
|
||||
'cogs.Logs',
|
||||
# 'cogs.Monitoring',
|
||||
'cogs.Poll',
|
||||
'cogs.Useful',
|
||||
'cogs.User',
|
||||
'jishaku',
|
||||
]
|
||||
|
||||
|
||||
async def _prefix_callable(bot, message: discord.message) -> list:
|
||||
<<<<<<< HEAD
|
||||
extras = [bot.cluster.get('Name') + '.']
|
||||
if message.guild is not None:
|
||||
if str(message.guild.id) in bot.prefixes:
|
||||
extras.extend(
|
||||
bot.prefixes.get(str(message.guild.id), "prefixes").split(
|
||||
bot.config.get("misc", "Separator")
|
||||
)
|
||||
)
|
||||
=======
|
||||
try:
|
||||
with open(f'./configs/guilds/{message.guild.id}.json', 'r') as f:
|
||||
data = json.load(f)
|
||||
|
||||
custom_prefix = data['prefixes']
|
||||
except FileNotFoundError:
|
||||
custom_prefix = ['']
|
||||
|
||||
extras = [bot.cluster.get('Name') + '.']
|
||||
extras.extend(custom_prefix)
|
||||
>>>>>>> cce7bb409303e9ad27ef4e5617d0bc9068810f13
|
||||
|
||||
return commands.when_mentioned_or(*extras)(bot, message)
|
||||
|
||||
|
||||
class TuxBot(commands.AutoShardedBot):
|
||||
|
||||
def __init__(self, ):
|
||||
super().__init__(command_prefix=_prefix_callable, pm_help=None,
|
||||
help_command=None, description=description,
|
||||
help_attrs=dict(hidden=True),
|
||||
activity=discord.Game(
|
||||
name=Texts().get('Starting...'))
|
||||
)
|
||||
|
||||
self.socket_stats = Counter()
|
||||
self.command_stats = Counter()
|
||||
|
||||
self.config = Config('./configs/config.cfg')
|
||||
self.blacklist = Config('./configs/blacklist.cfg')
|
||||
self.fallbacks = Config('./configs/fallbacks.cfg')
|
||||
self.cluster = self.fallbacks.find('True', key='This', first=True)
|
||||
|
||||
self.uptime: datetime = datetime.datetime.utcnow()
|
||||
self._prev_events = deque(maxlen=10)
|
||||
self.session = aiohttp.ClientSession(loop=self.loop)
|
||||
|
||||
self.database, self.metadata = database, metadata
|
||||
self.engine = sqlalchemy.create_engine(str(self.database.url))
|
||||
self.metadata.create_all(self.engine)
|
||||
|
||||
self.version = Version(*version, pre_release='rc2', build=build)
|
||||
self.owners_id = [int(owner_id) for owner_id in self.config.get('permissions', 'Owners').split(', ')]
|
||||
self.owner_id = int(self.owners_id[0])
|
||||
|
||||
for extension in l_extensions:
|
||||
try:
|
||||
self.load_extension(extension)
|
||||
print(Texts().get("Extension loaded successfully : ")
|
||||
+ extension)
|
||||
log.info(Texts().get("Extension loaded successfully : ")
|
||||
+ extension)
|
||||
except Exception as e:
|
||||
print(Texts().get("Failed to load extension : ")
|
||||
+ extension, file=sys.stderr)
|
||||
print(e)
|
||||
log.error(Texts().get("Failed to load extension : ")
|
||||
+ extension, exc_info=e)
|
||||
|
||||
@property
|
||||
def owner(self):
|
||||
return self.get_user(self.owner_id)
|
||||
|
||||
@property
|
||||
def owners(self):
|
||||
return [self.get_user(owner_id) for owner_id in self.owners_id]
|
||||
|
||||
async def is_owner(self, user: discord.User) -> bool:
|
||||
return user in self.owners
|
||||
|
||||
async def get_context(self, message, *, cls=None):
|
||||
return await super().get_context(message, cls=cls or ContextPlus)
|
||||
|
||||
async def on_socket_response(self, msg):
|
||||
self._prev_events.append(msg)
|
||||
|
||||
async def on_command_error(self, ctx: discord.ext.commands.Context, error):
|
||||
if isinstance(error, commands.NoPrivateMessage):
|
||||
await ctx.author.send(
|
||||
Texts().get("This command cannot be used in private messages.")
|
||||
)
|
||||
|
||||
elif isinstance(error, commands.DisabledCommand):
|
||||
await ctx.author.send(
|
||||
Texts().get(
|
||||
"Sorry. This command is disabled and cannot be used."
|
||||
)
|
||||
)
|
||||
elif isinstance(error, commands.CommandOnCooldown):
|
||||
await ctx.send(str(error))
|
||||
|
||||
async def process_commands(self, message: discord.message):
|
||||
ctx: commands.Context = await self.get_context(message)
|
||||
|
||||
if ctx.command is None:
|
||||
return
|
||||
|
||||
await self.invoke(ctx)
|
||||
|
||||
async def on_message(self, message: discord.message):
|
||||
if message.author.id in self.blacklist \
|
||||
or (message.guild is not None
|
||||
and message.guild.id in self.blacklist):
|
||||
return
|
||||
|
||||
if message.author.bot and message.author.id != int(
|
||||
self.config.get('bot', 'Tester')):
|
||||
return
|
||||
|
||||
await self.process_commands(message)
|
||||
|
||||
async def on_ready(self):
|
||||
if not hasattr(self, 'uptime'):
|
||||
self.uptime = datetime.datetime.utcnow()
|
||||
|
||||
print('-' * 60)
|
||||
print(Texts().get("Ready:") + f' {self.user} (ID: {self.user.id})')
|
||||
print(self.version)
|
||||
|
||||
presence: dict = dict(status=discord.Status.dnd)
|
||||
if self.config.get("bot", "Activity", fallback=None) is not None:
|
||||
presence.update(
|
||||
activity=discord.Game(
|
||||
name=self.config.get("bot", "Activity")
|
||||
)
|
||||
)
|
||||
print(f"Discord.py: {discord.__version__}")
|
||||
print(f"Server: {self.cluster.get('Name')}")
|
||||
print('-' * 60)
|
||||
|
||||
await self.change_presence(**presence)
|
||||
|
||||
@staticmethod
|
||||
async def on_resumed():
|
||||
print('resumed...')
|
||||
|
||||
@property
|
||||
def logs_webhook(self) -> discord.Webhook:
|
||||
webhook_config = self.config["webhook"]
|
||||
webhook = discord.Webhook.partial(
|
||||
id=webhook_config.get('ID'),
|
||||
token=webhook_config.get('Token'),
|
||||
adapter=discord.AsyncWebhookAdapter(
|
||||
self.session
|
||||
)
|
||||
)
|
||||
|
||||
return webhook
|
||||
|
||||
async def close(self):
|
||||
extensions = self.extensions.copy()
|
||||
for extension in extensions:
|
||||
self.unload_extension(extension)
|
||||
await super().close()
|
||||
await self.session.close()
|
||||
|
||||
def run(self):
|
||||
super().run(self.config.get("bot", "Token"), reconnect=True)
|
||||
|
||||
|
||||
@contextlib.contextmanager
|
||||
def setup_logging():
|
||||
logging.getLogger('discord').setLevel(logging.INFO)
|
||||
logging.getLogger('discord.http').setLevel(logging.WARNING)
|
||||
|
||||
log = logging.getLogger()
|
||||
log.setLevel(logging.INFO)
|
||||
|
||||
try:
|
||||
handler = logging.FileHandler(filename='logs/tuxbot.log',
|
||||
encoding='utf-8', mode='w')
|
||||
fmt = logging.Formatter('[{levelname:<7}] [{asctime}]'
|
||||
' {name}: {message}',
|
||||
'%Y-%m-%d %H:%M:%S', style='{')
|
||||
|
||||
handler.setFormatter(fmt)
|
||||
log.addHandler(handler)
|
||||
|
||||
yield
|
||||
finally:
|
||||
handlers = log.handlers[:]
|
||||
for handler in handlers:
|
||||
handler.close()
|
||||
log.removeHandler(handler)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
print(Texts().get('Starting...'))
|
||||
|
||||
app = TuxBot()
|
||||
|
||||
try:
|
||||
with setup_logging():
|
||||
app.run()
|
||||
except KeyboardInterrupt:
|
||||
app.close()
|
56
cogs/API.py
56
cogs/API.py
|
@ -1,56 +0,0 @@
|
|||
import logging
|
||||
|
||||
import discord
|
||||
from aiohttp import web
|
||||
from discord.ext import commands
|
||||
|
||||
from bot import TuxBot
|
||||
|
||||
log = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class API(commands.Cog):
|
||||
|
||||
def __init__(self, bot: TuxBot):
|
||||
self.bot = bot
|
||||
self.site = web.TCPSite
|
||||
|
||||
app = web.Application()
|
||||
app.add_routes([web.get('/users/{user_id}', self.users)])
|
||||
|
||||
self.runner = web.AppRunner(app)
|
||||
self.bot.loop.create_task(self.start_HTTPMonitoring_server())
|
||||
|
||||
async def start_HTTPMonitoring_server(self):
|
||||
host = self.bot.config.get('API', 'Host')
|
||||
port = self.bot.config.get('API', 'Port')
|
||||
|
||||
print(f"Starting API server on {host}:{port}")
|
||||
|
||||
await self.runner.setup()
|
||||
self.site = web.TCPSite(self.runner, host, port)
|
||||
await self.site.start()
|
||||
|
||||
async def users(self, request):
|
||||
try:
|
||||
user = await self.bot.fetch_user(request.match_info['user_id'])
|
||||
except discord.NotFound:
|
||||
return web.Response(status=404)
|
||||
|
||||
json = {
|
||||
'id': user.id,
|
||||
'username': user.name,
|
||||
'discriminator': user.discriminator,
|
||||
'avatar': user.avatar,
|
||||
'default_avatar': user.default_avatar.value,
|
||||
'bot': user.bot,
|
||||
'system': user.system,
|
||||
}
|
||||
|
||||
return web.json_response(
|
||||
json
|
||||
)
|
||||
|
||||
|
||||
def setup(bot: TuxBot):
|
||||
bot.add_cog(API(bot))
|
534
cogs/Admin.py
534
cogs/Admin.py
|
@ -1,534 +0,0 @@
|
|||
import asyncio
|
||||
import datetime
|
||||
import logging
|
||||
from typing import Union
|
||||
|
||||
import discord
|
||||
import humanize
|
||||
from discord.ext import commands
|
||||
|
||||
from bot import TuxBot
|
||||
from utils import Texts
|
||||
from utils.models import WarnModel
|
||||
from utils import command_extra, group_extra
|
||||
|
||||
log = logging.getLogger(__name__)
|
||||
|
||||
|
||||
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(
|
||||
ctx.author)
|
||||
|
||||
has_permission = permissions.administrator
|
||||
is_owner = await self.bot.is_owner(ctx.author)
|
||||
|
||||
return has_permission or is_owner
|
||||
|
||||
@staticmethod
|
||||
async def kick_ban_message(ctx: commands.Context,
|
||||
**kwargs) -> discord.Embed:
|
||||
member: discord.Member = kwargs.get('member')
|
||||
reason = kwargs.get(
|
||||
'reason',
|
||||
Texts('admin', ctx).get("Please enter a reason")
|
||||
)
|
||||
|
||||
if kwargs.get('type') == 'ban':
|
||||
title = '**Ban** ' + str(len(await ctx.guild.bans()))
|
||||
color = discord.Color.dark_red()
|
||||
else:
|
||||
title = '**Kick**'
|
||||
color = discord.Color.red()
|
||||
e = discord.Embed(
|
||||
title=title,
|
||||
description=reason,
|
||||
timestamp=datetime.datetime.utcnow(),
|
||||
color=color
|
||||
)
|
||||
e.set_author(
|
||||
name=f'{member.name}#{member.discriminator} ({member.id})',
|
||||
icon_url=member.avatar_url_as(format='jpg')
|
||||
)
|
||||
e.set_footer(
|
||||
text=f'{ctx.author.name}#{ctx.author.discriminator}',
|
||||
icon_url=ctx.author.avatar_url_as(format='png')
|
||||
)
|
||||
|
||||
return e
|
||||
|
||||
###########################################################################
|
||||
|
||||
@group_extra(name='say', invoke_without_command=True, category='text')
|
||||
async def _say(self, ctx: commands.Context, *, content: str):
|
||||
if ctx.invoked_subcommand is None:
|
||||
try:
|
||||
await ctx.message.delete()
|
||||
except discord.errors.Forbidden:
|
||||
pass
|
||||
|
||||
await ctx.send(content)
|
||||
|
||||
@_say.command(name='edit')
|
||||
async def _say_edit(self, ctx: commands.Context, message_id: int, *,
|
||||
content: str):
|
||||
try:
|
||||
await ctx.message.delete()
|
||||
except discord.errors.Forbidden:
|
||||
pass
|
||||
|
||||
try:
|
||||
message: discord.Message = await ctx.channel.fetch_message(
|
||||
message_id)
|
||||
await message.edit(content=content)
|
||||
except (discord.errors.NotFound, discord.errors.Forbidden):
|
||||
await ctx.send(
|
||||
Texts('utils', ctx).get("Unable to find the message"),
|
||||
delete_after=5)
|
||||
|
||||
@_say.command(name='to')
|
||||
async def _say_to(self, ctx: commands.Context,
|
||||
channel: Union[discord.TextChannel, discord.User], *,
|
||||
content):
|
||||
try:
|
||||
await ctx.message.delete()
|
||||
except discord.errors.Forbidden:
|
||||
pass
|
||||
|
||||
await channel.send(content)
|
||||
|
||||
###########################################################################
|
||||
|
||||
@command_extra(name='ban', category='administration')
|
||||
async def _ban(self, ctx: commands.Context, user: discord.Member, *,
|
||||
reason=""):
|
||||
try:
|
||||
member: discord.Member = await ctx.guild.fetch_member(user.id)
|
||||
|
||||
try:
|
||||
await member.ban(reason=reason)
|
||||
e: discord.Embed = await self.kick_ban_message(
|
||||
ctx,
|
||||
member=member,
|
||||
type='ban',
|
||||
reason=reason
|
||||
)
|
||||
|
||||
await ctx.send(embed=e)
|
||||
except discord.Forbidden:
|
||||
await ctx.send(
|
||||
Texts('admin', ctx).get("Unable to ban this user"),
|
||||
delete_after=5)
|
||||
except discord.errors.NotFound:
|
||||
await ctx.send(
|
||||
Texts('utils', ctx).get("Unable to find the user..."),
|
||||
delete_after=5)
|
||||
|
||||
###########################################################################
|
||||
|
||||
@command_extra(name='kick', category='administration')
|
||||
async def _kick(self, ctx: commands.Context, user: discord.Member, *,
|
||||
reason=""):
|
||||
try:
|
||||
member: discord.Member = await ctx.guild.fetch_member(user.id)
|
||||
|
||||
try:
|
||||
await member.kick(reason=reason)
|
||||
e: discord.Embed = await self.kick_ban_message(
|
||||
ctx,
|
||||
member=member,
|
||||
type='kick',
|
||||
reason=reason
|
||||
)
|
||||
|
||||
await ctx.send(embed=e)
|
||||
except discord.Forbidden:
|
||||
await ctx.send(
|
||||
Texts('admin', ctx).get("Unable to kick this user"),
|
||||
delete_after=5)
|
||||
except discord.errors.NotFound:
|
||||
await ctx.send(
|
||||
Texts('utils', ctx).get("Unable to find the user..."),
|
||||
delete_after=5)
|
||||
|
||||
###########################################################################
|
||||
|
||||
@command_extra(name='clear', category='text')
|
||||
async def _clear(self, ctx: commands.Context, count: int):
|
||||
try:
|
||||
await ctx.message.delete()
|
||||
await ctx.channel.purge(limit=count)
|
||||
except discord.errors.Forbidden:
|
||||
pass
|
||||
|
||||
###########################################################################
|
||||
|
||||
@group_extra(name='react', category='text')
|
||||
async def _react(self, ctx: commands.Context):
|
||||
if ctx.invoked_subcommand is None:
|
||||
await ctx.send_help('react')
|
||||
|
||||
@_react.command(name='add')
|
||||
async def _react_add(self, ctx: commands.Context, message_id: int, *,
|
||||
emojis: str):
|
||||
emojis: list = emojis.split(' ')
|
||||
|
||||
try:
|
||||
message: discord.Message = await ctx.channel.fetch_message(
|
||||
message_id)
|
||||
|
||||
for emoji in emojis:
|
||||
await message.add_reaction(emoji)
|
||||
except discord.errors.NotFound:
|
||||
await ctx.send(
|
||||
Texts('utils', ctx).get("Unable to find the message"),
|
||||
delete_after=5)
|
||||
|
||||
@_react.command(name='remove', aliases=['clear'])
|
||||
async def _react_remove(self, ctx: commands.Context, message_id: int):
|
||||
try:
|
||||
message: discord.Message = await ctx.channel.fetch_message(
|
||||
message_id)
|
||||
await message.clear_reactions()
|
||||
except discord.errors.NotFound:
|
||||
await ctx.send(
|
||||
Texts('utils', ctx).get("Unable to find the message"),
|
||||
delete_after=5)
|
||||
|
||||
###########################################################################
|
||||
|
||||
@group_extra(name='delete', invoke_without_command=True, category='text')
|
||||
async def _delete(self, ctx: commands.Context, message_id: int):
|
||||
try:
|
||||
await ctx.message.delete()
|
||||
except discord.errors.Forbidden:
|
||||
pass
|
||||
|
||||
try:
|
||||
message: discord.Message = await ctx.channel.fetch_message(
|
||||
message_id)
|
||||
await message.delete()
|
||||
except (discord.errors.NotFound, discord.errors.Forbidden):
|
||||
await ctx.send(
|
||||
Texts('utils', ctx).get("Unable to find the message"),
|
||||
delete_after=5)
|
||||
|
||||
@_delete.command(name='from', aliases=['to', 'in'])
|
||||
async def _delete_from(self, ctx: commands.Context,
|
||||
channel: discord.TextChannel, message_id: int):
|
||||
try:
|
||||
await ctx.message.delete()
|
||||
except discord.errors.Forbidden:
|
||||
pass
|
||||
|
||||
try:
|
||||
message: discord.Message = await channel.fetch_message(
|
||||
message_id
|
||||
)
|
||||
await message.delete()
|
||||
except (discord.errors.NotFound, discord.errors.Forbidden):
|
||||
await ctx.send(
|
||||
Texts('utils', ctx).get("Unable to find the message"),
|
||||
delete_after=5
|
||||
)
|
||||
|
||||
###########################################################################
|
||||
|
||||
async def get_warn(self, ctx: commands.Context,
|
||||
member: discord.Member = False):
|
||||
await ctx.trigger_typing()
|
||||
|
||||
if member:
|
||||
warns = WarnModel.objects.filter(
|
||||
server_id=str(ctx.guild.id),
|
||||
user_id=member.id
|
||||
)
|
||||
else:
|
||||
warns = WarnModel.objects.filter(
|
||||
server_id=str(ctx.guild.id)
|
||||
)
|
||||
warns_list = ''
|
||||
|
||||
for warn in await warns.all():
|
||||
row_id = warn.id
|
||||
user_id = warn.user_id
|
||||
user = await self.bot.fetch_user(user_id)
|
||||
reason = warn.reason
|
||||
ago = humanize.naturaldelta(
|
||||
datetime.datetime.now() - warn.created_at
|
||||
)
|
||||
|
||||
warns_list += f"[{row_id}] **{user}**: `{reason}` *({ago} ago)*\n"
|
||||
|
||||
return warns_list, warns
|
||||
|
||||
async def add_warn(self, ctx: commands.Context, member: discord.Member,
|
||||
reason):
|
||||
|
||||
now = datetime.datetime.now()
|
||||
warn = WarnModel(server_id=ctx.guild.id, user_id=member.id,
|
||||
reason=reason,
|
||||
created_at=now)
|
||||
|
||||
self.bot.database.session.add(warn)
|
||||
self.bot.database.session.commit()
|
||||
|
||||
@group_extra(name='warn', aliases=['warns'], category='administration')
|
||||
async def _warn(self, ctx: commands.Context):
|
||||
await ctx.trigger_typing()
|
||||
if ctx.invoked_subcommand is None:
|
||||
warns_list, warns = await self.get_warn(ctx)
|
||||
e = discord.Embed(
|
||||
title=f"{warns.count()} {Texts('admin', ctx).get('last warns')}: ",
|
||||
description=warns_list
|
||||
)
|
||||
|
||||
await ctx.send(embed=e)
|
||||
|
||||
@_warn.command(name='add', aliases=['new'])
|
||||
async def _warn_add(self, ctx: commands.Context, member: discord.Member,
|
||||
*, reason="N/A"):
|
||||
if not member:
|
||||
return await ctx.send(
|
||||
Texts('utils', ctx).get("Unable to find the user...")
|
||||
)
|
||||
|
||||
def check(pld: discord.RawReactionActionEvent):
|
||||
if pld.message_id != choice.id \
|
||||
or pld.user_id != ctx.author.id:
|
||||
return False
|
||||
return pld.emoji.name in ('1⃣', '2⃣', '3⃣')
|
||||
|
||||
warns_list, warns = await self.get_warn(ctx, member)
|
||||
|
||||
if warns.count() >= 2:
|
||||
e = discord.Embed(
|
||||
title=Texts('admin', ctx).get('More than 2 warns'),
|
||||
description=f"{member.mention} "
|
||||
+ Texts('admin', ctx).get('has more than 2 warns')
|
||||
)
|
||||
e.add_field(
|
||||
name='__Actions__',
|
||||
value=':one: kick\n'
|
||||
':two: ban\n'
|
||||
':three: ' + Texts('admin', ctx).get('ignore')
|
||||
)
|
||||
|
||||
choice = await ctx.send(embed=e)
|
||||
|
||||
for reaction in ('1⃣', '2⃣', '3⃣'):
|
||||
await choice.add_reaction(reaction)
|
||||
|
||||
try:
|
||||
payload = await self.bot.wait_for(
|
||||
'raw_reaction_add',
|
||||
check=check,
|
||||
timeout=50.0
|
||||
)
|
||||
except asyncio.TimeoutError:
|
||||
return await ctx.send(
|
||||
Texts('admin', ctx).get('Took too long. Aborting.')
|
||||
)
|
||||
finally:
|
||||
await choice.delete()
|
||||
|
||||
if payload.emoji.name == '1⃣':
|
||||
from jishaku.models import copy_context_with
|
||||
|
||||
alt_ctx = await copy_context_with(
|
||||
ctx,
|
||||
content=f"{ctx.prefix}"
|
||||
f"kick "
|
||||
f"{member} "
|
||||
f"{Texts('admin', ctx).get('More than 2 warns')}"
|
||||
)
|
||||
return await alt_ctx.command.invoke(alt_ctx)
|
||||
|
||||
elif payload.emoji.name == '2⃣':
|
||||
from jishaku.models import copy_context_with
|
||||
|
||||
alt_ctx = await copy_context_with(
|
||||
ctx,
|
||||
content=f"{ctx.prefix}"
|
||||
f"ban "
|
||||
f"{member} "
|
||||
f"{Texts('admin', ctx).get('More than 2 warns')}"
|
||||
)
|
||||
return await alt_ctx.command.invoke(alt_ctx)
|
||||
|
||||
await self.add_warn(ctx, member, reason)
|
||||
await ctx.send(
|
||||
content=f"{member.mention} "
|
||||
f"**{Texts('admin', ctx).get('got a warn')}**"
|
||||
f"\n**{Texts('admin', ctx).get('Reason')}:** `{reason}`"
|
||||
)
|
||||
|
||||
@_warn.command(name='remove', aliases=['revoke', 'del', 'delete'])
|
||||
async def _warn_remove(self, ctx: commands.Context, warn_id: int):
|
||||
warn = self.bot.database.session \
|
||||
.query(WarnModel) \
|
||||
.filter(WarnModel.id == warn_id) \
|
||||
.one()
|
||||
|
||||
self.bot.database.session.delete(warn)
|
||||
|
||||
await ctx.send(f"{Texts('admin', ctx).get('Warn with id')} `{warn_id}`"
|
||||
f" {Texts('admin', ctx).get('successfully removed')}")
|
||||
|
||||
@_warn.command(name='show', aliases=['list', 'all'])
|
||||
async def _warn_show(self, ctx: commands.Context, member: discord.Member):
|
||||
warns_list, warns = await self.get_warn(ctx, member)
|
||||
|
||||
e = discord.Embed(
|
||||
title=f"{warns.count()} {Texts('admin', ctx).get('last warns')}: ",
|
||||
description=warns_list
|
||||
)
|
||||
|
||||
await ctx.send(embed=e)
|
||||
|
||||
@_warn.command(name='edit', aliases=['change', 'modify'])
|
||||
async def _warn_edit(self, ctx: commands.Context, warn_id: int, *, reason):
|
||||
warn = self.bot.database.session \
|
||||
.query(WarnModel) \
|
||||
.filter(WarnModel.id == warn_id) \
|
||||
.one()
|
||||
warn.reason = reason
|
||||
|
||||
self.bot.database.session.commit()
|
||||
|
||||
await ctx.send(f"{Texts('admin', ctx).get('Warn with id')} `{warn_id}`"
|
||||
f" {Texts('admin', ctx).get('successfully edited')}")
|
||||
|
||||
###########################################################################
|
||||
|
||||
@command_extra(name='language', aliases=['lang', 'langue', 'langage'], category='server')
|
||||
async def _language(self, ctx: commands.Context, locale: str):
|
||||
available = self.bot.database.session \
|
||||
.query(LangModel.value) \
|
||||
.filter(LangModel.key == 'available') \
|
||||
.first()[0] \
|
||||
.split(',')
|
||||
|
||||
if locale.lower() not in available:
|
||||
await ctx.send(
|
||||
Texts('admin', ctx).get('Unable to find this language'))
|
||||
else:
|
||||
current = self.bot.database.session \
|
||||
.query(LangModel) \
|
||||
.filter(LangModel.key == str(ctx.guild.id))
|
||||
|
||||
if current.count() > 0:
|
||||
current = current.one()
|
||||
current.value = locale.lower()
|
||||
self.bot.database.session.commit()
|
||||
else:
|
||||
new_row = LangModel(key=str(ctx.guild.id),
|
||||
value=locale.lower())
|
||||
self.bot.database.session.add(new_row)
|
||||
self.bot.database.session.commit()
|
||||
|
||||
await ctx.send(
|
||||
Texts('admin', ctx).get('Language changed successfully'))
|
||||
|
||||
###########################################################################
|
||||
|
||||
@group_extra(name='prefix', aliases=['prefixes'], category='server')
|
||||
async def _prefix(self, ctx: commands.Context):
|
||||
if ctx.invoked_subcommand is None:
|
||||
await ctx.send_help('prefix')
|
||||
|
||||
@_prefix.command(name='add', aliases=['set', 'new'])
|
||||
async def _prefix_add(self, ctx: commands.Context, prefix: str):
|
||||
if str(ctx.guild.id) in self.bot.prefixes:
|
||||
prefixes = self.bot.prefixes.get(
|
||||
str(ctx.guild.id), "prefixes"
|
||||
).split(
|
||||
self.bot.config.get("misc", "separator")
|
||||
)
|
||||
|
||||
if prefix in prefixes:
|
||||
return await ctx.send(
|
||||
Texts('admin', ctx).get('This prefix already exists')
|
||||
)
|
||||
else:
|
||||
prefixes.append(prefix)
|
||||
self.bot.prefixes.set(
|
||||
str(ctx.guild.id),
|
||||
"prefixes",
|
||||
self.bot.config.get("misc", "separator")
|
||||
.join(prefixes)
|
||||
)
|
||||
with open('./configs/prefixes.cfg', 'w') as configfile:
|
||||
self.bot.prefixes.write(configfile)
|
||||
else:
|
||||
self.bot.prefixes.add_section(str(ctx.guild.id))
|
||||
self.bot.prefixes.set(str(ctx.guild.id), "prefixes", prefix)
|
||||
with open('./configs/prefixes.cfg', 'w') as configfile:
|
||||
self.bot.prefixes.write(configfile)
|
||||
|
||||
await ctx.send(
|
||||
Texts('admin', ctx).get('Prefix added successfully')
|
||||
)
|
||||
|
||||
@_prefix.command(name='remove', aliases=['drop', 'del', 'delete'])
|
||||
async def _prefix_remove(self, ctx: commands.Context, prefix: str):
|
||||
if str(ctx.guild.id) in self.bot.prefixes:
|
||||
prefixes = self.bot.prefixes.get(
|
||||
str(ctx.guild.id), "prefixes"
|
||||
).split(
|
||||
self.bot.config.get("misc", "separator")
|
||||
)
|
||||
|
||||
if prefix in prefixes:
|
||||
prefixes.remove(prefix)
|
||||
self.bot.prefixes.set(
|
||||
str(ctx.guild.id),
|
||||
"prefixes",
|
||||
self.bot.config.get("misc", "separator")
|
||||
.join(prefixes)
|
||||
)
|
||||
with open('./configs/prefixes.cfg', 'w') as configfile:
|
||||
self.bot.prefixes.write(configfile)
|
||||
|
||||
return await ctx.send(
|
||||
Texts('admin', ctx).get('Prefix removed successfully')
|
||||
)
|
||||
|
||||
await ctx.send(
|
||||
Texts('admin', ctx).get('This prefix does not exist')
|
||||
)
|
||||
|
||||
@_prefix.command(name='list', aliases=['show', 'all'])
|
||||
async def _prefix_list(self, ctx: commands.Context):
|
||||
extras = ['.']
|
||||
if ctx.message.guild is not None:
|
||||
extras = []
|
||||
if str(ctx.message.guild.id) in self.bot.prefixes:
|
||||
extras.extend(
|
||||
self.bot.prefixes.get(str(ctx.message.guild.id),
|
||||
"prefixes").split(
|
||||
self.bot.config.get("misc", "separator")
|
||||
)
|
||||
)
|
||||
|
||||
prefixes = [self.bot.user.mention]
|
||||
prefixes.extend(extras)
|
||||
|
||||
if len(prefixes) <= 1:
|
||||
text = Texts('admin', ctx) \
|
||||
.get('The only prefix for this guild is :\n')
|
||||
else:
|
||||
text = Texts('admin', ctx) \
|
||||
.get('Available prefixes for this guild are :\n')
|
||||
|
||||
await ctx.send(text + "\n • ".join(prefixes))
|
||||
|
||||
|
||||
def setup(bot: TuxBot):
|
||||
bot.add_cog(Admin(bot))
|
227
cogs/Help.py
227
cogs/Help.py
|
@ -1,227 +0,0 @@
|
|||
# Created by romain at 04/01/2020
|
||||
|
||||
import logging
|
||||
|
||||
import discord
|
||||
from discord.ext import commands
|
||||
|
||||
from bot import TuxBot
|
||||
from utils import Texts, GroupPlus
|
||||
from utils import FieldPages
|
||||
|
||||
log = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class HelpCommand(commands.HelpCommand):
|
||||
def __init__(self, *args, **kwargs):
|
||||
super().__init__(*args, **kwargs)
|
||||
self.ignore_cogs = ["Monitoring", "Help", "Jishaku"]
|
||||
self.owner_cogs = []
|
||||
self.admin_cogs = ["Admin"]
|
||||
|
||||
def command_formatting(self, e, command):
|
||||
prefix = self.context.prefix \
|
||||
if str(self.context.bot.user.id) not in self.context.prefix \
|
||||
else f"@{self.context.bot.user.name}"
|
||||
file = Texts(command.cog.qualified_name.lower() + '_help', self.context)
|
||||
|
||||
if command.parent is not None:
|
||||
description = file.get(f"_{command.parent}_{command.name}")
|
||||
usage = file.get(f"_{command.parent}_{command.name}__usage")
|
||||
else:
|
||||
description = file.get(f"_{command.name}")
|
||||
usage = file.get(f"_{command.name}__usage")
|
||||
|
||||
e.title = self.get_command_signature(command) + usage
|
||||
e.description = description
|
||||
|
||||
e.add_field(
|
||||
name=Texts(
|
||||
'help', self.context
|
||||
).get(
|
||||
'command_help.params'
|
||||
),
|
||||
value=usage
|
||||
)
|
||||
e.add_field(
|
||||
name=Texts(
|
||||
'help', self.context
|
||||
).get(
|
||||
'command_help.usage'
|
||||
),
|
||||
value=f"{prefix}{command.qualified_name} " + usage
|
||||
)
|
||||
|
||||
aliases = "`" + '`, `'.join(command.aliases) + "`"
|
||||
if aliases == "``":
|
||||
aliases = Texts(
|
||||
'help', self.context
|
||||
).get(
|
||||
'command_help.no_aliases'
|
||||
)
|
||||
e.add_field(
|
||||
name=Texts(
|
||||
'help', self.context
|
||||
).get(
|
||||
'command_help.aliases'
|
||||
),
|
||||
value=aliases
|
||||
)
|
||||
|
||||
return e
|
||||
|
||||
async def send_bot_help(self, mapping):
|
||||
owners = self.context.bot.owners
|
||||
prefix = self.context.prefix \
|
||||
if str(self.context.bot.user.id) not in self.context.prefix \
|
||||
else f"@{self.context.bot.user.name} "
|
||||
|
||||
e = discord.Embed(
|
||||
color=discord.Color.blue(),
|
||||
description=Texts(
|
||||
'help', self.context
|
||||
).get(
|
||||
'main_page.description'
|
||||
)
|
||||
)
|
||||
e.set_author(
|
||||
icon_url=self.context.author.avatar_url_as(format='png'),
|
||||
name=self.context.author
|
||||
)
|
||||
e.set_footer(
|
||||
text=Texts(
|
||||
'help', self.context
|
||||
).get(
|
||||
'main_page.footer'
|
||||
).format(
|
||||
prefix
|
||||
)
|
||||
)
|
||||
|
||||
for extension in self.context.bot.cogs.values():
|
||||
if self.context.author not in owners \
|
||||
and extension.__class__.__name__ in self.owner_cogs:
|
||||
continue
|
||||
if extension.__class__.__name__ in self.ignore_cogs:
|
||||
continue
|
||||
|
||||
count = len(extension.get_commands())
|
||||
text = Texts('help', self.context).get('main_page.commands')
|
||||
|
||||
if count <= 1:
|
||||
text = text[:-1]
|
||||
|
||||
e.add_field(
|
||||
name=f"__{extension.icon} **{extension.qualified_name}**__",
|
||||
value=f"{count} {text}"
|
||||
)
|
||||
|
||||
await self.context.send(embed=e)
|
||||
|
||||
async def send_cog_help(self, cog):
|
||||
pages = {}
|
||||
prefix = self.context.prefix \
|
||||
if str(self.context.bot.user.id) not in self.context.prefix \
|
||||
else f"@{self.context.bot.user.name}"
|
||||
file = Texts(cog.qualified_name.lower() + '_help', self.context)
|
||||
|
||||
if cog.__class__.__name__ in self.owner_cogs \
|
||||
and self.context.author not in self.context.bot.owners:
|
||||
return self.command_not_found(cog.qualified_name)
|
||||
|
||||
for cmd in cog.get_commands():
|
||||
if self.context.author not in self.context.bot.owners \
|
||||
and (cmd.hidden or cmd.category == "Hidden"):
|
||||
continue
|
||||
|
||||
if cmd.category not in pages:
|
||||
pages[cmd.category] = "```asciidoc\n"
|
||||
|
||||
pages[cmd.category] \
|
||||
+= f"{cmd.name}" \
|
||||
+ ' ' * int(13 - len(cmd.name)) \
|
||||
+ f":: {file.get(f'_{cmd.name}__short')}\n"
|
||||
|
||||
if isinstance(cmd, GroupPlus):
|
||||
for group_command in cmd.commands:
|
||||
pages[cmd.category] \
|
||||
+= f"└> {group_command.name}" \
|
||||
+ ' ' * int(10 - len(group_command.name)) \
|
||||
+ f":: {file.get(f'_{group_command.parent}_{group_command.name}__short')}\n"
|
||||
for e in pages:
|
||||
pages[e] += "```"
|
||||
formatted = []
|
||||
for name, cont in pages.items():
|
||||
formatted.append((name, cont))
|
||||
footer_text = Texts('help', self.context) \
|
||||
.get('main_page.footer') \
|
||||
.format(prefix)
|
||||
|
||||
pages = FieldPages(
|
||||
self.context,
|
||||
embed_color=discord.Color.blue(),
|
||||
entries=formatted,
|
||||
title=cog.qualified_name.upper(),
|
||||
thumbnail=cog.big_icon,
|
||||
footericon=self.context.bot.user.avatar_url,
|
||||
footertext=footer_text,
|
||||
per_page=1
|
||||
)
|
||||
await pages.paginate()
|
||||
|
||||
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)
|
||||
)
|
||||
file = Texts(group.qualified_name.lower() + '_help', self.context)
|
||||
|
||||
formatted = self.command_formatting(
|
||||
discord.Embed(color=discord.Color.blue()),
|
||||
group
|
||||
)
|
||||
sub_command_list = "⠀" # this is braille, please don't touch unless you know what you're doing
|
||||
for group_command in group.commands:
|
||||
sub_command_list += f"└> **{group_command.name}** - {file.get(f'_{group_command.parent}_{group_command.name}')}\n"
|
||||
|
||||
subcommands = Texts(
|
||||
'help', self.context
|
||||
).get(
|
||||
'command_help.subcommands'
|
||||
)
|
||||
|
||||
formatted.add_field(name=subcommands, value=sub_command_list, inline=False)
|
||||
await self.context.send(embed=formatted)
|
||||
|
||||
async def send_command_help(self, command):
|
||||
if isinstance(command, commands.Group):
|
||||
return await self.send_group_help(command)
|
||||
|
||||
if command.cog_name in self.ignore_cogs:
|
||||
return await self.send_error_message(
|
||||
self.command_not_found(command.name))
|
||||
|
||||
formatted = self.command_formatting(
|
||||
discord.Embed(color=discord.Color.blue()),
|
||||
command
|
||||
)
|
||||
|
||||
await self.context.send(embed=formatted)
|
||||
|
||||
def command_not_found(self, command):
|
||||
return Texts(
|
||||
'help', self.context
|
||||
).get(
|
||||
'main_page.not_found'
|
||||
).format(
|
||||
command
|
||||
)
|
||||
|
||||
|
||||
class Help(commands.Cog):
|
||||
def __init__(self, bot: TuxBot):
|
||||
bot.help_command = HelpCommand()
|
||||
|
||||
|
||||
def setup(bot: TuxBot):
|
||||
bot.add_cog(Help(bot))
|
180
cogs/Images.py
Normal file
180
cogs/Images.py
Normal file
|
@ -0,0 +1,180 @@
|
|||
import logging
|
||||
from io import BytesIO
|
||||
|
||||
import discord
|
||||
from discord.ext import commands, flags
|
||||
|
||||
from app import TuxBot
|
||||
from utils.functions.extra import ContextPlus
|
||||
|
||||
log = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class Images(commands.Cog, name="Images"):
|
||||
def __init__(self, bot):
|
||||
self.bot = bot
|
||||
self.image_api = "http://0.0.0.0:8080"
|
||||
|
||||
async def _send_meme(self, ctx: ContextPlus, endpoint: str, **passed_flags):
|
||||
async with ctx.typing():
|
||||
url = f"{self.image_api}/{endpoint}?"
|
||||
for key, val in passed_flags.items():
|
||||
if val:
|
||||
url += f"{key}={val}&"
|
||||
|
||||
async with self.bot.session.get(url) as r:
|
||||
if r.status != 200:
|
||||
return await ctx.send("Failed...")
|
||||
|
||||
data = BytesIO(await r.read())
|
||||
|
||||
await ctx.send(
|
||||
file=discord.File(data, "output.png")
|
||||
)
|
||||
|
||||
@commands.command(name="phcomment")
|
||||
@commands.cooldown(1, 5, commands.BucketType.user)
|
||||
async def _phcomment(self, ctx: ContextPlus, user: discord.User = None, *, message: commands.clean_content(fix_channel_mentions=True, escape_markdown=True)):
|
||||
async with ctx.typing():
|
||||
message = message.replace("&", "%26")
|
||||
if user is None:
|
||||
avatar = ctx.author.avatar_url_as(format='png')
|
||||
username = ctx.author.name
|
||||
else:
|
||||
avatar = user.avatar_url_as(format='png')
|
||||
username = user.name
|
||||
|
||||
url = f"{self.image_api}/ph/comment" \
|
||||
f"?image={avatar}" \
|
||||
f"&username={username}" \
|
||||
f"&message={message}"
|
||||
|
||||
async with self.bot.session.get(url) as r:
|
||||
if r.status != 200:
|
||||
return await ctx.send("Failed...")
|
||||
|
||||
data = BytesIO(await r.read())
|
||||
|
||||
await ctx.send(
|
||||
file=discord.File(data, "output.png")
|
||||
)
|
||||
|
||||
@commands.command(name="phvideo")
|
||||
@commands.cooldown(1, 5, commands.BucketType.user)
|
||||
async def _phvideo(self, ctx: ContextPlus, image: str, author: discord.User, *, title: commands.clean_content(fix_channel_mentions=True, escape_markdown=True)):
|
||||
async with ctx.typing():
|
||||
url = f"{self.image_api}/ph/video" \
|
||||
f"?image={image}" \
|
||||
f"&username={author.name}" \
|
||||
f"&title={title}"
|
||||
|
||||
async with self.bot.session.get(url) as r:
|
||||
if r.status != 200:
|
||||
return await ctx.send("Failed...")
|
||||
|
||||
data = BytesIO(await r.read())
|
||||
|
||||
await ctx.send(
|
||||
file=discord.File(data, "output.png")
|
||||
)
|
||||
|
||||
@flags.add_flag("--text1", type=str)
|
||||
@flags.add_flag("--text2", type=str)
|
||||
@flags.add_flag("--text3", type=str)
|
||||
@flags.command(name="balloon")
|
||||
@commands.cooldown(1, 5, commands.BucketType.user)
|
||||
async def _balloon(self, ctx: ContextPlus, **passed_flags):
|
||||
passed_flags["text3"] = passed_flags.get("text3")
|
||||
passed_flags["text4"] = passed_flags.get("text1")
|
||||
passed_flags["text5"] = passed_flags.get("text2")
|
||||
|
||||
await self._send_meme(ctx, 'balloon', **passed_flags)
|
||||
|
||||
@flags.add_flag("--text1", type=str)
|
||||
@flags.add_flag("--text2", type=str)
|
||||
@flags.add_flag("--text3", type=str)
|
||||
@flags.command(name="butterfly")
|
||||
@commands.cooldown(1, 5, commands.BucketType.user)
|
||||
async def _butterfly(self, ctx: ContextPlus, **passed_flags):
|
||||
await self._send_meme(ctx, 'butterfly', **passed_flags)
|
||||
|
||||
@flags.add_flag("--text1", type=str)
|
||||
@flags.add_flag("--text2", type=str)
|
||||
@flags.command(name="buttons")
|
||||
@commands.cooldown(1, 5, commands.BucketType.user)
|
||||
async def _buttons(self, ctx: ContextPlus, **passed_flags):
|
||||
await self._send_meme(ctx, 'buttons', **passed_flags)
|
||||
|
||||
@flags.add_flag("--text1", type=str)
|
||||
@flags.command(name="cmm")
|
||||
@commands.cooldown(1, 5, commands.BucketType.user)
|
||||
async def _cmm(self, ctx: ContextPlus, **passed_flags):
|
||||
await self._send_meme(ctx, 'change_my_mind', **passed_flags)
|
||||
|
||||
@flags.add_flag("--text1", type=str)
|
||||
@flags.add_flag("--text2", type=str)
|
||||
@flags.command(name="drake")
|
||||
@commands.cooldown(1, 5, commands.BucketType.user)
|
||||
async def _drake(self, ctx: ContextPlus, **passed_flags):
|
||||
await self._send_meme(ctx, 'drake', **passed_flags)
|
||||
|
||||
@flags.add_flag("--text1", type=str)
|
||||
@flags.add_flag("--text2", type=str, default=False)
|
||||
@flags.command(name="fry")
|
||||
@commands.cooldown(1, 5, commands.BucketType.user)
|
||||
async def _fry(self, ctx: ContextPlus, **passed_flags):
|
||||
await self._send_meme(ctx, 'fry', **passed_flags)
|
||||
|
||||
@flags.add_flag("--text1", type=str)
|
||||
@flags.add_flag("--text2", type=str, default=False)
|
||||
@flags.command(name="imagination")
|
||||
@commands.cooldown(1, 5, commands.BucketType.user)
|
||||
async def _imagination(self, ctx: ContextPlus, **passed_flags):
|
||||
await self._send_meme(ctx, 'imagination', **passed_flags)
|
||||
|
||||
@flags.add_flag("--text1", type=str)
|
||||
@flags.add_flag("--text2", type=str, default=False)
|
||||
@flags.command(name="everywhere")
|
||||
@commands.cooldown(1, 5, commands.BucketType.user)
|
||||
async def _everywhere(self, ctx: ContextPlus, **passed_flags):
|
||||
await self._send_meme(ctx, 'everywhere', **passed_flags)
|
||||
|
||||
@flags.add_flag("--text1", type=str)
|
||||
@flags.add_flag("--text2", type=str)
|
||||
@flags.add_flag("--text3", type=str)
|
||||
@flags.command(name="choice")
|
||||
@commands.cooldown(1, 5, commands.BucketType.user)
|
||||
async def _choice(self, ctx: ContextPlus, **passed_flags):
|
||||
await self._send_meme(ctx, 'choice', **passed_flags)
|
||||
|
||||
@flags.add_flag("--text1", type=str)
|
||||
@flags.command(name="pika")
|
||||
@commands.cooldown(1, 5, commands.BucketType.user)
|
||||
async def _pika(self, ctx: ContextPlus, **passed_flags):
|
||||
await self._send_meme(ctx, 'pika', **passed_flags)
|
||||
|
||||
@flags.add_flag("--text1", type=str)
|
||||
@flags.add_flag("--text2", type=str)
|
||||
@flags.add_flag("--text3", type=str)
|
||||
@flags.command(name="pkp")
|
||||
@commands.cooldown(1, 5, commands.BucketType.user)
|
||||
async def _pkp(self, ctx: ContextPlus, **passed_flags):
|
||||
await self._send_meme(ctx, 'pkp', **passed_flags)
|
||||
|
||||
@flags.add_flag("--text1", type=str)
|
||||
@flags.add_flag("--text2", type=str)
|
||||
@flags.command(name="puppet")
|
||||
@commands.cooldown(1, 5, commands.BucketType.user)
|
||||
async def _puppet(self, ctx: ContextPlus, **passed_flags):
|
||||
await self._send_meme(ctx, 'puppet', **passed_flags)
|
||||
|
||||
@flags.add_flag("--text1", type=str)
|
||||
@flags.command(name="scroll_of_truth", alias=['sot'])
|
||||
@commands.cooldown(1, 5, commands.BucketType.user)
|
||||
async def _sot(self, ctx: ContextPlus, **passed_flags):
|
||||
await self._send_meme(ctx, 'scroll_of_truth', **passed_flags)
|
||||
|
||||
|
||||
def setup(bot: TuxBot):
|
||||
cog = Images(bot)
|
||||
bot.add_cog(cog)
|
76
cogs/Logs.py
76
cogs/Logs.py
|
@ -18,9 +18,7 @@ import humanize
|
|||
import psutil
|
||||
from discord.ext import commands, tasks
|
||||
|
||||
from bot import TuxBot
|
||||
from utils import Texts
|
||||
from utils import command_extra
|
||||
from app import TuxBot
|
||||
|
||||
log = logging.getLogger(__name__)
|
||||
|
||||
|
@ -52,9 +50,6 @@ class Logs(commands.Cog):
|
|||
self._resumes = []
|
||||
self._identifies = defaultdict(list)
|
||||
|
||||
self.icon = ":newspaper:"
|
||||
self.big_icon = "https://emojipedia-us.s3.dualstack.us-west-1.amazonaws.com/thumbs/120/twitter/233/newspaper_1f4f0.png"
|
||||
|
||||
def _clear_gateway_data(self):
|
||||
one_week_ago = datetime.datetime.utcnow() - datetime.timedelta(days=7)
|
||||
to_remove = [
|
||||
|
@ -112,8 +107,19 @@ class Logs(commands.Cog):
|
|||
self.bot.socket_stats[msg.get('t')] += 1
|
||||
|
||||
@property
|
||||
def webhook(self):
|
||||
return self.bot.logs_webhook
|
||||
def logs(self):
|
||||
webhooks = {}
|
||||
|
||||
for key, value in self.bot.logs_channels.items():
|
||||
webhooks[key] = discord.Webhook.partial(
|
||||
id=value.get('webhook')['id'],
|
||||
token=value.get('webhook')['token'],
|
||||
adapter=discord.AsyncWebhookAdapter(
|
||||
self.bot.session
|
||||
)
|
||||
)
|
||||
|
||||
return webhooks
|
||||
|
||||
async def log_error(self, *, ctx=None, extra=None):
|
||||
e = discord.Embed(title='Error', colour=0xdd5f53)
|
||||
|
@ -131,7 +137,7 @@ class Logs(commands.Cog):
|
|||
e.add_field(name='Channel', value=channel)
|
||||
e.add_field(name='Guild', value=guild)
|
||||
|
||||
await self.webhook.send(embed=e)
|
||||
await self.logs.get('errors').send(embed=e)
|
||||
|
||||
async def send_guild_stats(self, e, guild):
|
||||
e.add_field(name='Name', value=guild.name)
|
||||
|
@ -155,7 +161,7 @@ class Logs(commands.Cog):
|
|||
if guild.me:
|
||||
e.timestamp = guild.me.joined_at
|
||||
|
||||
await self.webhook.send(embed=e)
|
||||
await self.logs.get('guilds').send(embed=e)
|
||||
|
||||
@commands.Cog.listener()
|
||||
async def on_guild_join(self, guild: discord.guild):
|
||||
|
@ -169,17 +175,37 @@ class Logs(commands.Cog):
|
|||
|
||||
@commands.Cog.listener()
|
||||
async def on_message(self, message: discord.message):
|
||||
if message.guild is None:
|
||||
e = discord.Embed(colour=0x0a97f5, title='New DM') # blue colour
|
||||
ctx = await self.bot.get_context(message)
|
||||
if ctx.valid:
|
||||
return
|
||||
|
||||
if isinstance(message.channel, discord.DMChannel):
|
||||
if message.author is self.bot.user:
|
||||
e = discord.Embed(
|
||||
title=f"DM to: {message.channel.recipient}",
|
||||
description=message.content,
|
||||
color=0x39e326
|
||||
)
|
||||
else:
|
||||
e = discord.Embed(
|
||||
title="New DM:",
|
||||
description=message.content,
|
||||
color=0x0A97F5
|
||||
)
|
||||
e.set_author(
|
||||
name=message.author,
|
||||
icon_url=message.author.avatar_url_as(format='png')
|
||||
name=message.channel.recipient,
|
||||
icon_url=message.channel.recipient.avatar_url_as(format="png")
|
||||
)
|
||||
e.description = message.content
|
||||
if len(message.attachments) > 0:
|
||||
e.set_image(url=message.attachments[0].url)
|
||||
e.set_footer(text=f"User ID: {message.author.id}")
|
||||
await self.webhook.send(embed=e)
|
||||
|
||||
if message.attachments:
|
||||
attachment_url = message.attachments[0].url
|
||||
e.set_image(url=attachment_url)
|
||||
|
||||
e.set_footer(
|
||||
text=f"User ID: {message.channel.recipient.id}"
|
||||
)
|
||||
|
||||
await self.logs["dm"].send(embed=e)
|
||||
|
||||
@commands.Cog.listener()
|
||||
async def on_command_error(self, ctx, error):
|
||||
|
@ -212,7 +238,7 @@ class Logs(commands.Cog):
|
|||
)
|
||||
e.description = f'```py\n{exc}\n```'
|
||||
e.timestamp = datetime.datetime.utcnow()
|
||||
await self.webhook.send(embed=e)
|
||||
await self.logs.get('errors').send(embed=e)
|
||||
|
||||
@commands.Cog.listener()
|
||||
async def on_socket_raw_send(self, data):
|
||||
|
@ -241,9 +267,9 @@ class Logs(commands.Cog):
|
|||
emoji = types.get(record.levelname, ':heavy_multiplication_x:')
|
||||
dt = datetime.datetime.utcfromtimestamp(record.created)
|
||||
msg = f'{emoji} `[{dt:%Y-%m-%d %H:%M:%S}] {record.message}`'
|
||||
await self.webhook.send(msg)
|
||||
await self.logs.get('gateway').send(msg)
|
||||
|
||||
@command_extra(name='commandstats', hidden=True, category='misc')
|
||||
@commands.command('commandstats')
|
||||
@commands.is_owner()
|
||||
async def _commandstats(self, ctx, limit=20):
|
||||
counter = self.bot.command_stats
|
||||
|
@ -258,7 +284,7 @@ class Logs(commands.Cog):
|
|||
|
||||
await ctx.send(f'```\n{output}\n```')
|
||||
|
||||
@command_extra(name='socketstats', hidden=True, category='misc')
|
||||
@commands.command('socketstats')
|
||||
@commands.is_owner()
|
||||
async def _socketstats(self, ctx):
|
||||
delta = datetime.datetime.utcnow() - self.bot.uptime
|
||||
|
@ -268,7 +294,7 @@ class Logs(commands.Cog):
|
|||
await ctx.send(
|
||||
f'{total} socket events observed ({cpm:.2f}/minute):\n{self.bot.socket_stats}')
|
||||
|
||||
@command_extra(name='uptime', category='misc')
|
||||
@commands.command('uptime')
|
||||
async def _uptime(self, ctx):
|
||||
uptime = humanize.naturaltime(
|
||||
datetime.datetime.utcnow() - self.bot.uptime)
|
||||
|
@ -287,7 +313,7 @@ async def on_error(self, event, *args):
|
|||
args_str.append('```')
|
||||
e.add_field(name='Args', value='\n'.join(args_str), inline=False)
|
||||
|
||||
hook = self.get_cog('Logs').webhook
|
||||
hook = self.get_cog('Logs').logs.get('errors')
|
||||
try:
|
||||
await hook.send(embed=e)
|
||||
except (discord.HTTPException, discord.NotFound,
|
||||
|
|
|
@ -1,110 +0,0 @@
|
|||
import logging
|
||||
import urllib.request
|
||||
from datetime import datetime
|
||||
|
||||
import discord
|
||||
from aiohttp import web
|
||||
from discord.ext import tasks, commands
|
||||
|
||||
from bot import TuxBot
|
||||
|
||||
log = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class Monitoring(commands.Cog):
|
||||
|
||||
def __init__(self, bot: TuxBot):
|
||||
self.bot = bot
|
||||
self.site = web.TCPSite
|
||||
|
||||
self.ping_clusters.start()
|
||||
|
||||
app = web.Application()
|
||||
app.add_routes([web.get('/', self.handle)])
|
||||
|
||||
self.runner = web.AppRunner(app)
|
||||
self.bot.loop.create_task(self.start_HTTPMonitoring_server())
|
||||
|
||||
def cog_unload(self):
|
||||
self.ping_clusters.stop()
|
||||
|
||||
@tasks.loop(seconds=10.0)
|
||||
async def ping_clusters(self):
|
||||
for cluster in self.bot.fallbacks:
|
||||
if cluster == 'DEFAULT':
|
||||
pass
|
||||
else:
|
||||
cluster = self.bot.fallbacks[cluster]
|
||||
if not cluster.get('This', False):
|
||||
host = cluster.get('Host')
|
||||
port = cluster.get('Port')
|
||||
|
||||
try:
|
||||
req = urllib.request.urlopen(
|
||||
f"http://{host}:{port}",
|
||||
timeout=2
|
||||
)
|
||||
except Exception:
|
||||
global_channel = await self.bot.fetch_channel(
|
||||
661347412463321098
|
||||
)
|
||||
|
||||
e = discord.Embed(
|
||||
title=f"Server `{cluster.get('Name')}`",
|
||||
color=discord.colour.Color.red(),
|
||||
description=f"Server **`{cluster.get('Name')}`** with address **`http://{host}:{port}`** is down ! ",
|
||||
timestamp=datetime.now()
|
||||
)
|
||||
e.set_thumbnail(
|
||||
url='https://upload.wikimedia.org/wikipedia/commons/7/75/Erroricon404.PNG'
|
||||
)
|
||||
|
||||
await global_channel.send(embed=e)
|
||||
else:
|
||||
print(req.read().decode())
|
||||
|
||||
@ping_clusters.before_loop
|
||||
async def before_pinging(self):
|
||||
await self.bot.wait_until_ready()
|
||||
|
||||
cluster = self.bot.cluster
|
||||
host = cluster.get('Host')
|
||||
port = cluster.get('Port')
|
||||
|
||||
global_channel = await self.bot.fetch_channel(
|
||||
661347412463321098
|
||||
)
|
||||
|
||||
e = discord.Embed(
|
||||
title=f"Server `{cluster.get('Name')}`",
|
||||
color=discord.colour.Color.green(),
|
||||
description=f"Server **`{cluster.get('Name')}`** with address **`http://{host}:{port}`** is started ! ",
|
||||
timestamp=datetime.now()
|
||||
)
|
||||
e.set_thumbnail(
|
||||
url='https://upload.wikimedia.org/wikipedia/commons/thumb/d/d1/MW-Icon-CheckMark.svg/1024px-MW-Icon-CheckMark.svg.png'
|
||||
)
|
||||
|
||||
await global_channel.send(embed=e)
|
||||
|
||||
async def start_HTTPMonitoring_server(self):
|
||||
host = self.bot.cluster.get('WebPage')
|
||||
port = self.bot.cluster.get('Port')
|
||||
|
||||
print(f"Starting HTTP Monitoring server on {host}:{port}")
|
||||
|
||||
await self.runner.setup()
|
||||
self.site = web.TCPSite(self.runner, host, port)
|
||||
await self.site.start()
|
||||
|
||||
async def handle(self, _):
|
||||
return web.json_response(
|
||||
{
|
||||
'message': "I'm alive !",
|
||||
'ws': self.bot.latency * 1000
|
||||
}
|
||||
)
|
||||
|
||||
|
||||
def setup(bot: TuxBot):
|
||||
bot.add_cog(Monitoring(bot))
|
222
cogs/Poll.py
222
cogs/Poll.py
|
@ -1,222 +0,0 @@
|
|||
import json
|
||||
import logging
|
||||
from typing import Union
|
||||
|
||||
import discord
|
||||
from discord.ext import commands
|
||||
from yarl import URL
|
||||
|
||||
from bot import TuxBot
|
||||
from utils import PollModel, ResponsesModel
|
||||
from utils import Texts
|
||||
from utils.functions import emotes as utils_emotes
|
||||
from utils import group_extra
|
||||
|
||||
log = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class Poll(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:
|
||||
poll = self.bot.database.session \
|
||||
.query(PollModel) \
|
||||
.filter(PollModel.message_id == pld.message_id)
|
||||
|
||||
if poll.count() > 0:
|
||||
poll = poll.one()
|
||||
emotes = utils_emotes.get(poll.available_choices)
|
||||
if pld.emoji.name in emotes:
|
||||
return poll
|
||||
|
||||
return False
|
||||
|
||||
async def remove_reaction(self, pld):
|
||||
channel: discord.TextChannel = self.bot.get_channel(pld.channel_id)
|
||||
message: discord.Message = await channel.fetch_message(pld.message_id)
|
||||
user: discord.User = await self.bot.fetch_user(pld.user_id)
|
||||
|
||||
await message.remove_reaction(pld.emoji.name, user)
|
||||
|
||||
@commands.Cog.listener()
|
||||
async def on_raw_reaction_add(self, pld: discord.RawReactionActionEvent):
|
||||
poll = self.get_poll(pld)
|
||||
|
||||
if poll:
|
||||
if poll.is_anonymous:
|
||||
try:
|
||||
await self.remove_reaction(pld)
|
||||
except discord.errors.Forbidden:
|
||||
pass
|
||||
choice = utils_emotes.get_index(pld.emoji.name)
|
||||
|
||||
responses = self.bot.database.session.query(ResponsesModel) \
|
||||
.filter(
|
||||
ResponsesModel.poll_id == poll.id,
|
||||
ResponsesModel.user == pld.user_id,
|
||||
ResponsesModel.choice == choice
|
||||
)
|
||||
|
||||
if responses.count() != 0:
|
||||
response = responses.first()
|
||||
self.bot.database.session.delete(response)
|
||||
self.bot.database.session.commit()
|
||||
else:
|
||||
response = ResponsesModel(
|
||||
user=pld.user_id,
|
||||
poll_id=poll.id,
|
||||
choice=choice
|
||||
)
|
||||
self.bot.database.session.add(response)
|
||||
self.bot.database.session.commit()
|
||||
|
||||
await self.update_poll(poll.id)
|
||||
|
||||
@commands.Cog.listener()
|
||||
async def on_raw_reaction_remove(self,
|
||||
pld: discord.RawReactionActionEvent):
|
||||
poll = self.get_poll(pld)
|
||||
|
||||
if poll:
|
||||
choice = utils_emotes.get_index(pld.emoji.name)
|
||||
|
||||
responses = self.bot.database.session.query(ResponsesModel) \
|
||||
.filter(
|
||||
ResponsesModel.poll_id == poll.id,
|
||||
ResponsesModel.user == pld.user_id,
|
||||
ResponsesModel.choice == choice
|
||||
)
|
||||
|
||||
if responses.count() != 0:
|
||||
response = responses.first()
|
||||
self.bot.database.session.delete(response)
|
||||
self.bot.database.session.commit()
|
||||
await self.update_poll(poll.id)
|
||||
|
||||
###########################################################################
|
||||
|
||||
async def create_poll(self, ctx: commands.Context, poll: str, anonymous):
|
||||
question = (poll.split('|')[0]).strip()
|
||||
responses = [response.strip() for response in poll.split('|')[1:]]
|
||||
emotes = utils_emotes.get(len(responses))
|
||||
|
||||
stmt = await ctx.send(Texts('poll', ctx).get('**Preparation...**'))
|
||||
|
||||
poll_row = PollModel()
|
||||
self.bot.database.session.add(poll_row)
|
||||
self.bot.database.session.flush()
|
||||
|
||||
e = discord.Embed(description=f"**{question}**")
|
||||
e.set_author(
|
||||
name=ctx.author,
|
||||
icon_url="https://cdn.gnous.eu/tuxbot/survey1.png"
|
||||
)
|
||||
for i, response in enumerate(responses):
|
||||
e.add_field(
|
||||
name=f"__{emotes[i]}` - {response.capitalize()}`__",
|
||||
value="**0** vote"
|
||||
)
|
||||
e.set_footer(text=f"ID: #{poll_row.id}")
|
||||
|
||||
poll_row.channel_id = stmt.channel.id
|
||||
poll_row.message_id = stmt.id
|
||||
poll_row.content = e.to_dict()
|
||||
poll_row.is_anonymous = anonymous
|
||||
poll_row.available_choices = len(responses)
|
||||
|
||||
self.bot.database.session.commit()
|
||||
|
||||
await stmt.edit(content='', embed=e)
|
||||
for emote in range(len(responses)):
|
||||
await stmt.add_reaction(emotes[emote])
|
||||
|
||||
async def update_poll(self, poll_id: int):
|
||||
poll = self.bot.database.session \
|
||||
.query(PollModel) \
|
||||
.filter(PollModel.id == poll_id) \
|
||||
.one()
|
||||
channel: discord.TextChannel = self.bot.get_channel(poll.channel_id)
|
||||
message: discord.Message = await channel.fetch_message(poll.message_id)
|
||||
|
||||
chart_base_url = "https://quickchart.io/chart?backgroundColor=white&c="
|
||||
chart_options = {
|
||||
'type': 'pie',
|
||||
'data': {
|
||||
'labels': [],
|
||||
'datasets': [
|
||||
{
|
||||
'data': []
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
content = json.loads(poll.content) \
|
||||
if isinstance(poll.content, str) \
|
||||
else poll.content
|
||||
raw_responses = self.bot.database.session \
|
||||
.query(ResponsesModel) \
|
||||
.filter(ResponsesModel.poll_id == poll_id)
|
||||
responses = {}
|
||||
|
||||
for response in raw_responses.all():
|
||||
if responses.get(response.choice):
|
||||
responses[response.choice] += 1
|
||||
else:
|
||||
responses[response.choice] = 1
|
||||
|
||||
for i, field in enumerate(content.get('fields')):
|
||||
responders = responses.get(i, 0)
|
||||
chart_options.get('data') \
|
||||
.get('labels') \
|
||||
.append(field.get('name')[5:].replace('__', ''))
|
||||
chart_options.get('data') \
|
||||
.get('datasets')[0] \
|
||||
.get('data') \
|
||||
.append(responders)
|
||||
|
||||
if responders <= 1:
|
||||
field['value'] = f"**{responders}** vote"
|
||||
else:
|
||||
field['value'] = f"**{responders}** votes"
|
||||
|
||||
e = discord.Embed(description=content.get('description'))
|
||||
e.set_author(
|
||||
name=content.get('author').get('name'),
|
||||
icon_url=content.get('author').get('icon_url')
|
||||
)
|
||||
chart_url = URL(chart_base_url + json.dumps(chart_options))
|
||||
e.set_thumbnail(url=str(chart_url))
|
||||
for field in content.get('fields'):
|
||||
e.add_field(
|
||||
name=field.get('name'),
|
||||
value=field.get('value'),
|
||||
inline=True
|
||||
)
|
||||
e.set_footer(text=content.get('footer').get('text'))
|
||||
|
||||
await message.edit(embed=e)
|
||||
|
||||
poll.content = json.dumps(content)
|
||||
self.bot.database.session.commit()
|
||||
|
||||
@group_extra(name='poll', aliases=['sondage'], category='poll')
|
||||
async def _poll(self, ctx: commands.Context):
|
||||
if ctx.invoked_subcommand is None:
|
||||
await ctx.send_help('poll')
|
||||
|
||||
@_poll.group(name='create', aliases=['new', 'nouveau'])
|
||||
async def _poll_create(self, ctx: commands.Context, *, poll: str):
|
||||
is_anonymous = '--anonyme' in poll
|
||||
poll = poll.replace('--anonyme', '')
|
||||
|
||||
await self.create_poll(ctx, poll, anonymous=is_anonymous)
|
||||
|
||||
|
||||
def setup(bot: TuxBot):
|
||||
bot.add_cog(Poll(bot))
|
410
cogs/Useful.py
410
cogs/Useful.py
|
@ -1,410 +0,0 @@
|
|||
# Created by romain at 04/01/2020
|
||||
import logging
|
||||
import os
|
||||
import pathlib
|
||||
import platform
|
||||
import random
|
||||
import re
|
||||
import socket
|
||||
import time
|
||||
from socket import AF_INET6
|
||||
from io import BytesIO
|
||||
from PIL import Image
|
||||
from PIL import ImageFont
|
||||
from PIL import ImageDraw
|
||||
from PIL import ImageOps
|
||||
|
||||
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 import Texts
|
||||
from utils import command_extra, group_extra
|
||||
|
||||
log = logging.getLogger(__name__)
|
||||
|
||||
|
||||
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():
|
||||
cmd = 'git log -n 3 -s --format="[\`%h\`](https://git.gnous.eu/gnouseu/tuxbot-bot/commits/%H) %s (%cr)"'
|
||||
|
||||
return os.popen(cmd).read().strip()
|
||||
|
||||
@staticmethod
|
||||
def fetch_info():
|
||||
total_lines = 0
|
||||
total_python_lines = 0
|
||||
file_amount = 0
|
||||
python_file_amount = 0
|
||||
ENV = "env"
|
||||
|
||||
for path, _, files in os.walk("."):
|
||||
for name in files:
|
||||
file_dir = str(pathlib.PurePath(path, name))
|
||||
if (
|
||||
not name.endswith(".py")
|
||||
and not name.endswith(".po")
|
||||
and not name.endswith(".json")
|
||||
) or ENV in file_dir:
|
||||
continue
|
||||
file_amount += 1
|
||||
python_file_amount += 1 if name.endswith(".py") else 0
|
||||
with open(file_dir, "r", encoding="utf-8") as file:
|
||||
for line in file:
|
||||
if not line.strip().startswith("#") \
|
||||
or not line.strip():
|
||||
total_lines += 1
|
||||
total_python_lines += 1 if name.endswith(".py") \
|
||||
else 0
|
||||
|
||||
return (file_amount, total_lines), (
|
||||
python_file_amount, total_python_lines)
|
||||
|
||||
@staticmethod
|
||||
def luhn_checker(number: int):
|
||||
digits = [int(x) for x in reversed(str(number))]
|
||||
|
||||
for index, digit in enumerate(digits, start=1):
|
||||
digit = digit * 2 if index % 2 == 0 else digit
|
||||
if digit >= 10:
|
||||
digit = sum(int(x) for x in list(str(digit)))
|
||||
|
||||
digits[index - 1] = digit
|
||||
|
||||
return sum(digits) % 10 == 0
|
||||
|
||||
###########################################################################
|
||||
|
||||
@command_extra(name='iplocalise', category='network')
|
||||
async def _iplocalise(self, ctx: commands.Context, addr, ip_type=''):
|
||||
addr = re.sub(r'http(s?)://', '', addr)
|
||||
addr = addr[:-1] if addr.endswith('/') else addr
|
||||
|
||||
await ctx.trigger_typing()
|
||||
|
||||
try:
|
||||
if 'v6' in ip_type:
|
||||
try:
|
||||
ip = socket.getaddrinfo(addr, None, AF_INET6)[1][4][0]
|
||||
except socket.gaierror:
|
||||
return await ctx.send(
|
||||
Texts('useful', 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('useful', ctx).get('Information for')}"
|
||||
f" ``{addr}`` *`({response.get('query')})`*",
|
||||
color=0x5858d7
|
||||
)
|
||||
|
||||
e.add_field(
|
||||
name=Texts('useful', ctx).get('Belongs to :'),
|
||||
value=response['org'] if response['org'] else 'N/A',
|
||||
inline=False
|
||||
)
|
||||
|
||||
e.add_field(
|
||||
name=Texts('useful', ctx).get('Is located at :'),
|
||||
value=response['city'] if response['city'] else 'N/A',
|
||||
inline=True
|
||||
)
|
||||
|
||||
e.add_field(
|
||||
name="Region :",
|
||||
value=f"{response['regionName'] if response['regionName'] else 'N/A'} "
|
||||
f"({response['country'] if response['country'] else '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('useful', ctx).get('info not available')}"
|
||||
f"``{response['query'] if response['query'] else 'N/A'}``")
|
||||
|
||||
except Exception as e:
|
||||
await ctx.send(e)
|
||||
await ctx.send(
|
||||
f"{Texts('useful', ctx).get('Cannot connect to host')} {addr}"
|
||||
)
|
||||
|
||||
###########################################################################
|
||||
|
||||
@command_extra(name='getheaders', category='network')
|
||||
async def _getheaders(self, ctx: commands.Context, addr: str):
|
||||
if (addr.startswith('http') or addr.startswith('ftp')) is not True:
|
||||
addr = f"http://{addr}"
|
||||
|
||||
await ctx.trigger_typing()
|
||||
|
||||
try:
|
||||
async with self.bot.session.get(addr) as s:
|
||||
e = discord.Embed(
|
||||
title=f"{Texts('useful', 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.ClientError:
|
||||
await ctx.send(
|
||||
f"{Texts('useful', ctx).get('Cannot connect to host')} {addr}"
|
||||
)
|
||||
|
||||
###########################################################################
|
||||
|
||||
@command_extra(name='git', aliases=['sources', 'source', 'github'], category='misc')
|
||||
async def _git(self, ctx):
|
||||
e = discord.Embed(
|
||||
title=Texts('useful', ctx).get('git repo'),
|
||||
description=Texts('useful', ctx).get('git text'),
|
||||
colour=0xE9D460
|
||||
)
|
||||
e.set_author(
|
||||
name='Gnous',
|
||||
icon_url="https://cdn.gnous.eu/logo1.png"
|
||||
)
|
||||
await ctx.send(embed=e)
|
||||
|
||||
###########################################################################
|
||||
|
||||
@command_extra(name='quote', category='misc')
|
||||
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)
|
||||
|
||||
###########################################################################
|
||||
|
||||
@command_extra(name='ping', category='network')
|
||||
async def _ping(self, ctx: commands.Context):
|
||||
start = time.perf_counter()
|
||||
await ctx.trigger_typing()
|
||||
end = time.perf_counter()
|
||||
|
||||
latency = round(self.bot.latency * 1000, 2)
|
||||
typing = round((end - start) * 1000, 2)
|
||||
discordapp = measure_latency(host='discordapp.com', wait=0)[0]
|
||||
|
||||
e = discord.Embed(title='Ping', color=discord.Color.teal())
|
||||
e.add_field(name='Websocket', value=f'{latency}ms')
|
||||
e.add_field(name='Typing', value=f'{typing}ms')
|
||||
e.add_field(name='discordapp.com', value=f'{discordapp}ms')
|
||||
await ctx.send(embed=e)
|
||||
|
||||
###########################################################################
|
||||
|
||||
@command_extra(name='info', aliases=['about'], category='misc')
|
||||
async def _info(self, ctx: commands.Context):
|
||||
proc = psutil.Process()
|
||||
total, python = self.fetch_info()
|
||||
|
||||
with proc.oneshot():
|
||||
mem = proc.memory_full_info()
|
||||
e = discord.Embed(
|
||||
title=Texts('useful', ctx).get('Information about TuxBot'),
|
||||
color=0x89C4F9)
|
||||
|
||||
e.add_field(
|
||||
name=f"__:busts_in_silhouette: "
|
||||
f"{Texts('useful', ctx).get('Development')}__",
|
||||
value=f"**Romain#5117:** [git](https://git.gnous.eu/Romain)\n"
|
||||
f"**Outout#4039:** [git](https://git.gnous.eu/mael)\n",
|
||||
inline=True
|
||||
)
|
||||
e.add_field(
|
||||
name="__<:python:596577462335307777> Python__",
|
||||
value=f"**python** `{platform.python_version()}`\n"
|
||||
f"**discord.py** `{discord.__version__}`",
|
||||
inline=True
|
||||
)
|
||||
e.add_field(
|
||||
name="__:gear: Usage__",
|
||||
value=f"**{humanize.naturalsize(mem.rss)}** "
|
||||
f"{Texts('useful', ctx).get('physical memory')}\n"
|
||||
f"**{humanize.naturalsize(mem.vms)}** "
|
||||
f"{Texts('useful', ctx).get('virtual memory')}\n",
|
||||
inline=True
|
||||
)
|
||||
|
||||
e.add_field(
|
||||
name=f"__{Texts('useful', ctx).get('Servers count')}__",
|
||||
value=str(len(self.bot.guilds)),
|
||||
inline=True
|
||||
)
|
||||
e.add_field(
|
||||
name=f"__{Texts('useful', ctx).get('Channels count')}__",
|
||||
value=str(len([_ for _ in self.bot.get_all_channels()])),
|
||||
inline=True
|
||||
)
|
||||
e.add_field(
|
||||
name=f"__{Texts('useful', ctx).get('Members count')}__",
|
||||
value=str(len([_ for _ in self.bot.get_all_members()])),
|
||||
inline=True
|
||||
)
|
||||
|
||||
e.add_field(
|
||||
name=f"__:file_folder: {Texts('useful', ctx).get('Files')}__",
|
||||
value=f"{total[0]} *({python[0]} <:python:596577462335307777>)*",
|
||||
inline=True
|
||||
)
|
||||
e.add_field(
|
||||
name=f"__¶ {Texts('useful', ctx).get('Lines')}__",
|
||||
value=f"{total[1]} *({python[1]} <:python:596577462335307777>)*",
|
||||
inline=True
|
||||
)
|
||||
|
||||
e.add_field(
|
||||
name=f"__{Texts('useful', ctx).get('Latest changes')}__",
|
||||
value=self._latest_commits(),
|
||||
inline=False
|
||||
)
|
||||
|
||||
e.add_field(
|
||||
name=f"__:link: {Texts('useful', ctx).get('Links')}__",
|
||||
value="[tuxbot.gnous.eu](https://tuxbot.gnous.eu/) "
|
||||
"| [gnous.eu](https://gnous.eu/) "
|
||||
"| [git](https://git.gnous.eu/gnouseu/tuxbot-bot) "
|
||||
"| [status](https://status.gnous.eu/check/154250) "
|
||||
f"| [{Texts('useful', ctx).get('Invite')}](https://discordapp.com/oauth2/authorize?client_id=301062143942590465&scope=bot&permissions=268749888)",
|
||||
inline=False
|
||||
)
|
||||
|
||||
e.set_footer(text=f'version: {self.bot.version} '
|
||||
f'• prefix: {ctx.prefix}')
|
||||
|
||||
await ctx.send(embed=e)
|
||||
|
||||
###########################################################################
|
||||
|
||||
@command_extra(name='credits', aliases=['contributors', 'authors'], category='misc')
|
||||
async def _credits(self, ctx: commands.Context):
|
||||
e = discord.Embed(
|
||||
title=Texts('useful', ctx).get('Contributors'),
|
||||
color=0x36393f
|
||||
)
|
||||
|
||||
e.add_field(
|
||||
name="**Outout#4039** ",
|
||||
value="• https://git.gnous.eu/mael ⠀\n"
|
||||
"• mael@gnous.eu\n"
|
||||
"• [@outoutxyz](https://twitter.com/outouxyz)",
|
||||
inline=True
|
||||
)
|
||||
e.add_field(
|
||||
name="**Romain#5117** ",
|
||||
value="• https://git.gnous.eu/Romain\n"
|
||||
"• romain@gnous.eu",
|
||||
inline=True
|
||||
)
|
||||
|
||||
await ctx.send(embed=e)
|
||||
|
||||
###########################################################################
|
||||
@group_extra(name='cb', aliases=['cc'], category='misc')
|
||||
@commands.cooldown(1, 5, type=commands.BucketType.user)
|
||||
async def _cb(self, ctx: commands.Context):
|
||||
if ctx.invoked_subcommand is None:
|
||||
await ctx.send_help('cb')
|
||||
|
||||
@_cb.command(name='validate', aliases=['valid', 'correct'], category='misc')
|
||||
@commands.cooldown(1, 5, type=commands.BucketType.user)
|
||||
async def _cb_validate(self, ctx: commands.Context, *, number: int):
|
||||
valid = self.luhn_checker(number)
|
||||
|
||||
await ctx.send(
|
||||
Texts(
|
||||
'useful', ctx
|
||||
).get(
|
||||
'valid_credit_card'
|
||||
if valid
|
||||
else 'invalid_credit_card'
|
||||
)
|
||||
)
|
||||
|
||||
@_cb.command(name='generate', aliases=['new', 'get'], category='misc')
|
||||
@commands.cooldown(1, 5, type=commands.BucketType.user)
|
||||
async def _cb_generate(self, ctx: commands.Context):
|
||||
await ctx.channel.trigger_typing()
|
||||
|
||||
number = random.randint(4000_0000_0000_0000, 5999_9999_9999_9999)
|
||||
while not self.luhn_checker(number):
|
||||
number = random.randint(4000_0000_0000_0000, 5999_9999_9999_9999)
|
||||
number = str(number)
|
||||
cvv = ''.join(random.choice("abcdefghij") for _ in range(3))
|
||||
|
||||
with Image.open("utils/images/blank_credit_card.png") as blank:
|
||||
cc_font = ImageFont.truetype('utils/fonts/credit_card.ttf', 26)
|
||||
user_font = ImageFont.truetype('utils/fonts/credit_card.ttf', 20)
|
||||
draw = ImageDraw.Draw(blank)
|
||||
|
||||
cvv_text = Image.new('L', (500, 50))
|
||||
cvv_draw = ImageDraw.Draw(cvv_text)
|
||||
cvv_draw.text((0, 0), cvv, font=user_font, fill=255)
|
||||
cvv_rotated = cvv_text.rotate(23, expand=1)
|
||||
|
||||
draw.text(
|
||||
(69, 510),
|
||||
' '.join([number[i:i+4] for i in range(0, len(number), 4)]),
|
||||
(210, 210, 210),
|
||||
font=cc_font
|
||||
)
|
||||
|
||||
draw.text(
|
||||
(69, 550),
|
||||
ctx.author.name.upper(),
|
||||
(210, 210, 210),
|
||||
font=user_font
|
||||
)
|
||||
blank.paste(ImageOps.colorize(cvv_rotated, (0, 0, 0), (0, 0, 0)), (470, 0), cvv_rotated)
|
||||
|
||||
output = BytesIO()
|
||||
blank.save(output, 'png')
|
||||
output.seek(0)
|
||||
|
||||
await ctx.send(file=discord.File(fp=output, filename="credit_card.png"))
|
||||
|
||||
|
||||
def setup(bot: TuxBot):
|
||||
bot.add_cog(Useful(bot))
|
64
cogs/User.py
64
cogs/User.py
|
@ -1,64 +0,0 @@
|
|||
import logging
|
||||
|
||||
from discord.ext import commands
|
||||
|
||||
from bot import TuxBot
|
||||
from utils import AliasesModel
|
||||
from utils import Texts
|
||||
from utils import group_extra
|
||||
|
||||
log = logging.getLogger(__name__)
|
||||
|
||||
|
||||
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"
|
||||
|
||||
###########################################################################
|
||||
|
||||
@group_extra(name='alias', aliases=['aliases'], category='alias')
|
||||
async def _alias(self, ctx: commands.Context):
|
||||
if ctx.invoked_subcommand is None:
|
||||
await ctx.send_help('alias')
|
||||
|
||||
@_alias.command(name='add', aliases=['set', 'new'])
|
||||
async def _alias_add(self, ctx: commands.Context, *, user_alias: str):
|
||||
is_global = False
|
||||
if '--global' in user_alias:
|
||||
is_global = True
|
||||
user_alias.replace('--global', '')
|
||||
|
||||
user_alias = user_alias.split(' -> ')
|
||||
if len(user_alias) != 2:
|
||||
return await ctx.send_help('alias')
|
||||
|
||||
command = user_alias[1]
|
||||
user_alias = user_alias[0]
|
||||
|
||||
if self.bot.get_command(command) is None:
|
||||
return await ctx.send(Texts('user').get('Command not found'))
|
||||
|
||||
alias = AliasesModel(
|
||||
user_id=ctx.author.id,
|
||||
alias=user_alias,
|
||||
command=command,
|
||||
guild="global" if is_global else str(ctx.guild.id)
|
||||
)
|
||||
|
||||
self.bot.database.session.add(alias)
|
||||
self.bot.database.session.commit()
|
||||
|
||||
@_alias.command(name='remove', aliases=['drop', 'del', 'delete'])
|
||||
async def _alias_remove(self, ctx: commands.Context, prefix: str):
|
||||
...
|
||||
|
||||
@_alias.command(name='list', aliases=['show', 'all'])
|
||||
async def _alias_list(self, ctx: commands.Context):
|
||||
...
|
||||
|
||||
|
||||
def setup(bot: TuxBot):
|
||||
bot.add_cog(User(bot))
|
5
configs/bot/blacklist.json
Normal file
5
configs/bot/blacklist.json
Normal file
|
@ -0,0 +1,5 @@
|
|||
{
|
||||
"channels": [],
|
||||
"guilds": [],
|
||||
"users": []
|
||||
}
|
8
configs/bot/protected.py
Normal file
8
configs/bot/protected.py
Normal file
|
@ -0,0 +1,8 @@
|
|||
from .settings import token, postgresql, logs
|
||||
|
||||
protected = [
|
||||
token, str(list(token)),
|
||||
postgresql, str(list(postgresql)),
|
||||
*[channel.get('webhook').get('token') for channel in logs.values()]
|
||||
]
|
||||
|
44
configs/bot/settings.py.example
Normal file
44
configs/bot/settings.py.example
Normal file
|
@ -0,0 +1,44 @@
|
|||
token = ""
|
||||
prefix = "drw."
|
||||
|
||||
main_guild = int
|
||||
|
||||
logs = {
|
||||
"gateway": {
|
||||
'channel': int,
|
||||
'webhook': {
|
||||
'id': int,
|
||||
'token': ''
|
||||
}
|
||||
},
|
||||
"dm": {
|
||||
'channel': int,
|
||||
'webhook': {
|
||||
'id': int,
|
||||
'token': ''
|
||||
}
|
||||
},
|
||||
"mentions": {
|
||||
'channel': int,
|
||||
'webhook': {
|
||||
'id': int,
|
||||
'token': ''
|
||||
}
|
||||
},
|
||||
"guilds": {
|
||||
'channel': int,
|
||||
'webhook': {
|
||||
'id': int,
|
||||
'token': ''
|
||||
}
|
||||
},
|
||||
"errors": {
|
||||
'channel': int,
|
||||
'webhook': {
|
||||
'id': int,
|
||||
'token': ''
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
postgresql = 'postgres://tuxbot:tuxbot@localhost:5432/tuxbot-rewrite'
|
3
configs/bot/whitelist.json
Normal file
3
configs/bot/whitelist.json
Normal file
|
@ -0,0 +1,3 @@
|
|||
{
|
||||
"owners": [269156684155453451]
|
||||
}
|
|
@ -1,24 +0,0 @@
|
|||
[bot]
|
||||
Token =
|
||||
Tester =
|
||||
Activity =
|
||||
|
||||
[postgresql]
|
||||
Username =
|
||||
Password =
|
||||
Host =
|
||||
DBName =
|
||||
|
||||
[permissions]
|
||||
Owners =
|
||||
|
||||
[webhook]
|
||||
ID =
|
||||
Token =
|
||||
|
||||
[misc]
|
||||
Separator =
|
||||
|
||||
[API]
|
||||
Host =
|
||||
Port =
|
|
@ -1,18 +0,0 @@
|
|||
[fr-srv01]
|
||||
Host =
|
||||
Name = fr-srv01
|
||||
WebPage = 0.0.0.0
|
||||
Port =
|
||||
|
||||
[rm-dev01]
|
||||
This = True
|
||||
Host = 127.0.0.1
|
||||
Name = rm-dev01
|
||||
WebPage = 0.0.0.0
|
||||
Port = 3389
|
||||
|
||||
[rm-srv01]
|
||||
Host = 127.0.0.1
|
||||
Name = rm-srv01
|
||||
WebPage = 0.0.0.0
|
||||
Port = 3390
|
|
@ -1,18 +0,0 @@
|
|||
[280805240977227776]
|
||||
prefixes = b1.[301062143942590465]*
|
||||
|
||||
[303633056944881686]
|
||||
prefixes = b1.[301062143942590465]*
|
||||
|
||||
[373881878471770112]
|
||||
prefixes = b1.
|
||||
|
||||
[336642139381301249]
|
||||
prefixes = ba.
|
||||
|
||||
[274247231534792704]
|
||||
prefixes = test.
|
||||
|
||||
[528679953399676938]
|
||||
prefixes = test.
|
||||
|
19
database.py
19
database.py
|
@ -1,19 +0,0 @@
|
|||
import sqlalchemy
|
||||
from utils.models import database, metadata
|
||||
import argparse
|
||||
|
||||
parser = argparse.ArgumentParser()
|
||||
parser.add_argument("-m", "--migrate", action="store_true")
|
||||
parser.add_argument("-s", "--seed", action="store_true")
|
||||
args = parser.parse_args()
|
||||
|
||||
if args.migrate:
|
||||
print("Migrate...")
|
||||
engine = sqlalchemy.create_engine(str(database.url))
|
||||
metadata.create_all(engine)
|
||||
print("Done!")
|
||||
|
||||
if args.seed:
|
||||
print('Seeding...')
|
||||
# todo: add seeding
|
||||
print("Done!")
|
|
@ -1,17 +0,0 @@
|
|||
#!/bin/bash
|
||||
|
||||
BASEDIR=$(pwd)
|
||||
|
||||
cd "$BASEDIR/utils/locales/en/LC_MESSAGES"
|
||||
|
||||
for i in *.po ; do
|
||||
[[ -f "$i" ]] || continue
|
||||
/usr/lib/python3.8/Tools/i18n/msgfmt.py -o "${i%.po}.mo" "${i%.po}"
|
||||
done
|
||||
|
||||
cd "$BASEDIR/utils/locales/fr/LC_MESSAGES"
|
||||
|
||||
for i in *.po ; do
|
||||
[[ -f "$i" ]] || continue
|
||||
/usr/lib/python3.8/Tools/i18n/msgfmt.py -o "${i%.po}.mo" "${i%.po}"
|
||||
done
|
|
@ -1,13 +1,27 @@
|
|||
requests
|
||||
humanize
|
||||
git+https://github.com/Rapptz/discord.py@master
|
||||
jishaku
|
||||
gitpython
|
||||
orm
|
||||
asyncpg
|
||||
psycopg2
|
||||
configparser
|
||||
psutil
|
||||
tcp_latency
|
||||
yarl
|
||||
pillow
|
||||
aiofiles==0.5.0
|
||||
aiohttp==3.6.2
|
||||
aiosqlite==0.13.0
|
||||
astunparse==1.6.3
|
||||
async-timeout==3.0.1
|
||||
asyncpg==0.20.1
|
||||
attrs==19.3.0
|
||||
braceexpand==0.1.5
|
||||
chardet==3.0.4
|
||||
ciso8601==2.1.3
|
||||
discord-flags==2.1.1
|
||||
discord.py==1.3.3
|
||||
humanize==2.4.0
|
||||
idna==2.9
|
||||
import-expression==1.1.2
|
||||
jishaku==1.18.2.188
|
||||
mpmath==1.1.0
|
||||
multidict==4.7.6
|
||||
Pillow==7.1.2
|
||||
psutil==5.7.0
|
||||
PyPika==0.37.6
|
||||
six==1.14.0
|
||||
sympy==1.5.1
|
||||
tortoise-orm==0.16.11
|
||||
typing-extensions==3.7.4.2
|
||||
websockets==8.1
|
||||
yarl==1.4.2
|
||||
|
|
2
todo
2
todo
|
@ -1,2 +0,0 @@
|
|||
reconnaissance d'image
|
||||
commande d'archivage pour les salons vocaux avec output mp4 dans lequel on voit le pseudo de celui qui parle
|
|
@ -1,6 +0,0 @@
|
|||
from utils.functions.config import *
|
||||
from utils.functions.lang import *
|
||||
from utils.functions.version import *
|
||||
|
||||
from utils.functions.extra import *
|
||||
from utils.functions.paginator import *
|
Binary file not shown.
|
@ -1,6 +0,0 @@
|
|||
from .config import Config
|
||||
from .database import Database
|
||||
from .extra import *
|
||||
from .lang import Texts
|
||||
from .paginator import *
|
||||
from .version import Version
|
|
@ -1,36 +0,0 @@
|
|||
from typing import List, Union
|
||||
|
||||
import configparser
|
||||
|
||||
|
||||
class Config(configparser.ConfigParser):
|
||||
__slots__ = ('name', '_db')
|
||||
|
||||
def __init__(self, name):
|
||||
super().__init__()
|
||||
|
||||
self._db = super()
|
||||
self._db.read(name)
|
||||
|
||||
def find(self, value: str, **kwargs) \
|
||||
-> Union[
|
||||
List[configparser.SectionProxy], configparser.SectionProxy
|
||||
]:
|
||||
key = kwargs.get('key', None)
|
||||
first = kwargs.get('first', False)
|
||||
|
||||
results = []
|
||||
|
||||
for name, section in self._db.items():
|
||||
if key is None:
|
||||
for k in section.keys():
|
||||
if section.get(k) == value:
|
||||
results.append(section)
|
||||
if first and len(results) == 1:
|
||||
return results[0]
|
||||
else:
|
||||
if section.get(key) == value:
|
||||
results.append(section)
|
||||
if first and len(results) == 1:
|
||||
return results[0]
|
||||
return results
|
|
@ -1,16 +0,0 @@
|
|||
from .config import Config
|
||||
|
||||
import sqlalchemy
|
||||
import databases
|
||||
|
||||
|
||||
class Database:
|
||||
def __init__(self, config: Config):
|
||||
conf_postgresql = config["postgresql"]
|
||||
postgresql = 'postgresql://{}:{}@{}/{}'.format(
|
||||
conf_postgresql.get("Username"), conf_postgresql.get("Password"),
|
||||
conf_postgresql.get("Host"), conf_postgresql.get("DBName"))
|
||||
|
||||
self.database = databases.Database(postgresql)
|
||||
self.metadata = sqlalchemy.MetaData()
|
||||
self.engine = sqlalchemy.create_engine(str(self.database.url))
|
|
@ -1,10 +0,0 @@
|
|||
emotes = ['1⃣', '2⃣', '3⃣', '4⃣', '5⃣', '6⃣', '7⃣', '8⃣', '9⃣', '🔟', '0⃣',
|
||||
'🇦', '🇧', '🇨', '🇩', '🇪', '🇫', '🇬', '🇭', '🇮']
|
||||
|
||||
|
||||
def get(count):
|
||||
return emotes[:count]
|
||||
|
||||
|
||||
def get_index(emote):
|
||||
return emotes.index(emote)
|
|
@ -1,32 +1,70 @@
|
|||
import ast
|
||||
import json
|
||||
import os
|
||||
|
||||
import discord
|
||||
from discord.ext import commands
|
||||
from utils.functions import Config
|
||||
|
||||
|
||||
class CommandsPlus(commands.Command):
|
||||
def __init__(self, func, **kwargs):
|
||||
super().__init__(func, **kwargs)
|
||||
self.category = kwargs.get("category", 'other')
|
||||
|
||||
|
||||
class GroupPlus(commands.Group):
|
||||
def __init__(self, func, **kwargs):
|
||||
super().__init__(func, **kwargs)
|
||||
self.category = kwargs.get("category", 'other')
|
||||
from configs.bot.protected import protected
|
||||
from configs.bot.settings import prefix
|
||||
|
||||
|
||||
class ContextPlus(commands.Context):
|
||||
async def send(self, content=None, **kwargs):
|
||||
config = Config('./configs/config.cfg')
|
||||
async def send(self, content=None, *args, **kwargs):
|
||||
if content is not None:
|
||||
for value in protected:
|
||||
content = content.replace(
|
||||
str(value),
|
||||
'[Deleted]'
|
||||
)
|
||||
|
||||
content = content.replace(config.get("bot", "Token"), 'Whoops! leaked token')
|
||||
content = content.replace(config.get("webhook", "Token"), 'Whoops! leaked token')
|
||||
if kwargs.get('content') is not None:
|
||||
for value in protected:
|
||||
kwargs['content'] = kwargs['content'].replace(
|
||||
str(value),
|
||||
'[Deleted]'
|
||||
)
|
||||
|
||||
return await super().send(content, **kwargs)
|
||||
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)
|
||||
)
|
||||
|
||||
return await super().send(content, *args, **kwargs)
|
||||
|
||||
|
||||
def command_extra(*args, **kwargs):
|
||||
return commands.command(*args, **kwargs, cls=CommandsPlus)
|
||||
async def get_prefix(bot, message):
|
||||
custom_prefix = [prefix]
|
||||
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 group_extra(*args, **kwargs):
|
||||
return commands.group(*args, **kwargs, cls=GroupPlus)
|
||||
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)
|
||||
|
|
|
@ -1,34 +0,0 @@
|
|||
import gettext
|
||||
import json
|
||||
|
||||
from discord.ext import commands
|
||||
|
||||
|
||||
class Texts:
|
||||
def __init__(self, base: str = 'base', ctx: commands.Context = None):
|
||||
self.locale = self.get_locale(ctx)
|
||||
self.base = base
|
||||
|
||||
def get(self, text: str) -> str:
|
||||
texts = gettext.translation(self.base, localedir='utils/locales',
|
||||
languages=[self.locale])
|
||||
texts.install()
|
||||
return texts.gettext(text)
|
||||
|
||||
def set(self, lang: str):
|
||||
self.locale = lang
|
||||
|
||||
@staticmethod
|
||||
def get_locale(ctx: commands.Context):
|
||||
lang = 'fr'
|
||||
if ctx is not None:
|
||||
try:
|
||||
with open(f'./configs/guilds/{ctx.guild.id}.json', 'r') as f:
|
||||
data = json.load(f)
|
||||
|
||||
lang = data['lang']
|
||||
|
||||
except FileNotFoundError:
|
||||
pass
|
||||
|
||||
return lang
|
|
@ -1,343 +0,0 @@
|
|||
"""
|
||||
|
||||
Based on https://github.com/Rapptz/RoboDanny/blob/3ec71c4c4031f868caff3027d71aecdebc3c5cec/cogs/utils/paginator.py
|
||||
Adapted by Romain J.
|
||||
|
||||
"""
|
||||
|
||||
import asyncio
|
||||
|
||||
import discord
|
||||
from discord.ext import commands
|
||||
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
|
||||
The context of the command.
|
||||
entries: List[str]
|
||||
A list of entries to paginate.
|
||||
per_page: int
|
||||
How many entries show up per page.
|
||||
show_entry_count: bool
|
||||
Whether to show an entry count in the footer.
|
||||
Attributes
|
||||
-----------
|
||||
embed: discord.Embed
|
||||
The embed object that is being used to send pagination info.
|
||||
Feel free to modify this externally. Only the description,
|
||||
footer fields, and colour are internally modified.
|
||||
permissions: discord.Permissions
|
||||
Our permissions for the channel.
|
||||
"""
|
||||
|
||||
def __init__(self, ctx, *, entries, per_page=12, show_entry_count=True,
|
||||
embed_color=discord.Color.blurple(), title=None,
|
||||
thumbnail=None, footericon=None, footertext=None, author=None,
|
||||
delete_after=None):
|
||||
self.bot = ctx.bot
|
||||
self.entries = entries
|
||||
self.message = ctx.message
|
||||
self.channel = ctx.channel
|
||||
self.author = author if author else ctx.author
|
||||
self.thumbnail = thumbnail
|
||||
self.footericon = footericon
|
||||
self.footertext = footertext
|
||||
self.title = title
|
||||
self.delete_after = delete_after
|
||||
self.per_page = per_page
|
||||
pages, left_over = divmod(len(self.entries), self.per_page)
|
||||
if left_over:
|
||||
pages += 1
|
||||
self.maximum_pages = pages
|
||||
self.embed = discord.Embed(colour=embed_color)
|
||||
self.paginating = len(entries) > per_page
|
||||
self.show_entry_count = show_entry_count
|
||||
self.reaction_emojis = [
|
||||
('\U000023ee\U0000fe0f', self.first_page),
|
||||
('\N{BLACK LEFT-POINTING TRIANGLE}', self.previous_page),
|
||||
('\U000023f9', self.stop_pages),
|
||||
('\N{BLACK RIGHT-POINTING TRIANGLE}', self.next_page),
|
||||
('\U000023ed\U0000fe0f', self.last_page)
|
||||
]
|
||||
|
||||
if ctx.guild is not None:
|
||||
self.permissions = self.channel.permissions_for(ctx.guild.me)
|
||||
else:
|
||||
self.permissions = self.channel.permissions_for(ctx.bot.user)
|
||||
|
||||
if not self.permissions.embed_links:
|
||||
raise commands.BotMissingPermissions(
|
||||
'I do not have permissions to : Embed links.'
|
||||
)
|
||||
|
||||
if not self.permissions.send_messages:
|
||||
raise commands.BotMissingPermissions('Bot cannot send messages.')
|
||||
|
||||
if self.paginating:
|
||||
# verify we can actually use the pagination session
|
||||
if not self.permissions.add_reactions:
|
||||
raise commands.BotMissingPermissions(
|
||||
'I do not have permissions to : Add Reactions.'
|
||||
)
|
||||
|
||||
if not self.permissions.read_message_history:
|
||||
raise commands.BotMissingPermissions(
|
||||
'I do not have permissions to : Read Message History.'
|
||||
)
|
||||
|
||||
def get_page(self, page):
|
||||
base = (page - 1) * self.per_page
|
||||
return self.entries[base:base + self.per_page]
|
||||
|
||||
def get_content(self, entries, page, *, first=False):
|
||||
return None
|
||||
|
||||
def get_embed(self, entries, page, *, first=False):
|
||||
self.prepare_embed(entries, page, first=first)
|
||||
return self.embed
|
||||
|
||||
def prepare_embed(self, entries, page, *, first=False):
|
||||
p = []
|
||||
for index, entry in enumerate(entries,
|
||||
1 + ((page - 1) * self.per_page)):
|
||||
p.append(f'`{index}.` {entry}')
|
||||
|
||||
if self.maximum_pages > 1:
|
||||
if self.show_entry_count:
|
||||
text = f'Showing page {page}/{self.maximum_pages} ({len(self.entries)} entries)'
|
||||
else:
|
||||
text = f'Showing page {page}/{self.maximum_pages}'
|
||||
|
||||
self.embed.set_footer(text=text)
|
||||
|
||||
if self.paginating and first:
|
||||
p.append('')
|
||||
|
||||
self.embed.description = '\n'.join(p)
|
||||
self.embed.title = self.title or discord.Embed.Empty
|
||||
self.embed.set_author(icon_url=self.author.avatar_url,
|
||||
name=str(self.author))
|
||||
|
||||
async def show_page(self, page, *, first=False):
|
||||
self.current_page = page
|
||||
entries = self.get_page(page)
|
||||
content = self.get_content(entries, page, first=first)
|
||||
embed = self.get_embed(entries, page, first=first)
|
||||
|
||||
if not self.paginating:
|
||||
return await self.channel.send(content=content, embed=embed)
|
||||
|
||||
if not first:
|
||||
await self.message.edit(content=content, embed=embed)
|
||||
return
|
||||
|
||||
self.message = await self.channel.send(content=content, embed=embed)
|
||||
for (reaction, _) in self.reaction_emojis:
|
||||
if self.maximum_pages == 2 and reaction in ('\u23ed', '\u23ee'):
|
||||
# no |<< or >>| buttons if we only have two pages
|
||||
# we can't forbid it if someone ends up using it but remove
|
||||
# it from the default set
|
||||
continue
|
||||
|
||||
await self.message.add_reaction(reaction)
|
||||
|
||||
async def checked_show_page(self, page):
|
||||
if page != 0 and page <= self.maximum_pages:
|
||||
await self.show_page(page)
|
||||
|
||||
async def first_page(self):
|
||||
"""goes to the first page"""
|
||||
await self.show_page(1)
|
||||
|
||||
async def last_page(self):
|
||||
"""goes to the last page"""
|
||||
await self.show_page(self.maximum_pages)
|
||||
|
||||
async def next_page(self):
|
||||
"""goes to the next page"""
|
||||
await self.checked_show_page(self.current_page + 1)
|
||||
|
||||
async def previous_page(self):
|
||||
"""goes to the previous page"""
|
||||
await self.checked_show_page(self.current_page - 1)
|
||||
|
||||
async def show_current_page(self):
|
||||
if self.paginating:
|
||||
await self.show_page(self.current_page)
|
||||
|
||||
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?'))
|
||||
|
||||
def message_check(m):
|
||||
return m.author == self.author and \
|
||||
self.channel == m.channel and \
|
||||
m.content.isdigit()
|
||||
|
||||
try:
|
||||
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)
|
||||
else:
|
||||
page = int(msg.content)
|
||||
to_delete.append(msg)
|
||||
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})'))
|
||||
await asyncio.sleep(5)
|
||||
|
||||
try:
|
||||
await self.channel.delete_messages(to_delete)
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
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')
|
||||
|
||||
for (emoji, func) in self.reaction_emojis:
|
||||
messages.append(f'{emoji} {func.__doc__}')
|
||||
|
||||
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.')
|
||||
await self.message.edit(content=None, embed=embed)
|
||||
|
||||
async def go_back_to_current_page():
|
||||
await asyncio.sleep(60.0)
|
||||
await self.show_current_page()
|
||||
|
||||
self.bot.loop.create_task(go_back_to_current_page())
|
||||
|
||||
async def stop_pages(self):
|
||||
"""stops the interactive pagination session"""
|
||||
await self.message.delete()
|
||||
self.paginating = False
|
||||
|
||||
def react_check(self, reaction, user):
|
||||
if user is None or user.id != self.author.id:
|
||||
return False
|
||||
|
||||
if reaction.message.id != self.message.id:
|
||||
return False
|
||||
|
||||
for (emoji, func) in self.reaction_emojis:
|
||||
if reaction.emoji == emoji:
|
||||
self.match = func
|
||||
return True
|
||||
return False
|
||||
|
||||
async def paginate(self):
|
||||
"""Actually paginate the entries and run the interactive loop if necessary."""
|
||||
first_page = self.show_page(1, first=True)
|
||||
if not self.paginating:
|
||||
await first_page
|
||||
else:
|
||||
# allow us to react to reactions right away if we're paginating
|
||||
self.bot.loop.create_task(first_page)
|
||||
|
||||
while self.paginating:
|
||||
try:
|
||||
reaction, user = await self.bot.wait_for(
|
||||
'reaction_add',
|
||||
check=self.react_check,
|
||||
timeout=self.delete_after
|
||||
)
|
||||
except asyncio.TimeoutError:
|
||||
self.paginating = False
|
||||
try:
|
||||
await self.message.delete()
|
||||
except:
|
||||
pass
|
||||
finally:
|
||||
break
|
||||
|
||||
try:
|
||||
await self.message.remove_reaction(reaction, user)
|
||||
except:
|
||||
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.
|
||||
"""
|
||||
|
||||
def __init__(self, ctx, *, entries, per_page=12, show_entry_count=True,
|
||||
title, thumbnail, footericon, footertext,
|
||||
embed_color=discord.Color.blurple()):
|
||||
super().__init__(ctx, entries=entries, per_page=per_page,
|
||||
show_entry_count=show_entry_count, title=title,
|
||||
thumbnail=thumbnail, footericon=footericon,
|
||||
footertext=footertext, embed_color=embed_color)
|
||||
|
||||
def prepare_embed(self, entries, page, *, first=False):
|
||||
self.embed.clear_fields()
|
||||
|
||||
for key, value in entries:
|
||||
self.embed.add_field(name=key, value=value, inline=False)
|
||||
|
||||
self.embed.title = self.title
|
||||
|
||||
if self.maximum_pages > 1:
|
||||
if self.show_entry_count:
|
||||
text = f' [{page}/{self.maximum_pages}]'
|
||||
else:
|
||||
text = f' [{page}/{self.maximum_pages}]'
|
||||
self.embed.title = self.title + text
|
||||
|
||||
self.embed.set_footer(icon_url=self.footericon, text=self.footertext)
|
||||
self.embed.set_thumbnail(url=self.thumbnail)
|
||||
|
||||
|
||||
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)
|
||||
for line in text.split('\n'):
|
||||
paginator.add_line(line)
|
||||
|
||||
super().__init__(ctx, entries=paginator.pages, per_page=1,
|
||||
show_entry_count=False)
|
||||
|
||||
def get_page(self, page):
|
||||
return self.entries[page - 1]
|
||||
|
||||
def get_embed(self, entries, page, *, first=False):
|
||||
return None
|
||||
|
||||
def get_content(self, entry, page, *, first=False):
|
||||
if self.maximum_pages > 1:
|
||||
return f'{entry}\nPage {page}/{self.maximum_pages}'
|
||||
return entry
|
|
@ -1,12 +0,0 @@
|
|||
class Version:
|
||||
def __init__(self, major: int, minor: int, patch: int, **kwargs):
|
||||
self.major: int = major
|
||||
self.minor: int = minor
|
||||
self.patch: int = patch
|
||||
|
||||
self.pre_release = kwargs.get('pre_release', '')
|
||||
self.build = kwargs.get('build', '')
|
||||
|
||||
def __str__(self) -> str:
|
||||
build = self.build[:10]
|
||||
return f'v{self.major}.{self.minor}.{self.patch}{self.pre_release}+{build}'
|
Binary file not shown.
Before Width: | Height: | Size: 70 KiB |
Binary file not shown.
Before Width: | Height: | Size: 42 KiB |
|
@ -1,61 +0,0 @@
|
|||
# SOME DESCRIPTIVE TITLE.
|
||||
# Copyright (C) YEAR ORGANIZATION
|
||||
# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
|
||||
#
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: PACKAGE VERSION\n"
|
||||
"POT-Creation-Date: 2019-09-08 19:04+0200\n"
|
||||
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
|
||||
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
||||
"Language-Team: LANGUAGE <LL@li.org>\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"Generated-By: pygettext.py 1.5\n"
|
||||
|
||||
|
||||
msgid "Please enter a reason"
|
||||
msgstr ""
|
||||
|
||||
msgid "Unable to ban this user"
|
||||
msgstr ""
|
||||
|
||||
msgid "Unable to kick this user"
|
||||
msgstr ""
|
||||
|
||||
msgid "last warns"
|
||||
msgstr ""
|
||||
|
||||
msgid "More than 2 warns"
|
||||
msgstr ""
|
||||
|
||||
msgid "has more than 2 warns"
|
||||
msgstr "has more than 2 warns, what do you want to do ?"
|
||||
|
||||
msgid "ignore"
|
||||
msgstr ""
|
||||
|
||||
msgid "Took too long. Aborting."
|
||||
msgstr ""
|
||||
|
||||
msgid "got a warn"
|
||||
msgstr ""
|
||||
|
||||
msgid "Reason"
|
||||
msgstr ""
|
||||
|
||||
msgid "WarnModel with id"
|
||||
msgstr ""
|
||||
|
||||
msgid "successfully removed"
|
||||
msgstr ""
|
||||
|
||||
msgid "successfully edited"
|
||||
msgstr ""
|
||||
|
||||
msgid "Unable to find this language"
|
||||
msgstr ""
|
||||
|
||||
msgid "Language changed successfully"
|
||||
msgstr ""
|
|
@ -1,252 +0,0 @@
|
|||
# SOME DESCRIPTIVE TITLE.
|
||||
# Copyright (C) YEAR ORGANIZATION
|
||||
# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
|
||||
#
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: PACKAGE VERSION\n"
|
||||
"POT-Creation-Date: 2019-09-08 19:04+0200\n"
|
||||
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
|
||||
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
||||
"Language-Team: LANGUAGE <LL@li.org>\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"Generated-By: pygettext.py 1.5\n"
|
||||
|
||||
###########################################################################
|
||||
########################## SAY ########################################
|
||||
###########################################################################
|
||||
|
||||
msgid '_say'
|
||||
msgstr ''
|
||||
|
||||
msgid '_say_short'
|
||||
msgstr '_say_short'
|
||||
|
||||
msgid '_say_usage'
|
||||
msgstr '_say_usage'
|
||||
|
||||
###########################################################################
|
||||
|
||||
msgid '_say_edit'
|
||||
msgstr ''
|
||||
|
||||
msgid '_say_edit__help'
|
||||
msgstr ''
|
||||
|
||||
msgid '_say_edit__usage'
|
||||
msgstr ''
|
||||
|
||||
###########################################################################
|
||||
|
||||
msgid '_say_to'
|
||||
msgstr ''
|
||||
|
||||
msgid '_say_to__help'
|
||||
msgstr ''
|
||||
|
||||
msgid '_say_to__usage'
|
||||
msgstr ''
|
||||
|
||||
###########################################################################
|
||||
########################## BAN ########################################
|
||||
###########################################################################
|
||||
msgid '_ban'
|
||||
msgstr ''
|
||||
|
||||
msgid '_ban__help'
|
||||
msgstr ''
|
||||
|
||||
msgid '_ban__usage'
|
||||
msgstr ''
|
||||
|
||||
###########################################################################
|
||||
########################## KICK #######################################
|
||||
###########################################################################
|
||||
|
||||
msgid '_kick'
|
||||
msgstr ''
|
||||
|
||||
msgid '_kick__help'
|
||||
msgstr ''
|
||||
|
||||
msgid '_kick__usage'
|
||||
msgstr ''
|
||||
|
||||
###########################################################################
|
||||
########################## CLEAR ######################################
|
||||
###########################################################################
|
||||
|
||||
msgid '_clear'
|
||||
msgstr ''
|
||||
|
||||
msgid '_clear__help'
|
||||
msgstr ''
|
||||
|
||||
msgid '_clear__usage'
|
||||
msgstr ''
|
||||
|
||||
###########################################################################
|
||||
########################## REACT ######################################
|
||||
###########################################################################
|
||||
|
||||
msgid '_react'
|
||||
msgstr ''
|
||||
|
||||
msgid '_react__help'
|
||||
msgstr ''
|
||||
|
||||
msgid '_react__usage'
|
||||
msgstr ''
|
||||
|
||||
###########################################################################
|
||||
|
||||
msgid '_react_remove'
|
||||
msgstr ''
|
||||
|
||||
msgid '_react_remove__help'
|
||||
msgstr ''
|
||||
|
||||
msgid '_react_remove__usage'
|
||||
msgstr ''
|
||||
|
||||
###########################################################################
|
||||
########################## DELETE #####################################
|
||||
###########################################################################
|
||||
|
||||
msgid '_delete'
|
||||
msgstr ''
|
||||
|
||||
msgid '_delete__help'
|
||||
msgstr ''
|
||||
|
||||
msgid '_delete__usage'
|
||||
msgstr ''
|
||||
|
||||
###########################################################################
|
||||
|
||||
msgid '_delete_from'
|
||||
msgstr ''
|
||||
|
||||
msgid '_delete_from__help'
|
||||
msgstr ''
|
||||
|
||||
msgid '_delete_from__usage'
|
||||
msgstr ''
|
||||
|
||||
###########################################################################
|
||||
########################## WARN #######################################
|
||||
###########################################################################
|
||||
|
||||
msgid '_warn'
|
||||
msgstr ''
|
||||
|
||||
msgid '_warn__help'
|
||||
msgstr ''
|
||||
|
||||
msgid '_warn__usage'
|
||||
msgstr ''
|
||||
|
||||
###########################################################################
|
||||
|
||||
msgid '_warn_new'
|
||||
msgstr ''
|
||||
|
||||
msgid '_warn_new__help'
|
||||
msgstr ''
|
||||
|
||||
msgid '_warn_new__usage'
|
||||
msgstr ''
|
||||
|
||||
###########################################################################
|
||||
|
||||
msgid '_warn_remove'
|
||||
msgstr ''
|
||||
|
||||
msgid '_warn_remove__help'
|
||||
msgstr ''
|
||||
|
||||
msgid '_warn_remove__usage'
|
||||
msgstr ''
|
||||
|
||||
###########################################################################
|
||||
|
||||
msgid '_warn_show'
|
||||
msgstr ''
|
||||
|
||||
msgid '_warn_show__help'
|
||||
msgstr ''
|
||||
|
||||
msgid '_warn_show__usage'
|
||||
msgstr ''
|
||||
|
||||
###########################################################################
|
||||
|
||||
msgid '_warn_edit'
|
||||
msgstr ''
|
||||
|
||||
msgid '_warn_edit__help'
|
||||
msgstr ''
|
||||
|
||||
msgid '_warn_edit__usage'
|
||||
msgstr ''
|
||||
|
||||
###########################################################################
|
||||
########################## LANGUAGE ###################################
|
||||
###########################################################################
|
||||
|
||||
msgid '_language'
|
||||
msgstr ''
|
||||
|
||||
msgid '_language__help'
|
||||
msgstr ''
|
||||
|
||||
msgid '_language__usage'
|
||||
msgstr ''
|
||||
|
||||
###########################################################################
|
||||
########################## PREFIX #####################################
|
||||
###########################################################################
|
||||
|
||||
msgid '_prefix'
|
||||
msgstr ''
|
||||
|
||||
msgid '_prefix__help'
|
||||
msgstr ''
|
||||
|
||||
msgid '_prefix__usage'
|
||||
msgstr ''
|
||||
|
||||
###########################################################################
|
||||
|
||||
msgid '_prefix_add'
|
||||
msgstr ''
|
||||
|
||||
msgid '_prefix_add__help'
|
||||
msgstr ''
|
||||
|
||||
msgid '_prefix_add__usage'
|
||||
msgstr ''
|
||||
|
||||
###########################################################################
|
||||
|
||||
msgid '_prefix_remove'
|
||||
msgstr ''
|
||||
|
||||
msgid '_prefix_remove__help'
|
||||
msgstr ''
|
||||
|
||||
msgid '_prefix_remove__usage'
|
||||
msgstr ''
|
||||
|
||||
###########################################################################
|
||||
|
||||
msgid '_prefix_list'
|
||||
msgstr ''
|
||||
|
||||
msgid '_prefix_list__help'
|
||||
msgstr ''
|
||||
|
||||
msgid '_prefix_list__usage'
|
||||
msgstr ''
|
|
@ -1,62 +0,0 @@
|
|||
# SOME DESCRIPTIVE TITLE.
|
||||
# Copyright (C) YEAR ORGANIZATION
|
||||
# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
|
||||
#
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: PACKAGE VERSION\n"
|
||||
"POT-Creation-Date: 2019-09-08 19:04+0200\n"
|
||||
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
|
||||
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
||||
"Language-Team: LANGUAGE <LL@li.org>\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"Generated-By: pygettext.py 1.5\n"
|
||||
|
||||
|
||||
msgid "Starting..."
|
||||
msgstr ""
|
||||
|
||||
msgid "Could not set up PostgreSQL..."
|
||||
msgstr ""
|
||||
|
||||
msgid "Launch without loading the <TEXT> module"
|
||||
msgstr ""
|
||||
|
||||
msgid "Search for update"
|
||||
msgstr ""
|
||||
|
||||
msgid "Checking for update..."
|
||||
msgstr ""
|
||||
|
||||
msgid "A new version is available !"
|
||||
msgstr ""
|
||||
|
||||
msgid "Update ? [Y/n] "
|
||||
msgstr ""
|
||||
|
||||
msgid "Downloading..."
|
||||
msgstr ""
|
||||
|
||||
msgid "Tuxbot is up to date"
|
||||
msgstr ""
|
||||
|
||||
msgid "Failed to load extension : "
|
||||
msgstr ""
|
||||
|
||||
msgid "Extension loaded successfully : "
|
||||
msgstr ""
|
||||
|
||||
msgid "This command cannot be used in private messages."
|
||||
msgstr ""
|
||||
|
||||
msgid "Sorry. This command is disabled and cannot be used."
|
||||
msgstr ""
|
||||
|
||||
msgid "In "
|
||||
msgstr ""
|
||||
|
||||
msgid "Ready:"
|
||||
msgstr ""
|
||||
|
|
@ -1,43 +0,0 @@
|
|||
# SOME DESCRIPTIVE TITLE.
|
||||
# Copyright (C) YEAR ORGANIZATION
|
||||
# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
|
||||
#
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: PACKAGE VERSION\n"
|
||||
"POT-Creation-Date: 2019-09-08 19:04+0200\n"
|
||||
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
|
||||
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
||||
"Language-Team: LANGUAGE <LL@li.org>\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"Generated-By: pygettext.py 1.5\n"
|
||||
|
||||
|
||||
msgid 'main_page.description'
|
||||
msgstr "When using commands, **<>** means a **required argument** and **[]** means an **optional** argument.\n***(Don't type these symbols!)***"
|
||||
|
||||
msgid 'main_page.commands'
|
||||
msgstr 'Commands'
|
||||
|
||||
msgid 'main_page.footer'
|
||||
msgstr '- Send {}help <Command> to see more help about a command.'
|
||||
|
||||
msgid 'main_page.not_found'
|
||||
msgstr 'No command called "{}" found.'
|
||||
|
||||
msgid 'command_help.subcommands'
|
||||
msgstr 'Subcommands'
|
||||
|
||||
msgid 'command_help.aliases'
|
||||
msgstr 'Aliases'
|
||||
|
||||
msgid 'command_help.no_aliases'
|
||||
msgstr 'No aliases'
|
||||
|
||||
msgid 'command_help.params'
|
||||
msgstr 'Parameters'
|
||||
|
||||
msgid 'command_help.usage'
|
||||
msgstr 'Usage'
|
|
@ -1,17 +0,0 @@
|
|||
# SOME DESCRIPTIVE TITLE.
|
||||
# Copyright (C) YEAR ORGANIZATION
|
||||
# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
|
||||
#
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: PACKAGE VERSION\n"
|
||||
"POT-Creation-Date: 2019-09-08 19:04+0200\n"
|
||||
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
|
||||
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
||||
"Language-Team: LANGUAGE <LL@li.org>\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"Generated-By: pygettext.py 1.5\n"
|
||||
|
||||
|
|
@ -1,20 +0,0 @@
|
|||
# SOME DESCRIPTIVE TITLE.
|
||||
# Copyright (C) YEAR ORGANIZATION
|
||||
# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
|
||||
#
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: PACKAGE VERSION\n"
|
||||
"POT-Creation-Date: 2019-09-08 19:04+0200\n"
|
||||
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
|
||||
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
||||
"Language-Team: LANGUAGE <LL@li.org>\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"Generated-By: pygettext.py 1.5\n"
|
||||
|
||||
|
||||
#: launcher.py:51
|
||||
msgid "**Preparation...**"
|
||||
msgstr ""
|
|
@ -1,17 +0,0 @@
|
|||
# SOME DESCRIPTIVE TITLE.
|
||||
# Copyright (C) YEAR ORGANIZATION
|
||||
# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
|
||||
#
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: PACKAGE VERSION\n"
|
||||
"POT-Creation-Date: 2019-09-08 19:04+0200\n"
|
||||
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
|
||||
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
||||
"Language-Team: LANGUAGE <LL@li.org>\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"Generated-By: pygettext.py 1.5\n"
|
||||
|
||||
|
|
@ -1,83 +0,0 @@
|
|||
# SOME DESCRIPTIVE TITLE.
|
||||
# Copyright (C) YEAR ORGANIZATION
|
||||
# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
|
||||
#
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: PACKAGE VERSION\n"
|
||||
"POT-Creation-Date: 2019-09-08 19:04+0200\n"
|
||||
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
|
||||
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
||||
"Language-Team: LANGUAGE <LL@li.org>\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"Generated-By: pygettext.py 1.5\n"
|
||||
|
||||
|
||||
msgid "Information about TuxBot"
|
||||
msgstr ""
|
||||
|
||||
msgid "Latest changes"
|
||||
msgstr ""
|
||||
|
||||
msgid "Development"
|
||||
msgstr ""
|
||||
|
||||
msgid "physical memory"
|
||||
msgstr ""
|
||||
|
||||
msgid "virtual memory"
|
||||
msgstr ""
|
||||
|
||||
msgid "Servers count"
|
||||
msgstr ""
|
||||
|
||||
msgid "Channels count"
|
||||
msgstr ""
|
||||
|
||||
msgid "Members count"
|
||||
msgstr ""
|
||||
|
||||
msgid "Links"
|
||||
msgstr ""
|
||||
|
||||
msgid "Files"
|
||||
msgstr ""
|
||||
|
||||
msgid "Lines"
|
||||
msgstr ""
|
||||
|
||||
msgid "Invite"
|
||||
msgstr ""
|
||||
|
||||
msgid "Contributors"
|
||||
msgstr ""
|
||||
|
||||
msgid "ipv6 not available"
|
||||
msgstr "Error, this address is not available in IPv6."
|
||||
|
||||
msgid "Information for"
|
||||
msgstr ""
|
||||
|
||||
msgid "Belongs to :"
|
||||
msgstr ""
|
||||
|
||||
msgid "Is located at :"
|
||||
msgstr ""
|
||||
|
||||
msgid "info not available"
|
||||
msgstr ""
|
||||
|
||||
msgid "Headers of"
|
||||
msgstr ""
|
||||
|
||||
msgid "Cannot connect to host"
|
||||
msgstr ""
|
||||
|
||||
msgid "git repo"
|
||||
msgstr "TuxBot-Bot's repository"
|
||||
|
||||
msgid "git text"
|
||||
msgstr "Whoa, do you want to see my Gitea repository to dissect me? No problem ! I am a Bot, I do not feel the pain! \n https://git.gnous.eu/gnouseu/tuxbot-bot"
|
||||
|
|
@ -1,17 +0,0 @@
|
|||
# SOME DESCRIPTIVE TITLE.
|
||||
# Copyright (C) YEAR ORGANIZATION
|
||||
# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
|
||||
#
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: PACKAGE VERSION\n"
|
||||
"POT-Creation-Date: 2019-09-08 19:04+0200\n"
|
||||
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
|
||||
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
||||
"Language-Team: LANGUAGE <LL@li.org>\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"Generated-By: pygettext.py 1.5\n"
|
||||
|
||||
|
|
@ -1,17 +0,0 @@
|
|||
# SOME DESCRIPTIVE TITLE.
|
||||
# Copyright (C) YEAR ORGANIZATION
|
||||
# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
|
||||
#
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: PACKAGE VERSION\n"
|
||||
"POT-Creation-Date: 2019-09-08 19:04+0200\n"
|
||||
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
|
||||
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
||||
"Language-Team: LANGUAGE <LL@li.org>\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"Generated-By: pygettext.py 1.5\n"
|
||||
|
||||
|
|
@ -1,22 +0,0 @@
|
|||
# SOME DESCRIPTIVE TITLE.
|
||||
# Copyright (C) YEAR ORGANIZATION
|
||||
# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
|
||||
#
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: PACKAGE VERSION\n"
|
||||
"POT-Creation-Date: 2019-09-08 19:04+0200\n"
|
||||
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
|
||||
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
||||
"Language-Team: LANGUAGE <LL@li.org>\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"Generated-By: pygettext.py 1.5\n"
|
||||
|
||||
|
||||
msgid "Unable to find the user..."
|
||||
msgstr ""
|
||||
|
||||
msgid "Unable to find the message"
|
||||
msgstr ""
|
|
@ -1,61 +0,0 @@
|
|||
# SOME DESCRIPTIVE TITLE.
|
||||
# Copyright (C) YEAR ORGANIZATION
|
||||
# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
|
||||
#
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: PACKAGE VERSION\n"
|
||||
"POT-Creation-Date: 2019-09-08 19:04+0200\n"
|
||||
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
|
||||
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
||||
"Language-Team: LANGUAGE <LL@li.org>\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"Generated-By: pygettext.py 1.5\n"
|
||||
|
||||
|
||||
msgid "Please enter a reason"
|
||||
msgstr "Merci d'entrer une raison"
|
||||
|
||||
msgid "Unable to ban this user"
|
||||
msgstr "Impossible de bannir cet utilisateur"
|
||||
|
||||
msgid "Unable to kick this user"
|
||||
msgstr "Impossible d'expulser cet utilisateur"
|
||||
|
||||
msgid "last warns"
|
||||
msgstr "derniers avertissements"
|
||||
|
||||
msgid "More than 2 warns"
|
||||
msgstr "Plus de 2 avertissements"
|
||||
|
||||
msgid "has more than 2 warns"
|
||||
msgstr "a plus de 2 avertissements, que voulez-vous faire?"
|
||||
|
||||
msgid "ignore"
|
||||
msgstr "ignorer"
|
||||
|
||||
msgid "Took too long. Aborting."
|
||||
msgstr "Temps expiré. Abandons."
|
||||
|
||||
msgid "got a warn"
|
||||
msgstr "a recu un avertissement"
|
||||
|
||||
msgid "Reason"
|
||||
msgstr "Raison"
|
||||
|
||||
msgid "WarnModel with id"
|
||||
msgstr "L'avertissement avec l'id"
|
||||
|
||||
msgid "successfully removed"
|
||||
msgstr "a été enlevé avec succes"
|
||||
|
||||
msgid "successfully edited"
|
||||
msgstr "a été édité avec succes"
|
||||
|
||||
msgid "Unable to find this language"
|
||||
msgstr "Impossible de trouver cette langue"
|
||||
|
||||
msgid "Language changed successfully"
|
||||
msgstr "Langue changée avec succès"
|
|
@ -1,263 +0,0 @@
|
|||
# SOME DESCRIPTIVE TITLE.
|
||||
# Copyright (C) YEAR ORGANIZATION
|
||||
# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
|
||||
#
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: PACKAGE VERSION\n"
|
||||
"POT-Creation-Date: 2019-09-08 19:04+0200\n"
|
||||
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
|
||||
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
||||
"Language-Team: LANGUAGE <LL@li.org>\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"Generated-By: pygettext.py 1.5\n"
|
||||
|
||||
###########################################################################
|
||||
########################## SAY ########################################
|
||||
###########################################################################
|
||||
|
||||
msgid '_say'
|
||||
msgstr 'Permet de faire en sorte que le TuxBot envoie votre message'
|
||||
|
||||
msgid '_say__short'
|
||||
msgstr 'Faire parler TuxBot'
|
||||
|
||||
msgid '_say_usage'
|
||||
msgstr '[sous-commande] <message>'
|
||||
|
||||
###########################################################################
|
||||
|
||||
msgid '_say_edit'
|
||||
msgstr "Permet de modifier le contenu d'un message envoyé par TuxBot"
|
||||
|
||||
msgid '_say_edit__short'
|
||||
msgstr 'Editer un message envoyé'
|
||||
|
||||
msgid '_say_edit__usage'
|
||||
msgstr '<ID/Lien du message> <message>'
|
||||
|
||||
###########################################################################
|
||||
|
||||
msgid '_say_to'
|
||||
msgstr "Permet de faire en sorte que le TuxBot envoi votre message dans un autre salon ou en MP à quelqu'un"
|
||||
|
||||
msgid '_say_to__short'
|
||||
msgstr 'Faire parler TuxBot dans un autre salon'
|
||||
|
||||
msgid '_say_to__usage'
|
||||
msgstr "<ID/Mention du salon ou ID/Mention d'un membre> <message>"
|
||||
|
||||
###########################################################################
|
||||
########################## BAN ########################################
|
||||
###########################################################################
|
||||
msgid '_ban'
|
||||
msgstr 'Permet de bannir un membre'
|
||||
|
||||
msgid '_ban__short'
|
||||
msgstr 'Bannir un membre'
|
||||
|
||||
msgid '_ban__usage'
|
||||
msgstr '<ID/Mention du membre>'
|
||||
|
||||
###########################################################################
|
||||
########################## KICK #######################################
|
||||
###########################################################################
|
||||
|
||||
msgid '_kick'
|
||||
msgstr "Permet d'expulser un membre"
|
||||
|
||||
msgid '_kick__short'
|
||||
msgstr 'Expulser un membre'
|
||||
|
||||
msgid '_kick__usage'
|
||||
msgstr '<ID/Mention du membre>'
|
||||
|
||||
###########################################################################
|
||||
########################## CLEAR ######################################
|
||||
###########################################################################
|
||||
|
||||
msgid '_clear'
|
||||
msgstr 'Permet de supprimer un nombre donné de message'
|
||||
|
||||
msgid '_clear__short'
|
||||
msgstr 'Supprime X messages'
|
||||
|
||||
msgid '_clear__usage'
|
||||
msgstr '<quantité>'
|
||||
|
||||
###########################################################################
|
||||
########################## REACT ######################################
|
||||
###########################################################################
|
||||
|
||||
msgid '_react'
|
||||
msgstr "Affiche l'aide relative a la commande `react`"
|
||||
|
||||
msgid '_react__short'
|
||||
msgstr "Afficher l'aide pour `react`"
|
||||
|
||||
msgid '_react__usage'
|
||||
msgstr '[sous-commande]'
|
||||
|
||||
###########################################################################
|
||||
|
||||
msgid '_react_add'
|
||||
msgstr "Permet d'ajouter une réaction à un message de la part de TuxBot"
|
||||
|
||||
msgid '_react_add__short'
|
||||
msgstr 'Ajouter une réaction'
|
||||
|
||||
msgid '_react_add__usage'
|
||||
msgstr '<ID/Lien du message> <émoji>'
|
||||
|
||||
###########################################################################
|
||||
|
||||
msgid '_react_remove'
|
||||
msgstr "Permet d'enlever toutes les réactions d'un message"
|
||||
|
||||
msgid '_react_remove__short'
|
||||
msgstr "Enlever toutes les réactions d'un message"
|
||||
|
||||
msgid '_react_remove__usage'
|
||||
msgstr '<ID/Lien du message>'
|
||||
|
||||
###########################################################################
|
||||
########################## DELETE #####################################
|
||||
###########################################################################
|
||||
|
||||
msgid '_delete'
|
||||
msgstr 'Permet de supprimer un message'
|
||||
|
||||
msgid '_delete__short'
|
||||
msgstr 'Supprimer un message'
|
||||
|
||||
msgid '_delete__usage'
|
||||
msgstr '[sous-commande] <ID/Lien du message>'
|
||||
|
||||
###########################################################################
|
||||
|
||||
msgid '_delete_from'
|
||||
msgstr 'Permet de supprimer un message dans un autre salon'
|
||||
|
||||
msgid '_delete_from__short'
|
||||
msgstr 'Supprimer un message dans un autre salon'
|
||||
|
||||
msgid '_delete_from__usage'
|
||||
msgstr '<ID/Mention du salon> <ID/Lien du message>'
|
||||
|
||||
###########################################################################
|
||||
########################## WARN #######################################
|
||||
###########################################################################
|
||||
|
||||
msgid '_warn'
|
||||
msgstr "Permet d'afficher les derniers avertissements donnés sur ce serveur"
|
||||
|
||||
msgid '_warn__short'
|
||||
msgstr 'Lister les derniers avertissements'
|
||||
|
||||
msgid '_warn__usage'
|
||||
msgstr '[sous-commande]'
|
||||
|
||||
###########################################################################
|
||||
|
||||
msgid '_warn_add'
|
||||
msgstr "Permet d'ajouter un avertissement à un membre en donnant une raison"
|
||||
|
||||
msgid '_warn_add__short'
|
||||
msgstr 'Ajouter un avertissement a un membre'
|
||||
|
||||
msgid '_warn_add__usage'
|
||||
msgstr '<ID/Pseudo/Mention du membre> <raison>'
|
||||
|
||||
###########################################################################
|
||||
|
||||
msgid '_warn_remove'
|
||||
msgstr "Permet de supprimer un avertissement qui a été donné à un membre"
|
||||
|
||||
msgid '_warn_remove__short'
|
||||
msgstr "Retirer l'avertissement d'un membre"
|
||||
|
||||
msgid '_warn_remove__usage'
|
||||
msgstr "<ID de l'avertissement>"
|
||||
|
||||
###########################################################################
|
||||
|
||||
msgid '_warn_show'
|
||||
msgstr "Permet d'afficher les derniers avertissements donnés à un membre"
|
||||
|
||||
msgid '_warn_show__short'
|
||||
msgstr "Lister les derniers avertissements d'un membre"
|
||||
|
||||
msgid '_warn_show__usage'
|
||||
msgstr '<ID/Pseudo/Mention du membre>'
|
||||
|
||||
###########################################################################
|
||||
|
||||
msgid '_warn_edit'
|
||||
msgstr "Permet de modifier la raison de l'avertissement donné à un membre"
|
||||
|
||||
msgid '_warn_edit__short'
|
||||
msgstr "Modifier la raison d'un avertissement"
|
||||
|
||||
msgid '_warn_edit__usage'
|
||||
msgstr "<ID de l'avertissement> <raison>"
|
||||
|
||||
###########################################################################
|
||||
########################## LANGUAGE ###################################
|
||||
###########################################################################
|
||||
|
||||
msgid '_language'
|
||||
msgstr 'Permet de définir la langue utilisée sur ce serveur'
|
||||
|
||||
msgid '_language__short'
|
||||
msgstr 'Définir la langue de Tuxbot'
|
||||
|
||||
msgid '_language__usage'
|
||||
msgstr '<langue>'
|
||||
|
||||
###########################################################################
|
||||
########################## PREFIX #####################################
|
||||
###########################################################################
|
||||
|
||||
msgid '_prefix'
|
||||
msgstr "Affiche l'aide relative a la commande `prefix`"
|
||||
|
||||
msgid '_prefix__short'
|
||||
msgstr "Afficher l'aide pour `prefix`"
|
||||
|
||||
msgid '_prefix__usage'
|
||||
msgstr '[sous-commande]'
|
||||
|
||||
###########################################################################
|
||||
|
||||
msgid '_prefix_add'
|
||||
msgstr "Permet d'ajouter un nouveau préfixe pour ce serveur"
|
||||
|
||||
msgid '_prefix_add__short'
|
||||
msgstr 'Ajouter un préfixe pour ce serveur'
|
||||
|
||||
msgid '_prefix_add__usage'
|
||||
msgstr '<prefixe>'
|
||||
|
||||
###########################################################################
|
||||
|
||||
msgid '_prefix_remove'
|
||||
msgstr "Permet retirer un préfixe pour ce serveur"
|
||||
|
||||
msgid '_prefix_remove__short'
|
||||
msgstr 'Retirer un préfixe pour ce serveur'
|
||||
|
||||
msgid '_prefix_remove__usage'
|
||||
msgstr '<prefixe>'
|
||||
|
||||
###########################################################################
|
||||
|
||||
msgid '_prefix_list'
|
||||
msgstr "Permet d'afficher tous les prefixes définis pour ce serveur"
|
||||
|
||||
msgid '_prefix_list__short'
|
||||
msgstr 'Lister les prefixes pour ce serveur'
|
||||
|
||||
msgid '_prefix_list__usage'
|
||||
msgstr '⠀'
|
|
@ -1,62 +0,0 @@
|
|||
# SOME DESCRIPTIVE TITLE.
|
||||
# Copyright (C) YEAR ORGANIZATION
|
||||
# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
|
||||
#
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: PACKAGE VERSION\n"
|
||||
"POT-Creation-Date: 2019-09-08 19:04+0200\n"
|
||||
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
|
||||
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
||||
"Language-Team: LANGUAGE <LL@li.org>\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"Generated-By: pygettext.py 1.5\n"
|
||||
|
||||
|
||||
msgid "Starting..."
|
||||
msgstr "Démarrage..."
|
||||
|
||||
msgid "Could not set up PostgreSQL..."
|
||||
msgstr "Impossible de lancer PostgreSQL..."
|
||||
|
||||
msgid "Launch without loading the <TEXT> module"
|
||||
msgstr "Lancer sans charger le module <TEXT>"
|
||||
|
||||
msgid "Search for update"
|
||||
msgstr "Rechercher les mises à jour"
|
||||
|
||||
msgid "Checking for update..."
|
||||
msgstr "Recherche de mise à jour..."
|
||||
|
||||
msgid "A new version is available !"
|
||||
msgstr "Une nouvelle version est disponible !"
|
||||
|
||||
msgid "Update ? [Y/n] "
|
||||
msgstr "Mettre à jour ? [O/n]"
|
||||
|
||||
msgid "Downloading..."
|
||||
msgstr "Téléchargement..."
|
||||
|
||||
msgid "Tuxbot is up to date"
|
||||
msgstr "Tuxbot est à jour"
|
||||
|
||||
msgid "Failed to load extension : "
|
||||
msgstr "Impossible de charger l'extension : "
|
||||
|
||||
msgid "Extension loaded successfully : "
|
||||
msgstr "Extension chargée avec succes : "
|
||||
|
||||
msgid "This command cannot be used in private messages."
|
||||
msgstr "Cette commande ne peut pas être utilisée en message privé."
|
||||
|
||||
msgid "Sorry. This command is disabled and cannot be used."
|
||||
msgstr "Désolé mais cette commande est désactivée."
|
||||
|
||||
msgid "In "
|
||||
msgstr "Dans "
|
||||
|
||||
msgid "Ready:"
|
||||
msgstr "Prêt :"
|
||||
|
|
@ -1,43 +0,0 @@
|
|||
# SOME DESCRIPTIVE TITLE.
|
||||
# Copyright (C) YEAR ORGANIZATION
|
||||
# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
|
||||
#
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: PACKAGE VERSION\n"
|
||||
"POT-Creation-Date: 2019-09-08 19:04+0200\n"
|
||||
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
|
||||
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
||||
"Language-Team: LANGUAGE <LL@li.org>\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"Generated-By: pygettext.py 1.5\n"
|
||||
|
||||
|
||||
msgid 'main_page.description'
|
||||
msgstr "Lorsque vous utilisez les commandes, **<>** correspond à un argument **obligatoire** et **[]** à un argument **optionnel**.\n***(N'écrivez pas ces symboles!)***"
|
||||
|
||||
msgid 'main_page.commands'
|
||||
msgstr 'Commandes'
|
||||
|
||||
msgid 'main_page.footer'
|
||||
msgstr "- Envoyez {}help <Commande> pour avoir plus d'aide sur la commande."
|
||||
|
||||
msgid 'main_page.not_found'
|
||||
msgstr 'Impossible de trouver la commande {}.'
|
||||
|
||||
msgid 'command_help.subcommands'
|
||||
msgstr 'Sous-commandes'
|
||||
|
||||
msgid 'command_help.aliases'
|
||||
msgstr 'Alias'
|
||||
|
||||
msgid 'command_help.no_aliases'
|
||||
msgstr 'Aucun alias'
|
||||
|
||||
msgid 'command_help.params'
|
||||
msgstr 'Parametres'
|
||||
|
||||
msgid 'command_help.usage'
|
||||
msgstr 'Utilisation'
|
|
@ -1,17 +0,0 @@
|
|||
# SOME DESCRIPTIVE TITLE.
|
||||
# Copyright (C) YEAR ORGANIZATION
|
||||
# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
|
||||
#
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: PACKAGE VERSION\n"
|
||||
"POT-Creation-Date: 2019-09-08 19:04+0200\n"
|
||||
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
|
||||
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
||||
"Language-Team: LANGUAGE <LL@li.org>\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"Generated-By: pygettext.py 1.5\n"
|
||||
|
||||
|
|
@ -1,19 +0,0 @@
|
|||
# SOME DESCRIPTIVE TITLE.
|
||||
# Copyright (C) YEAR ORGANIZATION
|
||||
# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
|
||||
#
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: PACKAGE VERSION\n"
|
||||
"POT-Creation-Date: 2019-09-08 19:04+0200\n"
|
||||
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
|
||||
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
||||
"Language-Team: LANGUAGE <LL@li.org>\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"Generated-By: pygettext.py 1.5\n"
|
||||
|
||||
|
||||
msgid "_uptime__short"
|
||||
msgstr "Retourne depuis quand TuxBot est en ligne."
|
|
@ -1,20 +0,0 @@
|
|||
# SOME DESCRIPTIVE TITLE.
|
||||
# Copyright (C) YEAR ORGANIZATION
|
||||
# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
|
||||
#
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: PACKAGE VERSION\n"
|
||||
"POT-Creation-Date: 2019-09-08 19:04+0200\n"
|
||||
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
|
||||
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
||||
"Language-Team: LANGUAGE <LL@li.org>\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"Generated-By: pygettext.py 1.5\n"
|
||||
|
||||
|
||||
#: launcher.py:51
|
||||
msgid "**Preparation...**"
|
||||
msgstr "**Préparation...**"
|
|
@ -1,40 +0,0 @@
|
|||
# SOME DESCRIPTIVE TITLE.
|
||||
# Copyright (C) YEAR ORGANIZATION
|
||||
# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
|
||||
#
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: PACKAGE VERSION\n"
|
||||
"POT-Creation-Date: 2019-09-08 19:04+0200\n"
|
||||
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
|
||||
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
||||
"Language-Team: LANGUAGE <LL@li.org>\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"Generated-By: pygettext.py 1.5\n"
|
||||
|
||||
|
||||
###########################################################################
|
||||
########################## POLLS #####################################
|
||||
###########################################################################
|
||||
|
||||
msgid '_poll'
|
||||
msgstr "Affiche l'aide relative a la commande `sondage`"
|
||||
|
||||
msgid '_poll__short'
|
||||
msgstr "Afficher l'aide pour `sondage`"
|
||||
|
||||
msgid '_poll__usage'
|
||||
msgstr '[sous-commande]'
|
||||
|
||||
###########################################################################
|
||||
|
||||
msgid '_poll_create'
|
||||
msgstr "Créez un sondage basé sur les réactions ! *(**BETA!** ajoutez `--anonyme` pour rendre les réponses anonymes)*"
|
||||
|
||||
msgid '_poll_create__short'
|
||||
msgstr 'Créer un sondage'
|
||||
|
||||
msgid '_poll_create__usage'
|
||||
msgstr '<question> | <réponse A> | <réponse B> | [réponse C] | [réponse D] | [...]'
|
|
@ -1,82 +0,0 @@
|
|||
# SOME DESCRIPTIVE TITLE.
|
||||
# Copyright (C) YEAR ORGANIZATION
|
||||
# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
|
||||
#
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: PACKAGE VERSION\n"
|
||||
"POT-Creation-Date: 2019-09-08 19:04+0200\n"
|
||||
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
|
||||
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
||||
"Language-Team: LANGUAGE <LL@li.org>\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"Generated-By: pygettext.py 1.5\n"
|
||||
|
||||
|
||||
msgid "Information about TuxBot"
|
||||
msgstr "Informations sur TuxBot"
|
||||
|
||||
msgid "Latest changes"
|
||||
msgstr "Derniers changements"
|
||||
|
||||
msgid "Development"
|
||||
msgstr "Développement"
|
||||
|
||||
msgid "physical memory"
|
||||
msgstr "mémoire physique"
|
||||
|
||||
msgid "virtual memory"
|
||||
msgstr "mémoire virtuelle"
|
||||
|
||||
msgid "Servers count"
|
||||
msgstr "Nombre de serveurs"
|
||||
|
||||
msgid "Channels count"
|
||||
msgstr "Nombre de salons"
|
||||
|
||||
msgid "Members count"
|
||||
msgstr "Nombre de membres"
|
||||
|
||||
msgid "Links"
|
||||
msgstr "Liens"
|
||||
|
||||
msgid "Files"
|
||||
msgstr "Fichiers"
|
||||
|
||||
msgid "Lines"
|
||||
msgstr "Lignes"
|
||||
|
||||
msgid "Invite"
|
||||
msgstr "Invitation"
|
||||
|
||||
msgid "Contributors"
|
||||
msgstr "Contributeurs"
|
||||
|
||||
msgid "ipv6 not available"
|
||||
msgstr "Erreur, cette adresse n'est pas disponible en IPv6."
|
||||
|
||||
msgid "Information for"
|
||||
msgstr "Informations pour"
|
||||
|
||||
msgid "Belongs to :"
|
||||
msgstr "Appartient à :"
|
||||
|
||||
msgid "Is located at :"
|
||||
msgstr "Se situe à :"
|
||||
|
||||
msgid "info not available"
|
||||
msgstr "Erreur, impossible d'obtenir des informations sur cette adresse IP"
|
||||
|
||||
msgid "Headers of"
|
||||
msgstr "Entêtes de"
|
||||
|
||||
msgid "Cannot connect to host"
|
||||
msgstr "Impossible de se connecter à l'hôte"
|
||||
|
||||
msgid "git repo"
|
||||
msgstr "Repos TuxBot-Bot"
|
||||
|
||||
msgid "git text"
|
||||
msgstr "Whoa tu veux voir mon repos Gitea pour me disséquer ? Pas de soucis ! Je suis un Bot, je ne ressens pas la douleur! \n https://git.gnous.eu/gnouseu/tuxbot-bot"
|
|
@ -1,17 +0,0 @@
|
|||
# SOME DESCRIPTIVE TITLE.
|
||||
# Copyright (C) YEAR ORGANIZATION
|
||||
# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
|
||||
#
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: PACKAGE VERSION\n"
|
||||
"POT-Creation-Date: 2019-09-08 19:04+0200\n"
|
||||
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
|
||||
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
||||
"Language-Team: LANGUAGE <LL@li.org>\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"Generated-By: pygettext.py 1.5\n"
|
||||
|
||||
|
|
@ -1,17 +0,0 @@
|
|||
# SOME DESCRIPTIVE TITLE.
|
||||
# Copyright (C) YEAR ORGANIZATION
|
||||
# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
|
||||
#
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: PACKAGE VERSION\n"
|
||||
"POT-Creation-Date: 2019-09-08 19:04+0200\n"
|
||||
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
|
||||
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
||||
"Language-Team: LANGUAGE <LL@li.org>\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"Generated-By: pygettext.py 1.5\n"
|
||||
|
||||
|
|
@ -1,22 +0,0 @@
|
|||
# SOME DESCRIPTIVE TITLE.
|
||||
# Copyright (C) YEAR ORGANIZATION
|
||||
# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
|
||||
#
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: PACKAGE VERSION\n"
|
||||
"POT-Creation-Date: 2019-09-08 19:04+0200\n"
|
||||
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
|
||||
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
||||
"Language-Team: LANGUAGE <LL@li.org>\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"Generated-By: pygettext.py 1.5\n"
|
||||
|
||||
|
||||
msgid "Unable to find the user..."
|
||||
msgstr "Impossibe de trouver l'utilisateur..."
|
||||
|
||||
msgid "Unable to find the message"
|
||||
msgstr "Impossible de trouver le message"
|
|
@ -1,18 +0,0 @@
|
|||
import databases
|
||||
import sqlalchemy
|
||||
from utils.functions import Config
|
||||
|
||||
conf_postgresql = Config('./configs/config.cfg')["postgresql"]
|
||||
postgresql = 'postgresql://{}:{}@{}/{}'.format(
|
||||
conf_postgresql.get("Username"), conf_postgresql.get("Password"),
|
||||
conf_postgresql.get("Host"), conf_postgresql.get("DBName"))
|
||||
|
||||
database = databases.Database(postgresql)
|
||||
metadata = sqlalchemy.MetaData()
|
||||
|
||||
engine = sqlalchemy.create_engine(str(database.url))
|
||||
metadata.create_all(engine)
|
||||
|
||||
from .warn import WarnModel
|
||||
from .poll import PollModel, ResponsesModel
|
||||
from .alias import AliasesModel
|
|
@ -1,14 +0,0 @@
|
|||
import orm
|
||||
from . import database, metadata
|
||||
|
||||
|
||||
class AliasesModel(orm.Model):
|
||||
__tablename__ = 'aliases'
|
||||
__database__ = database
|
||||
__metadata__ = metadata
|
||||
|
||||
id = orm.Integer(primary_key=True)
|
||||
user_id = orm.String(max_length=18)
|
||||
alias = orm.String(max_length=255)
|
||||
command = orm.String(max_length=255)
|
||||
guild = orm.String(max_length=255)
|
|
@ -1,29 +0,0 @@
|
|||
import orm
|
||||
from . import database, metadata
|
||||
|
||||
|
||||
class ResponsesModel(orm.Model):
|
||||
__tablename__ = 'responses'
|
||||
__database__ = database
|
||||
__metadata__ = metadata
|
||||
|
||||
id = orm.Integer(primary_key=True)
|
||||
user = orm.String(max_length=18)
|
||||
|
||||
choice = orm.Integer()
|
||||
|
||||
|
||||
class PollModel(orm.Model):
|
||||
__tablename__ = 'polls'
|
||||
__database__ = database
|
||||
__metadata__ = metadata
|
||||
|
||||
id = orm.Integer(primary_key=True)
|
||||
channel_id = orm.String(max_length=18)
|
||||
message_id = orm.String(max_length=18)
|
||||
|
||||
content = orm.JSON()
|
||||
is_anonymous = orm.Boolean()
|
||||
|
||||
available_choices = orm.Integer()
|
||||
choice = orm.ForeignKey(ResponsesModel)
|
|
@ -1,14 +0,0 @@
|
|||
import orm
|
||||
from . import database, metadata
|
||||
|
||||
|
||||
class WarnModel(orm.Model):
|
||||
__tablename__ = 'warns'
|
||||
__database__ = database
|
||||
__metadata__ = metadata
|
||||
|
||||
id = orm.Integer(primary_key=True)
|
||||
server_id = orm.String(max_length=18)
|
||||
user_id = orm.String(max_length=18)
|
||||
reason = orm.String(max_length=255)
|
||||
created_at = orm.DateTime()
|
Loading…
Reference in a new issue