diff --git a/.github/issue_template.md b/.github/issue_template.md deleted file mode 100644 index a2f9aff..0000000 --- a/.github/issue_template.md +++ /dev/null @@ -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. \ No newline at end of file diff --git a/.gitignore b/.gitignore index 45b11a6..02ae0be 100644 --- a/.gitignore +++ b/.gitignore @@ -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 \ No newline at end of file diff --git a/.idea/discord.xml b/.idea/discord.xml new file mode 100644 index 0000000..368d7c1 --- /dev/null +++ b/.idea/discord.xml @@ -0,0 +1,6 @@ + + + + + \ No newline at end of file diff --git a/.idea/inspectionProfiles/Project_Default.xml b/.idea/inspectionProfiles/Project_Default.xml new file mode 100644 index 0000000..f031c4e --- /dev/null +++ b/.idea/inspectionProfiles/Project_Default.xml @@ -0,0 +1,15 @@ + + + + \ No newline at end of file diff --git a/.idea/inspectionProfiles/profiles_settings.xml b/.idea/inspectionProfiles/profiles_settings.xml new file mode 100644 index 0000000..105ce2d --- /dev/null +++ b/.idea/inspectionProfiles/profiles_settings.xml @@ -0,0 +1,6 @@ + + + + \ No newline at end of file diff --git a/.idea/misc.xml b/.idea/misc.xml new file mode 100644 index 0000000..4941e09 --- /dev/null +++ b/.idea/misc.xml @@ -0,0 +1,7 @@ + + + + + + \ No newline at end of file diff --git a/.idea/modules.xml b/.idea/modules.xml new file mode 100644 index 0000000..dd59735 --- /dev/null +++ b/.idea/modules.xml @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/.idea/tuxbot-bot-rewrite.iml b/.idea/tuxbot-bot-rewrite.iml new file mode 100644 index 0000000..74d515a --- /dev/null +++ b/.idea/tuxbot-bot-rewrite.iml @@ -0,0 +1,10 @@ + + + + + + + + + + \ No newline at end of file diff --git a/.idea/vcs.xml b/.idea/vcs.xml new file mode 100644 index 0000000..78cface --- /dev/null +++ b/.idea/vcs.xml @@ -0,0 +1,11 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/workspace.xml b/.idea/workspace.xml new file mode 100644 index 0000000..5210e9e --- /dev/null +++ b/.idea/workspace.xml @@ -0,0 +1,199 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 1589922546510 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/LICENSE b/LICENSE deleted file mode 100755 index d60efe4..0000000 --- a/LICENSE +++ /dev/null @@ -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. diff --git a/README.md b/README.md deleted file mode 100644 index b543613..0000000 --- a/README.md +++ /dev/null @@ -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 ` (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?) diff --git a/app.py b/app.py new file mode 100644 index 0000000..97376fc --- /dev/null +++ b/app.py @@ -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() diff --git a/bot.py b/bot.py deleted file mode 100755 index 74e18ba..0000000 --- a/bot.py +++ /dev/null @@ -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() diff --git a/cogs/API.py b/cogs/API.py deleted file mode 100644 index a483b25..0000000 --- a/cogs/API.py +++ /dev/null @@ -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)) diff --git a/cogs/Admin.py b/cogs/Admin.py deleted file mode 100644 index a3bc330..0000000 --- a/cogs/Admin.py +++ /dev/null @@ -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)) diff --git a/cogs/Help.py b/cogs/Help.py deleted file mode 100644 index 396c23c..0000000 --- a/cogs/Help.py +++ /dev/null @@ -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)) diff --git a/cogs/Images.py b/cogs/Images.py new file mode 100644 index 0000000..957eece --- /dev/null +++ b/cogs/Images.py @@ -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) diff --git a/cogs/Logs.py b/cogs/Logs.py index 7caa4ec..a238d7b 100644 --- a/cogs/Logs.py +++ b/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, diff --git a/cogs/Monitoring.py b/cogs/Monitoring.py deleted file mode 100644 index 5827299..0000000 --- a/cogs/Monitoring.py +++ /dev/null @@ -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)) diff --git a/cogs/Poll.py b/cogs/Poll.py deleted file mode 100644 index 44dd1eb..0000000 --- a/cogs/Poll.py +++ /dev/null @@ -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)) diff --git a/cogs/Useful.py b/cogs/Useful.py deleted file mode 100644 index f4344c0..0000000 --- a/cogs/Useful.py +++ /dev/null @@ -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)) diff --git a/cogs/User.py b/cogs/User.py deleted file mode 100644 index ac0c830..0000000 --- a/cogs/User.py +++ /dev/null @@ -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)) diff --git a/configs/bot/blacklist.json b/configs/bot/blacklist.json new file mode 100644 index 0000000..cbbe594 --- /dev/null +++ b/configs/bot/blacklist.json @@ -0,0 +1,5 @@ +{ + "channels": [], + "guilds": [], + "users": [] +} \ No newline at end of file diff --git a/configs/bot/protected.py b/configs/bot/protected.py new file mode 100644 index 0000000..073705f --- /dev/null +++ b/configs/bot/protected.py @@ -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()] +] + diff --git a/configs/bot/settings.py.example b/configs/bot/settings.py.example new file mode 100644 index 0000000..626785d --- /dev/null +++ b/configs/bot/settings.py.example @@ -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' diff --git a/configs/bot/whitelist.json b/configs/bot/whitelist.json new file mode 100644 index 0000000..83434f3 --- /dev/null +++ b/configs/bot/whitelist.json @@ -0,0 +1,3 @@ +{ + "owners": [269156684155453451] +} \ No newline at end of file diff --git a/configs/config.cfg.example b/configs/config.cfg.example deleted file mode 100644 index e156f5d..0000000 --- a/configs/config.cfg.example +++ /dev/null @@ -1,24 +0,0 @@ -[bot] -Token = -Tester = -Activity = - -[postgresql] -Username = -Password = -Host = -DBName = - -[permissions] -Owners = - -[webhook] -ID = -Token = - -[misc] -Separator = - -[API] -Host = -Port = \ No newline at end of file diff --git a/configs/fallbacks.cfg.example b/configs/fallbacks.cfg.example deleted file mode 100644 index ea9bc7b..0000000 --- a/configs/fallbacks.cfg.example +++ /dev/null @@ -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 diff --git a/configs/prefixes.cfg b/configs/prefixes.cfg deleted file mode 100644 index 49d6637..0000000 --- a/configs/prefixes.cfg +++ /dev/null @@ -1,18 +0,0 @@ -[280805240977227776] -prefixes = b1.[301062143942590465]* - -[303633056944881686] -prefixes = b1.[301062143942590465]* - -[373881878471770112] -prefixes = b1. - -[336642139381301249] -prefixes = ba. - -[274247231534792704] -prefixes = test. - -[528679953399676938] -prefixes = test. - diff --git a/database.py b/database.py deleted file mode 100644 index 49127d5..0000000 --- a/database.py +++ /dev/null @@ -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!") diff --git a/generate_locales.sh b/generate_locales.sh deleted file mode 100755 index 78be2cd..0000000 --- a/generate_locales.sh +++ /dev/null @@ -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 \ No newline at end of file diff --git a/configs/blacklist.cfg b/models/__init__.py similarity index 100% rename from configs/blacklist.cfg rename to models/__init__.py diff --git a/requirements.txt b/requirements.txt index 442102d..d5a26eb 100644 --- a/requirements.txt +++ b/requirements.txt @@ -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 \ No newline at end of file +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 diff --git a/todo b/todo deleted file mode 100644 index 5ac368b..0000000 --- a/todo +++ /dev/null @@ -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 diff --git a/utils/__init__.py b/utils/__init__.py deleted file mode 100755 index ff23e97..0000000 --- a/utils/__init__.py +++ /dev/null @@ -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 * diff --git a/utils/fonts/credit_card.ttf b/utils/fonts/credit_card.ttf deleted file mode 100644 index 00abec8..0000000 Binary files a/utils/fonts/credit_card.ttf and /dev/null differ diff --git a/utils/functions/__init__.py b/utils/functions/__init__.py deleted file mode 100644 index 171e8cc..0000000 --- a/utils/functions/__init__.py +++ /dev/null @@ -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 diff --git a/utils/functions/config.py b/utils/functions/config.py deleted file mode 100644 index 64e3f69..0000000 --- a/utils/functions/config.py +++ /dev/null @@ -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 diff --git a/utils/functions/database.py b/utils/functions/database.py deleted file mode 100644 index 20388f0..0000000 --- a/utils/functions/database.py +++ /dev/null @@ -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)) diff --git a/utils/functions/emotes.py b/utils/functions/emotes.py deleted file mode 100644 index d296718..0000000 --- a/utils/functions/emotes.py +++ /dev/null @@ -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) diff --git a/utils/functions/extra.py b/utils/functions/extra.py index b07ad88..a186dd4 100644 --- a/utils/functions/extra.py +++ b/utils/functions/extra.py @@ -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) diff --git a/utils/functions/lang.py b/utils/functions/lang.py deleted file mode 100644 index fd3330b..0000000 --- a/utils/functions/lang.py +++ /dev/null @@ -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 diff --git a/utils/functions/paginator.py b/utils/functions/paginator.py deleted file mode 100644 index b18bd84..0000000 --- a/utils/functions/paginator.py +++ /dev/null @@ -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 diff --git a/utils/functions/version.py b/utils/functions/version.py deleted file mode 100644 index 9aaf3ec..0000000 --- a/utils/functions/version.py +++ /dev/null @@ -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}' diff --git a/utils/images/blank_credit_card.png b/utils/images/blank_credit_card.png deleted file mode 100644 index b0e5a57..0000000 Binary files a/utils/images/blank_credit_card.png and /dev/null differ diff --git a/utils/images/gnous.png b/utils/images/gnous.png deleted file mode 100644 index 0cbfdcf..0000000 Binary files a/utils/images/gnous.png and /dev/null differ diff --git a/utils/locales/en/LC_MESSAGES/admin.po b/utils/locales/en/LC_MESSAGES/admin.po deleted file mode 100644 index 93677bd..0000000 --- a/utils/locales/en/LC_MESSAGES/admin.po +++ /dev/null @@ -1,61 +0,0 @@ -# SOME DESCRIPTIVE TITLE. -# Copyright (C) YEAR ORGANIZATION -# FIRST AUTHOR , 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 \n" -"Language-Team: LANGUAGE \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 "" diff --git a/utils/locales/en/LC_MESSAGES/admin_help.po b/utils/locales/en/LC_MESSAGES/admin_help.po deleted file mode 100644 index 94d24bd..0000000 --- a/utils/locales/en/LC_MESSAGES/admin_help.po +++ /dev/null @@ -1,252 +0,0 @@ -# SOME DESCRIPTIVE TITLE. -# Copyright (C) YEAR ORGANIZATION -# FIRST AUTHOR , 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 \n" -"Language-Team: LANGUAGE \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 '' diff --git a/utils/locales/en/LC_MESSAGES/base.po b/utils/locales/en/LC_MESSAGES/base.po deleted file mode 100644 index 3ecd6d4..0000000 --- a/utils/locales/en/LC_MESSAGES/base.po +++ /dev/null @@ -1,62 +0,0 @@ -# SOME DESCRIPTIVE TITLE. -# Copyright (C) YEAR ORGANIZATION -# FIRST AUTHOR , 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 \n" -"Language-Team: LANGUAGE \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 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 "" - diff --git a/utils/locales/en/LC_MESSAGES/help.po b/utils/locales/en/LC_MESSAGES/help.po deleted file mode 100644 index 6e63ec3..0000000 --- a/utils/locales/en/LC_MESSAGES/help.po +++ /dev/null @@ -1,43 +0,0 @@ -# SOME DESCRIPTIVE TITLE. -# Copyright (C) YEAR ORGANIZATION -# FIRST AUTHOR , 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 \n" -"Language-Team: LANGUAGE \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 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' \ No newline at end of file diff --git a/utils/locales/en/LC_MESSAGES/logs.po b/utils/locales/en/LC_MESSAGES/logs.po deleted file mode 100644 index cdc6fcd..0000000 --- a/utils/locales/en/LC_MESSAGES/logs.po +++ /dev/null @@ -1,17 +0,0 @@ -# SOME DESCRIPTIVE TITLE. -# Copyright (C) YEAR ORGANIZATION -# FIRST AUTHOR , 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 \n" -"Language-Team: LANGUAGE \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" - - diff --git a/utils/locales/en/LC_MESSAGES/poll.po b/utils/locales/en/LC_MESSAGES/poll.po deleted file mode 100644 index 320f5d4..0000000 --- a/utils/locales/en/LC_MESSAGES/poll.po +++ /dev/null @@ -1,20 +0,0 @@ -# SOME DESCRIPTIVE TITLE. -# Copyright (C) YEAR ORGANIZATION -# FIRST AUTHOR , 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 \n" -"Language-Team: LANGUAGE \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 "" diff --git a/utils/locales/en/LC_MESSAGES/poll_help.po b/utils/locales/en/LC_MESSAGES/poll_help.po deleted file mode 100644 index cdc6fcd..0000000 --- a/utils/locales/en/LC_MESSAGES/poll_help.po +++ /dev/null @@ -1,17 +0,0 @@ -# SOME DESCRIPTIVE TITLE. -# Copyright (C) YEAR ORGANIZATION -# FIRST AUTHOR , 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 \n" -"Language-Team: LANGUAGE \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" - - diff --git a/utils/locales/en/LC_MESSAGES/useful.po b/utils/locales/en/LC_MESSAGES/useful.po deleted file mode 100644 index 904dd0b..0000000 --- a/utils/locales/en/LC_MESSAGES/useful.po +++ /dev/null @@ -1,83 +0,0 @@ -# SOME DESCRIPTIVE TITLE. -# Copyright (C) YEAR ORGANIZATION -# FIRST AUTHOR , 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 \n" -"Language-Team: LANGUAGE \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" - diff --git a/utils/locales/en/LC_MESSAGES/useful_help.po b/utils/locales/en/LC_MESSAGES/useful_help.po deleted file mode 100644 index cdc6fcd..0000000 --- a/utils/locales/en/LC_MESSAGES/useful_help.po +++ /dev/null @@ -1,17 +0,0 @@ -# SOME DESCRIPTIVE TITLE. -# Copyright (C) YEAR ORGANIZATION -# FIRST AUTHOR , 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 \n" -"Language-Team: LANGUAGE \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" - - diff --git a/utils/locales/en/LC_MESSAGES/user.po b/utils/locales/en/LC_MESSAGES/user.po deleted file mode 100644 index e69de29..0000000 diff --git a/utils/locales/en/LC_MESSAGES/user_help.po b/utils/locales/en/LC_MESSAGES/user_help.po deleted file mode 100644 index cdc6fcd..0000000 --- a/utils/locales/en/LC_MESSAGES/user_help.po +++ /dev/null @@ -1,17 +0,0 @@ -# SOME DESCRIPTIVE TITLE. -# Copyright (C) YEAR ORGANIZATION -# FIRST AUTHOR , 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 \n" -"Language-Team: LANGUAGE \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" - - diff --git a/utils/locales/en/LC_MESSAGES/utils.po b/utils/locales/en/LC_MESSAGES/utils.po deleted file mode 100644 index 01482bf..0000000 --- a/utils/locales/en/LC_MESSAGES/utils.po +++ /dev/null @@ -1,22 +0,0 @@ -# SOME DESCRIPTIVE TITLE. -# Copyright (C) YEAR ORGANIZATION -# FIRST AUTHOR , 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 \n" -"Language-Team: LANGUAGE \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 "" \ No newline at end of file diff --git a/utils/locales/fr/LC_MESSAGES/admin.po b/utils/locales/fr/LC_MESSAGES/admin.po deleted file mode 100644 index 83de253..0000000 --- a/utils/locales/fr/LC_MESSAGES/admin.po +++ /dev/null @@ -1,61 +0,0 @@ -# SOME DESCRIPTIVE TITLE. -# Copyright (C) YEAR ORGANIZATION -# FIRST AUTHOR , 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 \n" -"Language-Team: LANGUAGE \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" diff --git a/utils/locales/fr/LC_MESSAGES/admin_help.po b/utils/locales/fr/LC_MESSAGES/admin_help.po deleted file mode 100644 index 0df3a5b..0000000 --- a/utils/locales/fr/LC_MESSAGES/admin_help.po +++ /dev/null @@ -1,263 +0,0 @@ -# SOME DESCRIPTIVE TITLE. -# Copyright (C) YEAR ORGANIZATION -# FIRST AUTHOR , 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 \n" -"Language-Team: LANGUAGE \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] ' - -########################################################################### - -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 ' ' - -########################################################################### - -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 " " - -########################################################################### -########################## BAN ######################################## -########################################################################### -msgid '_ban' -msgstr 'Permet de bannir un membre' - -msgid '_ban__short' -msgstr 'Bannir un membre' - -msgid '_ban__usage' -msgstr '' - -########################################################################### -########################## KICK ####################################### -########################################################################### - -msgid '_kick' -msgstr "Permet d'expulser un membre" - -msgid '_kick__short' -msgstr 'Expulser un membre' - -msgid '_kick__usage' -msgstr '' - -########################################################################### -########################## CLEAR ###################################### -########################################################################### - -msgid '_clear' -msgstr 'Permet de supprimer un nombre donné de message' - -msgid '_clear__short' -msgstr 'Supprime X messages' - -msgid '_clear__usage' -msgstr '' - -########################################################################### -########################## 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 ' <é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 '' - -########################################################################### -########################## DELETE ##################################### -########################################################################### - -msgid '_delete' -msgstr 'Permet de supprimer un message' - -msgid '_delete__short' -msgstr 'Supprimer un message' - -msgid '_delete__usage' -msgstr '[sous-commande] ' - -########################################################################### - -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 ' ' - -########################################################################### -########################## 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 ' ' - -########################################################################### - -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 "" - -########################################################################### - -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 '' - -########################################################################### - -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 " " - -########################################################################### -########################## 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 '' - -########################################################################### -########################## 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 '' - -########################################################################### - -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 '' - -########################################################################### - -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 '⠀' diff --git a/utils/locales/fr/LC_MESSAGES/base.po b/utils/locales/fr/LC_MESSAGES/base.po deleted file mode 100644 index 61a4d25..0000000 --- a/utils/locales/fr/LC_MESSAGES/base.po +++ /dev/null @@ -1,62 +0,0 @@ -# SOME DESCRIPTIVE TITLE. -# Copyright (C) YEAR ORGANIZATION -# FIRST AUTHOR , 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 \n" -"Language-Team: LANGUAGE \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 module" -msgstr "Lancer sans charger le module " - -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 :" - diff --git a/utils/locales/fr/LC_MESSAGES/help.po b/utils/locales/fr/LC_MESSAGES/help.po deleted file mode 100644 index 232f3a3..0000000 --- a/utils/locales/fr/LC_MESSAGES/help.po +++ /dev/null @@ -1,43 +0,0 @@ -# SOME DESCRIPTIVE TITLE. -# Copyright (C) YEAR ORGANIZATION -# FIRST AUTHOR , 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 \n" -"Language-Team: LANGUAGE \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 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' \ No newline at end of file diff --git a/utils/locales/fr/LC_MESSAGES/logs.po b/utils/locales/fr/LC_MESSAGES/logs.po deleted file mode 100644 index cdc6fcd..0000000 --- a/utils/locales/fr/LC_MESSAGES/logs.po +++ /dev/null @@ -1,17 +0,0 @@ -# SOME DESCRIPTIVE TITLE. -# Copyright (C) YEAR ORGANIZATION -# FIRST AUTHOR , 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 \n" -"Language-Team: LANGUAGE \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" - - diff --git a/utils/locales/fr/LC_MESSAGES/logs_help.po b/utils/locales/fr/LC_MESSAGES/logs_help.po deleted file mode 100644 index 12ddb52..0000000 --- a/utils/locales/fr/LC_MESSAGES/logs_help.po +++ /dev/null @@ -1,19 +0,0 @@ -# SOME DESCRIPTIVE TITLE. -# Copyright (C) YEAR ORGANIZATION -# FIRST AUTHOR , 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 \n" -"Language-Team: LANGUAGE \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." \ No newline at end of file diff --git a/utils/locales/fr/LC_MESSAGES/poll.po b/utils/locales/fr/LC_MESSAGES/poll.po deleted file mode 100644 index ca29875..0000000 --- a/utils/locales/fr/LC_MESSAGES/poll.po +++ /dev/null @@ -1,20 +0,0 @@ -# SOME DESCRIPTIVE TITLE. -# Copyright (C) YEAR ORGANIZATION -# FIRST AUTHOR , 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 \n" -"Language-Team: LANGUAGE \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...**" diff --git a/utils/locales/fr/LC_MESSAGES/poll_help.po b/utils/locales/fr/LC_MESSAGES/poll_help.po deleted file mode 100644 index f379622..0000000 --- a/utils/locales/fr/LC_MESSAGES/poll_help.po +++ /dev/null @@ -1,40 +0,0 @@ -# SOME DESCRIPTIVE TITLE. -# Copyright (C) YEAR ORGANIZATION -# FIRST AUTHOR , 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 \n" -"Language-Team: LANGUAGE \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 ' | | | [réponse C] | [réponse D] | [...]' diff --git a/utils/locales/fr/LC_MESSAGES/useful.po b/utils/locales/fr/LC_MESSAGES/useful.po deleted file mode 100644 index 89525c0..0000000 --- a/utils/locales/fr/LC_MESSAGES/useful.po +++ /dev/null @@ -1,82 +0,0 @@ -# SOME DESCRIPTIVE TITLE. -# Copyright (C) YEAR ORGANIZATION -# FIRST AUTHOR , 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 \n" -"Language-Team: LANGUAGE \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" diff --git a/utils/locales/fr/LC_MESSAGES/useful_help.po b/utils/locales/fr/LC_MESSAGES/useful_help.po deleted file mode 100644 index cdc6fcd..0000000 --- a/utils/locales/fr/LC_MESSAGES/useful_help.po +++ /dev/null @@ -1,17 +0,0 @@ -# SOME DESCRIPTIVE TITLE. -# Copyright (C) YEAR ORGANIZATION -# FIRST AUTHOR , 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 \n" -"Language-Team: LANGUAGE \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" - - diff --git a/utils/locales/fr/LC_MESSAGES/user.po b/utils/locales/fr/LC_MESSAGES/user.po deleted file mode 100644 index e69de29..0000000 diff --git a/utils/locales/fr/LC_MESSAGES/user_help.po b/utils/locales/fr/LC_MESSAGES/user_help.po deleted file mode 100644 index cdc6fcd..0000000 --- a/utils/locales/fr/LC_MESSAGES/user_help.po +++ /dev/null @@ -1,17 +0,0 @@ -# SOME DESCRIPTIVE TITLE. -# Copyright (C) YEAR ORGANIZATION -# FIRST AUTHOR , 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 \n" -"Language-Team: LANGUAGE \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" - - diff --git a/utils/locales/fr/LC_MESSAGES/utils.po b/utils/locales/fr/LC_MESSAGES/utils.po deleted file mode 100644 index 9a8d3e6..0000000 --- a/utils/locales/fr/LC_MESSAGES/utils.po +++ /dev/null @@ -1,22 +0,0 @@ -# SOME DESCRIPTIVE TITLE. -# Copyright (C) YEAR ORGANIZATION -# FIRST AUTHOR , 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 \n" -"Language-Team: LANGUAGE \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" \ No newline at end of file diff --git a/utils/models/__init__.py b/utils/models/__init__.py deleted file mode 100644 index 36ba5cc..0000000 --- a/utils/models/__init__.py +++ /dev/null @@ -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 diff --git a/utils/models/alias.py b/utils/models/alias.py deleted file mode 100644 index 4a1a96c..0000000 --- a/utils/models/alias.py +++ /dev/null @@ -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) diff --git a/utils/models/poll.py b/utils/models/poll.py deleted file mode 100644 index a2f793e..0000000 --- a/utils/models/poll.py +++ /dev/null @@ -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) diff --git a/utils/models/warn.py b/utils/models/warn.py deleted file mode 100644 index 77f8833..0000000 --- a/utils/models/warn.py +++ /dev/null @@ -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()