├── runtime.txt ├── Procfile ├── tg_bot ├── strings │ ├── en │ │ ├── throws.json │ │ ├── hit.json │ │ ├── googletranslate.json │ │ ├── lang.json │ │ ├── afk.json │ │ ├── nice.json │ │ ├── backups.json │ │ ├── init.json │ │ ├── items.json │ │ ├── disable.json │ │ ├── slap.json │ │ ├── antiflood.json │ │ ├── filters.json │ │ ├── logchannel.json │ │ ├── admin.json │ │ ├── blacklist.json │ │ ├── bans.json │ │ ├── locks.json │ │ ├── gbans.json │ │ ├── runs.json │ │ ├── warns.json │ │ ├── misc.json │ │ └── main.json │ ├── de │ │ ├── throws.json │ │ ├── hit.json │ │ ├── googletranslate.json │ │ ├── lang.json │ │ ├── nice.json │ │ ├── afk.json │ │ ├── backups.json │ │ ├── items.json │ │ ├── init.json │ │ ├── disable.json │ │ ├── slap.json │ │ ├── antiflood.json │ │ ├── logchannel.json │ │ ├── filters.json │ │ ├── blacklist.json │ │ ├── admin.json │ │ ├── bans.json │ │ ├── locks.json │ │ ├── gbans.json │ │ ├── runs.json │ │ ├── warns.json │ │ └── misc.json │ ├── da │ │ ├── afk.json │ │ ├── init.json │ │ ├── admin.json │ │ └── main.json │ ├── fr │ │ ├── afk.json │ │ ├── init.json │ │ ├── admin.json │ │ └── main.json │ ├── __init__.py │ └── string_helper.py ├── modules │ ├── helper_funcs │ │ ├── __init__.py │ │ ├── chat_action.py │ │ ├── filters.py │ │ ├── handlers.py │ │ ├── backups.py │ │ └── extraction.py │ ├── sql │ │ ├── __init__.py │ │ ├── api_sql.py │ │ ├── mute.py │ │ ├── rules_sql.py │ │ ├── lang_sql.py │ │ ├── afk_sql.py │ │ ├── approval_sql.py │ │ ├── whisper_sql.py │ │ ├── log_channel_sql.py │ │ ├── rss_sql.py │ │ ├── userinfo_sql.py │ │ ├── antiflood_sql.py │ │ ├── reporting_sql.py │ │ ├── reputation_settings_sql.py │ │ ├── disable_sql.py │ │ └── reputation_sql.py │ ├── rest.py │ ├── __init__.py │ ├── googletranslate.py │ ├── lang.py │ ├── translation.py │ └── backups.py ├── restapi │ ├── models │ │ ├── modules │ │ │ ├── __init__.py │ │ │ └── admin.py │ │ ├── __init__.py │ │ ├── chats.py │ │ ├── users.py │ │ └── management.py │ ├── resources │ │ ├── __init__.py │ │ ├── modules │ │ │ ├── __init__.py │ │ │ └── admin.py │ │ ├── basic.py │ │ └── chats.py │ ├── auth.py │ └── __init__.py ├── caching.py └── sample_config.py ├── crowdin.yml ├── requirements.txt.works ├── requirements.txt ├── .gitignore ├── SECURITY.md ├── .github ├── ISSUE_TEMPLATE │ ├── api-transform.md │ └── bug_report.md ├── dependabot.yml └── workflows │ └── codeql-analysis.yml ├── start.sh ├── CONTRIBUTING.md ├── setup.sh ├── CODE_OF_CONDUCT.md └── commands.txt /runtime.txt: -------------------------------------------------------------------------------- 1 | python-3.6.4 2 | -------------------------------------------------------------------------------- /Procfile: -------------------------------------------------------------------------------- 1 | web: python3 -m tg_bot 2 | -------------------------------------------------------------------------------- /tg_bot/strings/en/throws.json: -------------------------------------------------------------------------------- 1 | { 2 | "1" : "throws", 3 | "2" : "flings", 4 | "3" : "chucks", 5 | "4" : "hurls" 6 | } -------------------------------------------------------------------------------- /tg_bot/strings/de/throws.json: -------------------------------------------------------------------------------- 1 | { 2 | "1": "wirft", 3 | "2": "schleudert", 4 | "3": "pfeffert", 5 | "4": "katapultiert" 6 | } -------------------------------------------------------------------------------- /crowdin.yml: -------------------------------------------------------------------------------- 1 | files: 2 | - source: /tg_bot/strings/en/*.json 3 | translation: /tg_bot/strings/%two_letters_code%/%original_file_name% 4 | -------------------------------------------------------------------------------- /tg_bot/strings/de/hit.json: -------------------------------------------------------------------------------- 1 | { 2 | "1": "trifft", 3 | "2": "trifft", 4 | "3": "schlägt", 5 | "4": "schlägt", 6 | "5": "verprügelt" 7 | } -------------------------------------------------------------------------------- /tg_bot/strings/en/hit.json: -------------------------------------------------------------------------------- 1 | { 2 | "1" : "hits", 3 | "2" : "whacks", 4 | "3" : "smacks", 5 | "4" : "slaps", 6 | "5" : "bashes" 7 | } -------------------------------------------------------------------------------- /requirements.txt.works: -------------------------------------------------------------------------------- 1 | future 2 | emoji 3 | requests 4 | sqlalchemy 5 | python-telegram-bot==11.1.0 6 | psycopg2-binary 7 | feedparser 8 | toml 9 | -------------------------------------------------------------------------------- /tg_bot/strings/en/googletranslate.json: -------------------------------------------------------------------------------- 1 | { 2 | "ERR_NO_LANG" : "Please tell me what language to translate to!", 3 | "ERR_NO_MSG" : "Please refer to a message.", 4 | "HELP" : "\n/translate : Translate a message." 5 | } -------------------------------------------------------------------------------- /tg_bot/strings/de/googletranslate.json: -------------------------------------------------------------------------------- 1 | { 2 | "ERR_NO_LANG": "Bitte sag mir, in welche Sprache ich übersetzen soll!", 3 | "ERR_NO_MSG": "Bitte verweise auf eine Nachricht.", 4 | "HELP": "\n/translate : Eine Nachricht übersetzen." 5 | } -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | future 2 | emoji 3 | requests 4 | sqlalchemy 5 | python-telegram-bot==13.2 6 | psycopg2-binary 7 | feedparser 8 | toml 9 | googletrans==4.0.0-rc1 10 | pillow 11 | alphabet-detector 12 | flask 13 | flask-restplus 14 | Werkzeug==0.16.0 15 | flask-httpauth 16 | schedule 17 | captcha -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *.pyc 2 | .idea/ 3 | .project 4 | .pydevproject 5 | .directory 6 | .vscode 7 | /tg_bot/config.py 8 | /tempscript.sh 9 | /tg_bot/config.toml 10 | /tg_bot/modules/mail.py 11 | /tg_bot/misc/ 12 | /tg_bot/modules/spotify.py 13 | /.kdev4/ 14 | /Temp/ 15 | /venv/ 16 | /venv2/ 17 | /NemesisPY.kdev4 18 | -------------------------------------------------------------------------------- /tg_bot/strings/en/lang.json: -------------------------------------------------------------------------------- 1 | { 2 | "ERR_UNKNOWN_LANG": "Unsupported language!", 3 | "LANG_SET" : "Language set.", 4 | "ERR_NO_LANG" : "You didn't tell me what language to set! Use /lang !", 5 | "CHAT_SETTINGS" : "Language in this chat, change with /lang: `{}`", 6 | "USER_SETTINGS" : "Your current language is `{}`.\nChange this with /lang in PM.", 7 | "HELP" : "\n/lang : Set the language" 8 | } 9 | -------------------------------------------------------------------------------- /tg_bot/strings/de/lang.json: -------------------------------------------------------------------------------- 1 | { 2 | "ERR_UNKNOWN_LANG": "Sprache wird nicht unterstützt!", 3 | "LANG_SET": "Sprache gesetzt.", 4 | "ERR_NO_LANG": "Du hast mir nicht gesagt, welche Sprache du setzen willst! Benutze /lang !", 5 | "CHAT_SETTINGS": "Sprache in diesem Chat, ändern mit /lang: `{}`", 6 | "USER_SETTINGS": "Deine aktuelle Sprache ist `{}`.\nÄndere dies mit /lang in PM.", 7 | "HELP": "\n/lang : Sprache festlegen" 8 | } 9 | -------------------------------------------------------------------------------- /tg_bot/strings/da/afk.json: -------------------------------------------------------------------------------- 1 | { 2 | "MSG_IS_AFK_NOW": "{} is now AFK!", 3 | "MSG_IS_NOT_AFK": "{} is no longer AFK!", 4 | "MSG_IS_AFK": "{} is AFK!", 5 | "MSG_IS_AFK_REASON": "{} is AFK! says its because of:\n{}", 6 | "HELP": " - /afk : mark yourself as AFK.\n - brb : same as the afk command - but not a command.\n\nWhen marked as AFK, any mentions will be replied to with a message to say you're not available!", 7 | "MODULE_NAME": "AFK" 8 | } -------------------------------------------------------------------------------- /tg_bot/strings/fr/afk.json: -------------------------------------------------------------------------------- 1 | { 2 | "MSG_IS_AFK_NOW": "{} is now AFK!", 3 | "MSG_IS_NOT_AFK": "{} is no longer AFK!", 4 | "MSG_IS_AFK": "{} is AFK!", 5 | "MSG_IS_AFK_REASON": "{} is AFK! says its because of:\n{}", 6 | "HELP": " - /afk : mark yourself as AFK.\n - brb : same as the afk command - but not a command.\n\nWhen marked as AFK, any mentions will be replied to with a message to say you're not available!", 7 | "MODULE_NAME": "AFK" 8 | } -------------------------------------------------------------------------------- /tg_bot/strings/en/afk.json: -------------------------------------------------------------------------------- 1 | { 2 | "MSG_IS_AFK_NOW" : "{} is now AFK!", 3 | "MSG_IS_NOT_AFK" : "{} is no longer AFK!", 4 | "MSG_IS_AFK" : "{} is AFK!", 5 | "MSG_IS_AFK_REASON" : "{} is AFK! says its because of:\n{}", 6 | "HELP" : " - /afk : mark yourself as AFK.\n - brb : same as the afk command - but not a command.\n\nWhen marked as AFK, any mentions will be replied to with a message to say you're not available!", 7 | "MODULE_NAME" : "AFK" 8 | } -------------------------------------------------------------------------------- /tg_bot/strings/en/nice.json: -------------------------------------------------------------------------------- 1 | { 2 | "1" : "Theres only one path to go: Your own.", 3 | "2" : "The first step is you have to say that you can. ~Will Smith", 4 | "3" : "Keep looking up… that’s the secret of life. ~Charlie Brown", 5 | "4" : "Happiness can be found even in the darkest of times, if one only remembers to turn on the light ~Albus Dumbledore", 6 | "5" : "Follow your dreams, they know the way.", 7 | "6" : "World is a huge story, and we all are a part of it." 8 | } -------------------------------------------------------------------------------- /SECURITY.md: -------------------------------------------------------------------------------- 1 | # Security Policy 2 | 3 | ## Supported Versions 4 | 5 | The following versions are currently supported: 6 | 7 | | Version | Supported | 8 | | ------- | ------------------ | 9 | | 2.0.x | :white_check_mark: | 10 | | legacy | :x: | 11 | 12 | Legacy refers to everything that is not version 2. 13 | 14 | ## Reporting a Vulnerability 15 | 16 | If you find a Vulnerability, please open an issue, we will work on it as soon as possible. 17 | -------------------------------------------------------------------------------- /tg_bot/strings/de/nice.json: -------------------------------------------------------------------------------- 1 | { 2 | "1": "Es gibt nur einen richtigen Weg: den eigenen.", 3 | "2": "The first step is you have to say that you can. ~Will Smith", 4 | "3": "Sehe nach oben - Das ist das Geheimnis des Lebens. ~Charlie Brown", 5 | "4": "Happiness can be found even in the darkest of times, if one only remembers to turn on the light ~Albus Dumbledore", 6 | "5": "Follow your dreams, they know the way.", 7 | "6": "World is a huge story, and we all are a part of it." 8 | } -------------------------------------------------------------------------------- /tg_bot/strings/de/afk.json: -------------------------------------------------------------------------------- 1 | { 2 | "MSG_IS_AFK_NOW": "{} ist jetzt abwesend!", 3 | "MSG_IS_NOT_AFK": "{} ist nicht mehr abwesend!", 4 | "MSG_IS_AFK": "{} ist abwesend!", 5 | "MSG_IS_AFK_REASON": "{} ist abwesend! Grund: {}", 6 | "HELP": " - /afk : Markiert dich als abwesend.\n - brb : Wie der /afk Befehl, nur kein Befehl.\n\nWenn du als abwesend markiert bist, werden alle Erwähnungen mit einer Nachricht beantwortet, die sagt, dass du derzeit nicht verfügbar bist!", 7 | "MODULE_NAME": "AFK" 8 | } -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/api-transform.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: API Transform 3 | about: This is gonna be used whenever something needs to be ported to the new API 4 | Version- 5 | title: CallbackContext in [MODULE] Module 6 | labels: enhancement, Python-Telegram-Bot, Version 2.0 7 | assignees: KaratekHD 8 | 9 | --- 10 | 11 | We need to implement the new CallbackContext feature of v12 of [Python-Telegram-Bot](https://github.com/python-telegram-bot/python-telegram-bot) for this Module - see https://git.io/fxJuV 12 | -------------------------------------------------------------------------------- /tg_bot/strings/en/backups.json: -------------------------------------------------------------------------------- 1 | { 2 | "MSG_REUPLOAD" : "Try downloading and reuploading the file as yourself before importing - this one seems to be iffy!", 3 | "MSG_IMPORT_SUCCESS" : "Backup fully imported. Welcome back! :D", 4 | "MSG_EXPORT_SUCCESS" : "Here you go.", 5 | "HELP" : "\n*Admin only:*\n - /import: reply to a group butler backup file to import as much as possible, making the transfer super simple! Note that files/photos can't be imported due to telegram restrictions.\n - /export: !!! This isn't a command yet, but should be coming soon!" 6 | } -------------------------------------------------------------------------------- /tg_bot/strings/de/backups.json: -------------------------------------------------------------------------------- 1 | { 2 | "MSG_REUPLOAD": "Versuche, die Datei herunterzuladen und neu hochzuladen - diese scheint nicht ganz richtig zu sein!", 3 | "MSG_IMPORT_SUCCESS": "Backup vollständig importiert. Willkommen zurück! :D", 4 | "MSG_EXPORT_SUCCESS": "Bitte schön.", 5 | "HELP": "\n*Admin only:*\n - /import: reply to a group butler backup file to import as much as possible, making the transfer super simple! Note that files/photos can't be imported due to telegram restrictions.\n - /export: !!! This isn't a command yet, but should be coming soon!" 6 | } -------------------------------------------------------------------------------- /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | # To get started with Dependabot version updates, you'll need to specify which 2 | # package ecosystems to update and where the package manifests are located. 3 | # Please see the documentation for all configuration options: 4 | # https://help.github.com/github/administering-a-repository/configuration-options-for-dependency-updates 5 | 6 | version: 2 7 | updates: 8 | - package-ecosystem: "pip" # See documentation for possible values 9 | directory: "/" # Location of package manifests 10 | schedule: 11 | interval: "daily" 12 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/bug_report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Bug report 3 | about: Create a report to help us improve 4 | title: '' 5 | labels: bug 6 | assignees: '' 7 | 8 | --- 9 | 10 | **Describe the bug** 11 | A clear and concise description of what the bug is. 12 | 13 | **To Reproduce** 14 | Steps to reproduce the behavior: 15 | 1. Go to '...' 16 | 2. Click on '....' 17 | 3. Scroll down to '....' 18 | 4. See error 19 | 20 | **Expected behavior** 21 | A clear and concise description of what you expected to happen. 22 | 23 | **Screenshots** 24 | If applicable, add screenshots to help explain your problem. 25 | 26 | **Version information (please complete the following information):** 27 | - Device: [e.g. iPhone6] 28 | - OS: [e.g. iOS8.1] 29 | - Telegram Version [e.g. 7.0] 30 | 31 | **Additional context** 32 | Add any other context about the problem here. 33 | -------------------------------------------------------------------------------- /tg_bot/modules/helper_funcs/__init__.py: -------------------------------------------------------------------------------- 1 | # OpenGM - Powerful Telegram group managment bot 2 | # Copyright (C) 2017 - 2019 Paul Larsen 3 | # Copyright (C) 2019 - 2020 KaratekHD 4 | # 5 | # This program is free software: you can redistribute it and/or modify 6 | # it under the terms of the GNU General Public License as published by 7 | # the Free Software Foundation, either version 3 of the License, or 8 | # (at your option) any later version. 9 | # 10 | # This program is distributed in the hope that it will be useful, 11 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | # GNU General Public License for more details. 14 | # 15 | # You should have received a copy of the GNU General Public License 16 | # along with this program. If not, see . 17 | -------------------------------------------------------------------------------- /start.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # 3 | # Nemesis - Powerful Telegram group managment bot 4 | # Copyright (C) 2017 - 2019 Paul Larsen 5 | # Copyright (C) 2019 - 2020 KaratekHD 6 | # 7 | # This program is free software: you can redistribute it and/or modify 8 | # it under the terms of the GNU General Public License as published by 9 | # the Free Software Foundation, either version 3 of the License, or 10 | # (at your option) any later version. 11 | # 12 | # This program is distributed in the hope that it will be useful, 13 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 | # GNU General Public License for more details. 16 | # 17 | # You should have received a copy of the GNU General Public License 18 | # along with this program. If not, see . 19 | # 20 | python3 -m tg_bot -------------------------------------------------------------------------------- /tg_bot/restapi/models/modules/__init__.py: -------------------------------------------------------------------------------- 1 | # OpenGM - Powerful Telegram group managment bot 2 | # Copyright (C) 2017 - 2019 Paul Larsen 3 | # Copyright (C) 2019 - 2020 KaratekHD 4 | # 5 | # This program is free software: you can redistribute it and/or modify 6 | # it under the terms of the GNU General Public License as published by 7 | # the Free Software Foundation, either version 3 of the License, or 8 | # (at your option) any later version. 9 | # 10 | # This program is distributed in the hope that it will be useful, 11 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | # GNU General Public License for more details. 14 | # 15 | # You should have received a copy of the GNU General Public License 16 | # along with this program. If not, see . 17 | -------------------------------------------------------------------------------- /tg_bot/restapi/resources/__init__.py: -------------------------------------------------------------------------------- 1 | # OpenGM - Powerful Telegram group managment bot 2 | # Copyright (C) 2017 - 2019 Paul Larsen 3 | # Copyright (C) 2019 - 2020 KaratekHD 4 | # 5 | # This program is free software: you can redistribute it and/or modify 6 | # it under the terms of the GNU General Public License as published by 7 | # the Free Software Foundation, either version 3 of the License, or 8 | # (at your option) any later version. 9 | # 10 | # This program is distributed in the hope that it will be useful, 11 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | # GNU General Public License for more details. 14 | # 15 | # You should have received a copy of the GNU General Public License 16 | # along with this program. If not, see . 17 | 18 | -------------------------------------------------------------------------------- /tg_bot/restapi/resources/modules/__init__.py: -------------------------------------------------------------------------------- 1 | # OpenGM - Powerful Telegram group managment bot 2 | # Copyright (C) 2017 - 2019 Paul Larsen 3 | # Copyright (C) 2019 - 2020 KaratekHD 4 | # 5 | # This program is free software: you can redistribute it and/or modify 6 | # it under the terms of the GNU General Public License as published by 7 | # the Free Software Foundation, either version 3 of the License, or 8 | # (at your option) any later version. 9 | # 10 | # This program is distributed in the hope that it will be useful, 11 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | # GNU General Public License for more details. 14 | # 15 | # You should have received a copy of the GNU General Public License 16 | # along with this program. If not, see . 17 | -------------------------------------------------------------------------------- /tg_bot/restapi/models/__init__.py: -------------------------------------------------------------------------------- 1 | # OpenGM - Powerful Telegram group managment bot 2 | # Copyright (C) 2017 - 2019 Paul Larsen 3 | # Copyright (C) 2019 - 2020 KaratekHD 4 | # 5 | # This program is free software: you can redistribute it and/or modify 6 | # it under the terms of the GNU General Public License as published by 7 | # the Free Software Foundation, either version 3 of the License, or 8 | # (at your option) any later version. 9 | # 10 | # This program is distributed in the hope that it will be useful, 11 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | # GNU General Public License for more details. 14 | # 15 | # You should have received a copy of the GNU General Public License 16 | # along with this program. If not, see . 17 | 18 | 19 | -------------------------------------------------------------------------------- /tg_bot/strings/da/init.json: -------------------------------------------------------------------------------- 1 | { 2 | "ERR_INVALID_PYTHON_VERSION": "You MUST have a python version of at least 3.6! Multiple features depend on this. Bot quitting.", 3 | "ERR_INVALID_OWNER_ID": "Your OWNER_ID env variable is not a valid integer.", 4 | "ERR_INVALID_SUDO_ID": "Your sudo users list does not contain valid integers.", 5 | "ERR_INVALID_SUPPORT_ID": "Your support users list does not contain valid integers.", 6 | "ERR_INVALID_WHITELIST_ID": "Your whitelisted users list does not contain valid integers.", 7 | "ERR_CONFIG_INVALID_OWNER_ID": "Your OWNER_ID variable is not a valid integer.", 8 | "ERR_CONFIG_INVALID_SUDO_ID": "Your sudo users list does not contain valid integers.", 9 | "ERR_CONFIG_INVALID_SUPPORT_ID": "Your support users list does not contain valid integers.", 10 | "ERR_CONFIG_INVALID_WHITELIST_ID": "Your whitelisted users list does not contain valid integers." 11 | } -------------------------------------------------------------------------------- /tg_bot/strings/fr/init.json: -------------------------------------------------------------------------------- 1 | { 2 | "ERR_INVALID_PYTHON_VERSION": "You MUST have a python version of at least 3.6! Multiple features depend on this. Bot quitting.", 3 | "ERR_INVALID_OWNER_ID": "Your OWNER_ID env variable is not a valid integer.", 4 | "ERR_INVALID_SUDO_ID": "Your sudo users list does not contain valid integers.", 5 | "ERR_INVALID_SUPPORT_ID": "Your support users list does not contain valid integers.", 6 | "ERR_INVALID_WHITELIST_ID": "Your whitelisted users list does not contain valid integers.", 7 | "ERR_CONFIG_INVALID_OWNER_ID": "Your OWNER_ID variable is not a valid integer.", 8 | "ERR_CONFIG_INVALID_SUDO_ID": "Your sudo users list does not contain valid integers.", 9 | "ERR_CONFIG_INVALID_SUPPORT_ID": "Your support users list does not contain valid integers.", 10 | "ERR_CONFIG_INVALID_WHITELIST_ID": "Your whitelisted users list does not contain valid integers." 11 | } -------------------------------------------------------------------------------- /tg_bot/strings/en/init.json: -------------------------------------------------------------------------------- 1 | { 2 | "ERR_INVALID_PYTHON_VERSION" : "You MUST have a python version of at least 3.6! Multiple features depend on this. Bot quitting.", 3 | "ERR_INVALID_OWNER_ID" : "Your OWNER_ID env variable is not a valid integer.", 4 | "ERR_INVALID_SUDO_ID" : "Your sudo users list does not contain valid integers.", 5 | "ERR_INVALID_SUPPORT_ID" : "Your support users list does not contain valid integers.", 6 | "ERR_INVALID_WHITELIST_ID" : "Your whitelisted users list does not contain valid integers.", 7 | "ERR_CONFIG_INVALID_OWNER_ID" : "Your OWNER_ID variable is not a valid integer.", 8 | "ERR_CONFIG_INVALID_SUDO_ID" : "Your sudo users list does not contain valid integers.", 9 | "ERR_CONFIG_INVALID_SUPPORT_ID" : "Your support users list does not contain valid integers.", 10 | "ERR_CONFIG_INVALID_WHITELIST_ID" : "Your whitelisted users list does not contain valid integers." 11 | } -------------------------------------------------------------------------------- /tg_bot/strings/de/items.json: -------------------------------------------------------------------------------- 1 | { 2 | "1": "Gusseisenpfanne", 3 | "2": "große Forelle", 4 | "3": "Baseballschläger", 5 | "4": "Cricketschläger", 6 | "5": "Holzrohr", 7 | "6": "Nagel", 8 | "7": "Drucker", 9 | "8": "Schaufel", 10 | "9": "CRT-Bildschirm", 11 | "10": "Physikbuch", 12 | "11": "Toaster", 13 | "12": "Porträt von Richard Stallman", 14 | "13": "Hammer", 15 | "14": "Fernseher", 16 | "15": "fünf Tonnen Lastwagen", 17 | "16": "Rolle Klebeband", 18 | "17": "Buch", 19 | "18": "Bratpfanne", 20 | "19": "Handtasche", 21 | "20": "Laptop", 22 | "21": "alter Fernseher", 23 | "22": "Sack voll Steinen", 24 | "23": "Regenbogenforelle", 25 | "24": "Gummihühnchen", 26 | "25": "Fledermaus", 27 | "26": "Feuerlöscher", 28 | "27": "schweren Stein", 29 | "28": "Schmutz", 30 | "29": "Bienenstock", 31 | "30": "verfaultes Fleisch", 32 | "31": "Bär", 33 | "32": "Tonne Steine" 34 | } -------------------------------------------------------------------------------- /tg_bot/strings/en/items.json: -------------------------------------------------------------------------------- 1 | { 2 | "1" : "cast iron skillet", 3 | "2" : "large trout", 4 | "3" : "baseball bat", 5 | "4" : "cricket bat", 6 | "5" : "wooden cane", 7 | "6" : "nail", 8 | "7" : "printer", 9 | "8" : "shovel", 10 | "9" : "CRT monitor", 11 | "10" : "physics textbook", 12 | "11" : "toaster", 13 | "12" : "portrait of Richard Stallman", 14 | "13" : "hammer", 15 | "14" : "television", 16 | "15" : "five ton truck", 17 | "16" : "roll of duct tape", 18 | "17" : "book", 19 | "18" : "Frying pan", 20 | "19" : "handbag", 21 | "20" : "laptop", 22 | "21" : "old television", 23 | "22" : "sack of rocks", 24 | "23" : "rainbow trout", 25 | "24" : "rubber chicken", 26 | "25" : "spiked bat", 27 | "26" : "fire extinguisher", 28 | "27" : "heavy rock", 29 | "28" : "chunk of dirt", 30 | "29" : "beehive", 31 | "30" : "piece of rotten meat", 32 | "31" : "bear", 33 | "32" : "ton of bricks" 34 | } -------------------------------------------------------------------------------- /tg_bot/strings/de/init.json: -------------------------------------------------------------------------------- 1 | { 2 | "ERR_INVALID_PYTHON_VERSION": "Es wird MINDESTENS Python 3.6 benötigt! Einige Funktionen hängen davon ab. Ende.", 3 | "ERR_INVALID_OWNER_ID": "Deine OWNER_ID Umgebungsvariable ist kein gültiger Zahlenwert.", 4 | "ERR_INVALID_SUDO_ID": "Deine Sudo User Lists beinhaltet keine gültigen Zahlenwerte.", 5 | "ERR_INVALID_SUPPORT_ID": "Deine Liste der Support-Benutzer enthält keine gültigen ganzen Zahlen.", 6 | "ERR_INVALID_WHITELIST_ID": "Deine Whitelist-Benutzerliste enthält keine gültigen ganzen Zahlen.", 7 | "ERR_CONFIG_INVALID_OWNER_ID": "Deine OWNER_ID ist kein gültiger Zahlenwert.", 8 | "ERR_CONFIG_INVALID_SUDO_ID": "Deine sudo-Benutzerliste enthält keine gültigen Zahlen.", 9 | "ERR_CONFIG_INVALID_SUPPORT_ID": "Deine Liste der Support-Benutzer enthält keine gültigen ganzen Zahlen.", 10 | "ERR_CONFIG_INVALID_WHITELIST_ID": "Deine Whitelist-Benutzerliste enthält keine gültigen ganzen Zahlen." 11 | } -------------------------------------------------------------------------------- /tg_bot/strings/en/disable.json: -------------------------------------------------------------------------------- 1 | { 2 | "DISABLED_COMMAND" : "Disabled the use of `{}`", 3 | "ERR_INVALID_COMMAND" : "That command can't be disabled", 4 | "ERR_NO_COMMAND" : "What should I disable?", 5 | "ENABLED_COMMAND" : "Enabled the use of `{}`", 6 | "ERR_NOT_DISABLED" : "Is that even disabled?", 7 | "ERR_NO_COMMAND_TO_ENABLE" : "What should I enable?", 8 | "LIST_OF_COMMANDS" : "The following commands are toggleable:\n{}", 9 | "NO_CMD_AVAILABLE" : "No commands can be disabled.", 10 | "NO_CMD_DISABLED" : "No commands are disabled!", 11 | "DISABLED_COMMANDS" : "The following commands are currently restricted:\n{}", 12 | "STATS" : "{} disabled items, across {} chats.", 13 | "MODULE_NAME" : "Command disabling", 14 | "HELP" : " - /cmds: check the current status of disabled commands\n\n*Admin only:*\n - /enable : enable that command\n - /disable : disable that command\n - /listcmds: list all possible toggleable commands" 15 | } -------------------------------------------------------------------------------- /tg_bot/restapi/auth.py: -------------------------------------------------------------------------------- 1 | # OpenGM - Powerful Telegram group managment bot 2 | # Copyright (C) 2017 - 2019 Paul Larsen 3 | # Copyright (C) 2019 - 2020 KaratekHD 4 | # 5 | # This program is free software: you can redistribute it and/or modify 6 | # it under the terms of the GNU General Public License as published by 7 | # the Free Software Foundation, either version 3 of the License, or 8 | # (at your option) any later version. 9 | # 10 | # This program is distributed in the hope that it will be useful, 11 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | # GNU General Public License for more details. 14 | # 15 | # You should have received a copy of the GNU General Public License 16 | # along with this program. If not, see . 17 | 18 | 19 | import tg_bot.modules.sql.api_sql as sql 20 | 21 | 22 | def verify_auth_token(token): 23 | sql.verify_key(token) 24 | -------------------------------------------------------------------------------- /tg_bot/strings/de/disable.json: -------------------------------------------------------------------------------- 1 | { 2 | "DISABLED_COMMAND": "Die Verwendung von `{}` deaktiviert", 3 | "ERR_INVALID_COMMAND": "Dieser Befehl kann nicht deaktiviert werden", 4 | "ERR_NO_COMMAND": "Was soll ich deaktivieren?", 5 | "ENABLED_COMMAND": "Die Verwendung von `{}` ist aktiviert", 6 | "ERR_NOT_DISABLED": "Ist das überhaupt deaktiviert?", 7 | "ERR_NO_COMMAND_TO_ENABLE": "Was sollte ich aktivieren?", 8 | "LIST_OF_COMMANDS": "Die folgenden Befehle sind umschaltbar:\n{}", 9 | "NO_CMD_AVAILABLE": "Es können keine Befehle deaktiviert werden.", 10 | "NO_CMD_DISABLED": "Keine Befehle sind deaktiviert!", 11 | "DISABLED_COMMANDS": "Die folgenden Befehle sind derzeit eingeschränkt:\n{}", 12 | "STATS": "{} deaktivierte Elemente, über {} Chats hinweg.", 13 | "MODULE_NAME": "Befehl deaktivieren", 14 | "HELP": " - /cmds: den aktuellen Status von deaktivierten Befehlen überprüfen\n\n*Nur Admins:*\n - /enable : diesen Befehl aktivieren\n - /disable : diesen Befehl deaktivieren\n - /listcmds: alle möglichen umschaltbaren Befehle auflisten" 15 | } -------------------------------------------------------------------------------- /tg_bot/strings/en/slap.json: -------------------------------------------------------------------------------- 1 | { 2 | "1" : "{user1} {hits} {user2} with a {item}.", 3 | "2" : "{user1} {hits} {user2} in the face with a {item}.", 4 | "3" : "{user1} {hits} {user2} around a bit with a {item}.", 5 | "4" : "{user1} {throws} a {item} at {user2}.", 6 | "5" : "{user1} grabs a {item} and {throws} it at {user2}'s face.", 7 | "6" : "{user1} launches a {item} in {user2}'s general direction.", 8 | "7" : "{user1} starts slapping {user2} silly with a {item}.", 9 | "8" : "{user1} pins {user2} down and repeatedly {hits} them with a {item}.", 10 | "9" : "{user1} grabs up a {item} and {hits} {user2} with it.", 11 | "10" : "{user1} ties {user2} to a chair and {throws} a {item} at them.", 12 | "11" : "{user1} gave a friendly push to help {user2} learn to swim in lava.", 13 | "12" : "{user1} takes a billiardtable and starts hitting {user2}.", 14 | "13" : "{user1} rips out a tree and throws it at {user2}.", 15 | "14" : "{user1} throws a steak at {user2}.", 16 | "15" : "{user1} tortures {user2} using the cruciatus curse.", 17 | "16" : "{user1} tortures {user2} using Rictusempra.", 18 | "17" : "{user1} tortures {user2} using Sectumsempra." 19 | } -------------------------------------------------------------------------------- /tg_bot/restapi/models/chats.py: -------------------------------------------------------------------------------- 1 | # OpenGM - Powerful Telegram group managment bot 2 | # Copyright (C) 2017 - 2019 Paul Larsen 3 | # Copyright (C) 2019 - 2020 KaratekHD 4 | # 5 | # This program is free software: you can redistribute it and/or modify 6 | # it under the terms of the GNU General Public License as published by 7 | # the Free Software Foundation, either version 3 of the License, or 8 | # (at your option) any later version. 9 | # 10 | # This program is distributed in the hope that it will be useful, 11 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | # GNU General Public License for more details. 14 | # 15 | # You should have received a copy of the GNU General Public License 16 | # along with this program. If not, see . 17 | 18 | from flask_restplus import fields 19 | 20 | 21 | def create_chat_model(api): 22 | model = api.model('Chats', { 23 | 'id': fields.String(description="unique group identifier", required=True), 24 | 'name': fields.String(description="group name", required=True) 25 | }) 26 | return model 27 | -------------------------------------------------------------------------------- /tg_bot/strings/de/slap.json: -------------------------------------------------------------------------------- 1 | { 2 | "1": "{user1} {hits} {user2} mit einem {item}.", 3 | "2": "{user1} {hits} {user2} mit einem {item} ins Gesicht.", 4 | "3": "{user1} {hits} {user2} ein bisschen mit einem {item}.", 5 | "4": "{user1} {throws} ein {item} nach {user2}.", 6 | "5": "{user1} schnappt sich {item} und {throws} es ins Gesicht von {user2}.", 7 | "6": "{user1} schleudert ein {item} in die Richtung von {user2}.", 8 | "7": "{user1} fängt an, auf {user2} mit einem {item} ein zu schlagen.", 9 | "8": "{user1} wirft {user2} um und {hits} ihn wiederholt mit einem {item}.", 10 | "9": "{user1} greift einen {item} und {hits} {user2} damit.", 11 | "10": "{user1} bindet {user2} an einen Stuhl und {throws} einen {item} auf ihn.", 12 | "11": "{user1} hat {user2} einen freundlichen Stoß gegeben, um ihm/ihr beim Schwimmen in Lava zu helfen.", 13 | "12": "{user1} takes a billiardtable and starts hitting {user2}.", 14 | "13": "{user1} reißt einen Baum aus und wirft ihn nach {user2}.", 15 | "14": "{user1} wirft ein Steak auf {user2}.", 16 | "15": "{user1} tortures {user2} using the cruciatus curse.", 17 | "16": "{user1} tortures {user2} using Rictusempra.", 18 | "17": "{user1} tortures {user2} using Sectumsempra." 19 | } -------------------------------------------------------------------------------- /tg_bot/restapi/resources/basic.py: -------------------------------------------------------------------------------- 1 | # OpenGM - Powerful Telegram group managment bot 2 | # Copyright (C) 2017 - 2019 Paul Larsen 3 | # Copyright (C) 2019 - 2020 KaratekHD 4 | # 5 | # This program is free software: you can redistribute it and/or modify 6 | # it under the terms of the GNU General Public License as published by 7 | # the Free Software Foundation, either version 3 of the License, or 8 | # (at your option) any later version. 9 | # 10 | # This program is distributed in the hope that it will be useful, 11 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | # GNU General Public License for more details. 14 | # 15 | # You should have received a copy of the GNU General Public License 16 | # along with this program. If not, see . 17 | 18 | from http import HTTPStatus 19 | 20 | from flask_restplus import Namespace, Resource 21 | 22 | basic_api = Namespace("basic", description="Basic tasks that do not require an authorisation.") 23 | 24 | 25 | @basic_api.route("") 26 | class Version(Resource): 27 | @staticmethod 28 | def get(): 29 | '''Get API Version''' 30 | return "Nemesis Telegram Bot v2.0 Development Preview 1", HTTPStatus.OK 31 | 32 | 33 | -------------------------------------------------------------------------------- /tg_bot/modules/sql/__init__.py: -------------------------------------------------------------------------------- 1 | # OpenGM - Powerful Telegram group managment bot 2 | # Copyright (C) 2017 - 2019 Paul Larsen 3 | # Copyright (C) 2019 - 2020 KaratekHD 4 | # 5 | # This program is free software: you can redistribute it and/or modify 6 | # it under the terms of the GNU General Public License as published by 7 | # the Free Software Foundation, either version 3 of the License, or 8 | # (at your option) any later version. 9 | # 10 | # This program is distributed in the hope that it will be useful, 11 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | # GNU General Public License for more details. 14 | # 15 | # You should have received a copy of the GNU General Public License 16 | # along with this program. If not, see . 17 | 18 | 19 | from sqlalchemy import create_engine 20 | from sqlalchemy.ext.declarative import declarative_base 21 | from sqlalchemy.orm import sessionmaker, scoped_session 22 | 23 | from tg_bot import DB_URI 24 | 25 | 26 | def start() -> scoped_session: 27 | engine = create_engine(DB_URI, client_encoding="utf8") 28 | BASE.metadata.bind = engine 29 | BASE.metadata.create_all(engine) 30 | return scoped_session(sessionmaker(bind=engine, autoflush=False)) 31 | 32 | 33 | BASE = declarative_base() 34 | SESSION = start() 35 | -------------------------------------------------------------------------------- /tg_bot/restapi/__init__.py: -------------------------------------------------------------------------------- 1 | # OpenGM - Powerful Telegram group managment bot 2 | # Copyright (C) 2017 - 2019 Paul Larsen 3 | # Copyright (C) 2019 - 2020 KaratekHD 4 | # 5 | # This program is free software: you can redistribute it and/or modify 6 | # it under the terms of the GNU General Public License as published by 7 | # the Free Software Foundation, either version 3 of the License, or 8 | # (at your option) any later version. 9 | # 10 | # This program is distributed in the hope that it will be useful, 11 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | # GNU General Public License for more details. 14 | # 15 | # You should have received a copy of the GNU General Public License 16 | # along with this program. If not, see . 17 | 18 | from flask import Flask 19 | from flask_restplus import Api 20 | from tg_bot.restapi.resources.basic import basic_api 21 | from tg_bot.restapi.resources.chats import chats_api 22 | import tg_bot.restapi.resources.management as management 23 | import tg_bot.restapi.resources.modules.admin as admin 24 | 25 | app = Flask("Nemesis Telegram Bot") 26 | api = Api(app, version="2.0 Development Preview 1", title="Nemesis Telegram Bot") 27 | 28 | api.add_namespace(basic_api) 29 | api.add_namespace(chats_api) 30 | api.add_namespace(management.api) 31 | api.add_namespace(admin.api) -------------------------------------------------------------------------------- /tg_bot/strings/en/antiflood.json: -------------------------------------------------------------------------------- 1 | { 2 | "MSG_KICK" : "I like to leave the flooding to natural disasters. But you, you were just a disappointment. Get out.", 3 | "MSG_KICK_HTML" : "{}:\n#BANNED\nUser: {}\nFlooded the group.", 4 | "ERR_NO_PERMS" : "I can't kick people here, give me permissions first! Until then, I'll disable antiflood.", 5 | "ERR_NO_PERMS_HTML" : "{}:\n#INFO\nDon't have kick permissions, so automatically disabled antiflood.", 6 | "MSG_DISABLED" : "Antiflood has been disabled.", 7 | "MSG_DISABLED_HTML" : "{}:\n#SETFLOOD\nAdmin: {}\nDisabled antiflood.", 8 | "ERR_BAD_AMOUNT" : "Antiflood has to be either 0 (disabled), or a number bigger than 3!", 9 | "MSG_SUCCESS" : "Antiflood has been updated and set to {}", 10 | "MSG_SUCCESS_HTML" : "{}:\n#SETFLOOD\nAdmin: {}\nSet antiflood to {}.", 11 | "ERR_BAD_REQUEST" : "Unrecognised argument - please use a number, 'off', or 'no'.", 12 | "MSG_DISABLED" : "I'm not currently enforcing flood control!", 13 | "MSG_INFO" : "I'm currently banning users if they send more than {} consecutive messages.", 14 | "CHAT_SETTINGS_OFF" : "*Not* currently enforcing flood control.", 15 | "CHAT_SETTINGS_ON" : "Antiflood is set to `{}` messages.", 16 | "HELP" : " - /flood: Get the current flood control setting\n\n*Admin only:*\n - /setflood : enables or disables flood control", 17 | "MODULE_NAME" : "AntiFlood" 18 | } -------------------------------------------------------------------------------- /tg_bot/strings/de/antiflood.json: -------------------------------------------------------------------------------- 1 | { 2 | "MSG_KICK": "Ich überlasse die Überschwemmungen gerne den Naturkatastrophen. Aber du, du warst nur eine Enttäuschung. Verschwinde.", 3 | "MSG_KICK_HTML": "{}:\n#GEBANNT\nBenutzer: {}\nHat die Gruppe geflutet.", 4 | "ERR_NO_PERMS": "Ich kann keine Leute Kicken. Gib mir erst Berechtigungen! Bis dahin deaktiviere ich Antispam.", 5 | "ERR_NO_PERMS_HTML": "{}:\n#INFO\nDu hast keine Kick Berechtigung, also deaktiviere den antiflood automatisch.", 6 | "MSG_DISABLED": "Ich führe derzeit keinen Hochwasserschutz durch!", 7 | "MSG_DISABLED_HTML": "{}:\n#EINSTELLUNGVONFLOOD\nAdmin: {}\nDeaktivierte Antiflood.", 8 | "ERR_BAD_AMOUNT": "Antiflood muss entweder 0 (deaktiviert) oder eine Zahl größer als 3 sein!", 9 | "MSG_SUCCESS": "Antiflood wurde aktualisiert und auf {} gesetzt", 10 | "MSG_SUCCESS_HTML": "{}:\n#SETFLOOD \nAdmin: {}\nSetz Antiflood auf {}.", 11 | "ERR_BAD_REQUEST": "Unbekanntes Beispiel - bitte verwende eine Zahl, \"aus\" oder \"nein\".", 12 | "MSG_INFO": "Ich bin gerade dabei, Benutzer zu sperren, wenn sie mehr als {} aufeinanderfolgende Nachrichten senden.", 13 | "CHAT_SETTINGS_OFF": "*Nicht* derzeit den Flutschutz durchsetzen.", 14 | "CHAT_SETTINGS_ON": "Antispam ist auf `{}` Nachrichten eingestellt.", 15 | "HELP": " - /flood: Abrufen der aktuellen Flutkontrolleinstellung\n\n*nur Admins:*\n - /setflood : aktiviert oder deaktiviert den Flutschutz", 16 | "MODULE_NAME": "Antispam" 17 | } -------------------------------------------------------------------------------- /tg_bot/strings/__init__.py: -------------------------------------------------------------------------------- 1 | # OpenGM - Powerful Telegram group managment bot 2 | # Copyright (C) 2017 - 2019 Paul Larsen 3 | # Copyright (C) 2019 - 2020 KaratekHD 4 | # 5 | # This program is free software: you can redistribute it and/or modify 6 | # it under the terms of the GNU General Public License as published by 7 | # the Free Software Foundation, either version 3 of the License, or 8 | # (at your option) any later version. 9 | # 10 | # This program is distributed in the hope that it will be useful, 11 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | # GNU General Public License for more details. 14 | # 15 | # You should have received a copy of the GNU General Public License 16 | # along with this program. If not, see . 17 | # 18 | # This program is free software: you can redistribute it and/or modify 19 | # it under the terms of the GNU General Public License as published by 20 | # the Free Software Foundation, either version 3 of the License, or 21 | # (at your option) any later version. 22 | # 23 | # This program is distributed in the hope that it will be useful, 24 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 25 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 26 | # GNU General Public License for more details. 27 | # 28 | # You should have received a copy of the GNU General Public License 29 | # along with this program. If not, see . 30 | 31 | -------------------------------------------------------------------------------- /tg_bot/restapi/models/modules/admin.py: -------------------------------------------------------------------------------- 1 | # OpenGM - Powerful Telegram group managment bot 2 | # Copyright (C) 2017 - 2019 Paul Larsen 3 | # Copyright (C) 2019 - 2020 KaratekHD 4 | # 5 | # This program is free software: you can redistribute it and/or modify 6 | # it under the terms of the GNU General Public License as published by 7 | # the Free Software Foundation, either version 3 of the License, or 8 | # (at your option) any later version. 9 | # 10 | # This program is distributed in the hope that it will be useful, 11 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | # GNU General Public License for more details. 14 | # 15 | # You should have received a copy of the GNU General Public License 16 | # along with this program. If not, see . 17 | 18 | 19 | from flask_restplus import fields 20 | 21 | from tg_bot.restapi.models import users 22 | 23 | 24 | def create_chat_model(api): 25 | model = api.model("Chat", { 26 | "id": fields.Integer(description="Telegram ID of group", required=True), 27 | "name": fields.String(description="Name of group", required=True), 28 | "is_muted": fields.Boolean(description="Global mute status", required=True), 29 | # "link": fields.String(description="Convenience property. If username is available, returns a t.me link of the user.", required=False), 30 | "admins": fields.Nested(users.create_user_model(api), description="Administrators", required=False) 31 | }) 32 | return model -------------------------------------------------------------------------------- /tg_bot/strings/en/filters.json: -------------------------------------------------------------------------------- 1 | { 2 | "BASIC_FILTER_STRING" : "*Filters in this chat:*\n", 3 | "NO_FILTERS_ACTIVE" : "No filters are active here!", 4 | "ERR_NO_MESSAGE" : "There is no note message - You can't JUST have buttons, you need a message to go with it!", 5 | "ERR_NO_ANSWER" : "You didn't specify what to reply with!", 6 | "HANDLER_ADDED" : "Handler '{}' added!", 7 | "HANDLER_REMOVED" : "Yep, I'll stop replying to that.", 8 | "ERR_NOT_A_FILTER" : "That's not a current filter - run /filters for all active filters.", 9 | "ERR_BAD_URL" : "You seem to be trying to use an unsupported url protocol. Telegram doesn't support buttons for some protocols, such as tg://. Please try again, or ask in @MarieSupport for help.", 10 | "ERR_NO_REPLY" : "his note could not be sent, as it is incorrectly formatted. Ask in @MarieSupport if you can't figure out why!", 11 | "ERR_COULDNT_PARSE" : "Message %s could not be parsed", 12 | "ERR_COULDNT_PARSE_FILTER" : "Could not parse filter %s in chat %s", 13 | "STATS" : "{} filters, across {} chats.", 14 | "CHAT_SETTINGS" : "There are `{}` custom filters here.", 15 | "HELP" : " - /filters: list all active filters in this chat.\n\n*Admin only:*\n - /filter : add a filter to this chat. The bot will now reply that message whenever 'keyword' is mentioned. If you reply to a sticker with a keyword, the bot will reply with that sticker. NOTE: all filter keywords are in lowercase. If you want your keyword to be a sentence, use quotes. eg: /filter \"hey there\" How you doin?\n - /stop : stop that filter.", 16 | "MODULE_NAME" : "Filters" 17 | } -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contributing 2 | 3 | Contributions are very welcome! Here are some guidelines on how the project is designed. 4 | 5 | ### CodeStyle 6 | 7 | - Adhere to PEP8 as much as possible. 8 | 9 | - Line lengths should be under 120 characters, use list comprehensions over map/filter, don't leave trailing whitespace. 10 | 11 | - More complex pieces of code should be commented for future reference. 12 | 13 | ### Structure 14 | 15 | There are a few self-imposed rules on the project structure, to keep the project as tidy as possible. 16 | - All modules should go into the `modules/` directory. 17 | - Any database accesses should be done in `modules/sql/` - no instances of SESSION should be imported anywhere else. 18 | - Make sure your database sessions are properly scoped! Always close them properly. 19 | - When creating a new module, there should be as few changes to other files as possible required to incorporate it. 20 | Removing the module file should result in a bot which is still in perfect working condition. 21 | - If a module is dependent on multiple other files, which might not be loaded, then create a list of at module 22 | load time, in `__main__`, by looking at attributes. This is how migration, /help, /stats, /info, and many other things 23 | are based off of. It allows the bot to work fine with the LOAD and NO_LOAD configurations. 24 | - Keep in mind that some things might clash; eg a regex handler could clash with a command handler - in this case, you 25 | should put them in different dispatcher groups. 26 | 27 | Might seem complicated, but it'll make sense when you get into it. Feel free to ask me for a hand/advice! 28 | -------------------------------------------------------------------------------- /tg_bot/restapi/models/users.py: -------------------------------------------------------------------------------- 1 | # OpenGM - Powerful Telegram group managment bot 2 | # Copyright (C) 2017 - 2019 Paul Larsen 3 | # Copyright (C) 2019 - 2020 KaratekHD 4 | # 5 | # This program is free software: you can redistribute it and/or modify 6 | # it under the terms of the GNU General Public License as published by 7 | # the Free Software Foundation, either version 3 of the License, or 8 | # (at your option) any later version. 9 | # 10 | # This program is distributed in the hope that it will be useful, 11 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | # GNU General Public License for more details. 14 | # 15 | # You should have received a copy of the GNU General Public License 16 | # along with this program. If not, see . 17 | 18 | from flask_restplus import fields 19 | 20 | from tg_bot.restapi.models.chats import create_chat_model 21 | 22 | 23 | def create_user_model(api): 24 | model = api.model("User", { 25 | "id": fields.Integer(description="Telegram ID of user", required=True), 26 | "first_name": fields.String(description="First name of user", required=True), 27 | "last_name": fields.String(description="Last name of user", required=False), 28 | "username": fields.String(description="Username", required=False), 29 | "link": fields.String(description="Convenience property. If username is available, returns a t.me link of the user.", required=False), 30 | "groups": fields.Nested(create_chat_model(api), description="All chats the user is part of.", required=False) 31 | }) 32 | return model -------------------------------------------------------------------------------- /tg_bot/strings/de/logchannel.json: -------------------------------------------------------------------------------- 1 | { 2 | "LINK": "\nLink: Klicke hier", 3 | "ERR_MISSING_RETURN_STATE": "%s was set as loggable, but had no return statement.", 4 | "ERR_LOG_CHANNEL_DELETED": "This log channel has been deleted - unsetting.", 5 | "ERR_IN_FORMATING": "\n\nFormatierung wurde wegen eines unerwarteten Fehlers deaktiviert.", 6 | "CURRENT_LOG": "This group has all it's logs sent to: {} (`{}`)", 7 | "NO_LOG": "No log channel has been set for this group!", 8 | "MSG_FORWARD": "Now, forward the /setlog to the group you want to tie this channel to!", 9 | "ERR_CANT_DELETE": "Error deleting message in log channel. Should work anyway though.", 10 | "LOG_SET": "This channel has been set as the log channel for {}.", 11 | "SUCCESS_SET": "Successfully set log channel!", 12 | "ERR_GENERAL": "ERROR in setting the log channel.", 13 | "STEPS": "The steps to set a log channel are:\n - add bot to the desired channel\n - send /setlog to the channel\n - forward the /setlog to the group\n", 14 | "SUCCESS_UNSET": "Log channel has been un-set.", 15 | "SUCCESS_UNSET_CHANNEL": "Kanal wurde von {} getrennt", 16 | "ERR_NO_LOG": "No log channel has been set yet!", 17 | "SETTINGS": "This group has all it's logs sent to: {} (`{}`)", 18 | "SETTINGS_CLEAN": "No log channel is set for this group!", 19 | "HELP": "*Admin only:*\n- /logchannel: get log channel info\n- /setlog: set the log channel.\n- /unsetlog: unset the log channel.\n\nSetting the log channel is done by:\n- adding the bot to the desired channel (as an admin!)\n- sending /setlog in the channel\n- forwarding the /setlog to the group", 20 | "MODULE_NAME": "Log Channels" 21 | } -------------------------------------------------------------------------------- /tg_bot/strings/en/logchannel.json: -------------------------------------------------------------------------------- 1 | { 2 | "LINK" : "\nLink: click here", 3 | "ERR_MISSING_RETURN_STATE" : "%s was set as loggable, but had no return statement.", 4 | "ERR_LOG_CHANNEL_DELETED" : "This log channel has been deleted - unsetting.", 5 | "ERR_IN_FORMATING" : "\n\nFormatting has been disabled due to an unexpected error.", 6 | "CURRENT_LOG" : "This group has all it's logs sent to: {} (`{}`)", 7 | "NO_LOG" : "No log channel has been set for this group!", 8 | "MSG_FORWARD" : "Now, forward the /setlog to the group you want to tie this channel to!", 9 | "ERR_CANT_DELETE" : "Error deleting message in log channel. Should work anyway though.", 10 | "LOG_SET" : "This channel has been set as the log channel for {}.", 11 | "SUCCESS_SET" : "Successfully set log channel!", 12 | "ERR_GENERAL" : "ERROR in setting the log channel.", 13 | "STEPS" : "The steps to set a log channel are:\n - add bot to the desired channel\n - send /setlog to the channel\n - forward the /setlog to the group\n", 14 | "SUCCESS_UNSET" : "Log channel has been un-set.", 15 | "SUCCESS_UNSET_CHANNEL" : "Channel has been unlinked from {}", 16 | "ERR_NO_LOG" : "No log channel has been set yet!", 17 | "SETTINGS" : "This group has all it's logs sent to: {} (`{}`)", 18 | "SETTINGS_CLEAN" : "No log channel is set for this group!", 19 | "HELP" : "*Admin only:*\n- /logchannel: get log channel info\n- /setlog: set the log channel.\n- /unsetlog: unset the log channel.\n\nSetting the log channel is done by:\n- adding the bot to the desired channel (as an admin!)\n- sending /setlog in the channel\n- forwarding the /setlog to the group", 20 | "MODULE_NAME" : "Log Channels" 21 | } -------------------------------------------------------------------------------- /tg_bot/strings/da/admin.json: -------------------------------------------------------------------------------- 1 | { 2 | "ERR_NO_USER": "You don't seem to be referring to a user.", 3 | "ERR_CANT_PROMOTE_ADMIN": "How am I meant to promote someone that's already an admin?", 4 | "ERR_CANT_PROMOTE_MYSELF": "I can't promote myself! Get an admin to do it for me.", 5 | "PROMOTE_SUCCESS": "Successfully promoted!", 6 | "PROMOTE_SUCCESS_HTML": "{}:\n#PROMOTED\nAdmin: {}\nUser: {}", 7 | "ERR_DEMOTE_CREATOR": "This person CREATED the chat, how would I demote them?", 8 | "ERR_DEMOTE_NON_ADMIN": "Can't demote what wasn't promoted!", 9 | "ERR_CANT_DEMOTE_MYSELF": "I can't demote myself! Get an admin to do it for me.", 10 | "DEMOTE_SUCCESS": "Successfully demoted!", 11 | "DEMOTE_SUCCESS_HTML": "{}:\n#DEMOTED\nAdmin: {}\nUser: {}", 12 | "ERR_GENERAL": "Could not demote. I might not be an admin, or the admin status was appointed by another user, so I can't act upon them!", 13 | "PINNED_HTML": "{}:\n#PINNED\nAdmin: {}", 14 | "UNPINNED_HTML": "{}:\nUNPINNED\nAdmin: {}", 15 | "ERR_NO_PERMS_INVITELINK": "I don't have access to the invite link, try changing my permissions!", 16 | "ERR_NO_SUPERGROUP": "I can only give you invite links for supergroups and channels, sorry!", 17 | "THIS_CHAT": "this chat", 18 | "ADMINS_IN": "Admins in *{}*:", 19 | "YOU_ADMIN": "ou are *admin*: `{}`", 20 | "HELP": " - /adminlist: list of admins in the chat\n\n*Admin only:*\n - /pin: silently pins the message replied to - add 'loud' or 'notify' to give notifs to users.\n - /unpin: unpins the currently pinned message\n - /invitelink: gets invitelink\n - /promote: promotes the user replied to\n - /demote: demotes the user replied to", 21 | "MODULE_NAME": "Admin" 22 | } -------------------------------------------------------------------------------- /tg_bot/strings/fr/admin.json: -------------------------------------------------------------------------------- 1 | { 2 | "ERR_NO_USER": "You don't seem to be referring to a user.", 3 | "ERR_CANT_PROMOTE_ADMIN": "How am I meant to promote someone that's already an admin?", 4 | "ERR_CANT_PROMOTE_MYSELF": "I can't promote myself! Get an admin to do it for me.", 5 | "PROMOTE_SUCCESS": "Successfully promoted!", 6 | "PROMOTE_SUCCESS_HTML": "{}:\n#PROMOTED\nAdmin: {}\nUser: {}", 7 | "ERR_DEMOTE_CREATOR": "This person CREATED the chat, how would I demote them?", 8 | "ERR_DEMOTE_NON_ADMIN": "Can't demote what wasn't promoted!", 9 | "ERR_CANT_DEMOTE_MYSELF": "I can't demote myself! Get an admin to do it for me.", 10 | "DEMOTE_SUCCESS": "Successfully demoted!", 11 | "DEMOTE_SUCCESS_HTML": "{}:\n#DEMOTED\nAdmin: {}\nUser: {}", 12 | "ERR_GENERAL": "Could not demote. I might not be an admin, or the admin status was appointed by another user, so I can't act upon them!", 13 | "PINNED_HTML": "{}:\n#PINNED\nAdmin: {}", 14 | "UNPINNED_HTML": "{}:\nUNPINNED\nAdmin: {}", 15 | "ERR_NO_PERMS_INVITELINK": "I don't have access to the invite link, try changing my permissions!", 16 | "ERR_NO_SUPERGROUP": "I can only give you invite links for supergroups and channels, sorry!", 17 | "THIS_CHAT": "this chat", 18 | "ADMINS_IN": "Admins in *{}*:", 19 | "YOU_ADMIN": "ou are *admin*: `{}`", 20 | "HELP": " - /adminlist: list of admins in the chat\n\n*Admin only:*\n - /pin: silently pins the message replied to - add 'loud' or 'notify' to give notifs to users.\n - /unpin: unpins the currently pinned message\n - /invitelink: gets invitelink\n - /promote: promotes the user replied to\n - /demote: demotes the user replied to", 21 | "MODULE_NAME": "Admin" 22 | } -------------------------------------------------------------------------------- /tg_bot/strings/de/filters.json: -------------------------------------------------------------------------------- 1 | { 2 | "BASIC_FILTER_STRING": "*Filter in diesem Chat:*\n", 3 | "NO_FILTERS_ACTIVE": "Hier sind keine Filter aktiv!", 4 | "ERR_NO_MESSAGE": "There is no note message - You can't JUST have buttons, you need a message to go with it!", 5 | "ERR_NO_ANSWER": "Du hast nicht angegeben, womit ich antworten soll!", 6 | "HANDLER_ADDED": "Handler '{}' hinzugefügt!", 7 | "HANDLER_REMOVED": "Ja, ich höre auf, darauf zu antworten.", 8 | "ERR_NOT_A_FILTER": "Das ist kein aktueller Filter - führ /filters für alle aktiven Filter aus.", 9 | "ERR_BAD_URL": "Du scheinst zu versuchen, ein nicht unterstütztes url-Protokoll zu verwenden. Telegram unterstützt keine Schaltflächen für einige Protokolle, wie zum Beispiel tg://. Bitte versuch es erneut, oder frag in @MarieSupport nach Hilfe.", 10 | "ERR_NO_REPLY": "deine Nachricht konnte nicht gesendet werden, da sie falsch formatiert ist. Frag in @MarieSupport nach, wenn du nicht herausfinden kannst, warum!", 11 | "ERR_COULDNT_PARSE": "Nachricht %s konnte nicht analysiert werden.", 12 | "ERR_COULDNT_PARSE_FILTER": "Could not parse filter %s in chat %s", 13 | "STATS": "{} Filter, über {} Chats.", 14 | "CHAT_SETTINGS": "Es gibt hier `{}` benutzerdefinierte Filter.", 15 | "HELP": " - /filters: listet alle aktiven Filter in diesem Chat auf.\n\n*nur Admins:*\n - /filter : diesem Chat einen Filter hinzufügen. Der Bot antwortet nun auf diese Nachricht immer dann, wenn 'Schlüsselwörter' erwähnt werden. Wenn du auf einen Sticker mit einem Schlüsselwort antwortest, wird der Bot mit diesem Sticker antworten. HINWEIS: Alle Filter-Schlüsselwörter sind klein geschrieben. Wenn du möchtest, dass dein Schlüsselwort ein Satz ist, verwende Anführungszeichen. zum Beispiel: /filter \"guten tag\" Wie geht es dir?\n - /stop : diesen Filter stoppen.", 16 | "MODULE_NAME": "Filter" 17 | } -------------------------------------------------------------------------------- /tg_bot/strings/en/admin.json: -------------------------------------------------------------------------------- 1 | { 2 | "ERR_NO_USER" : "You don't seem to be referring to a user.", 3 | "ERR_CANT_PROMOTE_ADMIN" : "How am I meant to promote someone that's already an admin?", 4 | "ERR_CANT_PROMOTE_MYSELF" : "I can't promote myself! Get an admin to do it for me.", 5 | "PROMOTE_SUCCESS" : "Successfully promoted!", 6 | "PROMOTE_SUCCESS_HTML" : "{}:\n#PROMOTED\nAdmin: {}\nUser: {}", 7 | "ERR_DEMOTE_CREATOR" : "This person CREATED the chat, how would I demote them?", 8 | "ERR_DEMOTE_NON_ADMIN" : "Can't demote what wasn't promoted!", 9 | "ERR_CANT_DEMOTE_MYSELF" : "I can't demote myself! Get an admin to do it for me.", 10 | "DEMOTE_SUCCESS" : "Successfully demoted!", 11 | "DEMOTE_SUCCESS_HTML" : "{}:\n#DEMOTED\nAdmin: {}\nUser: {}", 12 | "ERR_GENERAL" : "Could not demote. I might not be an admin, or the admin status was appointed by another user, so I can't act upon them!", 13 | "PINNED_HTML" : "{}:\n#PINNED\nAdmin: {}", 14 | "UNPINNED_HTML" : "{}:\nUNPINNED\nAdmin: {}", 15 | "ERR_NO_PERMS_INVITELINK" : "I don't have access to the invite link, try changing my permissions!", 16 | "ERR_NO_SUPERGROUP" : "I can only give you invite links for supergroups and channels, sorry!", 17 | "THIS_CHAT" : "this chat", 18 | "ADMINS_IN" : "Admins in *{}*:", 19 | "YOU_ADMIN" : "You are *admin*: `{}`", 20 | "HELP" : " - /adminlist: list of admins in the chat\n\n*Admin only:*\n - /pin: silently pins the message replied to - add 'loud' or 'notify' to give notifs to users.\n - /unpin: unpins the currently pinned message\n - /invitelink: gets invitelink\n - /promote: promotes the user replied to\n - /demote: demotes the user replied to", 21 | "MODULE_NAME" : "Admin", 22 | "MSG_CHAT_UMUTED" : "This chat is now unmuted, everyone may write now!", 23 | "MSG_CHAT_MUTED" : "This chat is now muted, only administrators may write now!" 24 | } -------------------------------------------------------------------------------- /tg_bot/strings/en/blacklist.json: -------------------------------------------------------------------------------- 1 | { 2 | "BASE_BLACKLIST_STRING" : "Current blacklisted words:\n", 3 | "MSG_NO_BLACKLIST" : "There are no blacklisted messages here!", 4 | "MSG_BLACKLIST_ADD_SUCCESS" : "Added {} to the blacklist!", 5 | "MSG_BLACKLIST_ADD_SUCCESS_MULTIPLE" : "Added {} triggers to the blacklist.", 6 | "ERR_BAD_REQUEST" : "Tell me which words you would like to add to the blacklist", 7 | "MSG_REMOVED_SUCCESS" : "Removed {} from the blacklist!", 8 | "ERR_NOT_VALID_TRIGGER" : "This isn't a blacklisted trigger...!", 9 | "MSG_REMOVED_SUCCESS_MULTIPLE" : "Removed {} triggers from the blacklist.", 10 | "ERR_NOT_VALID_TRIGGER_MULTIPLE" : "None of these triggers exist, so they weren't removed.", 11 | "ERR_NOT_ALL_VALID_TRIGGER" : "Removed {} triggers from the blacklist. {} did not exist, so were not removed.", 12 | "ERR_REMOVE_BAD_REQUEST" : "Tell me which words you would like to remove from the blacklist.", 13 | "ERR_CONSOLE_CANT_DELETE_MESSAGE" : "Error while deleting blacklist message.", 14 | "CHAT_SETTINGS" : "There are {} blacklisted words.", 15 | "STATS" : "{} blacklist triggers, across {} chats.", 16 | "MODULE_NAME" : "Word Blacklists", 17 | "HELP" : "Blacklists are used to stop certain triggers from being said in a group. Any time the trigger is mentioned, the message will immediately be deleted. A good combo is sometimes to pair this up with warn filters!\n\n*NOTE:* blacklists do not affect group admins.\n\n - /blacklist: View the current blacklisted words.\n\n*Admin only:*\n - /addblacklist : Add a trigger to the blacklist. Each line is considered one trigger, so using different lines will allow you to add multiple triggers.\n - /unblacklist : Remove triggers from the blacklist. Same newline logic applies here, so you can remove multiple triggers at once.\n - /rmblacklist : Same as above." 18 | } -------------------------------------------------------------------------------- /tg_bot/modules/rest.py: -------------------------------------------------------------------------------- 1 | # OpenGM - Powerful Telegram group managment bot 2 | # Copyright (C) 2017 - 2019 Paul Larsen 3 | # Copyright (C) 2019 - 2020 KaratekHD 4 | # 5 | # This program is free software: you can redistribute it and/or modify 6 | # it under the terms of the GNU General Public License as published by 7 | # the Free Software Foundation, either version 3 of the License, or 8 | # (at your option) any later version. 9 | # 10 | # This program is distributed in the hope that it will be useful, 11 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | # GNU General Public License for more details. 14 | # 15 | # You should have received a copy of the GNU General Public License 16 | # along with this program. If not, see . 17 | 18 | 19 | 20 | import secrets 21 | 22 | from telegram.ext import CallbackContext, CommandHandler 23 | 24 | from tg_bot import dispatcher 25 | import tg_bot.modules.sql.api_sql as sql 26 | from telegram import Update, ParseMode 27 | 28 | 29 | def get_api_key(update: Update, context: CallbackContext): 30 | if update.effective_chat.type == "private": 31 | generated_key = secrets.token_urlsafe(30) 32 | chat_id = update.effective_chat.id 33 | sql.set_key(chat_id, generated_key) 34 | update.effective_message.reply_text(f"Your Api key is\n\n" 35 | f"`{generated_key}`\n" 36 | f"This key can be used to execute tasks as your user, so keep it secret!", parse_mode=ParseMode.MARKDOWN) 37 | 38 | 39 | __mod_name__ = "REST Api" 40 | 41 | 42 | def __help__(update: Update) -> str: 43 | return "Access the bots features using the brand new REST Api!" 44 | 45 | 46 | KEY_HANDLER = CommandHandler("apikey", get_api_key, run_async=True) 47 | 48 | dispatcher.add_handler(KEY_HANDLER) 49 | -------------------------------------------------------------------------------- /tg_bot/modules/sql/api_sql.py: -------------------------------------------------------------------------------- 1 | # OpenGM - Powerful Telegram group managment bot 2 | # Copyright (C) 2017 - 2019 Paul Larsen 3 | # Copyright (C) 2019 - 2020 KaratekHD 4 | # 5 | # This program is free software: you can redistribute it and/or modify 6 | # it under the terms of the GNU General Public License as published by 7 | # the Free Software Foundation, either version 3 of the License, or 8 | # (at your option) any later version. 9 | # 10 | # This program is distributed in the hope that it will be useful, 11 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | # GNU General Public License for more details. 14 | # 15 | # You should have received a copy of the GNU General Public License 16 | # along with this program. If not, see . 17 | 18 | 19 | 20 | from sqlalchemy import Column, UnicodeText, Integer, BigInteger 21 | from tg_bot.modules.sql import SESSION, BASE 22 | 23 | 24 | class Api(BASE): 25 | __tablename__ = "api" 26 | user_id = Column(BigInteger, primary_key=True) 27 | key = Column(UnicodeText) 28 | 29 | def __init__(self, user_id, key=None): 30 | self.user_id = user_id 31 | self.key = key 32 | 33 | def __repr__(self): 34 | return "".format(self.username, self.user_id) 35 | 36 | 37 | Api.__table__.create(checkfirst=True) 38 | 39 | 40 | def set_key(user_id, key): 41 | user = SESSION.query(Api).get(user_id) 42 | if not user: 43 | user = Api(user_id, key) 44 | SESSION.add(user) 45 | SESSION.flush() 46 | else: 47 | user.key = key 48 | SESSION.commit() 49 | 50 | 51 | def verify_key(key): 52 | result = SESSION.query(Api).filter(Api.key == str(key)).scalar() 53 | ret = None 54 | if result: 55 | ret = result.user_id 56 | SESSION.close() 57 | return ret 58 | 59 | 60 | def get_key(user_id): 61 | key = SESSION.query(Api).get(str(user_id)) 62 | ret = "null" 63 | if key: 64 | ret = key.key 65 | 66 | SESSION.close() 67 | return ret -------------------------------------------------------------------------------- /tg_bot/caching.py: -------------------------------------------------------------------------------- 1 | # OpenGM - Powerful Telegram group managment bot 2 | # Copyright (C) 2017 - 2019 Paul Larsen 3 | # Copyright (C) 2019 - 2020 KaratekHD 4 | # 5 | # This program is free software: you can redistribute it and/or modify 6 | # it under the terms of the GNU General Public License as published by 7 | # the Free Software Foundation, either version 3 of the License, or 8 | # (at your option) any later version. 9 | # 10 | # This program is distributed in the hope that it will be useful, 11 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | # GNU General Public License for more details. 14 | # 15 | # You should have received a copy of the GNU General Public License 16 | # along with this program. If not, see . 17 | 18 | import time 19 | 20 | 21 | class MWT: 22 | """Memoize With Timeout""" 23 | 24 | _caches = {} 25 | _timeouts = {} 26 | 27 | def __init__(self, timeout=2): 28 | self.timeout = timeout 29 | 30 | def collect(self): 31 | """Clear cache of results which have timed out""" 32 | for func in self._caches: 33 | cache = {} 34 | for key in self._caches[func]: 35 | if (time.time() - self._caches[func][key][1]) < self._timeouts[func]: 36 | cache[key] = self._caches[func][key] 37 | self._caches[func] = cache 38 | 39 | def __call__(self, f): 40 | self.cache = self._caches[f] = {} 41 | self._timeouts[f] = self.timeout 42 | 43 | def func(*args, **kwargs): 44 | kw = sorted(kwargs.items()) 45 | key = (args, tuple(kw)) 46 | try: 47 | v = self.cache[key] 48 | # print("cache") 49 | if (time.time() - v[1]) > self.timeout: 50 | raise KeyError 51 | except KeyError: 52 | # print("new") 53 | v = self.cache[key] = f(*args, **kwargs), time.time() 54 | return v[0] 55 | 56 | func.func_name = f.__name__ 57 | 58 | return func -------------------------------------------------------------------------------- /tg_bot/modules/helper_funcs/chat_action.py: -------------------------------------------------------------------------------- 1 | # OpenGM - Powerful Telegram group managment bot 2 | # Copyright (C) 2017 - 2019 Paul Larsen 3 | # Copyright (C) 2019 - 2020 KaratekHD 4 | # 5 | # This program is free software: you can redistribute it and/or modify 6 | # it under the terms of the GNU General Public License as published by 7 | # the Free Software Foundation, either version 3 of the License, or 8 | # (at your option) any later version. 9 | # 10 | # This program is distributed in the hope that it will be useful, 11 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | # GNU General Public License for more details. 14 | # 15 | # You should have received a copy of the GNU General Public License 16 | # along with this program. If not, see . 17 | 18 | 19 | from functools import wraps 20 | from telegram import error, ChatAction 21 | 22 | 23 | def send_message(message, text, *args, **kwargs): 24 | try: 25 | return message.reply_text(text, *args, **kwargs) 26 | except error.BadRequest as err: 27 | if str(err) == "Reply message not found": 28 | return message.reply_text(text, quote=False, *args, **kwargs) 29 | 30 | 31 | def typing_action(func): 32 | """Sends typing action while processing func command.""" 33 | 34 | @wraps(func) 35 | def command_func(update, context, *args, **kwargs): 36 | context.bot.send_chat_action( 37 | chat_id=update.effective_chat.id, action=ChatAction.TYPING 38 | ) 39 | return func(update, context, *args, **kwargs) 40 | 41 | return command_func 42 | 43 | 44 | def send_action(action): 45 | """Sends `action` while processing func command.""" 46 | 47 | def decorator(func): 48 | @wraps(func) 49 | def command_func(update, context, *args, **kwargs): 50 | context.bot.send_chat_action( 51 | chat_id=update.effective_chat.id, action=action 52 | ) 53 | return func(update, context, *args, **kwargs) 54 | 55 | return command_func 56 | 57 | return decorator -------------------------------------------------------------------------------- /tg_bot/modules/__init__.py: -------------------------------------------------------------------------------- 1 | # OpenGM - Powerful Telegram group managment bot 2 | # Copyright (C) 2017 - 2019 Paul Larsen 3 | # Copyright (C) 2019 - 2020 KaratekHD 4 | # 5 | # This program is free software: you can redistribute it and/or modify 6 | # it under the terms of the GNU General Public License as published by 7 | # the Free Software Foundation, either version 3 of the License, or 8 | # (at your option) any later version. 9 | # 10 | # This program is distributed in the hope that it will be useful, 11 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | # GNU General Public License for more details. 14 | # 15 | # You should have received a copy of the GNU General Public License 16 | # along with this program. If not, see . 17 | 18 | 19 | import sys 20 | from tg_bot import LOAD, NO_LOAD, LOGGER 21 | 22 | 23 | def __list_all_modules(): 24 | from os.path import dirname, basename, isfile 25 | import glob 26 | 27 | # This generates a list of modules in this folder for the * in __main__ to work. 28 | mod_paths = glob.glob(dirname(__file__) + "/*.py") 29 | all_modules = [ 30 | basename(f)[:-3] 31 | for f in mod_paths 32 | if isfile(f) and f.endswith(".py") and not f.endswith("__init__.py") 33 | ] 34 | 35 | if LOAD or NO_LOAD: 36 | to_load = LOAD 37 | if to_load: 38 | if not all( 39 | any(mod == module_name for module_name in all_modules) 40 | for mod in to_load 41 | ): 42 | LOGGER.error("Invalid loadorder names. Quitting.") 43 | sys.exit(1) 44 | 45 | else: 46 | to_load = all_modules 47 | 48 | if NO_LOAD: 49 | LOGGER.info("Not loading: {}".format(NO_LOAD)) 50 | return [item for item in to_load if item not in NO_LOAD] 51 | 52 | return to_load 53 | 54 | return all_modules 55 | 56 | ALL_MODULES = sorted(__list_all_modules()) 57 | LOGGER.info("Modules to load: %s", str(ALL_MODULES)) 58 | __all__ = ALL_MODULES + ["ALL_MODULES"] 59 | -------------------------------------------------------------------------------- /tg_bot/modules/googletranslate.py: -------------------------------------------------------------------------------- 1 | # OpenGM - Powerful Telegram group managment bot 2 | # Copyright (C) 2017 - 2019 Paul Larsen 3 | # Copyright (C) 2019 - 2020 KaratekHD 4 | # 5 | # This program is free software: you can redistribute it and/or modify 6 | # it under the terms of the GNU General Public License as published by 7 | # the Free Software Foundation, either version 3 of the License, or 8 | # (at your option) any later version. 9 | # 10 | # This program is distributed in the hope that it will be useful, 11 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | # GNU General Public License for more details. 14 | # 15 | # You should have received a copy of the GNU General Public License 16 | # along with this program. If not, see . 17 | 18 | from googletrans import Translator 19 | from telegram import Update 20 | from telegram.ext import CallbackContext, CommandHandler 21 | from tg_bot import dispatcher 22 | from tg_bot.strings.string_helper import get_string 23 | 24 | 25 | def translate(update: Update, context: CallbackContext): 26 | msg = update.effective_message 27 | args = context.args 28 | if not args: 29 | msg.reply_text(get_string("googletranslate", "ERR_NO_LANG", update.effective_chat.id)) # ERR_NO_LANG 30 | return 31 | text = update.effective_message.reply_to_message 32 | if not text: 33 | msg.reply_text(get_string("googletranslate", "ERR_NO_MSG", update.effective_chat.id)) # ERR_NO_MSG 34 | return 35 | try : 36 | translator = Translator() 37 | translated = translator.translate(text.text, dest=args[0]).text 38 | except ValueError as excp: 39 | msg.reply_text(str(excp)) 40 | return 41 | msg.reply_text(translated) 42 | 43 | 44 | TRANSLATION_HANDLER = CommandHandler("translate", translate, run_async=True) 45 | 46 | 47 | dispatcher.add_handler(TRANSLATION_HANDLER) 48 | 49 | __mod_name__ = "Translation" 50 | 51 | def __help__(update: Update) -> str: 52 | return get_string("googletranslate", "HELP", update.effective_chat.id) # HELP 53 | 54 | 55 | -------------------------------------------------------------------------------- /tg_bot/strings/de/blacklist.json: -------------------------------------------------------------------------------- 1 | { 2 | "BASE_BLACKLIST_STRING": "Aktuelle Wörter auf der schwarzen Liste:\n", 3 | "MSG_NO_BLACKLIST": "Hier gibt es keine Wörter auf der schwarzen Liste!", 4 | "MSG_BLACKLIST_ADD_SUCCESS": "{} wurde auf die schwarze Liste gesetzt!", 5 | "MSG_BLACKLIST_ADD_SUCCESS_MULTIPLE": "{} wurden auf die schwarze Liste gesetzt.", 6 | "ERR_BAD_REQUEST": "Sag mir, welche Wörter ich auf die schwarze Liste setzen soll", 7 | "MSG_REMOVED_SUCCESS": "<{} wurde von der schwarzen Liste entfernt!", 8 | "ERR_NOT_VALID_TRIGGER": "Das ist kein gültiger Blacklist Auslöser...!", 9 | "MSG_REMOVED_SUCCESS_MULTIPLE": "<{} wurden von der schwarzen Liste entfernt.", 10 | "ERR_NOT_VALID_TRIGGER_MULTIPLE": "Keiner dieser Auslöser existiert, also konnten sie nicht entfernt werden.", 11 | "ERR_NOT_ALL_VALID_TRIGGER": "{} wurden entfernt. {} existieren nicht, wurden entsprechend auch nicht entfernt.", 12 | "ERR_REMOVE_BAD_REQUEST": "Sag mir, welche Wörter ich von der schwarzen Liste entfernen soll.", 13 | "ERR_CONSOLE_CANT_DELETE_MESSAGE": "Es gab einen Fehler beim Löschen der Nachrichten auf der schwarzen Liste.", 14 | "CHAT_SETTINGS": "Das sind die Wörter auf der schwarzen Liste:{}.", 15 | "STATS": "{} Blacklist Auslöser, in {} Chats.", 16 | "MODULE_NAME": "Wortblacklist", 17 | "HELP": "Blacklists werden verwendet, um zu verhindern, dass bestimmte Trigger in einer Gruppe ausgesprochen werden. Jedes Mal, wenn der Trigger erwähnt wird, wird die Nachricht sofort gelöscht. Eine gute Kombination ist es manchmal, dies mit Warnfiltern zu kombinieren!\n\n*HINWEIS:* Blacklists haben keine Auswirkungen auf Gruppenadministratoren.\n\n - /blacklist: Die Wörter auf der aktuellen auf der Blacklist werden anzeigen.\n\n*Nur Admin:*\n - /addblacklist : Einen Trigger zur Blacklist hinzufügen. Jede Zeile wird als ein Trigger betrachtet, so dass Sie bei Verwendung verschiedener Zeilen mehrere Trigger hinzufügen können.\n - /unblacklist : Trigger aus der Blacklist entfernen. Hier gilt dieselbe Newline-Logik, so dass Sie mehrere Trigger auf einmal entfernen können.\n - /rmblacklist : Dasselbe wie oben." 18 | } -------------------------------------------------------------------------------- /tg_bot/strings/de/admin.json: -------------------------------------------------------------------------------- 1 | { 2 | "ERR_NO_USER": "Du nimmst auf keinen Benutzer Bezug.", 3 | "ERR_CANT_PROMOTE_ADMIN": "Wie soll ich jemanden zum Admin ernennen, der schon einer ist?", 4 | "ERR_CANT_PROMOTE_MYSELF": "Ich kann mich nicht selber befördern! Lass es einen Admin für mich machen.", 5 | "PROMOTE_SUCCESS": "Erfolgreich befördert!", 6 | "PROMOTE_SUCCESS_HTML": "{}:\n#BEFÖRDERT\nAdmin:{}\nBenutzer:{}", 7 | "ERR_DEMOTE_CREATOR": "Diese Person ist der BESITZER des Chats, wie soll ich ihm seine Rechte entziehen?!", 8 | "ERR_DEMOTE_NON_ADMIN": "Ich kann niemandem Rechte entziehen, der nie welche hatte!", 9 | "ERR_CANT_DEMOTE_MYSELF": "Ich kann mir nicht selber die Rechte entziehen! Und wollte es auch nicht...", 10 | "DEMOTE_SUCCESS": "Erfolgreich degradiert!", 11 | "DEMOTE_SUCCESS_HTML": "{}:\n#DEGRADIEREN\nAdmin: {}\nBenutzer: {}", 12 | "ERR_GENERAL": "Ich konnte nicht degradieren. Möglicherweise bin ich kein Admin, oder der Admin-Status wurde von einem anderen Benutzer ernannt, so dass ich nicht nach dir handeln kann!", 13 | "PINNED_HTML": "{}:\n#ANGEPINNT\nAdmin: {}", 14 | "UNPINNED_HTML": "{}:\nABGEPINNT\nAdmin: {}", 15 | "ERR_NO_PERMS_INVITELINK": "Ich habe keinen Zugang zum Einladungslink, bitte überprüfe meine Rechte!", 16 | "ERR_NO_SUPERGROUP": "Ich kann Einladungslinks nur für Supergruppen und Kanäle ausgeben!", 17 | "THIS_CHAT": "dieser Chat", 18 | "ADMINS_IN": "Admins in *{}*:", 19 | "YOU_ADMIN": "Du bist ein *Admin*: `{}`", 20 | "HELP": " -/adminlist: Liste der Admins im Chat\n\n*Nur Admins:*\n - /pin: pinnt die Nachricht, auf die geantwortet wird, still an - füge 'laut' oder 'benachrichtigen' hinzu, um die Benutzer zu benachrichtigen.\n - /unpin: hebt die aktuell angeheftete Nachricht auf\n - /invitelink: Einladungslink wird gesendet\n - /promote: befördert den Benutzer, auf den geantwortet wurde\n - /demote: degradiert den Benutzer, auf den geantwortet wurde", 21 | "MODULE_NAME": "Admin", 22 | "MSG_CHAT_UMUTED": "Dieser Chat ist nun nicht mehr stummgeschaltet, jeder darf nun reden!", 23 | "MSG_CHAT_MUTED": "Dieser Chat ist nun stummgeschaltet, nur Administratoren können jetzt schreiben!" 24 | } -------------------------------------------------------------------------------- /tg_bot/strings/en/bans.json: -------------------------------------------------------------------------------- 1 | { 2 | "ERR_NO_TARGET" : "You don't seem to be referring to a user.", 3 | "ERR_USER_NOT_FOUND" : "I can't seem to find this user", 4 | "ERR_TARGET_IS_ADMIN" : "I really wish I could ban admins...", 5 | "ERR_TARGET_ITSELF" : "I'm not gonna BAN myself, are you crazy?", 6 | "MSG_BAN_HTML" : "{}:\n#BANNED\nAdmin: {}\nUser: {} ({})", 7 | "MSG_BAN_HTML_REASON" : "\nReason: {}", 8 | "MSG_BAN_SUCCESS" : "User in your Channel was banned from the group.", 9 | "ERR_CONSOLE_CANT_BAN" : "ERROR banning user %s in chat %s (%s) due to %s", 10 | "ERR_CANT_BAN" : "Well damn, I can't ban that user.", 11 | "ERR_TEMPBAN_NO_TIME" : "You haven't specified a time to ban this user for!", 12 | "MSG_TEMPBAN_HTML" : "{}:\n#TEMP BANNED\nAdmin: {}\nUser: {} ({})\nTime: {}", 13 | "MSG_TEMPBAN_HTML_REASON" : "\nReason: {}", 14 | "MSG_TEMPBAN_SUCCES" : "Banned! User will be banned for {}.", 15 | "ERR_KICK_TARGET_ADMIN" : "I really wish I could kick admins...", 16 | "ERR_KICK_TARGET_ITSELF" : "Yeahhh I'm not gonna do that", 17 | "MSG_KICK_SUCCESS" : "Kicked!", 18 | "MSG_KICK_HTML" : "{}:\n#KICKED\nAdmin: {}\nUser: {} ({})", 19 | "MSG_KICK_HTML_REASON" : "\nReason: {}", 20 | "ERR_CANT_KICK" : "Well damn, I can't kick that user.", 21 | "ERR_KICKME_TARGET_IS_ADMIN" : "I wish I could... but you're an admin.", 22 | "MSG_KICKME_SUCCESS" : "No problem.", 23 | "ERR_KICKME_GENERAL" : "Huh? I can't :/", 24 | "ERR_UNBAN_ITSELF" : "How would I unban myself if I wasn't here...?", 25 | "ERR_UNBAN_NOT_BANNED" : "Why are you trying to unban someone that's already in the chat?", 26 | "MSG_UNBAN_SUCCESS" : "Yep, this user can join!", 27 | "MSG_UNBAN_HTML" : "{}:\n#UNBANNED\nAdmin: {}\nUser: {} ({})", 28 | "MSG_UNBAN_HTML_REASON" : "\nReason: {}", 29 | "HELP" : " - /kickme: kicks the user who issued the command\n\n*Admin only:*\n - /ban : bans a user. (via handle, or reply)\n - /tban x(m/h/d): bans a user for x time. (via handle, or reply). m = minutes, h = hours, d = days.\n - /unban : unbans a user. (via handle, or reply)\n - /kick : kicks a user, (via handle, or reply)", 30 | "MODULE_NAME" : "Bans" 31 | } -------------------------------------------------------------------------------- /tg_bot/modules/sql/mute.py: -------------------------------------------------------------------------------- 1 | # OpenGM - Powerful Telegram group managment bot 2 | # Copyright (C) 2017 - 2019 Paul Larsen 3 | # Copyright (C) 2019 - 2020 KaratekHD 4 | # 5 | # This program is free software: you can redistribute it and/or modify 6 | # it under the terms of the GNU General Public License as published by 7 | # the Free Software Foundation, either version 3 of the License, or 8 | # (at your option) any later version. 9 | # 10 | # This program is distributed in the hope that it will be useful, 11 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | # GNU General Public License for more details. 14 | # 15 | # You should have received a copy of the GNU General Public License 16 | # along with this program. If not, see . 17 | 18 | 19 | import threading 20 | 21 | from sqlalchemy import Column, String, func, distinct, Boolean 22 | 23 | from tg_bot.modules.sql import SESSION, BASE 24 | 25 | 26 | class Globalmute(BASE): 27 | __tablename__ = "mute" 28 | chat_id = Column(String(14), primary_key=True) 29 | muted = Column(Boolean, default=False) 30 | 31 | def __init__(self, chat_id): 32 | self.chat_id = chat_id 33 | 34 | def __repr__(self): 35 | return "".format(self.chat_id, self.muted) 36 | 37 | 38 | Globalmute.__table__.create(checkfirst=True) 39 | 40 | INSERTION_LOCK = threading.RLock() 41 | 42 | 43 | def set_muted(chat_id, muted): 44 | with INSERTION_LOCK: 45 | l = SESSION.query(Globalmute).get(str(chat_id)) 46 | if not l: 47 | l = Globalmute(str(chat_id)) 48 | l.muted = muted 49 | 50 | SESSION.add(l) 51 | SESSION.commit() 52 | 53 | 54 | def get_muted(chat_id): 55 | m = SESSION.query(Globalmute).get(str(chat_id)) 56 | ret = False 57 | if m: 58 | ret = m.muted 59 | 60 | SESSION.close() 61 | return ret 62 | 63 | 64 | def num_chats(): 65 | try: 66 | return SESSION.query(func.count(distinct(Globalmute.chat_id))).scalar() 67 | finally: 68 | SESSION.close() 69 | 70 | 71 | def migrate_chat(old_chat_id, new_chat_id): 72 | with INSERTION_LOCK: 73 | chat = SESSION.query(Globalmute).get(str(old_chat_id)) 74 | if chat: 75 | chat.chat_id = str(new_chat_id) 76 | SESSION.commit() 77 | -------------------------------------------------------------------------------- /tg_bot/modules/helper_funcs/filters.py: -------------------------------------------------------------------------------- 1 | # OpenGM - Powerful Telegram group managment bot 2 | # Copyright (C) 2017 - 2019 Paul Larsen 3 | # Copyright (C) 2019 - 2020 KaratekHD 4 | # 5 | # This program is free software: you can redistribute it and/or modify 6 | # it under the terms of the GNU General Public License as published by 7 | # the Free Software Foundation, either version 3 of the License, or 8 | # (at your option) any later version. 9 | # 10 | # This program is distributed in the hope that it will be useful, 11 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | # GNU General Public License for more details. 14 | # 15 | # You should have received a copy of the GNU General Public License 16 | # along with this program. If not, see . 17 | 18 | 19 | from telegram import Message 20 | from telegram.ext import MessageFilter 21 | 22 | from tg_bot import SUPPORT_USERS, SUDO_USERS, OWNER_ID, CO_OWNER_ID 23 | 24 | 25 | class CustomFilters: 26 | class _Supporters(MessageFilter): 27 | def filter(self, message: Message): 28 | return bool(message.from_user and message.from_user.id in SUPPORT_USERS) 29 | 30 | support_filter = _Supporters() 31 | 32 | class _Sudoers(MessageFilter): 33 | def filter(self, message: Message): 34 | return bool(message.from_user and message.from_user.id in SUDO_USERS) 35 | 36 | sudo_filter = _Sudoers() 37 | 38 | class _Admins(MessageFilter): 39 | def filter(self, message: Message): 40 | return bool((message.from_user and message.from_user.id == OWNER_ID) or (message.from_user and message.from_user.id == CO_OWNER_ID)) 41 | 42 | admin_filter = _Admins() 43 | 44 | class _MimeType(MessageFilter): 45 | def __init__(self, mimetype): 46 | self.mime_type = mimetype 47 | self.name = "CustomFilters.mime_type({})".format(self.mime_type) 48 | 49 | def filter(self, message: Message): 50 | return bool(message.document and message.document.mime_type == self.mime_type) 51 | 52 | mime_type = _MimeType 53 | 54 | class _HasText(MessageFilter): 55 | def filter(self, message: Message): 56 | return bool(message.text or message.sticker or message.photo or message.document or message.video) 57 | 58 | has_text = _HasText() 59 | -------------------------------------------------------------------------------- /tg_bot/modules/sql/rules_sql.py: -------------------------------------------------------------------------------- 1 | # OpenGM - Powerful Telegram group managment bot 2 | # Copyright (C) 2017 - 2019 Paul Larsen 3 | # Copyright (C) 2019 - 2020 KaratekHD 4 | # 5 | # This program is free software: you can redistribute it and/or modify 6 | # it under the terms of the GNU General Public License as published by 7 | # the Free Software Foundation, either version 3 of the License, or 8 | # (at your option) any later version. 9 | # 10 | # This program is distributed in the hope that it will be useful, 11 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | # GNU General Public License for more details. 14 | # 15 | # You should have received a copy of the GNU General Public License 16 | # along with this program. If not, see . 17 | 18 | 19 | import threading 20 | 21 | from sqlalchemy import Column, String, UnicodeText, func, distinct 22 | 23 | from tg_bot.modules.sql import SESSION, BASE 24 | 25 | 26 | class Rules(BASE): 27 | __tablename__ = "rules" 28 | chat_id = Column(String(14), primary_key=True) 29 | rules = Column(UnicodeText, default="") 30 | 31 | def __init__(self, chat_id): 32 | self.chat_id = chat_id 33 | 34 | def __repr__(self): 35 | return "".format(self.chat_id, self.rules) 36 | 37 | 38 | Rules.__table__.create(checkfirst=True) 39 | 40 | INSERTION_LOCK = threading.RLock() 41 | 42 | 43 | def set_rules(chat_id, rules_text): 44 | with INSERTION_LOCK: 45 | rules = SESSION.query(Rules).get(str(chat_id)) 46 | if not rules: 47 | rules = Rules(str(chat_id)) 48 | rules.rules = rules_text 49 | 50 | SESSION.add(rules) 51 | SESSION.commit() 52 | 53 | 54 | def get_rules(chat_id): 55 | rules = SESSION.query(Rules).get(str(chat_id)) 56 | ret = "" 57 | if rules: 58 | ret = rules.rules 59 | 60 | SESSION.close() 61 | return ret 62 | 63 | 64 | def num_chats(): 65 | try: 66 | return SESSION.query(func.count(distinct(Rules.chat_id))).scalar() 67 | finally: 68 | SESSION.close() 69 | 70 | 71 | def migrate_chat(old_chat_id, new_chat_id): 72 | with INSERTION_LOCK: 73 | chat = SESSION.query(Rules).get(str(old_chat_id)) 74 | if chat: 75 | chat.chat_id = str(new_chat_id) 76 | SESSION.commit() 77 | -------------------------------------------------------------------------------- /tg_bot/modules/sql/lang_sql.py: -------------------------------------------------------------------------------- 1 | # OpenGM - Powerful Telegram group managment bot 2 | # Copyright (C) 2017 - 2019 Paul Larsen 3 | # Copyright (C) 2019 - 2020 KaratekHD 4 | # 5 | # This program is free software: you can redistribute it and/or modify 6 | # it under the terms of the GNU General Public License as published by 7 | # the Free Software Foundation, either version 3 of the License, or 8 | # (at your option) any later version. 9 | # 10 | # This program is distributed in the hope that it will be useful, 11 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | # GNU General Public License for more details. 14 | # 15 | # You should have received a copy of the GNU General Public License 16 | # along with this program. If not, see . 17 | 18 | 19 | import threading 20 | 21 | from sqlalchemy import Column, String, UnicodeText, func, distinct 22 | 23 | from tg_bot.modules.sql import SESSION, BASE 24 | from tg_bot import DEFAULT_LANG 25 | 26 | 27 | class Lang(BASE): 28 | __tablename__ = "lang" 29 | chat_id = Column(String(14), primary_key=True) 30 | lang = Column(UnicodeText, default="") 31 | 32 | def __init__(self, chat_id): 33 | self.chat_id = chat_id 34 | 35 | def __repr__(self): 36 | return "".format(self.chat_id, self.lang) 37 | 38 | 39 | Lang.__table__.create(checkfirst=True) 40 | 41 | INSERTION_LOCK = threading.RLock() 42 | 43 | 44 | def set_lang(chat_id, lang_text): 45 | with INSERTION_LOCK: 46 | l = SESSION.query(Lang).get(str(chat_id)) 47 | if not l: 48 | l = Lang(str(chat_id)) 49 | l.lang = lang_text 50 | 51 | SESSION.add(l) 52 | SESSION.commit() 53 | 54 | 55 | def get_lang(chat_id): 56 | lang = SESSION.query(Lang).get(str(chat_id)) 57 | ret = DEFAULT_LANG 58 | if lang: 59 | ret = lang.lang 60 | 61 | SESSION.close() 62 | return ret 63 | 64 | 65 | def num_chats(): 66 | try: 67 | return SESSION.query(func.count(distinct(Lang.chat_id))).scalar() 68 | finally: 69 | SESSION.close() 70 | 71 | 72 | def migrate_chat(old_chat_id, new_chat_id): 73 | with INSERTION_LOCK: 74 | chat = SESSION.query(Lang).get(str(old_chat_id)) 75 | if chat: 76 | chat.chat_id = str(new_chat_id) 77 | SESSION.commit() 78 | -------------------------------------------------------------------------------- /tg_bot/strings/en/locks.json: -------------------------------------------------------------------------------- 1 | { 2 | "LOCKS" : "Locks: ", 3 | "LOCK_SUCCESS" : "Locked {} messages for all non-admins!", 4 | "LOCK_SUCCESS_HTML" : "{}:\n#LOCK\nAdmin: {}\nLocked {}.", 5 | "LOCK_SUCCESS_2" : "Locked {} for all non-admins!", 6 | "ERR_NO_ARGS" : "What are you trying to lock...? Try /locktypes for the list of lockables", 7 | "ERR_NO_PERMS" : "I'm not an administrator, or haven't got delete rights.", 8 | "UNLOCK_SUCCESS" : "Unlocked {} for everyone!", 9 | "UNLOCK_SUCCESS_HTML" : "{}:{}:\nAdmin: {}\nUnlocked {}.", 10 | "ERR_UNLOCK_NO_PERMS" : "What are you trying to unlock...? Try /locktypes for the list of lockables", 11 | "ERR_NO_ARGS_BUT_DIFFERENT" : "What are you trying to unlock...?", 12 | "ERR_IS_BOT_WITHOUT_PERMS" : "I see a bot, and I've been told to stop them joining... but I'm not admin!", 13 | "MSG_BOT_KICKED" : "Only admins are allowed to add bots to this chat! Get outta here.", 14 | "ERR_LOCKABLE" : "ERROR in lockables", 15 | "ERR_RESTRICTIONS" : "ERROR in restrictions", 16 | "NO_LOCKS" : "There are no current locks in this chat.", 17 | "CURRENT_LOCKS" : "These are the locks in this chat:", 18 | "STICKER" : "\n - sticker = `{}`", 19 | "AUDIO" : "\n - audio = `{}`", 20 | "VOICE" : "\n - voice = `{}", 21 | "DOCUMENT" : "\n - document = `{}`", 22 | "VIDEO" : "\n - video = `{}`", 23 | "VIDEONOTE" : "\n - videonote = `{}`", 24 | "CONTACT" : "\n - contact = `{}`", 25 | "PHOTO" : "\n - photo = `{}`", 26 | "GIF" : "\n - gif = `{}`", 27 | "URL" : "\n - url = `{}`", 28 | "BOTS" : "\n - bots = `{}`", 29 | "FORWARD" : "\n - forward = `{}`", 30 | "GAME" : "\n - game = `{}`", 31 | "LOCATION" : "\n - location = `{}`", 32 | "MESSAGES" : "\n - messages = `{}`", 33 | "MEDIA" : "\n - media = `{}`", 34 | "OTHER" : "\n - other = `{}`", 35 | "PREVIEWS" : "\n - previews = `{}`", 36 | "ALL" : "\n - all = `{}`", 37 | "HELP" : " - /locktypes: a list of possible locktypes\n\n*Admin only:*\n - /lock : lock items of a certain type (not available in private)\n - /unlock : unlock items of a certain type (not available in private)\n - /locks: the current list of locks in this chat.\n\nLocks can be used to restrict a group's users.\neg:\nLocking urls will auto-delete all messages with urls, locking stickers will delete all stickers, etc.\nLocking bots will stop non-admins from adding bots to the chat.", 38 | "MODULE_NAME" : "Locks" 39 | } -------------------------------------------------------------------------------- /tg_bot/restapi/resources/chats.py: -------------------------------------------------------------------------------- 1 | # OpenGM - Powerful Telegram group managment bot 2 | # Copyright (C) 2017 - 2019 Paul Larsen 3 | # Copyright (C) 2019 - 2020 KaratekHD 4 | # 5 | # This program is free software: you can redistribute it and/or modify 6 | # it under the terms of the GNU General Public License as published by 7 | # the Free Software Foundation, either version 3 of the License, or 8 | # (at your option) any later version. 9 | # 10 | # This program is distributed in the hope that it will be useful, 11 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | # GNU General Public License for more details. 14 | # 15 | # You should have received a copy of the GNU General Public License 16 | # along with this program. If not, see . 17 | 18 | from http import HTTPStatus 19 | 20 | from flask import request, abort 21 | from flask_restplus import Namespace, Resource 22 | from telegram import TelegramError 23 | 24 | import tg_bot.modules.sql.api_sql as sql 25 | import tg_bot.modules.sql.users_sql as user_sql 26 | from tg_bot import dispatcher 27 | from tg_bot.restapi.models.chats import create_chat_model 28 | 29 | chats_api = Namespace("chats", description="Gather information about chats you have access to.") 30 | 31 | chat = create_chat_model(chats_api) 32 | 33 | 34 | @chats_api.route("/") 35 | @chats_api.param('id', 'The group identifier') 36 | @chats_api.response(404, 'Chat not found.') 37 | @chats_api.response(401, "Unauthorized") 38 | @chats_api.response(410, "Bot is not a member of the chat (anymore).") 39 | class Chats(Resource): 40 | @chats_api.marshal_with(chat) 41 | @staticmethod 42 | def get(id): 43 | '''Gets a chat by id''' 44 | key = request.args.get('api_key') 45 | if not key: 46 | abort(HTTPStatus.UNAUTHORIZED, "Unauthorized") 47 | user_id = sql.verify_key(key) 48 | chats = [] 49 | for element in user_sql.get_chats_by_member(user_id): 50 | chats.append(element.chat) 51 | if id not in chats: 52 | abort(HTTPStatus.NOT_FOUND, "Chat not found.") 53 | else: 54 | try: 55 | name = dispatcher.bot.get_chat(id).title 56 | except TelegramError as excp: 57 | if excp.message == 'Chat not found': 58 | abort(HTTPStatus.GONE, "Bot is not a member of the chat (anymore).") 59 | return {"id": id, "name": name} 60 | -------------------------------------------------------------------------------- /tg_bot/strings/de/bans.json: -------------------------------------------------------------------------------- 1 | { 2 | "ERR_NO_TARGET": "Du beziehst dich auf keinen Benutzer.", 3 | "ERR_USER_NOT_FOUND": "Ich kann diesen Benutzer nicht finden", 4 | "ERR_TARGET_IS_ADMIN": "Ich wünschte, ich könnte einen Admin bannen...", 5 | "ERR_TARGET_ITSELF": "Ich werde mich doch nicht selber bannen, bist du verrückt?", 6 | "MSG_BAN_HTML": "{}:\n#GEBANNT\nAdmin: {}\nBenutzer: {} ({})", 7 | "MSG_BAN_HTML_REASON": "\nGrund: {}", 8 | "MSG_BAN_SUCCESS": "Dieser Benutzer wurde in dieser Gruppe gebannt.", 9 | "ERR_CONSOLE_CANT_BAN": "FEHLER beim Bannen von %s im Chat %s (%s) Wegen %s", 10 | "ERR_CANT_BAN": "Verdammt, ich kann diesen Benutzer nicht bannen.", 11 | "ERR_TEMPBAN_NO_TIME": "Du hast keine Zeit angegeben, für die du diesen Benutzer sperren möchtest!", 12 | "MSG_TEMPBAN_HTML": "{}:\n#Temporär gebannt\nAdmin: {}\nBenutzer: {} ({})\nDauer: {}", 13 | "MSG_TEMPBAN_HTML_REASON": "\nGrund: {}", 14 | "MSG_TEMPBAN_SUCCES": "Gebannt! Dieser User wird gebannt für {}.", 15 | "ERR_KICK_TARGET_ADMIN": "Ich wünschte wirklich ich könnte Admins kicken...", 16 | "ERR_KICK_TARGET_ITSELF": "Ganz bestimmt tue ich das...", 17 | "MSG_KICK_SUCCESS": "Gekickt!", 18 | "MSG_KICK_HTML": "{}:\n#KICKED\nAdmin: {}\nBenutzer: {} ({})", 19 | "MSG_KICK_HTML_REASON": "\nGrund: {}", 20 | "ERR_CANT_KICK": "Verdammt, ich kann diesen User nicht kicken.", 21 | "ERR_KICKME_TARGET_IS_ADMIN": "Ich wünschte, ich könnte... aber du bist ein Admin.", 22 | "MSG_KICKME_SUCCESS": "Kein Problem.", 23 | "ERR_KICKME_GENERAL": "Was? Ich kann nicht :/", 24 | "ERR_UNBAN_ITSELF": "Wie sollte ich mich selbst entbannen, wenn ich gar nicht da wäre...?", 25 | "ERR_UNBAN_NOT_BANNED": "Warum versuchst du jemanden zu entbannen der bereits im Chat ist?", 26 | "MSG_UNBAN_SUCCESS": "Jap, dieser User kann beitreten!", 27 | "MSG_UNBAN_HTML": "{}:\n#ENTBANNT\nAdmin: {}\nBenutzer: {} ({})", 28 | "MSG_UNBAN_HTML_REASON": "\nGrund: {}", 29 | "HELP": " - /kickme: kickt den Benutzer, der den Befehl erteilt hat\n\n*nur Admins*\n - /ban : bannt einen Benutzer. (über antworten oder mit @)\n - /tban x(m/st/t): bannt einen Benutzer für eine x Zeit. (über antworten oder mit @). m = Minuten, h = Stunden, d = Tage.\n - /unban : entbannt einen Benutzer. (über antworten oder mit @)\n - /kick : kickt einen Benutzer, (über antworten oder mit @)", 30 | "MODULE_NAME": "Banns" 31 | } -------------------------------------------------------------------------------- /tg_bot/modules/helper_funcs/handlers.py: -------------------------------------------------------------------------------- 1 | # OpenGM - Powerful Telegram group managment bot 2 | # Copyright (C) 2017 - 2019 Paul Larsen 3 | # Copyright (C) 2019 - 2020 KaratekHD 4 | # 5 | # This program is free software: you can redistribute it and/or modify 6 | # it under the terms of the GNU General Public License as published by 7 | # the Free Software Foundation, either version 3 of the License, or 8 | # (at your option) any later version. 9 | # 10 | # This program is distributed in the hope that it will be useful, 11 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | # GNU General Public License for more details. 14 | # 15 | # You should have received a copy of the GNU General Public License 16 | # along with this program. If not, see . 17 | 18 | 19 | import telegram.ext as tg 20 | from telegram import Update 21 | 22 | CMD_STARTERS = ('/', '!') 23 | 24 | 25 | class CustomCommandHandler(tg.CommandHandler): 26 | def __init__(self, command, callback, **kwargs): 27 | if "admin_ok" in kwargs: 28 | del kwargs["admin_ok"] 29 | super().__init__(command, callback, **kwargs) 30 | 31 | def check_update(self, update): 32 | if isinstance(update, Update) and update.effective_message: 33 | message = update.effective_message 34 | 35 | if message.text and len(message.text) > 1: 36 | fst_word = message.text.split(None, 1)[0] 37 | if len(fst_word) > 1 and any( 38 | fst_word.startswith(start) for start in CMD_STARTERS 39 | ): 40 | args = message.text.split()[1:] 41 | command = fst_word[1:].split("@") 42 | command.append( 43 | message.bot.username 44 | ) # in case the command was sent without a username 45 | 46 | if not ( 47 | command[0].lower() in self.command 48 | and command[1].lower() == message.bot.username.lower() 49 | ): 50 | return None 51 | 52 | filter_result = self.filters(update) 53 | if filter_result: 54 | return args, filter_result 55 | return False 56 | 57 | 58 | class CustomRegexHandler(tg.RegexHandler): 59 | def __init__(self, pattern, callback, friendly="", **kwargs): 60 | super().__init__(pattern, callback, **kwargs) 61 | -------------------------------------------------------------------------------- /tg_bot/restapi/models/management.py: -------------------------------------------------------------------------------- 1 | # OpenGM - Powerful Telegram group managment bot 2 | # Copyright (C) 2017 - 2019 Paul Larsen 3 | # Copyright (C) 2019 - 2020 KaratekHD 4 | # 5 | # This program is free software: you can redistribute it and/or modify 6 | # it under the terms of the GNU General Public License as published by 7 | # the Free Software Foundation, either version 3 of the License, or 8 | # (at your option) any later version. 9 | # 10 | # This program is distributed in the hope that it will be useful, 11 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | # GNU General Public License for more details. 14 | # 15 | # You should have received a copy of the GNU General Public License 16 | # along with this program. If not, see . 17 | 18 | from flask_restplus import fields 19 | 20 | from tg_bot.restapi.models.users import create_user_model 21 | 22 | 23 | def create_chatnumber_model(api): 24 | model = api.model('Total Chats', { 25 | 'number': fields.Integer(description="Number of group the bot has registered.", required=True) 26 | }) 27 | return model 28 | 29 | 30 | def create_countusers_model(api): 31 | model = api.model('Total Users', { 32 | 'number': fields.Integer(description="Number of users the bot has registered.", required=True) 33 | }) 34 | return model 35 | 36 | 37 | def create_chat_model(api): 38 | model = api.model('Chat', { 39 | 'id': fields.Integer(description="Telegram ID of chat", required=True), 40 | 'name': fields.String(description="Name of the group", required=True) 41 | }) 42 | return model 43 | 44 | 45 | def create_chatlist_model(api): 46 | model = api.model('Chats', { 47 | 'chats': fields.Nested(create_chat_model(api), description="list of chats", required=True) 48 | }) 49 | return model 50 | 51 | 52 | def create_broadcast_model(api): 53 | model = api.model("Broadcast", { 54 | 'message': fields.String(description="The message that was broadcasted.", required=True), 55 | "failed": fields.Integer(description="Number of chats that failed receiving the broadcast.", required=True), 56 | "failed_chats": fields.Nested(create_chat_model(api), description="Chats that failed receiving the broadcast.", required=False) 57 | }) 58 | return model 59 | 60 | 61 | def create_userlist_model(api): 62 | model = api.model('Users', { 63 | 'users': fields.Nested(create_user_model(api), description="list of users", required=True) 64 | }) 65 | return model -------------------------------------------------------------------------------- /tg_bot/strings/string_helper.py: -------------------------------------------------------------------------------- 1 | # OpenGM - Powerful Telegram group managment bot 2 | # Copyright (C) 2017 - 2019 Paul Larsen 3 | # Copyright (C) 2019 - 2020 KaratekHD 4 | # 5 | # This program is free software: you can redistribute it and/or modify 6 | # it under the terms of the GNU General Public License as published by 7 | # the Free Software Foundation, either version 3 of the License, or 8 | # (at your option) any later version. 9 | # 10 | # This program is distributed in the hope that it will be useful, 11 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | # GNU General Public License for more details. 14 | # 15 | # You should have received a copy of the GNU General Public License 16 | # along with this program. If not, see . 17 | # 18 | # This program is free software: you can redistribute it and/or modify 19 | # it under the terms of the GNU General Public License as published by 20 | # the Free Software Foundation, either version 3 of the License, or 21 | # (at your option) any later version. 22 | # 23 | # This program is distributed in the hope that it will be useful, 24 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 25 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 26 | # GNU General Public License for more details. 27 | # 28 | # You should have received a copy of the GNU General Public License 29 | # along with this program. If not, see . 30 | 31 | import json 32 | import os 33 | import random 34 | 35 | 36 | # get string from json file 37 | def get_string(module: str, name: str, lang: str): 38 | try: 39 | if not os.path.isfile(os.path.dirname(os.path.abspath(__file__)) + "/" + lang + "/" + module + ".json"): 40 | lang = "en" 41 | with open(os.path.dirname(os.path.abspath(__file__)) + "/" + lang + "/" + module + ".json") as f: 42 | data = json.load(f) 43 | return data[name] 44 | except FileNotFoundError as excp: 45 | return excp.__cause__ 46 | except KeyError as e: 47 | return e.__cause__ 48 | 49 | 50 | 51 | 52 | # for /runs, /slap etc. 53 | def get_random_string(module: str, lang: str): 54 | if not os.path.isfile(os.path.dirname(os.path.abspath(__file__)) + "/" + lang + "/" + module + ".json"): 55 | lang = "en" 56 | with open(os.path.dirname(os.path.abspath(__file__)) + "/" + lang + "/" + module + ".json") as f: 57 | data = json.load(f) 58 | i = len(data) 59 | r = str(random.randint(1, i)) 60 | return data[r] 61 | -------------------------------------------------------------------------------- /.github/workflows/codeql-analysis.yml: -------------------------------------------------------------------------------- 1 | # For most projects, this workflow file will not need changing; you simply need 2 | # to commit it to your repository. 3 | # 4 | # You may wish to alter this file to override the set of languages analyzed, 5 | # or to provide custom queries or build logic. 6 | # 7 | # ******** NOTE ******** 8 | # We have attempted to detect the languages in your repository. Please check 9 | # the `language` matrix defined below to confirm you have the correct set of 10 | # supported CodeQL languages. 11 | # 12 | name: "CodeQL" 13 | 14 | on: 15 | push: 16 | branches: [ master ] 17 | pull_request: 18 | # The branches below must be a subset of the branches above 19 | branches: [ master ] 20 | schedule: 21 | - cron: '45 7 * * 6' 22 | 23 | jobs: 24 | analyze: 25 | name: Analyze 26 | runs-on: ubuntu-latest 27 | 28 | strategy: 29 | fail-fast: false 30 | matrix: 31 | language: [ 'python' ] 32 | # CodeQL supports [ 'cpp', 'csharp', 'go', 'java', 'javascript', 'python' ] 33 | # Learn more: 34 | # https://docs.github.com/en/free-pro-team@latest/github/finding-security-vulnerabilities-and-errors-in-your-code/configuring-code-scanning#changing-the-languages-that-are-analyzed 35 | 36 | steps: 37 | - name: Checkout repository 38 | uses: actions/checkout@v2 39 | 40 | # Initializes the CodeQL tools for scanning. 41 | - name: Initialize CodeQL 42 | uses: github/codeql-action/init@v1 43 | with: 44 | languages: ${{ matrix.language }} 45 | # If you wish to specify custom queries, you can do so here or in a config file. 46 | # By default, queries listed here will override any specified in a config file. 47 | # Prefix the list here with "+" to use these queries and those in the config file. 48 | # queries: ./path/to/local/query, your-org/your-repo/queries@main 49 | 50 | # Autobuild attempts to build any compiled languages (C/C++, C#, or Java). 51 | # If this step fails, then you should remove it and run the build manually (see below) 52 | - name: Autobuild 53 | uses: github/codeql-action/autobuild@v1 54 | 55 | # ℹ️ Command-line programs to run using the OS shell. 56 | # 📚 https://git.io/JvXDl 57 | 58 | # ✏️ If the Autobuild fails above, remove it and uncomment the following three lines 59 | # and modify them (or add more) to build your code if your project 60 | # uses a compiled language 61 | 62 | #- run: | 63 | # make bootstrap 64 | # make release 65 | 66 | - name: Perform CodeQL Analysis 67 | uses: github/codeql-action/analyze@v1 68 | -------------------------------------------------------------------------------- /setup.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # 3 | # Nemesis - Powerful Telegram group managment bot 4 | # Copyright (C) 2017 - 2019 Paul Larsen 5 | # Copyright (C) 2019 - 2020 KaratekHD 6 | # 7 | # This program is free software: you can redistribute it and/or modify 8 | # it under the terms of the GNU General Public License as published by 9 | # the Free Software Foundation, either version 3 of the License, or 10 | # (at your option) any later version. 11 | # 12 | # This program is distributed in the hope that it will be useful, 13 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 | # GNU General Public License for more details. 16 | # 17 | # You should have received a copy of the GNU General Public License 18 | # along with this program. If not, see . 19 | # 20 | 21 | if [ "$EUID" -ne 0 ] 22 | then echo "ERROR: Please run as root" 23 | # exit 24 | fi 25 | echo "WARNING: THIS SCRIPT WILL CREATE A CONFIG FILE AND INSTALL ALL REQUIREMENTS; YOU STILL HAVE TO SETUP A DATABASE!" 26 | # shellcheck disable=SC1068 27 | BOOL=true 28 | while $BOOL; do 29 | read -p "QUESTION: Do you wish to install this program? [y/n] " yn 30 | case $yn in 31 | [Yy]* ) BOOL=false; break;; 32 | [Nn]* ) exit;; 33 | * ) echo "ERROR: Please answer yes or no.";; 34 | esac 35 | done 36 | if [ -f /etc/os-release ] 37 | then 38 | if grep -q openSUSE "/etc/os-release"; then 39 | echo "INFO: Running on openSUSE. Great!" 40 | else 41 | echo "ERROR: This script only supports openSUSE. Exiting." 42 | exit 43 | fi 44 | else 45 | echo "ERROR: /etc/os-release doesn't exist. Aborting." 46 | exit 47 | fi 48 | RPM=$(rpm -q python38-base) 49 | if echo "$RPM" | grep -q "not installed"; then 50 | echo "INFO: Python is not installed on your system. Installing..."; 51 | zypper install --recommends --no-confirm python38-base 52 | else 53 | echo "INFO: Python 3 is installed on your system. Great!"; 54 | fi 55 | RPM=$(rpm -q python3-pip) 56 | if echo "$RPM" | grep -q "not installed"; then 57 | echo "INFO: PIP3 is not installed on your system. Installing..."; 58 | zypper install --recommends --no-confirm python3-pip 59 | else 60 | echo "INFO: PIP3 is installed on your system. Great!"; 61 | fi 62 | RPM=$(rpm -q gcc) 63 | if echo "$RPM" | grep -q "not installed"; then 64 | echo "INFO: GCC is not installed on your system. Installing..."; 65 | zypper install --recommends --no-confirm gcc 66 | else 67 | echo "INFO: GCC is installed on your system. Great!"; 68 | fi 69 | echo "Installing requirements...." 70 | pip3 install -r requirements.txt 71 | -------------------------------------------------------------------------------- /tg_bot/strings/de/locks.json: -------------------------------------------------------------------------------- 1 | { 2 | "LOCKS": "Sperren: ", 3 | "LOCK_SUCCESS": "{} Nachrichten für alle Nicht-Admins gesperrt!", 4 | "LOCK_SUCCESS_HTML": "{}:\n#LOCK\nAdmin: {}\nGesperrt {}.", 5 | "LOCK_SUCCESS_2": "{} Nachrichten für alle Nicht-Admins gesperrt!", 6 | "ERR_NO_ARGS": "Was versuchst du zu sperren...? Versuche /locktypes für die Liste der Sperrmöglichkeiten", 7 | "ERR_NO_PERMS": "Ich bin kein Admin, oder habe keine Löschrechte.", 8 | "UNLOCK_SUCCESS": "Habe {} für jeden entsperrt!", 9 | "UNLOCK_SUCCESS_HTML": "{}:{}:\nAdmin: {}\nentsperrt {}.", 10 | "ERR_UNLOCK_NO_PERMS": "Was versuchst du zu entsperren...? Versuche /locktypes für die Liste der Sperrmöglichkeiten", 11 | "ERR_NO_ARGS_BUT_DIFFERENT": "Was versuchst du zu entsperren...?", 12 | "ERR_IS_BOT_WITHOUT_PERMS": "Ich sehe einen Bot, und mir wurde gesagt ich soll ihn vom beitreten stoppen... weil ich kein Admin bin!", 13 | "MSG_BOT_KICKED": "Nur Administratoren dürfen Bots zu diesem Chat hinzufügen! Verschwinden von hier.", 14 | "ERR_LOCKABLE": "FEHLER beim sperren/entsperren", 15 | "ERR_RESTRICTIONS": "FEHLER in Beschränkungen", 16 | "NO_LOCKS": "Es gibt keine Sperren in diesem Chat.", 17 | "CURRENT_LOCKS": "Das sind die Sperren in diesem Chat:", 18 | "STICKER": "\n - Sticker = `{}`", 19 | "AUDIO": "\n - Audio = `{}`", 20 | "VOICE": "\n - Sprache = `{}", 21 | "DOCUMENT": "\n - Dokument = `{}`", 22 | "VIDEO": "\n - Video = `{}`", 23 | "VIDEONOTE": "\n - videonote = `{}`", 24 | "CONTACT": "\n - Kontakt = `{}`", 25 | "PHOTO": "\n - Foto = `{}`", 26 | "GIF": "\n - gif = `{}`", 27 | "URL": "\n - url = `{}`", 28 | "BOTS": "\n - Bots = `{}`", 29 | "FORWARD": "\n - weiterleiten = `{}`", 30 | "GAME": "\n - Spiel = `{}`", 31 | "LOCATION": "\n - Standort = `{}`", 32 | "MESSAGES": "\n - Nachrichten = `{}`", 33 | "MEDIA": "\n - media = `{}`", 34 | "OTHER": "\n - andere = `{}`", 35 | "PREVIEWS": "\n - Vorschau = `{}`", 36 | "ALL": "\n - alle/s = `{}`", 37 | "HELP": " - /locktypes: eine Liste von möglichen Sperrtypen\n\n*Nur für Admins:*\n - /lock : Elemente eines bestimmten Typs sperren (nicht privat verfügbar)\n - /unlock : Elemente eines bestimmten Typs entsperren (nicht privat verfügbar)\n - /locks: die aktuelle Liste der Sperren in diesem Chat.\n\nSperren können benutzt werden, um die Benutzer einer Gruppe zu beschränken.\nz. B.:\nDas Sperren von URLs löscht automatisch alle Nachrichten mit Urls, das Sperren von Aufklebern löscht alle Aufkleber usw.\nDas Sperren von Bots hält Nicht-Administratoren davon ab, Bots zum Chat hinzuzufügen.", 38 | "MODULE_NAME": "Sperren" 39 | } -------------------------------------------------------------------------------- /tg_bot/modules/lang.py: -------------------------------------------------------------------------------- 1 | # OpenGM - Powerful Telegram group managment bot 2 | # Copyright (C) 2017 - 2019 Paul Larsen 3 | # Copyright (C) 2019 - 2020 KaratekHD 4 | # 5 | # This program is free software: you can redistribute it and/or modify 6 | # it under the terms of the GNU General Public License as published by 7 | # the Free Software Foundation, either version 3 of the License, or 8 | # (at your option) any later version. 9 | # 10 | # This program is distributed in the hope that it will be useful, 11 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | # GNU General Public License for more details. 14 | # 15 | # You should have received a copy of the GNU General Public License 16 | # along with this program. If not, see . 17 | 18 | 19 | from typing import List 20 | 21 | from telegram import Update 22 | from telegram.ext import CommandHandler, CallbackContext 23 | 24 | from tg_bot import dispatcher 25 | from tg_bot.modules.helper_funcs.chat_status import bot_admin, user_admin 26 | import tg_bot.modules.sql.lang_sql as sql 27 | from tg_bot.strings.string_helper import get_string 28 | 29 | 30 | @bot_admin 31 | @user_admin 32 | def setlang(update: Update, context: CallbackContext): 33 | chat_id = update.effective_chat.id 34 | msg = update.effective_message # type: Optional[Message] 35 | raw_text = msg.text 36 | args = raw_text.split(None, 1) # use python's maxsplit to separate cmd and args 37 | if len(args) == 2: 38 | txt = args[1] 39 | SUPPORTED_LANGUAGES = ["de", "en"] 40 | if txt not in SUPPORTED_LANGUAGES: 41 | msg.reply_text(get_string("lang", "ERR_UNKNOWN_LANG", sql.get_lang(chat_id))) # ERR_UNKNOWN_LANG 42 | else: 43 | sql.set_lang(chat_id, txt) 44 | msg.reply_text(get_string("lang", "LANG_SET", sql.get_lang(chat_id))) # LANG_SET 45 | 46 | else: 47 | msg.reply_text(get_string("lang", "ERR_NO_LANG", sql.get_lang(chat_id))) # ERR_NO_LANG 48 | 49 | 50 | __mod_name__ = "Languages" 51 | 52 | 53 | def __chat_settings__(chat_id): 54 | return get_string("lang", "CHAT_SETTINGS", sql.get_lang(chat_id)).format(sql.get_lang(chat_id)) # CHAT_SETTINGS 55 | 56 | 57 | def __user_settings__(user_id): 58 | return get_string("lang", "USER_SETTINGS", sql.get_lang(user_id)).format( 59 | sql.get_lang(user_id)) # USER_SETTINGS 60 | 61 | 62 | def __help__(update: Update) -> str: 63 | return get_string("lang", "HELP", sql.get_lang(update.effective_chat.id)) # HELP 64 | 65 | 66 | LANG_HANDLER = CommandHandler("lang", setlang, pass_args=True, run_async=True) 67 | 68 | dispatcher.add_handler(LANG_HANDLER) 69 | -------------------------------------------------------------------------------- /tg_bot/modules/translation.py: -------------------------------------------------------------------------------- 1 | # OpenGM - Powerful Telegram group managment bot 2 | # Copyright (C) 2017 - 2019 Paul Larsen 3 | # Copyright (C) 2019 - 2020 KaratekHD 4 | # 5 | # This program is free software: you can redistribute it and/or modify 6 | # it under the terms of the GNU General Public License as published by 7 | # the Free Software Foundation, either version 3 of the License, or 8 | # (at your option) any later version. 9 | # 10 | # This program is distributed in the hope that it will be useful, 11 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | # GNU General Public License for more details. 14 | # 15 | # You should have received a copy of the GNU General Public License 16 | # along with this program. If not, see . 17 | 18 | 19 | import json 20 | from pprint import pprint 21 | 22 | import requests 23 | from telegram import Update 24 | from telegram.ext import CallbackContext 25 | 26 | from tg_bot import dispatcher 27 | 28 | # Open API key 29 | from tg_bot.modules.disable import DisableAbleCommandHandler 30 | 31 | API_KEY = "6ae0c3a0-afdc-4532-a810-82ded0054236" 32 | URL = "http://services.gingersoftware.com/Ginger/correct/json/GingerTheText" 33 | 34 | 35 | def translate(update: Update, context: CallbackContext): 36 | if update.effective_message.reply_to_message: 37 | msg = update.effective_message.reply_to_message 38 | 39 | params = dict( 40 | lang="US", 41 | clientVersion="2.0", 42 | apiKey=API_KEY, 43 | text=msg.text 44 | ) 45 | 46 | res = requests.get(URL, params=params) 47 | # print(res) 48 | # print(res.text) 49 | pprint(json.loads(res.text)) 50 | changes = json.loads(res.text).get('LightGingerTheTextResult') 51 | curr_string = "" 52 | 53 | prev_end = 0 54 | 55 | for change in changes: 56 | start = change.get('From') 57 | end = change.get('To') + 1 58 | suggestions = change.get('Suggestions') 59 | if suggestions: 60 | sugg_str = suggestions[0].get('Text') # should look at this list more 61 | curr_string += msg.text[prev_end:start] + sugg_str 62 | 63 | prev_end = end 64 | 65 | curr_string += msg.text[prev_end:] 66 | print(curr_string) 67 | update.effective_message.reply_text(curr_string) 68 | 69 | 70 | def __help__(update: Update) -> str: 71 | return "\n - /t: while replying to a message, will reply with a grammar corrected version (English Only!)" 72 | 73 | __mod_name__ = "Grammar" 74 | 75 | 76 | TRANSLATE_HANDLER = DisableAbleCommandHandler('t', translate, run_async=True) 77 | 78 | dispatcher.add_handler(TRANSLATE_HANDLER) 79 | -------------------------------------------------------------------------------- /tg_bot/strings/en/gbans.json: -------------------------------------------------------------------------------- 1 | { 2 | "ERR_NO_TARGET" : "You don't seem to be referring to a user.", 3 | "ERR_SUDO_USER" : "I spy, with my little eye... a sudo user war! Why are you guys turning on each other?", 4 | "ERR_SUPPORT_USER" : "OOOH someone's trying to gban a support user! *grabs popcorn*", 5 | "ERR_IS_ITSELF" : "-_- So funny, lets gban myself why don't I? Nice try.", 6 | "ERR_NO_USER" : "That's not a user!", 7 | "ERR_GBANNED_NO_REASON" : "This user is already gbanned; I'd change the reason, but you haven't given me one...", 8 | "ALREADY_BANNED" : "This user is already gbanned, for the following reason:\n{}\nI've gone and updated it with your new reason!", 9 | "ALREADY_BANNED_WITHOUT_REASON" : "This user is already gbanned, but had no reason set; I've gone and updated it!", 10 | "BANNED" : "*Blows dust off of banhammer* \uD83D\uDE09", 11 | "BROADCAST" : "{} is gbanning user {} because:\n{}", 12 | "BROADCAST_NO_REASON" : "No reason given", 13 | "GENERAL_ERROR" : "Could not gban due to: {}", 14 | "SUCCESS" : "gban complete!", 15 | "SUCCESS_REPLY" : "Person has been gbanned.", 16 | "ERR_NOT_BANNED" : "This user is not gbanned!", 17 | "UNBANNED" : "I'll give {} a second chance, globally.", 18 | "UNBANNED_BC" : "{} has ungbanned user {}", 19 | "ERR_UNBANN_GENERAL" : "Could not un-gban due to: {}", 20 | "UNBANN_SCS" : "un-gban complete!", 21 | "UNBANN_SCS_REPLY" : "Person has been un-gbanned.", 22 | "EXPORT_HEAD" : "Screw these guys.\n", 23 | "REASON" : "Reason: {}\n", 24 | "EXPORT_SUCCESS" : "Here is the list of currently gbanned users.", 25 | "THIS_IS_A_BAD_PERSON" : "This is a bad person, they shouldn't be here!", 26 | "GBANS_ON" : "I've enabled gbans in this group. This will help protect you from spammers, unsavoury characters, and the biggest trolls.", 27 | "GBANS_OFF" : "I've disabled gbans in this group. GBans wont affect your users anymore. You'll be less protected from any trolls and spammers though!", 28 | "GBAN_NO_ARGS" : "Give me some arguments to choose a setting! on/off, yes/no!\n\nYour current setting is: {}\nWhen True, any gbans that happen will also happen in your group. When False, they won't, leaving you at the possible mercy of spammers.", 29 | "STATS" : "{} gbanned users.", 30 | "USER_INFO" : "Globally banned: {}", 31 | "USER_INFO_YES" : "Yes", 32 | "USER_INFO_REASON" : "\nReason: {}", 33 | "USER_INFO_NO" : "No", 34 | "CHAT_SETTINGS" : "This chat is enforcing *gbans*: `{}`.", 35 | "HELP" : "*Admin only:*\n - /gbanstat : Will disable the effect of global bans on your group, or return your current settings.\n\nGbans, also known as global bans, are used by the bot owners to ban spammers across all groups. This helps protect you and your groups by removing spam flooders as quickly as possible. They can be disabled for you group by calling /gbanstat", 36 | "MODULE_NAME" : "Global Bans" 37 | } -------------------------------------------------------------------------------- /tg_bot/modules/sql/afk_sql.py: -------------------------------------------------------------------------------- 1 | # OpenGM - Powerful Telegram group managment bot 2 | # Copyright (C) 2017 - 2019 Paul Larsen 3 | # Copyright (C) 2019 - 2020 KaratekHD 4 | # 5 | # This program is free software: you can redistribute it and/or modify 6 | # it under the terms of the GNU General Public License as published by 7 | # the Free Software Foundation, either version 3 of the License, or 8 | # (at your option) any later version. 9 | # 10 | # This program is distributed in the hope that it will be useful, 11 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | # GNU General Public License for more details. 14 | # 15 | # You should have received a copy of the GNU General Public License 16 | # along with this program. If not, see . 17 | 18 | 19 | import threading 20 | 21 | from sqlalchemy import Column, UnicodeText, Boolean, Integer, BigInteger 22 | 23 | from tg_bot.modules.sql import BASE, SESSION 24 | 25 | 26 | class AFK(BASE): 27 | __tablename__ = "afk_users" 28 | 29 | user_id = Column(BigInteger, primary_key=True) 30 | is_afk = Column(Boolean) 31 | reason = Column(UnicodeText) 32 | 33 | def __init__(self, user_id, reason="", is_afk=True): 34 | self.user_id = user_id 35 | self.reason = reason 36 | self.is_afk = is_afk 37 | 38 | def __repr__(self): 39 | return "afk_status for {}".format(self.user_id) 40 | 41 | 42 | AFK.__table__.create(checkfirst=True) 43 | INSERTION_LOCK = threading.RLock() 44 | 45 | AFK_USERS = {} 46 | 47 | 48 | def is_afk(user_id): 49 | return user_id in AFK_USERS 50 | 51 | 52 | def check_afk_status(user_id): 53 | if user_id in AFK_USERS: 54 | return True, AFK_USERS[user_id] 55 | return False, "" 56 | 57 | 58 | def set_afk(user_id, reason=""): 59 | with INSERTION_LOCK: 60 | curr = SESSION.query(AFK).get(user_id) 61 | if not curr: 62 | curr = AFK(user_id, reason, True) 63 | else: 64 | curr.is_afk = True 65 | curr.reason = reason 66 | 67 | AFK_USERS[user_id] = reason 68 | 69 | SESSION.add(curr) 70 | SESSION.commit() 71 | 72 | 73 | def rm_afk(user_id): 74 | with INSERTION_LOCK: 75 | curr = SESSION.query(AFK).get(user_id) 76 | if curr: 77 | if user_id in AFK_USERS: # sanity check 78 | del AFK_USERS[user_id] 79 | 80 | SESSION.delete(curr) 81 | SESSION.commit() 82 | return True 83 | 84 | SESSION.close() 85 | return False 86 | 87 | 88 | def __load_afk_users(): 89 | global AFK_USERS 90 | try: 91 | all_afk = SESSION.query(AFK).all() 92 | AFK_USERS = {user.user_id: user.reason for user in all_afk if user.is_afk} 93 | finally: 94 | SESSION.close() 95 | 96 | 97 | __load_afk_users() 98 | -------------------------------------------------------------------------------- /tg_bot/modules/sql/approval_sql.py: -------------------------------------------------------------------------------- 1 | # OpenGM - Powerful Telegram group managment bot 2 | # Copyright (C) 2017 - 2019 Paul Larsen 3 | # Copyright (C) 2019 - 2020 KaratekHD 4 | # 5 | # This program is free software: you can redistribute it and/or modify 6 | # it under the terms of the GNU General Public License as published by 7 | # the Free Software Foundation, either version 3 of the License, or 8 | # (at your option) any later version. 9 | # 10 | # This program is distributed in the hope that it will be useful, 11 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | # GNU General Public License for more details. 14 | # 15 | # You should have received a copy of the GNU General Public License 16 | # along with this program. If not, see . 17 | 18 | import threading 19 | 20 | from sqlalchemy import Column, String 21 | 22 | from tg_bot.modules.sql import BASE, SESSION 23 | 24 | 25 | class Approval(BASE): 26 | __tablename__ = "approval" 27 | chat_id = Column(String(14), primary_key=True) 28 | user_id = Column(String(14), primary_key=True) 29 | 30 | def __init__(self, chat_id, user_id): 31 | self.chat_id = str(chat_id) # ensure string 32 | self.user_id = user_id 33 | 34 | 35 | Approval.__table__.create(checkfirst=True) 36 | 37 | INSERTION_LOCK = threading.RLock() 38 | 39 | APPROVALS = {} 40 | 41 | 42 | def approve(chat_id, user_id): 43 | with INSERTION_LOCK: 44 | approval = Approval(str(chat_id), str(user_id)) 45 | APPROVALS[str(chat_id)] = APPROVALS[str(chat_id)].append(str(user_id)) 46 | SESSION.merge(approval) 47 | SESSION.commit() 48 | 49 | 50 | def rm_approve(chat_id, user_id): 51 | with INSERTION_LOCK: 52 | approval = SESSION.query(Approval).get((str(chat_id), str(user_id))) 53 | if approval: 54 | SESSION.delete(approval) 55 | SESSION.commit() 56 | 57 | 58 | def check_approval(chat_id, user_id): 59 | approval = SESSION.query(Approval).get((str(chat_id), str(user_id))) 60 | if approval: 61 | return True 62 | return False 63 | 64 | 65 | def migrate_chat(old_chat_id, new_chat_id): 66 | with INSERTION_LOCK: 67 | chat_filters = SESSION.query(Approval).filter(Approval.chat_id == str(old_chat_id)).all() 68 | for approval in chat_filters: 69 | approval.chat_id = str(new_chat_id) 70 | SESSION.commit() 71 | 72 | 73 | def remove_all(chat_id): 74 | with INSERTION_LOCK: 75 | m = SESSION.query(Approval).filter(Approval.chat_id == str(chat_id)).all() 76 | for element in m: 77 | approval = SESSION.query(Approval).get((str(chat_id), str(element.user_id))) 78 | SESSION.delete(approval) 79 | SESSION.commit() 80 | 81 | 82 | def get_chat_approvals(chat_id): 83 | m = SESSION.query(Approval).filter(Approval.chat_id == str(chat_id)).all() 84 | return m -------------------------------------------------------------------------------- /tg_bot/strings/de/gbans.json: -------------------------------------------------------------------------------- 1 | { 2 | "ERR_NO_TARGET": "Du beziehst dich auf keinen Benutzer.", 3 | "ERR_SUDO_USER": "Was sehe ich da? Ihr Team-Mitglieder bekriegt euch gegenseitig? Was ist denn da los?", 4 | "ERR_SUPPORT_USER": "Ui, jemand versucht, einen Support-Benutzer zu gbannen! *greift nach Popcorn*", 5 | "ERR_IS_ITSELF": "-_- So lustig, ich banne mich selber, warum nicht? Netter Versuch.", 6 | "ERR_NO_USER": "Das ist kein Benutzer!", 7 | "ERR_GBANNED_NO_REASON": "Dieser Benutzer ist bereits gegbannet; ich würde den Grund ändern, aber du hast mir keinen gegeben...", 8 | "ALREADY_BANNED": "Dieser Benutzer ist bereits aus folgendem Grund verbannt:\n{}\nIch habe ihn mit deinem neuen Grund aktualisiert!", 9 | "ALREADY_BANNED_WITHOUT_REASON": "This user is already gbanned, but had no reason set; I've gone and updated it!", 10 | "BANNED": "*Staub vom Banhammer* 😉", 11 | "BROADCAST": "{} gbannt Benutzer {} weil:\n{}", 12 | "BROADCAST_NO_REASON": "Es wurde kein Grund angegeben", 13 | "GENERAL_ERROR": "Konnte aufgrund von {} nicht gbannen", 14 | "SUCCESS": "gban erfolgreich!", 15 | "SUCCESS_REPLY": "Person wurde gegbannt.", 16 | "ERR_NOT_BANNED": "Dieser Benutzer ist nicht gebannt!", 17 | "UNBANNED": "Ich gebe {} eine zweite Chance, global.", 18 | "UNBANNED_BC": "{} hat Benutzer {} entbannt", 19 | "ERR_UNBANN_GENERAL": "Konnte gban nicht entfernen: {}", 20 | "UNBANN_SCS": "entgbannen erfolgreich!", 21 | "UNBANN_SCS_REPLY": "Die Person wurde entbannt.", 22 | "EXPORT_HEAD": "Screw these guys.\n", 23 | "REASON": "Grund: {}\n", 24 | "EXPORT_SUCCESS": "Hier ist die Liste der derzeit gbannten Benutzer.", 25 | "THIS_IS_A_BAD_PERSON": "Das ist ein schlechter Mensch, der hier nicht sein sollte!", 26 | "GBANS_ON": "I've enabled gbans in this group. This will help protect you from spammers, unsavoury characters, and the biggest trolls.", 27 | "GBANS_OFF": "I've disabled gbans in this group. GBans wont affect your users anymore. You'll be less protected from any trolls and spammers though!", 28 | "GBAN_NO_ARGS": "Give me some arguments to choose a setting! on/off, yes/no!\n\nYour current setting is: {}\nWhen True, any gbans that happen will also happen in your group. When False, they won't, leaving you at the possible mercy of spammers.", 29 | "STATS": "{} gbannte Benutzer.", 30 | "USER_INFO": "Global gebannt: {}", 31 | "USER_INFO_YES": "Ja", 32 | "USER_INFO_REASON": "\nGrund: {}", 33 | "USER_INFO_NO": "Nein", 34 | "CHAT_SETTINGS": "Dieser Chat erzwingt *gbans*: `{}`.", 35 | "HELP": "*Nur Admin:*\n - /gbanstat : Deaktiviere den Effekt globaler Verbote auf deine Gruppe oder stell deine aktuellen Einstellungen zurück.\n\nGbans, auch als globale Verbote bekannt, werden von den Bot-Besitzern benutzt, um Spammer über alle Gruppen hinweg zu verbieten. Dies hilft, dich und deine Gruppen zu schützen, indem Spam-Überflutungen so schnell wie möglich entfernt werden. Sie können für deine Gruppe deaktiviert werden, indem du /gbanstat anrufst", 36 | "MODULE_NAME": "Globale Bans" 37 | } -------------------------------------------------------------------------------- /tg_bot/modules/helper_funcs/backups.py: -------------------------------------------------------------------------------- 1 | # OpenGM - Powerful Telegram group managment bot 2 | # Copyright (C) 2017 - 2019 Paul Larsen 3 | # Copyright (C) 2019 - 2020 KaratekHD 4 | # 5 | # This program is free software: you can redistribute it and/or modify 6 | # it under the terms of the GNU General Public License as published by 7 | # the Free Software Foundation, either version 3 of the License, or 8 | # (at your option) any later version. 9 | # 10 | # This program is distributed in the hope that it will be useful, 11 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | # GNU General Public License for more details. 14 | # 15 | # You should have received a copy of the GNU General Public License 16 | # along with this program. If not, see . 17 | 18 | import toml 19 | from telegram import Bot, Chat 20 | 21 | import tg_bot.modules.sql.cust_filters_sql as filters 22 | import tg_bot.modules.sql.rules_sql as rules_sql 23 | import tg_bot.modules.sql.notes_sql as notes_sql 24 | from tg_bot import dispatcher 25 | from tg_bot.modules.cust_filters import HANDLER_GROUP 26 | from tg_bot.modules.helper_funcs.string_handling import markdown_parser 27 | from tg_bot.modules.sql import welcome_sql, antiflood_sql, global_bans_sql, lang_sql 28 | 29 | 30 | def import_filter(chatid, trigger, reply): 31 | 32 | is_sticker = False 33 | is_document = False 34 | is_image = False 35 | is_voice = False 36 | is_audio = False 37 | is_video = False 38 | buttons = [] 39 | for handler in dispatcher.handlers.get(HANDLER_GROUP, []): 40 | if handler.filters == (trigger, chatid): 41 | dispatcher.remove_handler(handler, HANDLER_GROUP) 42 | 43 | filters.add_filter(chatid, trigger, reply, is_sticker, is_document, is_image, is_audio, is_voice, is_video, 44 | buttons) 45 | 46 | def import_rules(chatid, rules): 47 | markdown_rules = markdown_parser(rules) 48 | rules_sql.set_rules(chatid, markdown_rules) 49 | 50 | def import_note(chatid, name, text): 51 | notes_sql.import_note_to_db(chatid, name, text) 52 | 53 | def export_data(chat : Chat, bot: Bot) -> str: 54 | export = {"bot": {"id": bot.id, "name": bot.first_name, "username": bot.username}, 55 | "chat": {"id": chat.id, "title": chat.title, "members": chat.get_members_count()}, 56 | "welcomes": {"welcome": welcome_sql.get_custom_welcome(chat.id), 57 | "goodbye": welcome_sql.get_custom_gdbye(chat.id)}, 58 | "antiflood": {"limit": antiflood_sql.get_flood_limit(chat.id)}, 59 | "gbans": {"enabled": global_bans_sql.does_chat_gban(chat.id)}, 60 | "languages": {"lang": lang_sql.get_lang(chat.id)}, "rules": {"text": rules_sql.get_rules(chat.id)}, 61 | "filters": {"null": "null"} 62 | } 63 | 64 | for i in filters.get_chat_triggers(chat.id): 65 | export["filters"][i] = filters.get_filter(chat.id, i).reply 66 | 67 | del export["filters"]["null"] 68 | return toml.dumps(export) 69 | -------------------------------------------------------------------------------- /tg_bot/sample_config.py: -------------------------------------------------------------------------------- 1 | if not __name__.endswith("sample_config"): 2 | import sys 3 | print("The README is there to be read. Extend this sample config to a config file, don't just rename and change " 4 | "values here. Doing that WILL backfire on you.\nBot quitting.", file=sys.stderr) 5 | sys.exit(1) 6 | 7 | 8 | # OpenGM - Powerful Telegram group managment bot 9 | # Copyright (C) 2017 - 2019 Paul Larsen 10 | # Copyright (C) 2019 - 2020 KaratekHD 11 | # 12 | # This program is free software: you can redistribute it and/or modify 13 | # it under the terms of the GNU General Public License as published by 14 | # the Free Software Foundation, either version 3 of the License, or 15 | # (at your option) any later version. 16 | # 17 | # This program is distributed in the hope that it will be useful, 18 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 19 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 20 | # GNU General Public License for more details. 21 | # 22 | # You should have received a copy of the GNU General Public License 23 | # along with this program. If not, see . 24 | 25 | 26 | # Create a new config.py file in same dir and import, then extend this class. 27 | class Config: 28 | LOGGER = True 29 | 30 | # REQUIRED 31 | API_KEY = "YOUR KEY HERE" 32 | OWNER_ID = "YOUR ID HERE" # If you dont know, run the bot and do /id in your private chat with it 33 | OWNER_USERNAME = "YOUR USERNAME HERE" 34 | 35 | # RECOMMENDED 36 | SQLALCHEMY_DATABASE_URI = 'sqldbtype://username:pw@hostname:port/db_name' # needed for any database modules 37 | MESSAGE_DUMP = None # needed to make sure 'save from' messages persist 38 | LOAD = [] 39 | # sed has been disabled after the discovery that certain long-running sed commands maxed out cpu usage 40 | # and killed the bot. Be careful re-enabling it! 41 | # rest is still in development ans should remain disabled unless you really know what you're doing. 42 | NO_LOAD = ['translation', 'rest'] 43 | WEBHOOK = False 44 | URL = None 45 | DEFAULT_LANG = "en" 46 | 47 | # OPTIONAL 48 | SUDO_USERS = [] # List of id's (not usernames) for users which have sudo access to the bot. 49 | SUPPORT_USERS = [] # List of id's (not usernames) for users which are allowed to gban, but can also be banned. 50 | WHITELIST_USERS = [] # List of id's (not usernames) for users which WONT be banned/kicked by the bot. 51 | DONATION_LINK = None # EG, paypal 52 | CERT_PATH = None 53 | PORT = 5000 54 | DEL_CMDS = False # Whether or not you should delete "blue text must click" commands 55 | STRICT_GBAN = False 56 | WORKERS = 8 # Number of subthreads to use. This is the recommended amount - see for yourself what works best! 57 | BAN_STICKER = 'CAACAgIAAx0CRMLKjgACBjtgHtmyflcZm_zsltAYGf_AtIy60AAClgEAAhZCawp7Vw4iU3POsB4E' # banhammer marie sticker 58 | ALLOW_EXCL = False # Allow ! commands as well as / 59 | CO_OWNER_ID = "" # a persons ID 60 | 61 | 62 | class Production(Config): 63 | LOGGER = False 64 | 65 | 66 | class Development(Config): 67 | LOGGER = True 68 | -------------------------------------------------------------------------------- /tg_bot/strings/en/runs.json: -------------------------------------------------------------------------------- 1 | { 2 | "1" : "Where do you think you're going?", 3 | "2" : "Huh? what? did they get away?", 4 | "3" : "ZZzzZZzz... Huh? what? oh, just them again, nevermind.", 5 | "4" : "Get back here!", 6 | "5" : "Not so fast...", 7 | "6" : "Look out for the wall!", 8 | "7" : "Don't leave me alone with them!!", 9 | "8" : "You run, you die.", 10 | "9" : "Jokes on you, I'm everywhere", 11 | "10" : "You're gonna regret that...", 12 | "11" : "You could also try /kickme, I hear that's fun.", 13 | "12" : "Go bother someone else, no-one here cares.", 14 | "13" : "You can run, but you can't hide.", 15 | "14" : "Is that all you've got?", 16 | "15" : "I'm behind you...", 17 | "16" : "You've got company!", 18 | "17" : "We can do this the easy way, or the hard way.", 19 | "18" : "You just don't get it, do you?", 20 | "19" : "Yeah, you better run!", 21 | "20" : "Please, remind me how much I care?", 22 | "21" : "I'd run faster if I were you.", 23 | "22" : "That's definitely the droid we're looking for.", 24 | "23" : "May the odds be ever in your favour.", 25 | "24" : "Famous last words.", 26 | "25" : "And they disappeared forever, never to be seen again.", 27 | "26" : "\"Oh, look at me! I'm so cool, I can run from a bot!\" - this person", 28 | "27" : "Yeah yeah, just tap /kickme already.", 29 | "28" : "Here, take this ring and head to Mordor while you're at it.", 30 | "29" : "Legend has it, they're still running...", 31 | "30" : "Unlike Harry Potter, your parents can't protect you from me.", 32 | "31" : "Fear leads to anger. Anger leads to hate. Hate leads to suffering. If you keep running in fear, you might be the next Vader.", 33 | "32" : "Multiple calculations later, I have decided my interest in your shenanigans is exactly 0.", 34 | "33" : "Legend has it, they're still running.", 35 | "34" : "Keep it up, not sure we want you here anyway.", 36 | "35" : "You're a wiza- Oh. Wait. You're not Harry, keep moving.", 37 | "36" : "NO RUNNING IN THE HALLWAYS!", 38 | "37" : "Hasta la vista, baby.", 39 | "38" : "Who let the dogs out?", 40 | "39" : "It's funny, because no one cares.", 41 | "40" : "Ah, what a waste. I liked that one.", 42 | "41" : "Frankly, my dear, I don't give a damn.", 43 | "42" : "My milkshake brings all the boys to yard... So run faster!", 44 | "43" : "You can't HANDLE the truth!", 45 | "44" : "A long time ago, in a galaxy far far away... Someone would've cared about that. Not anymore though.", 46 | "45" : "Hey, look at them! They're running from the inevitable banhammer... Cute.", 47 | "46" : "Han shot first. So will I.", 48 | "47" : "What are you running after, a white rabbit?", 49 | "48" : "As The Doctor would say... RUN!", 50 | "49" : "I take you to the Castle of Aaaarrrrrgggghhhh!", 51 | "50" : "The Enrichment Center is required to remind you that you will be baked, and then there will be cake.", 52 | "51" : "I'm going to kill you, and all the cake is gone.", 53 | "52" : "Is Konrad spamming again?!", 54 | "53" : "I will get you.", 55 | "54" : "Wait, are you trying to run?", 56 | "55" : "That's the wrong direction.", 57 | "56" : "You know that you are running in a hamsterwheel, dont you?" 58 | } -------------------------------------------------------------------------------- /tg_bot/modules/sql/whisper_sql.py: -------------------------------------------------------------------------------- 1 | # OpenGM - Powerful Telegram group managment bot 2 | # Copyright (C) 2017 - 2019 Paul Larsen 3 | # Copyright (C) 2019 - 2020 KaratekHD 4 | # 5 | # This program is free software: you can redistribute it and/or modify 6 | # it under the terms of the GNU General Public License as published by 7 | # the Free Software Foundation, either version 3 of the License, or 8 | # (at your option) any later version. 9 | # 10 | # This program is distributed in the hope that it will be useful, 11 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | # GNU General Public License for more details. 14 | # 15 | # You should have received a copy of the GNU General Public License 16 | # along with this program. If not, see . 17 | 18 | import threading 19 | 20 | from sqlalchemy import Column, String, Integer, BigInteger 21 | 22 | from tg_bot.modules.sql import BASE, SESSION 23 | 24 | 25 | class whisper_message(): 26 | message = "" 27 | sender_id = 0 28 | receiver_id = 0 29 | 30 | def __init__(self, sender_id, receiver_id, message): 31 | self.sender_id = sender_id 32 | self.receiver_id = receiver_id 33 | self.message = message 34 | 35 | 36 | class Whispers(BASE): 37 | __tablename__ = "whispers" 38 | 39 | whisper_id = Column(String(14), primary_key=True) 40 | receiver_id = Column(BigInteger) 41 | sender_id = Column(BigInteger) 42 | message = Column(String, default="") 43 | 44 | def __init__(self, whisper_id, receiver_id, sender_id): 45 | self.whisper_id = whisper_id 46 | self.receiver_id = receiver_id 47 | self.sender_id = sender_id 48 | 49 | 50 | Whispers.__table__.create(checkfirst=True) 51 | 52 | INSERTION_LOCK = threading.RLock() 53 | 54 | 55 | def add_whisper(sender_id, receiver_id, message, id): 56 | with INSERTION_LOCK: 57 | w = Whispers(id, receiver_id, sender_id) 58 | w.message = message 59 | SESSION.add(w) 60 | SESSION.commit() 61 | 62 | 63 | def get_message(whisper_id): 64 | try: 65 | w = SESSION.query(Whispers).get(str(whisper_id)) 66 | if not w: 67 | return "null" 68 | result = whisper_message(w.sender_id, w.receiver_id, w.message) 69 | return result 70 | finally: 71 | SESSION.close() 72 | 73 | class Number(BASE): 74 | __tablename__ = "whisperids" 75 | 76 | bot_id = Column(BigInteger, primary_key=True) 77 | id = Column(Integer, default=0) 78 | 79 | def __init__(self, bot_id): 80 | self.bot_id = bot_id 81 | self.id = 0 82 | 83 | 84 | Number.__table__.create(checkfirst=True) 85 | 86 | 87 | def get_whispers(bot_id): 88 | r = SESSION.query(Number).get(bot_id) 89 | ret = 0 90 | if r: 91 | ret = r.id 92 | 93 | SESSION.close() 94 | return ret 95 | 96 | 97 | def increase_whisper_ids(bot_id): 98 | r = SESSION.query(Number).get(bot_id) 99 | if not r: 100 | r = Number(bot_id) 101 | r.id += 1 102 | SESSION.add(r) 103 | SESSION.commit() 104 | 105 | -------------------------------------------------------------------------------- /tg_bot/modules/sql/log_channel_sql.py: -------------------------------------------------------------------------------- 1 | # OpenGM - Powerful Telegram group managment bot 2 | # Copyright (C) 2017 - 2019 Paul Larsen 3 | # Copyright (C) 2019 - 2020 KaratekHD 4 | # 5 | # This program is free software: you can redistribute it and/or modify 6 | # it under the terms of the GNU General Public License as published by 7 | # the Free Software Foundation, either version 3 of the License, or 8 | # (at your option) any later version. 9 | # 10 | # This program is distributed in the hope that it will be useful, 11 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | # GNU General Public License for more details. 14 | # 15 | # You should have received a copy of the GNU General Public License 16 | # along with this program. If not, see . 17 | 18 | 19 | import threading 20 | 21 | from sqlalchemy import Column, String, func, distinct 22 | 23 | from tg_bot.modules.sql import BASE, SESSION 24 | 25 | 26 | class GroupLogs(BASE): 27 | __tablename__ = "log_channels" 28 | chat_id = Column(String(14), primary_key=True) 29 | log_channel = Column(String(14), nullable=False) 30 | 31 | def __init__(self, chat_id, log_channel): 32 | self.chat_id = str(chat_id) 33 | self.log_channel = str(log_channel) 34 | 35 | 36 | GroupLogs.__table__.create(checkfirst=True) 37 | 38 | LOGS_INSERTION_LOCK = threading.RLock() 39 | 40 | CHANNELS = {} 41 | 42 | 43 | def set_chat_log_channel(chat_id, log_channel): 44 | with LOGS_INSERTION_LOCK: 45 | res = SESSION.query(GroupLogs).get(str(chat_id)) 46 | if res: 47 | res.log_channel = log_channel 48 | else: 49 | res = GroupLogs(chat_id, log_channel) 50 | SESSION.add(res) 51 | 52 | CHANNELS[str(chat_id)] = log_channel 53 | SESSION.commit() 54 | 55 | 56 | def get_chat_log_channel(chat_id): 57 | return CHANNELS.get(str(chat_id)) 58 | 59 | 60 | def stop_chat_logging(chat_id): 61 | with LOGS_INSERTION_LOCK: 62 | res = SESSION.query(GroupLogs).get(str(chat_id)) 63 | if res: 64 | if str(chat_id) in CHANNELS: 65 | del CHANNELS[str(chat_id)] 66 | 67 | log_channel = res.log_channel 68 | SESSION.delete(res) 69 | SESSION.commit() 70 | return log_channel 71 | 72 | 73 | def num_logchannels(): 74 | try: 75 | return SESSION.query(func.count(distinct(GroupLogs.chat_id))).scalar() 76 | finally: 77 | SESSION.close() 78 | 79 | 80 | def migrate_chat(old_chat_id, new_chat_id): 81 | with LOGS_INSERTION_LOCK: 82 | chat = SESSION.query(GroupLogs).get(str(old_chat_id)) 83 | if chat: 84 | chat.chat_id = str(new_chat_id) 85 | SESSION.add(chat) 86 | if str(old_chat_id) in CHANNELS: 87 | CHANNELS[str(new_chat_id)] = CHANNELS.get(str(old_chat_id)) 88 | 89 | SESSION.commit() 90 | 91 | 92 | def __load_log_channels(): 93 | global CHANNELS 94 | try: 95 | all_chats = SESSION.query(GroupLogs).all() 96 | CHANNELS = {chat.chat_id: chat.log_channel for chat in all_chats} 97 | finally: 98 | SESSION.close() 99 | 100 | 101 | __load_log_channels() 102 | -------------------------------------------------------------------------------- /tg_bot/modules/sql/rss_sql.py: -------------------------------------------------------------------------------- 1 | # OpenGM - Powerful Telegram group managment bot 2 | # Copyright (C) 2017 - 2019 Paul Larsen 3 | # Copyright (C) 2019 - 2020 KaratekHD 4 | # 5 | # This program is free software: you can redistribute it and/or modify 6 | # it under the terms of the GNU General Public License as published by 7 | # the Free Software Foundation, either version 3 of the License, or 8 | # (at your option) any later version. 9 | # 10 | # This program is distributed in the hope that it will be useful, 11 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | # GNU General Public License for more details. 14 | # 15 | # You should have received a copy of the GNU General Public License 16 | # along with this program. If not, see . 17 | 18 | 19 | import threading 20 | 21 | from sqlalchemy import Column, UnicodeText, Integer 22 | 23 | from tg_bot.modules.sql import BASE, SESSION 24 | 25 | 26 | class RSS(BASE): 27 | __tablename__ = "rss_feed" 28 | id = Column(Integer, primary_key=True) 29 | chat_id = Column(UnicodeText, nullable=False) 30 | feed_link = Column(UnicodeText) 31 | old_entry_link = Column(UnicodeText) 32 | 33 | def __init__(self, chat_id, feed_link, old_entry_link): 34 | self.chat_id = chat_id 35 | self.feed_link = feed_link 36 | self.old_entry_link = old_entry_link 37 | 38 | def __repr__(self): 39 | return "".format(self.chat_id, 40 | self.feed_link, 41 | self.old_entry_link) 42 | 43 | 44 | RSS.__table__.create(checkfirst=True) 45 | INSERTION_LOCK = threading.RLock() 46 | 47 | 48 | def check_url_availability(tg_chat_id, tg_feed_link): 49 | try: 50 | return SESSION.query(RSS).filter(RSS.feed_link == tg_feed_link, 51 | RSS.chat_id == tg_chat_id).all() 52 | finally: 53 | SESSION.close() 54 | 55 | 56 | def add_url(tg_chat_id, tg_feed_link, tg_old_entry_link): 57 | with INSERTION_LOCK: 58 | action = RSS(tg_chat_id, tg_feed_link, tg_old_entry_link) 59 | 60 | SESSION.add(action) 61 | SESSION.commit() 62 | 63 | 64 | def remove_url(tg_chat_id, tg_feed_link): 65 | with INSERTION_LOCK: 66 | # this loops to delete any possible duplicates for the same TG User ID, TG Chat ID and link 67 | for row in check_url_availability(tg_chat_id, tg_feed_link): 68 | # add the action to the DB query 69 | SESSION.delete(row) 70 | 71 | SESSION.commit() 72 | 73 | 74 | def get_urls(tg_chat_id): 75 | try: 76 | return SESSION.query(RSS).filter(RSS.chat_id == tg_chat_id).all() 77 | finally: 78 | SESSION.close() 79 | 80 | 81 | def get_all(): 82 | try: 83 | return SESSION.query(RSS).all() 84 | finally: 85 | SESSION.close() 86 | 87 | 88 | def update_url(row_id, new_entry_links): 89 | with INSERTION_LOCK: 90 | row = SESSION.query(RSS).get(row_id) 91 | 92 | # set the new old_entry_link with the latest update from the RSS Feed 93 | row.old_entry_link = new_entry_links[0] 94 | 95 | # commit the changes to the DB 96 | SESSION.commit() 97 | -------------------------------------------------------------------------------- /tg_bot/strings/de/runs.json: -------------------------------------------------------------------------------- 1 | { 2 | "1": "Wo willst du hin?", 3 | "2": "Hm? Was? Bist du entkommen?", 4 | "3": "ZZzzZZZZzz... Huh? Was? Oh, du schon wieder, ach egal ist unwichtig.", 5 | "4": "Komm zurück!", 6 | "5": "Nicht so schnell...", 7 | "6": "Vorsicht bei der Mauer!", 8 | "7": "Lass mich nicht alleine mit denen!!", 9 | "8": "Wenn du rennst, stirbst du.", 10 | "9": "Ich habe Spaß gemacht. Ich bin überall.", 11 | "10": "Das wirst du bereuen...", 12 | "11": "Versuch mal /kickme, das soll lustig sein.", 13 | "12": "Belästige jemand anderen, das interessiert hier niemanden.", 14 | "13": "Du kannst wegrennen, aber du kannst dich nicht verstecken.", 15 | "14": "Ist das alles was du hast?", 16 | "15": "Ich bin hinter dir...", 17 | "16": "Du hast Besuch!", 18 | "17": "Wir können das auf die leichte oder auf die harte Tour machen.", 19 | "18": "Du verstehst es einfach nicht, oder?", 20 | "19": "Ja, lauf besser weg!", 21 | "20": "Bitte, erinnerst du mich daran, wie wichtig mir das ist?", 22 | "21": "An deiner Stelle würde ich schneller rennen.", 23 | "22": "Das ist definitiv der Droide, nach dem wir suchen.", 24 | "23": "Mögen die Erfolgschancen immer zu deinen Gunsten stehen.", 25 | "24": "Berühmte letzte Worte.", 26 | "25": "Und dann verschwandest du für immer und wurdest nie wieder gesehen.", 27 | "26": "\"Oh, seht mich an! Ich bin so cool, ich kann vor einem Bot weglaufen!\" - diese Person", 28 | "27": "Geheimtipp: versuch mal /kickme.", 29 | "28": "Hier, nimm diesen Ring und geh nach Mordor, wenn du schon dabei bist.", 30 | "29": "Der Legende nach, läufst du immer noch...", 31 | "30": "Anders als bei Harry Potter können deine Eltern dich nicht vor mir beschützen.", 32 | "31": "Angst führt zu Wut. Wut führt zu Hass. Hass führt zu Leid. Wenn du weiter in Angst rennst, könntest du der nächste Vader sein.", 33 | "32": "Nach mehrere Berechnungen habe ich entschieden, dass mein Interesse an deinem Blödsinn genau 0 ist.", 34 | "33": "Die Legende besagt, dass du immer noch läufst.", 35 | "34": "Mach weiter so, wir sind nicht sicher, ob wir dich überhaupt hier haben wollen.", 36 | "35": "Du bist ein Zaub- Oh. Moment. Du bist nicht Harry, mach weiter.", 37 | "36": "KEIN RENNEN IN DEN GÄNGEN!", 38 | "37": "Hasta la vista, baby.", 39 | "38": "Wer hat die Hunde raus gelassen?", 40 | "39": "Es ist lustig, weil es niemanden kümmert.", 41 | "40": "Ah, was für eine Verschwendung. Das hat mir gefallen.", 42 | "41": "Offen gesagt, Schatz, das ist mir scheißegal.", 43 | "42": "Bring mir meinen Milchshake. Lauf schneller!", 44 | "43": "Du kannst die Warheit nicht ERTRAGEN!", 45 | "44": "Es war einmal vor langer Zeit in einer weit, weit entfernten Galaxie... Jemand hat sich drum gekümmert. Aber das ist vorbei.", 46 | "45": "Hey, sieh dich an! Du fliehst vor dem unvermeidlichen Banhammer... Wie süß.", 47 | "46": "Du hast zuerst geschossen. Jetzt bin ich dran.", 48 | "47": "Hinter was bist du her, hinter einem weißen Kaninchen?", 49 | "48": "Der Arzt würde sagen... LAUF!", 50 | "49": "Ich bringe dich in die Festung von Mordor!", 51 | "50": "Das Enrichment Center ist verpflichtet, dich daran zu erinnern, dass du gebacken wirst, und dann gibt es Kuchen.", 52 | "51": "Ich werde dich killen und der ganze Kuchen ist verloren.", 53 | "52": "Konrad, spamst du wieder?!", 54 | "53": "Ich kriege dich.", 55 | "54": "Warte, versuchst du weg zu rennen?", 56 | "55": "Das ist die falsche Richtung.", 57 | "56": "You know that you are running in a hamsterwheel, dont you?" 58 | } -------------------------------------------------------------------------------- /CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 | # Contributor Covenant Code of Conduct 2 | 3 | ## Our Pledge 4 | 5 | In the interest of fostering an open and welcoming environment, we as 6 | contributors and maintainers pledge to making participation in our project and 7 | our community a harassment-free experience for everyone, regardless of age, body 8 | size, disability, ethnicity, sex characteristics, gender identity and expression, 9 | level of experience, education, socio-economic status, nationality, personal 10 | appearance, race, religion, or sexual identity and orientation. 11 | 12 | ## Our Standards 13 | 14 | Examples of behavior that contributes to creating a positive environment 15 | include: 16 | 17 | * Using welcoming and inclusive language 18 | * Being respectful of differing viewpoints and experiences 19 | * Gracefully accepting constructive criticism 20 | * Focusing on what is best for the community 21 | * Showing empathy towards other community members 22 | 23 | Examples of unacceptable behavior by participants include: 24 | 25 | * The use of sexualized language or imagery and unwelcome sexual attention or 26 | advances 27 | * Trolling, insulting/derogatory comments, and personal or political attacks 28 | * Public or private harassment 29 | * Publishing others' private information, such as a physical or electronic 30 | address, without explicit permission 31 | * Other conduct which could reasonably be considered inappropriate in a 32 | professional setting 33 | 34 | ## Our Responsibilities 35 | 36 | Project maintainers are responsible for clarifying the standards of acceptable 37 | behavior and are expected to take appropriate and fair corrective action in 38 | response to any instances of unacceptable behavior. 39 | 40 | Project maintainers have the right and responsibility to remove, edit, or 41 | reject comments, commits, code, wiki edits, issues, and other contributions 42 | that are not aligned to this Code of Conduct, or to ban temporarily or 43 | permanently any contributor for other behaviors that they deem inappropriate, 44 | threatening, offensive, or harmful. 45 | 46 | ## Scope 47 | 48 | This Code of Conduct applies both within project spaces and in public spaces 49 | when an individual is representing the project or its community. Examples of 50 | representing a project or community include using an official project e-mail 51 | address, posting via an official social media account, or acting as an appointed 52 | representative at an online or offline event. Representation of a project may be 53 | further defined and clarified by project maintainers. 54 | 55 | ## Enforcement 56 | 57 | Instances of abusive, harassing, or otherwise unacceptable behavior may be 58 | reported by contacting the project team at kontakt@karatek.net. All 59 | complaints will be reviewed and investigated and will result in a response that 60 | is deemed necessary and appropriate to the circumstances. The project team is 61 | obligated to maintain confidentiality with regard to the reporter of an incident. 62 | Further details of specific enforcement policies may be posted separately. 63 | 64 | Project maintainers who do not follow or enforce the Code of Conduct in good 65 | faith may face temporary or permanent repercussions as determined by other 66 | members of the project's leadership. 67 | 68 | ## Attribution 69 | 70 | This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, 71 | available at https://www.contributor-covenant.org/version/1/4/code-of-conduct.html 72 | 73 | [homepage]: https://www.contributor-covenant.org 74 | 75 | For answers to common questions about this code of conduct, see 76 | https://www.contributor-covenant.org/faq 77 | -------------------------------------------------------------------------------- /tg_bot/strings/da/main.json: -------------------------------------------------------------------------------- 1 | { 2 | "PM_START_TEXT": "Hi {}, my name is {}! If you have any questions on how to use me, read /help - and then head to @MarieSupport.\n\nI'm a group manager bot built in python3, using the python-telegram-bot library, and am fully opensource;\nyou can find what makes me tick [here](github.com/KaratekHD/tgbot)!\n\nFeel free to submit pull requests on github, or to contact my support group, @MarieSupport, with any bugs, questions\nor feature requests you might have :)\nI also have a news channel, @MarieNews for announcements on new features, downtime, etc.\n\nYou can find the list of available commands with /help.\nYou can also read my documentation at [karatek.net](https://karatek.net/Projects/Nemesisdocs/).\n\nBy using Nemesis, you agree to the privacy policies of Karatek Software Development, located at [karatek.net](https://karatek.net/Legal/privacy/).", 3 | "HELP_STRINGS": "Hey there! My name is *{}*.\nI'm a modular group management bot with a few fun extras! Have a look at the following for an idea of some of\nthe things I can help you with. You can also read my documentation at [karatek.net](https://karatek.net/Projects/Nemesisdocs/).\n\n*Main* commands available:\n - /start: start the bot\n - /help: PM's you this message.\n - /help : PM's you info about that module.\n - /settings:\n - in PM: will send you your settings for all supported modules.\n - in a group: will redirect you to pm, with all that chat's settings.\n\n{}\nAnd the following:", 4 | "HELP_STRINGS_PART_2": "\nAll commands can either be used with / or !.\n", 5 | "NO_TWO_MODULES": "Can't have two modules with the same name! Please change one", 6 | "EDITED_MESSAGE": "This person edited a message", 7 | "START_IN_GROUP": "Yo, whadup?", 8 | "HELP_FOR_MODULE": "Here is the help for the *{}* module:\n", 9 | "ERR_MSG_NOT_MODIFIED": "Message is not modified", 10 | "ERR_QUERY_ID_INVALID": "Query_id_invalid", 11 | "ERR_MSG_CANT_DELETE": "Message can't be deleted", 12 | "ERR_EXCP_HELP_BUTTONS": "Exception in help buttons. %s", 13 | "PM_FOR_HELP": "Contact me in PM to get the list of possible commands.", 14 | "PM_FOR_HELP_BUTTON": "Help", 15 | "HELP_FOR_MODULE_AVAILABLE": "Here is the available help for the *{}* module:\n", 16 | "CURRENT_SETTINGS": "These are your current settings:", 17 | "ERR_NO_USER_SETTINGS": "Seems like there aren't any user specific settings available :'(", 18 | "Q_SETTINGS_WHICH_MODULE": "Seems like there aren't any chat settings available :'(\\nSend this in a group chat you're admin in to find its current settings!", 19 | "MODULE_SETTINGS": "*{}* has the following settings for the *{}* module:\n\n", 20 | "LOT_OF_SETTINGS": "Hi there! There are quite a few settings for {} - go ahead and pick what you're interested in.", 21 | "ERR_EXCP_SETTINGS_BUTTONS": "Exception in settings buttons. %s", 22 | "CLICK_HERE_FOR_SETTINGS": "Click here to get this chat's settings, as well as yours.", 23 | "SETTINGS": "Settings", 24 | "YOUR_SETTINGS": "Click here to check your settings.", 25 | "MIGRATING": "Migrating from %s, to %s", 26 | "MIGRATING_SUCCESS": "Successfully migrated!", 27 | "WEBHOOKS": "Using webhooks.", 28 | "LONG_POLLING": "Using long polling.", 29 | "ERR_UNKNOWN": "An uncaught error was raised while handling the error", 30 | "ERR_DISPATCHERHANDLERSTOP": "Stopping further handlers due to DispatcherHandlerStop", 31 | "ERR_TELEGRAM": "A TelegramError was raised while processing the Update", 32 | "ERR_ERRHANDLER": "Error handler stopped further handlers", 33 | "ERR_UPDATE_UNKNOWN": "An uncaught error was raised while processing the update", 34 | "MODULES_LOADED": "Successfully loaded modules: " 35 | } -------------------------------------------------------------------------------- /tg_bot/strings/fr/main.json: -------------------------------------------------------------------------------- 1 | { 2 | "PM_START_TEXT": "Hi {}, my name is {}! If you have any questions on how to use me, read /help - and then head to @MarieSupport.\n\nI'm a group manager bot built in python3, using the python-telegram-bot library, and am fully opensource;\nyou can find what makes me tick [here](github.com/KaratekHD/tgbot)!\n\nFeel free to submit pull requests on github, or to contact my support group, @MarieSupport, with any bugs, questions\nor feature requests you might have :)\nI also have a news channel, @MarieNews for announcements on new features, downtime, etc.\n\nYou can find the list of available commands with /help.\nYou can also read my documentation at [karatek.net](https://karatek.net/Projects/Nemesisdocs/).\n\nBy using Nemesis, you agree to the privacy policies of Karatek Software Development, located at [karatek.net](https://karatek.net/Legal/privacy/).", 3 | "HELP_STRINGS": "Hey there! My name is *{}*.\nI'm a modular group management bot with a few fun extras! Have a look at the following for an idea of some of\nthe things I can help you with. You can also read my documentation at [karatek.net](https://karatek.net/Projects/Nemesisdocs/).\n\n*Main* commands available:\n - /start: start the bot\n - /help: PM's you this message.\n - /help : PM's you info about that module.\n - /settings:\n - in PM: will send you your settings for all supported modules.\n - in a group: will redirect you to pm, with all that chat's settings.\n\n{}\nAnd the following:", 4 | "HELP_STRINGS_PART_2": "\nAll commands can either be used with / or !.\n", 5 | "NO_TWO_MODULES": "Can't have two modules with the same name! Please change one", 6 | "EDITED_MESSAGE": "This person edited a message", 7 | "START_IN_GROUP": "Yo, whadup?", 8 | "HELP_FOR_MODULE": "Here is the help for the *{}* module:\n", 9 | "ERR_MSG_NOT_MODIFIED": "Message is not modified", 10 | "ERR_QUERY_ID_INVALID": "Query_id_invalid", 11 | "ERR_MSG_CANT_DELETE": "Message can't be deleted", 12 | "ERR_EXCP_HELP_BUTTONS": "Exception in help buttons. %s", 13 | "PM_FOR_HELP": "Contact me in PM to get the list of possible commands.", 14 | "PM_FOR_HELP_BUTTON": "Help", 15 | "HELP_FOR_MODULE_AVAILABLE": "Here is the available help for the *{}* module:\n", 16 | "CURRENT_SETTINGS": "These are your current settings:", 17 | "ERR_NO_USER_SETTINGS": "Seems like there aren't any user specific settings available :'(", 18 | "Q_SETTINGS_WHICH_MODULE": "Seems like there aren't any chat settings available :'(\\nSend this in a group chat you're admin in to find its current settings!", 19 | "MODULE_SETTINGS": "*{}* has the following settings for the *{}* module:\n\n", 20 | "LOT_OF_SETTINGS": "Hi there! There are quite a few settings for {} - go ahead and pick what you're interested in.", 21 | "ERR_EXCP_SETTINGS_BUTTONS": "Exception in settings buttons. %s", 22 | "CLICK_HERE_FOR_SETTINGS": "Click here to get this chat's settings, as well as yours.", 23 | "SETTINGS": "Settings", 24 | "YOUR_SETTINGS": "Click here to check your settings.", 25 | "MIGRATING": "Migrating from %s, to %s", 26 | "MIGRATING_SUCCESS": "Successfully migrated!", 27 | "WEBHOOKS": "Using webhooks.", 28 | "LONG_POLLING": "Using long polling.", 29 | "ERR_UNKNOWN": "An uncaught error was raised while handling the error", 30 | "ERR_DISPATCHERHANDLERSTOP": "Stopping further handlers due to DispatcherHandlerStop", 31 | "ERR_TELEGRAM": "A TelegramError was raised while processing the Update", 32 | "ERR_ERRHANDLER": "Error handler stopped further handlers", 33 | "ERR_UPDATE_UNKNOWN": "An uncaught error was raised while processing the update", 34 | "MODULES_LOADED": "Successfully loaded modules: " 35 | } -------------------------------------------------------------------------------- /tg_bot/modules/sql/userinfo_sql.py: -------------------------------------------------------------------------------- 1 | # OpenGM - Powerful Telegram group managment bot 2 | # Copyright (C) 2017 - 2019 Paul Larsen 3 | # Copyright (C) 2019 - 2020 KaratekHD 4 | # 5 | # This program is free software: you can redistribute it and/or modify 6 | # it under the terms of the GNU General Public License as published by 7 | # the Free Software Foundation, either version 3 of the License, or 8 | # (at your option) any later version. 9 | # 10 | # This program is distributed in the hope that it will be useful, 11 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | # GNU General Public License for more details. 14 | # 15 | # You should have received a copy of the GNU General Public License 16 | # along with this program. If not, see . 17 | 18 | 19 | import threading 20 | 21 | from sqlalchemy import Column, Integer, UnicodeText, BigInteger 22 | 23 | from tg_bot.modules.sql import SESSION, BASE 24 | 25 | 26 | class UserInfo(BASE): 27 | __tablename__ = "userinfo" 28 | user_id = Column(BigInteger, primary_key=True) 29 | info = Column(UnicodeText) 30 | 31 | def __init__(self, user_id, info): 32 | self.user_id = user_id 33 | self.info = info 34 | 35 | def __repr__(self): 36 | return "" % self.user_id 37 | 38 | 39 | class UserBio(BASE): 40 | __tablename__ = "userbio" 41 | user_id = Column(BigInteger, primary_key=True) 42 | bio = Column(UnicodeText) 43 | 44 | def __init__(self, user_id, bio): 45 | self.user_id = user_id 46 | self.bio = bio 47 | 48 | def __repr__(self): 49 | return "" % self.user_id 50 | 51 | 52 | UserInfo.__table__.create(checkfirst=True) 53 | UserBio.__table__.create(checkfirst=True) 54 | 55 | INSERTION_LOCK = threading.RLock() 56 | 57 | 58 | def get_user_me_info(user_id): 59 | userinfo = SESSION.query(UserInfo).get(user_id) 60 | SESSION.close() 61 | if userinfo: 62 | return userinfo.info 63 | return None 64 | 65 | 66 | def set_user_me_info(user_id, info): 67 | with INSERTION_LOCK: 68 | userinfo = SESSION.query(UserInfo).get(user_id) 69 | if userinfo: 70 | userinfo.info = info 71 | else: 72 | userinfo = UserInfo(user_id, info) 73 | SESSION.add(userinfo) 74 | SESSION.commit() 75 | 76 | 77 | def get_user_bio(user_id): 78 | userbio = SESSION.query(UserBio).get(user_id) 79 | SESSION.close() 80 | if userbio: 81 | return userbio.bio 82 | return None 83 | 84 | 85 | def set_user_bio(user_id, bio): 86 | with INSERTION_LOCK: 87 | userbio = SESSION.query(UserBio).get(user_id) 88 | if userbio: 89 | userbio.bio = bio 90 | else: 91 | userbio = UserBio(user_id, bio) 92 | 93 | SESSION.add(userbio) 94 | SESSION.commit() 95 | 96 | 97 | def clear_user_info(user_id): 98 | with INSERTION_LOCK: 99 | curr = SESSION.query(UserInfo).get(user_id) 100 | if curr: 101 | SESSION.delete(curr) 102 | SESSION.commit() 103 | return True 104 | 105 | SESSION.close() 106 | return False 107 | 108 | 109 | def clear_user_bio(user_id): 110 | with INSERTION_LOCK: 111 | curr = SESSION.query(UserBio).get(user_id) 112 | if curr: 113 | SESSION.delete(curr) 114 | SESSION.commit() 115 | return True 116 | 117 | SESSION.close() 118 | return False 119 | -------------------------------------------------------------------------------- /tg_bot/strings/en/warns.json: -------------------------------------------------------------------------------- 1 | { 2 | "CURRENT_WARNING_FILTER_STRING" : "Current warning filters in this chat:", 3 | "ERR_USER_IS_ADMIN" : "Damn admins, can't even be warned!", 4 | "AUTOMATED_TAG" : "Automated warn filter.", 5 | "MSG_KICK" : "{} warnings, {} has been kicked!", 6 | "MSG_BAN" : "{} warnings, {} has been banned!", 7 | "MSG_WARNBAN_HTML" : "{}:\n#WARN_BAN\nAdmin: {}\nUser: {} ({})\nReason: {}\nCounts: {}/{}", 8 | "BUTTON_REMOVE" : "Remove warn", 9 | "MSG_WARN_SUCCESS" : "{} has {}/{} warnings... watch out!", 10 | "MSG_WARN_SUCCESS_REASON" : "\nReason for last warn:\n{}", 11 | "MSG_WARN_HTML" : "{}:\n#WARN\nAdmin: {}\nUser: {} ({})\nReason: {}\nCounts: {}/{}", 12 | "MSG_WARN_DEL": "Warn removed by {}.", 13 | "MSG_UNWARN_HTML" : "{}:\n#UNWARN\nAdmin: {}\nUser: {} ({})", 14 | "MSG_UNWARN_HAS_NO_WARNS" : "User has already has no warns.", 15 | "ERR_NO_USER" : "No user was designated!", 16 | "MSG_RESET" : "Warnings have been reset!", 17 | "MSG_RESET_HTML" : "{}:\n#RESETWARNS\nAdmin: {}\nUser: {} ({})", 18 | "MSG_INFO" : "This user has {}/{} warnings, for the following reasons:", 19 | "MSG_INFO_NOREASON" : "User has {}/{} warnings, but no reasons for any of them.", 20 | "MSG_INFO_NO_WARNS" : "This user hasn't got any warnings!", 21 | "MSG_FILTER_ADDED" : "Warn handler added for '{}'!", 22 | "ERR_NO_FILTERS" : "No warning filters are active here!", 23 | "MSG_REMOVE_FILTER" : "Yep, I'll stop warning people for that.", 24 | "ERR_NO_FILTER" : "That's not a current warning filter - run /warnlist for all active warning filters.", 25 | "ERR_WRONG_NUMBER" : "The minimum warn limit is 3!", 26 | "MSG_UPDATE_SETTINGS" : "Updated the warn limit to {}", 27 | "MSG_UPDATE_SETTINGS_HTML" : "{}:\n#SET_WARN_LIMIT\nAdmin: {}\nSet the warn limit to {}", 28 | "ERR_NO_ARG" : "Give me a number as an arg!", 29 | "MSG_CURRENT_SETTINGS" : "The current warn limit is {}", 30 | "BAN_SETTING" : "Too many warns will now result in a ban!", 31 | "BAN_SETTING_HTML" : "{}:\nAdmin: {}\nHas enabled strong warns. Users will be banned.", 32 | "KICK_SETTING" : "Too many warns will now result in a kick! Users will be able to join again after.", 33 | "KICK_SETTING_HTML" : "{}:\nAdmin: {}\nHas disabled strong warns. Users will only be kicked.", 34 | "ERR_SET_WRONG_ARG" : "I only understand on/yes/no/off!", 35 | "INFO_KICK" : "Warns are currently set to *kick* users when they exceed the limits.", 36 | "INFO_BAN" : "Warns are currently set to *ban* users when they exceed the limits.", 37 | "STATS" : "{} overall warns, across {} chats.\n{} warn filters, across {} chats.", 38 | "CHAT_SETTINGS" : "This chat has `{}` warn filters. It takes `{}` warns before the user gets *{}*.", 39 | "KICKED" : "kicked", 40 | "BANNED" : "banned", 41 | "HELP" : "\n - /warns : get a user's number, and reason, of warnings.\n - /warnlist: list of all current warning filters\n\n*Admin only:*\n - /warn : warn a user. After 3 warns, the user will be banned from the group. Can also be used as a reply.\n - /resetwarn : reset the warnings for a user. Can also be used as a reply.\n - /addwarn : set a warning filter on a certain keyword. If you want your keyword to be a sentence, encompass it with quotes, as such: `/addwarn \"very angry\" This is an angry user`. \n - /nowarn : stop a warning filter\n - /warnlimit : set the warning limit\n - /strongwarn : If set to on, exceeding the warn limit will result in a ban. Else, will just kick." 42 | } -------------------------------------------------------------------------------- /tg_bot/modules/sql/antiflood_sql.py: -------------------------------------------------------------------------------- 1 | # OpenGM - Powerful Telegram group managment bot 2 | # Copyright (C) 2017 - 2019 Paul Larsen 3 | # Copyright (C) 2019 - 2020 KaratekHD 4 | # 5 | # This program is free software: you can redistribute it and/or modify 6 | # it under the terms of the GNU General Public License as published by 7 | # the Free Software Foundation, either version 3 of the License, or 8 | # (at your option) any later version. 9 | # 10 | # This program is distributed in the hope that it will be useful, 11 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | # GNU General Public License for more details. 14 | # 15 | # You should have received a copy of the GNU General Public License 16 | # along with this program. If not, see . 17 | 18 | 19 | import threading 20 | 21 | from sqlalchemy import Column, Integer, String, BigInteger 22 | 23 | from tg_bot.modules.sql import BASE, SESSION 24 | 25 | DEF_COUNT = 0 26 | DEF_LIMIT = 0 27 | DEF_OBJ = (None, DEF_COUNT, DEF_LIMIT) 28 | 29 | 30 | class FloodControl(BASE): 31 | __tablename__ = "antiflood" 32 | chat_id = Column(String(14), primary_key=True) 33 | user_id = Column(BigInteger) 34 | count = Column(Integer, default=DEF_COUNT) 35 | limit = Column(Integer, default=DEF_LIMIT) 36 | 37 | def __init__(self, chat_id): 38 | self.chat_id = str(chat_id) # ensure string 39 | 40 | def __repr__(self): 41 | return "" % self.chat_id 42 | 43 | 44 | FloodControl.__table__.create(checkfirst=True) 45 | 46 | INSERTION_LOCK = threading.RLock() 47 | 48 | CHAT_FLOOD = {} 49 | 50 | 51 | def set_flood(chat_id, amount): 52 | with INSERTION_LOCK: 53 | flood = SESSION.query(FloodControl).get(str(chat_id)) 54 | if not flood: 55 | flood = FloodControl(str(chat_id)) 56 | 57 | flood.user_id = None 58 | flood.limit = amount 59 | 60 | CHAT_FLOOD[str(chat_id)] = (None, DEF_COUNT, amount) 61 | 62 | SESSION.add(flood) 63 | SESSION.commit() 64 | 65 | 66 | def update_flood(chat_id: str, user_id) -> bool: 67 | if str(chat_id) in CHAT_FLOOD: 68 | curr_user_id, count, limit = CHAT_FLOOD.get(str(chat_id), DEF_OBJ) 69 | 70 | if limit == 0: # no antiflood 71 | return False 72 | 73 | if user_id != curr_user_id or user_id is None: # other user 74 | CHAT_FLOOD[str(chat_id)] = (user_id, DEF_COUNT + 1, limit) 75 | return False 76 | 77 | count += 1 78 | if count > limit: # too many msgs, kick 79 | CHAT_FLOOD[str(chat_id)] = (None, DEF_COUNT, limit) 80 | return True 81 | 82 | # default -> update 83 | CHAT_FLOOD[str(chat_id)] = (user_id, count, limit) 84 | return False 85 | 86 | 87 | def get_flood_limit(chat_id): 88 | return CHAT_FLOOD.get(str(chat_id), DEF_OBJ)[2] 89 | 90 | 91 | def migrate_chat(old_chat_id, new_chat_id): 92 | with INSERTION_LOCK: 93 | flood = SESSION.query(FloodControl).get(str(old_chat_id)) 94 | if flood: 95 | CHAT_FLOOD[str(new_chat_id)] = CHAT_FLOOD.get(str(old_chat_id), DEF_OBJ) 96 | flood.chat_id = str(new_chat_id) 97 | SESSION.commit() 98 | 99 | SESSION.close() 100 | 101 | 102 | def __load_flood_settings(): 103 | global CHAT_FLOOD 104 | try: 105 | all_chats = SESSION.query(FloodControl).all() 106 | CHAT_FLOOD = {chat.chat_id: (None, DEF_COUNT, chat.limit) for chat in all_chats} 107 | finally: 108 | SESSION.close() 109 | 110 | 111 | __load_flood_settings() 112 | -------------------------------------------------------------------------------- /tg_bot/modules/sql/reporting_sql.py: -------------------------------------------------------------------------------- 1 | # OpenGM - Powerful Telegram group managment bot 2 | # Copyright (C) 2017 - 2019 Paul Larsen 3 | # Copyright (C) 2019 - 2020 KaratekHD 4 | # 5 | # This program is free software: you can redistribute it and/or modify 6 | # it under the terms of the GNU General Public License as published by 7 | # the Free Software Foundation, either version 3 of the License, or 8 | # (at your option) any later version. 9 | # 10 | # This program is distributed in the hope that it will be useful, 11 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | # GNU General Public License for more details. 14 | # 15 | # You should have received a copy of the GNU General Public License 16 | # along with this program. If not, see . 17 | 18 | 19 | import threading 20 | from typing import Union 21 | 22 | from sqlalchemy import Column, Integer, String, Boolean, BigInteger 23 | 24 | from tg_bot.modules.sql import SESSION, BASE 25 | 26 | 27 | class ReportingUserSettings(BASE): 28 | __tablename__ = "user_report_settings" 29 | user_id = Column(BigInteger, primary_key=True) 30 | should_report = Column(Boolean, default=True) 31 | 32 | def __init__(self, user_id): 33 | self.user_id = user_id 34 | 35 | def __repr__(self): 36 | return "".format(self.user_id) 37 | 38 | 39 | class ReportingChatSettings(BASE): 40 | __tablename__ = "chat_report_settings" 41 | chat_id = Column(String(14), primary_key=True) 42 | should_report = Column(Boolean, default=True) 43 | 44 | def __init__(self, chat_id): 45 | self.chat_id = str(chat_id) 46 | 47 | def __repr__(self): 48 | return "".format(self.chat_id) 49 | 50 | 51 | ReportingUserSettings.__table__.create(checkfirst=True) 52 | ReportingChatSettings.__table__.create(checkfirst=True) 53 | 54 | CHAT_LOCK = threading.RLock() 55 | USER_LOCK = threading.RLock() 56 | 57 | 58 | def chat_should_report(chat_id: Union[str, int]) -> bool: 59 | try: 60 | chat_setting = SESSION.query(ReportingChatSettings).get(str(chat_id)) 61 | if chat_setting: 62 | return chat_setting.should_report 63 | return False 64 | finally: 65 | SESSION.close() 66 | 67 | 68 | def user_should_report(user_id: int) -> bool: 69 | try: 70 | user_setting = SESSION.query(ReportingUserSettings).get(user_id) 71 | if user_setting: 72 | return user_setting.should_report 73 | return True 74 | finally: 75 | SESSION.close() 76 | 77 | 78 | def set_chat_setting(chat_id: Union[int, str], setting: bool): 79 | with CHAT_LOCK: 80 | chat_setting = SESSION.query(ReportingChatSettings).get(str(chat_id)) 81 | if not chat_setting: 82 | chat_setting = ReportingChatSettings(chat_id) 83 | 84 | chat_setting.should_report = setting 85 | SESSION.add(chat_setting) 86 | SESSION.commit() 87 | 88 | 89 | def set_user_setting(user_id: int, setting: bool): 90 | with USER_LOCK: 91 | user_setting = SESSION.query(ReportingUserSettings).get(user_id) 92 | if not user_setting: 93 | user_setting = ReportingUserSettings(user_id) 94 | 95 | user_setting.should_report = setting 96 | SESSION.add(user_setting) 97 | SESSION.commit() 98 | 99 | 100 | def migrate_chat(old_chat_id, new_chat_id): 101 | with CHAT_LOCK: 102 | chat_notes = SESSION.query(ReportingChatSettings).filter( 103 | ReportingChatSettings.chat_id == str(old_chat_id)).all() 104 | for note in chat_notes: 105 | note.chat_id = str(new_chat_id) 106 | SESSION.commit() 107 | -------------------------------------------------------------------------------- /tg_bot/modules/sql/reputation_settings_sql.py: -------------------------------------------------------------------------------- 1 | # OpenGM - Powerful Telegram group managment bot 2 | # Copyright (C) 2017 - 2019 Paul Larsen 3 | # Copyright (C) 2019 - 2020 KaratekHD 4 | # 5 | # This program is free software: you can redistribute it and/or modify 6 | # it under the terms of the GNU General Public License as published by 7 | # the Free Software Foundation, either version 3 of the License, or 8 | # (at your option) any later version. 9 | # 10 | # This program is distributed in the hope that it will be useful, 11 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | # GNU General Public License for more details. 14 | # 15 | # You should have received a copy of the GNU General Public License 16 | # along with this program. If not, see . 17 | 18 | 19 | import threading 20 | from typing import Union 21 | 22 | from sqlalchemy import Column, Integer, String, Boolean, BigInteger 23 | 24 | from tg_bot.modules.sql import SESSION, BASE 25 | 26 | 27 | class ReputationUserSettings(BASE): 28 | __tablename__ = "user_reputation_settings" 29 | user_id = Column(BigInteger, primary_key=True) 30 | should_reputate = Column(Boolean, default=True) 31 | 32 | def __init__(self, user_id): 33 | self.user_id = user_id 34 | 35 | def __repr__(self): 36 | return "".format(self.user_id) 37 | 38 | 39 | class ReputationChatSettings(BASE): 40 | __tablename__ = "chat_reputation_settings" 41 | chat_id = Column(String(14), primary_key=True) 42 | should_reputate = Column(Boolean, default=True) 43 | 44 | def __init__(self, chat_id): 45 | self.chat_id = str(chat_id) 46 | 47 | def __repr__(self): 48 | return "".format(self.chat_id) 49 | 50 | 51 | ReputationUserSettings.__table__.create(checkfirst=True) 52 | ReputationChatSettings.__table__.create(checkfirst=True) 53 | 54 | CHAT_LOCK = threading.RLock() 55 | USER_LOCK = threading.RLock() 56 | 57 | 58 | def chat_should_reputate(chat_id: Union[str, int]) -> bool: 59 | try: 60 | chat_setting = SESSION.query(ReputationChatSettings).get(str(chat_id)) 61 | if chat_setting: 62 | return chat_setting.should_reputate 63 | return False 64 | finally: 65 | SESSION.close() 66 | 67 | 68 | def user_should_reputate(user_id: int) -> bool: 69 | try: 70 | user_setting = SESSION.query(ReputationUserSettings).get(user_id) 71 | if user_setting: 72 | return user_setting.should_reputate 73 | return True 74 | finally: 75 | SESSION.close() 76 | 77 | 78 | def set_chat_setting(chat_id: Union[int, str], setting: bool): 79 | with CHAT_LOCK: 80 | chat_setting = SESSION.query(ReputationChatSettings).get(str(chat_id)) 81 | if not chat_setting: 82 | chat_setting = ReputationChatSettings(chat_id) 83 | 84 | chat_setting.should_reputate = setting 85 | SESSION.add(chat_setting) 86 | SESSION.commit() 87 | 88 | 89 | def set_user_setting(user_id: int, setting: bool): 90 | with USER_LOCK: 91 | user_setting = SESSION.query(ReputationUserSettings).get(user_id) 92 | if not user_setting: 93 | user_setting = ReputationUserSettings(user_id) 94 | 95 | user_setting.should_reputate = setting 96 | SESSION.add(user_setting) 97 | SESSION.commit() 98 | 99 | 100 | def migrate_chat(old_chat_id, new_chat_id): 101 | with CHAT_LOCK: 102 | chat_notes = SESSION.query(ReputationChatSettings).filter( 103 | ReputationChatSettings.chat_id == str(old_chat_id)).all() 104 | for note in chat_notes: 105 | note.chat_id = str(new_chat_id) 106 | SESSION.commit() 107 | -------------------------------------------------------------------------------- /tg_bot/strings/en/misc.json: -------------------------------------------------------------------------------- 1 | { 2 | "MSG_ID_WITH_FORWARD" : "The original sender, {}, has an ID of `{}`.\nThe forwarder, {}, has an ID of `{}`.", 3 | "MSG_ID_USER" : "{}'s id is `{}`.", 4 | "MSG_YOUR_ID" : "Your id is `{}`.", 5 | "MSG_GROUP_ID" : "This group's id is `{}`.", 6 | "ERR_CANT_EXTRACT_USER" : "I can't extract a user from this.", 7 | "MSG_USER_INFO_GENERAL" : "User info:\nID: {}\nFirst Name: {}", 8 | "MSG_USER_INFO_LAST_NAME" : "\nLast Name: {}", 9 | "MSG_USER_INFO_USERNAME" : "\nUsername: @{}", 10 | "MSG_USER_INFO_LINK" : "\nPermanent user link: {}", 11 | "MSG_USER_INFO_OWNER" : "\n\nThis person is my owner - I would never do anything against them!", 12 | "MSG_USER_INFO_CO_OWNER" : "\n\nThis person is my co-owner - Just as powerful as my owner! Seems like he really trusts them, so will I.", 13 | "MSG_USER_INFO_SUDO" : "\nThis person is one of my sudo users! Nearly as powerful as my owner - so watch it.", 14 | "MSG_USER_INFO_SUPPORT" : "\nThis person is one of my support users! Not quite a sudo user, but can still gban you off the map.", 15 | "MSG_USER_INFO_WHITELIST" : "\nThis person has been whitelisted! That means I'm not allowed to ban/kick them.", 16 | "MSG_BANHAMMER_TIME" : "Its always banhammer time for me!", 17 | "MSG_TIME" : "It's {} in {}", 18 | "MSG_DELETING_DATA" : "Deleting identifiable data...", 19 | "MSG_DELETING_SUCCESS" : "Your personal data has been deleted.\n\nNote that this will not unban you from any chats, as that is telegram data, not Nemesis data. Flooding, warns, and gbans are also preserved, as of [this](https://ico.org.uk/for-organisations/guide-to-the-general-data-protection-regulation-gdpr/individual-rights/right-to-erasure/), which clearly states that the right to erasure does not apply \"for the performance of a task carried out in the public interest\", as is the case for the aforementioned pieces of data.", 20 | "MARKDOWN_HELP" : "Markdown is a very powerful formatting tool supported by telegram. {} has some enhancements, to make sure that saved messages are correctly parsed, and to allow you to create buttons.\n\n- _italic_: wrapping text with '_' will produce italic text\n- *bold*: wrapping text with '*' will produce bold text\n- `code`: wrapping text with '`' will produce monospaced text, also known as 'code'\n- [sometext](someURL): this will create a link - the message will just show sometext, and tapping on it will open the page at someURL.\nEG: [test](example.com)\n\n- [buttontext](buttonurl:someURL): this is a special enhancement to allow users to have telegram buttons in their markdown. buttontext will be what is displayed on the button, and someurl will be the url which is opened.\nEG: [This is a button](buttonurl:example.com)\n\nIf you want multiple buttons on the same line, use :same, as such:\n[one](buttonurl://example.com)\n[two](buttonurl://google.com:same)\nThis will create two buttons on a single line, instead of one button per line.\nKeep in mind that your message MUST contain some text other than just a button!", 21 | "MARKDOWN_HELP_FORWARD" : "Try forwarding the following message to me, and you'll see!", 22 | "MARKDOWN_HELP_FORWARD_MSG" : "/save test This is a markdown test. _italics_, *bold*, `code`, [URL](example.com) [button](buttonurl:github.com) [button2](buttonurl://google.com:same)", 23 | "CURRENT_STATS" : "Current stats:\n", 24 | "HELP" : " - /id: get the current group id. If used by replying to a message, gets that user's id.\n - /runs: reply a random string from an array of replies.\n - /slap: slap a user, or get slapped if not a reply.\n - /info: get information about a user.\n - /gdpr: deletes your information from the bot's database. Private chats only.\n\n - /markdownhelp: quick summary of how markdown works in telegram - can only be called in private chats." 25 | } -------------------------------------------------------------------------------- /tg_bot/modules/sql/disable_sql.py: -------------------------------------------------------------------------------- 1 | # OpenGM - Powerful Telegram group managment bot 2 | # Copyright (C) 2017 - 2019 Paul Larsen 3 | # Copyright (C) 2019 - 2020 KaratekHD 4 | # 5 | # This program is free software: you can redistribute it and/or modify 6 | # it under the terms of the GNU General Public License as published by 7 | # the Free Software Foundation, either version 3 of the License, or 8 | # (at your option) any later version. 9 | # 10 | # This program is distributed in the hope that it will be useful, 11 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | # GNU General Public License for more details. 14 | # 15 | # You should have received a copy of the GNU General Public License 16 | # along with this program. If not, see . 17 | 18 | 19 | import threading 20 | 21 | from sqlalchemy import Column, String, UnicodeText, func, distinct 22 | 23 | from tg_bot.modules.sql import SESSION, BASE 24 | 25 | 26 | class Disable(BASE): 27 | __tablename__ = "disabled_commands" 28 | chat_id = Column(String(14), primary_key=True) 29 | command = Column(UnicodeText, primary_key=True) 30 | 31 | def __init__(self, chat_id, command): 32 | self.chat_id = chat_id 33 | self.command = command 34 | 35 | def __repr__(self): 36 | return "Disabled cmd {} in {}".format(self.command, self.chat_id) 37 | 38 | 39 | Disable.__table__.create(checkfirst=True) 40 | DISABLE_INSERTION_LOCK = threading.RLock() 41 | 42 | DISABLED = {} 43 | 44 | 45 | def disable_command(chat_id, disable): 46 | with DISABLE_INSERTION_LOCK: 47 | disabled = SESSION.query(Disable).get((str(chat_id), disable)) 48 | 49 | if not disabled: 50 | DISABLED.setdefault(str(chat_id), set()).add(disable) 51 | 52 | disabled = Disable(str(chat_id), disable) 53 | SESSION.add(disabled) 54 | SESSION.commit() 55 | return True 56 | 57 | SESSION.close() 58 | return False 59 | 60 | 61 | def enable_command(chat_id, enable): 62 | with DISABLE_INSERTION_LOCK: 63 | disabled = SESSION.query(Disable).get((str(chat_id), enable)) 64 | 65 | if disabled: 66 | if enable in DISABLED.get(str(chat_id)): # sanity check 67 | DISABLED.setdefault(str(chat_id), set()).remove(enable) 68 | 69 | SESSION.delete(disabled) 70 | SESSION.commit() 71 | return True 72 | 73 | SESSION.close() 74 | return False 75 | 76 | 77 | def is_command_disabled(chat_id, cmd): 78 | return cmd in DISABLED.get(str(chat_id), set()) 79 | 80 | 81 | def get_all_disabled(chat_id): 82 | return DISABLED.get(str(chat_id), set()) 83 | 84 | 85 | def num_chats(): 86 | try: 87 | return SESSION.query(func.count(distinct(Disable.chat_id))).scalar() 88 | finally: 89 | SESSION.close() 90 | 91 | 92 | def num_disabled(): 93 | try: 94 | return SESSION.query(Disable).count() 95 | finally: 96 | SESSION.close() 97 | 98 | 99 | def migrate_chat(old_chat_id, new_chat_id): 100 | with DISABLE_INSERTION_LOCK: 101 | chats = SESSION.query(Disable).filter(Disable.chat_id == str(old_chat_id)).all() 102 | for chat in chats: 103 | chat.chat_id = str(new_chat_id) 104 | SESSION.add(chat) 105 | 106 | if str(old_chat_id) in DISABLED: 107 | DISABLED[str(new_chat_id)] = DISABLED.get(str(old_chat_id), set()) 108 | 109 | SESSION.commit() 110 | 111 | 112 | def __load_disabled_commands(): 113 | global DISABLED 114 | try: 115 | all_chats = SESSION.query(Disable).all() 116 | for chat in all_chats: 117 | DISABLED.setdefault(chat.chat_id, set()).add(chat.command) 118 | 119 | finally: 120 | SESSION.close() 121 | 122 | 123 | __load_disabled_commands() 124 | -------------------------------------------------------------------------------- /tg_bot/strings/de/warns.json: -------------------------------------------------------------------------------- 1 | { 2 | "CURRENT_WARNING_FILTER_STRING": "Aktuelle Warnfilter in diesem Chat:", 3 | "ERR_USER_IS_ADMIN": "Verdammte Admins, können nicht einmal gewarnt werden!", 4 | "AUTOMATED_TAG": "Automatischer Warn-Filter.", 5 | "MSG_KICK": "{} Warnungen, {} wurde herausgeschmissen!", 6 | "MSG_BAN": "{} Warnungen, {} wurde gebannt!", 7 | "MSG_WARNBAN_HTML": "{}:\n#WARNUNG_BAN\nAdmin: {}\nBenutzer: {} ({})\nGrund: {}\nAnzahlen: {}/{}", 8 | "BUTTON_REMOVE": "Warnen entfernen", 9 | "MSG_WARN_SUCCESS": "{} hat {}/{} Warnungen... Achtung!", 10 | "MSG_WARN_SUCCESS_REASON": "\nGrund für die letzte Warnung:\n{}", 11 | "MSG_WARN_HTML": "{}:\n#WARNUNG\nAdmin: {}\nBenutzer: {} ({})\nGrund: {}\nAnzahlen: {}/{}", 12 | "MSG_WARN_DEL": "Warnung entfernt von {}.", 13 | "MSG_UNWARN_HTML": "{}:\n#ENTWARNT\nAdmin: {}\nBenutzer: {} ({})", 14 | "MSG_UNWARN_HAS_NO_WARNS": "Dieser Benutzer hat noch keine Warnungen.", 15 | "ERR_NO_USER": "Es wurde kein Benutzer bestimmt!", 16 | "MSG_RESET": "Warnungen wurden zurückgesetzt!", 17 | "MSG_RESET_HTML": "{}:\n#WARNUNGENZURÜCKGESETZT\nAdmin: {}\nBenutzer: {} ({})", 18 | "MSG_INFO": "Dieser Benutzer hat {}/{} Warnungen aus den folgenden Gründen:", 19 | "MSG_INFO_NOREASON": "Benutzer hat {}/{} Warnungen, aber keine Gründe für irgendeinen von ihnen.", 20 | "MSG_INFO_NO_WARNS": "Dieser Benutzer hat keine Warnung!", 21 | "MSG_FILTER_ADDED": "Warnung für '{}' hinzugefügt!", 22 | "ERR_NO_FILTERS": "Hier sind keine Warnungs-Filter aktiv!", 23 | "MSG_REMOVE_FILTER": "Ja, ich werde aufhören Leute dafür zu warnen.", 24 | "ERR_NO_FILTER": "Das ist kein aktueller Warn-Filter - führe /warnlist aus für alle aktive Warn-Filter.", 25 | "ERR_WRONG_NUMBER": "Das minimale Warn-Limit ist 3!", 26 | "MSG_UPDATE_SETTINGS": "Warnlimit auf {} aktualisiert", 27 | "MSG_UPDATE_SETTINGS_HTML": "{}:\n#SETZE_WARN_LIMIT\nAdmin: {}\nSetzt das Warnlimit auf {}", 28 | "ERR_NO_ARG": "Gib mir eine Nummer als Argument!", 29 | "MSG_CURRENT_SETTINGS": "Das aktuelle Warnlimit ist {}", 30 | "BAN_SETTING": "Zu viele Warnung führen dazu, das man herausgeschmissen wird!", 31 | "BAN_SETTING_HTML": "{}:\nAdmin: {}\nhat starke Warnungen aktiviert. Benutzer werden gebannt.", 32 | "KICK_SETTING": "Zu viele Warnungen führen jetzt zu einem Kick! Benutzer können danach wieder beitreten.", 33 | "KICK_SETTING_HTML": "{}:\nAdmin: {}\nhat starke Warnungen deaktiviert. Benutzer werden jetzt nur gekickt.", 34 | "ERR_SET_WRONG_ARG": "Ich verstehe nur on/yes/no/off (Ein, Ja, Nein, Aus)!", 35 | "INFO_KICK": "Warnungen sind aktuell auf *kick* gesetzt, wenn Benutzer das Limit überschreiten.", 36 | "INFO_BAN": "Warnungen sind aktuell auf *ban* gesetzt, wenn Benutzer das Limit überschreiten.", 37 | "STATS": "{} Warnungen insgesamt, in über {} Chats.\n{} Warnungen für Filter, in über {} Chats.", 38 | "CHAT_SETTINGS": "Dieser Chat hat `{}` Warnfilter. Er benötigt `{}` Warnungen, bevor der Benutzer *{}* erhält.", 39 | "KICKED": "gekickt", 40 | "BANNED": "gebannt", 41 | "HELP": "\n - /warns : erhalte die Anzahl und den Grund für Warnungen.\n - /warnlist: Liste aller aktuellen Warnfilter\n\n*Nur Admins:*\n - /warn : Benutzer warnen. Nach 3 Warnungen wird der Benutzer aus der Gruppe verbannt. Kann auch als Antwort verwendet werden.\n - /resetwarn : Zurücksetzen der Warnungen für einen Benutzer. Kann auch als Antwort verwendet werden.\n - /addwarn : Setze einen Warnfilter auf ein bestimmtes Schlüsselwort. Wenn Sie wollen, dass Ihr Keyword ein Satz ist, schließen Sie es mit Zitaten als solche: `/addwarn \"sehr wütend`. Dies ist ein wütender Benutzer`. \n - /nowarn : Stoppe einen Warnfilter\n - /warnlimit : Setze das Warnlimit\n - /strongwarn : Wenn dies aktiviert ist, führt das Überschreiten des Warnlimits führt zu einem Verbot. Sonst wird einfach kicken." 42 | } -------------------------------------------------------------------------------- /tg_bot/modules/helper_funcs/extraction.py: -------------------------------------------------------------------------------- 1 | # OpenGM - Powerful Telegram group managment bot 2 | # Copyright (C) 2017 - 2019 Paul Larsen 3 | # Copyright (C) 2019 - 2020 KaratekHD 4 | # 5 | # This program is free software: you can redistribute it and/or modify 6 | # it under the terms of the GNU General Public License as published by 7 | # the Free Software Foundation, either version 3 of the License, or 8 | # (at your option) any later version. 9 | # 10 | # This program is distributed in the hope that it will be useful, 11 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | # GNU General Public License for more details. 14 | # 15 | # You should have received a copy of the GNU General Public License 16 | # along with this program. If not, see . 17 | 18 | 19 | from typing import List, Optional 20 | 21 | from telegram import Message, MessageEntity 22 | from telegram.error import BadRequest 23 | 24 | from tg_bot import LOGGER 25 | from tg_bot.modules.users import get_user_id 26 | 27 | 28 | def id_from_reply(message): 29 | prev_message = message.reply_to_message 30 | if not prev_message: 31 | return None, None 32 | user_id = prev_message.from_user.id 33 | res = message.text.split(None, 1) 34 | if len(res) < 2: 35 | return user_id, "" 36 | return user_id, res[1] 37 | 38 | 39 | def extract_user(message: Message, args: List[str]) -> Optional[int]: 40 | return extract_user_and_text(message, args)[0] 41 | 42 | 43 | def extract_user_and_text(message: Message, args: List[str]) -> (Optional[int], Optional[str]): 44 | prev_message = message.reply_to_message 45 | split_text = message.text.split(None, 1) 46 | 47 | if len(split_text) < 2: 48 | return id_from_reply(message) # only option possible 49 | 50 | text_to_parse = split_text[1] 51 | 52 | text = "" 53 | 54 | entities = list(message.parse_entities([MessageEntity.TEXT_MENTION])) 55 | if len(entities) > 0: 56 | ent = entities[0] 57 | else: 58 | ent = None 59 | 60 | # if entity offset matches (command end/text start) then all good 61 | if entities and ent and ent.offset == len(message.text) - len(text_to_parse): 62 | ent = entities[0] 63 | user_id = ent.user.id 64 | text = message.text[ent.offset + ent.length:] 65 | 66 | elif len(args) >= 1 and args[0][0] == '@': 67 | user = args[0] 68 | if user.isdigit(): 69 | user_id = user 70 | else: 71 | user_id = get_user_id(user) 72 | if not user_id: 73 | message.reply_text("I don't have that user in my db. You'll be able to interact with them if " 74 | "you reply to that person's message instead, or forward one of that user's messages.") 75 | return None, None 76 | res = message.text.split(None, 2) 77 | if len(res) >= 3: 78 | text = res[2] 79 | 80 | elif len(args) >= 1 and args[0].isdigit(): 81 | user_id = int(args[0]) 82 | res = message.text.split(None, 2) 83 | if len(res) >= 3: 84 | text = res[2] 85 | 86 | elif prev_message: 87 | user_id, text = id_from_reply(message) 88 | 89 | else: 90 | return None, None 91 | 92 | try: 93 | message.bot.get_chat(user_id) 94 | except BadRequest as excp: 95 | if excp.message in ("User_id_invalid", "Chat not found"): 96 | message.reply_text("I don't seem to have interacted with this user before - please forward a message from " 97 | "them to give me control! (like a voodoo doll, I need a piece of them to be able " 98 | "to execute certain commands...)") 99 | else: 100 | LOGGER.exception("Exception %s on user %s", excp.message, user_id) 101 | 102 | return None, None 103 | 104 | return user_id, text 105 | 106 | 107 | def extract_text(message) -> str: 108 | return message.text or message.caption or (message.sticker.emoji if message.sticker else None) 109 | -------------------------------------------------------------------------------- /tg_bot/modules/backups.py: -------------------------------------------------------------------------------- 1 | # OpenGM - Powerful Telegram group managment bot 2 | # Copyright (C) 2017 - 2019 Paul Larsen 3 | # Copyright (C) 2019 - 2020 KaratekHD 4 | # 5 | # This program is free software: you can redistribute it and/or modify 6 | # it under the terms of the GNU General Public License as published by 7 | # the Free Software Foundation, either version 3 of the License, or 8 | # (at your option) any later version. 9 | # 10 | # This program is distributed in the hope that it will be useful, 11 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | # GNU General Public License for more details. 14 | # 15 | # You should have received a copy of the GNU General Public License 16 | # along with this program. If not, see . 17 | 18 | 19 | import json 20 | from io import BytesIO 21 | from typing import Optional 22 | 23 | from telegram import Message, Chat, Update 24 | from telegram.error import BadRequest 25 | from telegram.ext import CommandHandler, CallbackContext 26 | 27 | from tg_bot import dispatcher 28 | from tg_bot.modules.helper_funcs.chat_action import typing_action 29 | from tg_bot.modules.helper_funcs.chat_status import user_admin, bot_admin 30 | import tg_bot.modules.helper_funcs.backups as helper 31 | from tg_bot.strings.string_helper import get_string 32 | import tg_bot.modules.sql.lang_sql as lang 33 | 34 | 35 | @user_admin 36 | @bot_admin 37 | # NOTE: This file won't be translated (for now), since this feature is gonna get rewritten completely. 38 | def import_data(update: Update, context: CallbackContext): 39 | msg = update.effective_message # type: Optional[Message] 40 | bot = context.bot 41 | chat = update.effective_chat # type: Optional[Chat] 42 | # TODO: allow uploading doc with command, not just as reply 43 | # only work with a doc 44 | if msg.reply_to_message and msg.reply_to_message.document: 45 | try: 46 | file_info = bot.get_file(msg.reply_to_message.document.file_id) 47 | except BadRequest: 48 | msg.reply_text(get_string("backups", "MSG_REUPLOAD", lang.get_lang(update.effective_chat.id))) # MSG_REUPLOAD 49 | return 50 | 51 | with BytesIO() as file: 52 | file_info.download(out=file) 53 | file.seek(0) 54 | data = json.load(file) 55 | 56 | if (data["data"]["filters"]["filters"] is not None): 57 | filters = data["data"]["filters"]["filters"] 58 | for i in filters: 59 | keyword = i["name"] 60 | text = i["text"] 61 | helper.import_filter(chat.id, keyword, text) 62 | # TODO: some of that link logic 63 | # NOTE: consider default permissions stuff? 64 | data = data["data"] 65 | rules = data["rules"] 66 | helper.import_rules(chat.id, rules["content"]) 67 | notes = data["notes"] 68 | if (notes["notes"] is not None): 69 | notes = notes["notes"] 70 | for i in notes: 71 | if i["type"] is 0: 72 | helper.import_note(chat.id, i["name"], i["text"]) 73 | 74 | msg.reply_text(get_string("backups", "MSG_IMPORT_SUCCESS", lang.get_lang(update.effective_chat.id))) # MSG_IMPORT_SUCCESS 75 | 76 | 77 | @user_admin 78 | @typing_action 79 | def export_data(update: Update, context: CallbackContext): 80 | bot = context.bot 81 | with BytesIO(str.encode(helper.export_data(update.effective_chat, bot))) as output: 82 | output.name = str(update.effective_chat.id) + ".toml" 83 | update.effective_message.reply_document(document=output, filename=str(update.effective_chat.id) + ".toml", 84 | caption="Here you go.") # MSG_EXPORT_SUCCESS 85 | 86 | 87 | __mod_name__ = "Backups" 88 | 89 | 90 | def __help__(update: Update) -> str: 91 | return get_string("backups", "HELP", lang.get_lang(update.effective_chat.id)) # HELP 92 | 93 | 94 | IMPORT_HANDLER = CommandHandler("import", import_data) 95 | EXPORT_HANDLER = CommandHandler("export", export_data, run_async=True) 96 | 97 | dispatcher.add_handler(IMPORT_HANDLER) 98 | dispatcher.add_handler(EXPORT_HANDLER) 99 | -------------------------------------------------------------------------------- /tg_bot/modules/sql/reputation_sql.py: -------------------------------------------------------------------------------- 1 | # OpenGM - Powerful Telegram group managment bot 2 | # Copyright (C) 2017 - 2019 Paul Larsen 3 | # Copyright (C) 2019 - 2020 KaratekHD 4 | # 5 | # This program is free software: you can redistribute it and/or modify 6 | # it under the terms of the GNU General Public License as published by 7 | # the Free Software Foundation, either version 3 of the License, or 8 | # (at your option) any later version. 9 | # 10 | # This program is distributed in the hope that it will be useful, 11 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | # GNU General Public License for more details. 14 | # 15 | # You should have received a copy of the GNU General Public License 16 | # along with this program. If not, see . 17 | 18 | import threading 19 | 20 | from sqlalchemy import Column, String, UnicodeText, Integer, BigInteger 21 | from tg_bot.modules.sql import BASE, SESSION 22 | 23 | 24 | class LatestRepMessage(BASE): 25 | __tablename__ = "rep_messages" 26 | chat_id = Column(String, primary_key=True) 27 | msg_id = Column(UnicodeText, default="") 28 | 29 | def __init__(self, chat_id): 30 | self.chat_id = str(chat_id) 31 | 32 | 33 | LatestRepMessage.__table__.create(checkfirst=True) 34 | 35 | INSERTION_LOCK = threading.RLock() 36 | 37 | 38 | def migrate_chat_latest_messages(old_chat_id, new_chat_id): 39 | with INSERTION_LOCK: 40 | chat = SESSION.query(LatestRepMessage).get(str(old_chat_id)) 41 | if chat: 42 | chat.chat_id = str(new_chat_id) 43 | SESSION.commit() 44 | 45 | 46 | def set_latest_rep_message(chat_id, msg_id): 47 | with INSERTION_LOCK: 48 | l = SESSION.query(LatestRepMessage).get(str(chat_id)) 49 | if not l: 50 | l = LatestRepMessage(str(chat_id)) 51 | l.msg_id = msg_id 52 | SESSION.add(l) 53 | SESSION.commit() 54 | 55 | 56 | def get_latest_rep_message(chat_id): 57 | l = SESSION.query(LatestRepMessage).get(str(chat_id)) 58 | ret = 0 59 | if l: 60 | ret = l.msg_id 61 | 62 | SESSION.close() 63 | return ret 64 | 65 | 66 | class Reputation(BASE): 67 | # I know this is messed up. 68 | # The chat id is stored in the column 'user_id', and the chat id in 'user_id'. 69 | # But I am to lazy to fix this, as this is already rolled out and fixing this would 70 | # require to migrate existing entries. 71 | # And this works, so why should I touch it? 72 | __tablename__ = "reputations" 73 | 74 | user_id = Column(BigInteger, primary_key=True) 75 | chat_id = Column(String(14), primary_key=True) 76 | reputation = Column(Integer, default=0) 77 | 78 | def __init__(self, user_id, chat_id): 79 | self.user_id = user_id 80 | self.chat_id = str(chat_id) 81 | self.reputation = 0 82 | 83 | 84 | Reputation.__table__.create(checkfirst=True) 85 | 86 | 87 | def increase_reputation(user_id, chat_id): 88 | with INSERTION_LOCK: 89 | user = SESSION.query(Reputation).get((user_id, str(chat_id))) 90 | if not user: 91 | user = Reputation(user_id, str(chat_id)) 92 | user.reputation += 1 93 | SESSION.add(user) 94 | SESSION.commit() 95 | 96 | 97 | def decrease_reputation(user_id, chat_id): 98 | with INSERTION_LOCK: 99 | user = SESSION.query(Reputation).get((user_id, str(chat_id))) 100 | if not user: 101 | user = Reputation(user_id, str(chat_id)) 102 | user.reputation -= 1 103 | SESSION.add(user) 104 | SESSION.commit() 105 | 106 | 107 | def get_reputation(user_id, chat_id): 108 | try: 109 | user = SESSION.query(Reputation).get((user_id, str(chat_id))) 110 | if not user: 111 | return 0 112 | num = user.reputation 113 | return num 114 | finally: 115 | SESSION.close() 116 | 117 | 118 | def migrate_chat(old_chat_id, new_chat_id): 119 | with INSERTION_LOCK: 120 | chat = SESSION.query(Reputation).get(str(old_chat_id)) 121 | if chat: 122 | chat.chat_id = str(new_chat_id) 123 | SESSION.commit() -------------------------------------------------------------------------------- /commands.txt: -------------------------------------------------------------------------------- 1 | start - Starts the bot 2 | help - Get a list of commands 3 | settings - Manage this chats settings, as well as yours 4 | about - Display version information, credits and licenses 5 | rules - Get this chat's rules 6 | setrules - Set this chat's rules 7 | clearrules - Clear this chat's rules 8 | runs - Check whether the bot is running 9 | slap - 'Slaps' another user 10 | ip - Get the bot's ip (Staff only!) 11 | id - Get a user's or group's Telegram ID 12 | info - Display information about a user 13 | echo - Make the Bot say something (Staff only!) 14 | gdpr - Delete your personal information from the bot's database 15 | markdownhelp - Send some help for markdown's syntax 16 | stats - Display some statistics about the bot's usage (Staff only!) 17 | promote - Promote an user 18 | demote - Demote an user 19 | pin - Pin a message to the top of the group 20 | unpin - remove the pinned message 21 | invitelink - Get the group's invitelink 22 | adminlist - Display a list containing all admins in a chat 23 | afk - Mark yourself as away from keyboard (AFK) 24 | del - Delete a message 25 | purge - Delete a bunch of messages 26 | export - Exports your current chat settings to a .toml file 27 | import - Import a .json file from Rose's export feature 28 | ban - Bans an user 29 | kickme - Try it out! 30 | kick - Kicks an user 31 | tempban - Bans an user for a specific period of time 32 | unban - Reverts the ban of an user 33 | filter - Add a new filter 34 | filters - List all filters in the current group 35 | stop - Delete a filter 36 | broadcast - Broadcast a message to all chats the bot is in (Staff only!) 37 | chatlist - Get a file containing all chats the bot is in (Staff only!) 38 | lang - Set this chat's language 39 | t - Correct grammar in replied message (english only) 40 | setflood - Set the antiflood setting for the current chat 41 | flood - get the current antiflood settings 42 | gban - Globally ban a user (Staff only!) 43 | ungban - Globally unban a user (Staff only!) 44 | gbanlist - Get a list of all globally banned users (Staff only!) 45 | gbanstat - Toggle whether global bans should effect your group 46 | blacklist - Get all words on the current blacklist 47 | addblacklist - Blacklist a word 48 | unblacklist - Remove a word from the blacklist 49 | globalmute - Mutes the entire chat, so all messages not sent by admins will get instantly deleted 50 | kang - Save a sticker in your own stickerpack 51 | stickerid - Get the ID of a sticker 52 | getsticker - download a sticker as png 53 | translate - Translate a message using google translate 54 | welcome - Send the current welcome message 55 | goodbye - Send the current goodbye message 56 | setwelcome - Set the welcome message 57 | setgoodbye - Set the goodbye message 58 | resetwelcome - Reset the welcome message to the default value 59 | resetgoodbye - Reset the goodbye message to the default value 60 | cleanwelcome - Toggle whether the bot should delete old welcome messages 61 | warn - Warn an user 62 | resetwarn - Reset warns of an user to 0 63 | resetwarns - Reset warns of an user to 0 64 | warns - List all warns of an user 65 | addwarn - Add a warn filter 66 | nowarn - Remove a warn filter 67 | stopwarn - Remove a warn filter 68 | warnlist - List all warn filters 69 | warnfilters - List all warn filters 70 | warnlimit - Set the maximum number of warns an user can have before it gets punished 71 | strongwarn - Toggle whether reaching the warnlimit should ban or just kick the user 72 | mute - Mute an user 73 | unmute - Unmute an user 74 | tempmute - Mute an user temporary 75 | report - Report a message 76 | get - Get a note 77 | save - Save a note 78 | clear - Delete a note 79 | rss - shows the link's data and the last entry, for testing purposes. 80 | addrss - add an RSS link to the subscriptions. 81 | listrss - shows the list of rss feeds that the chat is currently subscribed to. 82 | removerss - removes the RSS link from the subscriptions. 83 | me - will get your or another user's info 84 | setme - will set your info 85 | bio - will get your or another user's bio. This cannot be set by yourself. 86 | setbio - while replying, will save another user's bio 87 | locktypes - a list of possible locktypes 88 | lock - lock items of a certain type (not available in private) 89 | unlock - unlock items of a certain type (not available in private) 90 | locks - the current list of locks in this chat. -------------------------------------------------------------------------------- /tg_bot/strings/en/main.json: -------------------------------------------------------------------------------- 1 | { 2 | "PM_START_TEXT" : "Hi {}, my name is {}! If you have any questions on how to use me, read /help - and then head to @MarieSupport.\n\nI'm an instance of OpenGM, an open source group manager bot built in python3, using the python-telegram-bot library, and am fully opensource;\nyou can find what makes me tick [here](github.com/KaratekHD/Nemesis)!\n\nFeel free to submit pull requests on github, or to contact my support group, @MarieSupport, with any bugs, questions\nor feature requests you might have :)\nI also have a news channel, @MarieNews for announcements on new features, downtime, etc.\n\nYou can find the list of available commands with /help.\nYou can also read my documentation at [opengm.karatek.net](https://opengm.karatek.net)", 3 | "HELP_STRINGS" : "Hey there! My name is {}.\nI'm a modular group management bot with a few fun extras! Have a look at the following for an idea of some of\nthe things I can help you with. You can also read my documentation at [opengm.karatek.net](https://opengm.karatek.net/).\n\n*Main* commands available:\n - /start: start the bot\n - /help: PM's you this message.\n - /help : PM's you info about that module.\n - /settings:\n - in PM: will send you your settings for all supported modules.\n - in a group: will redirect you to pm, with all that chat's settings.\n\n{}\nAnd the following:", 4 | "HELP_STRINGS_PART_2" : "\nAll commands can either be used with / or !.\n", 5 | "NO_TWO_MODULES" : "Can't have two modules with the same name! Please change one", 6 | "EDITED_MESSAGE" : "This person edited a message", 7 | "START_IN_GROUP" : "Yo, whadup?", 8 | "HELP_FOR_MODULE" : "Here is the help for the *{}* module:\n", 9 | "ERR_MSG_NOT_MODIFIED" : "Message is not modified", 10 | "ERR_QUERY_ID_INVALID" : "Query_id_invalid", 11 | "ERR_MSG_CANT_DELETE" : "Message can't be deleted", 12 | "ERR_EXCP_HELP_BUTTONS" : "Exception in help buttons. %s", 13 | "PM_FOR_HELP" : "Contact me in PM to get the list of possible commands.", 14 | "PM_FOR_HELP_BUTTON" : "Help", 15 | "HELP_FOR_MODULE_AVAILABLE" : "Here is the available help for the *{}* module:\n", 16 | "CURRENT_SETTINGS" : "These are your current settings:", 17 | "ERR_NO_USER_SETTINGS" : "Seems like there aren't any user specific settings available :'(", 18 | "Q_SETTINGS_WHICH_MODULE" : "Which module would you like to check {}'s settings for?", 19 | "Q_SETTINGS_TO_GROUP" : "Seems like there aren't any chat settings available :'(\\nSend this in a group chat you're admin in to find its current settings!", 20 | "MODULE_SETTINGS" : "*{}* has the following settings for the *{}* module:\n\n", 21 | "LOT_OF_SETTINGS" : "Hi there! There are quite a few settings for {} - go ahead and pick what you're interested in.", 22 | "ERR_EXCP_SETTINGS_BUTTONS" : "Exception in settings buttons. %s", 23 | "CLICK_HERE_FOR_SETTINGS" : "Click here to get this chat's settings, as well as yours.", 24 | "SETTINGS" : "Settings", 25 | "YOUR_SETTINGS" : "Click here to check your settings.", 26 | "MIGRATING" : "Migrating from %s, to %s", 27 | "MIGRATING_SUCCESS" : "Successfully migrated!", 28 | "WEBHOOKS" : "Using webhooks.", 29 | "LONG_POLLING" : "Using long polling.", 30 | "ERR_UNKNOWN" : "An uncaught error was raised while handling the error", 31 | "ERR_DISPATCHERHANDLERSTOP" : "Stopping further handlers due to DispatcherHandlerStop", 32 | "ERR_TELEGRAM" : "A TelegramError was raised while processing the Update", 33 | "ERR_ERRHANDLER" : "Error handler stopped further handlers", 34 | "ERR_UPDATE_UNKNOWN" : "An uncaught error was raised while processing the update", 35 | "MODULES_LOADED" : "Successfully loaded modules: ", 36 | "ABOUT_TITLE" : "Nemesis - Powerful open-source group manager*\n", 37 | "ABOUT_GPL": "This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or(at your option) any later version.\n\n", 38 | "ABOUT_GF" : "*Huge thank you to the one person who just stands by me and makes me enjoy life more. I'm pretty sure the person knows she's meant, so, thank you for being part of my life!*\n\n", 39 | "ABOUT_CONSTRIBUTORS" : "*Contributors:*\n\n", 40 | "ABOUT_DEV" : "*Development:*\n", 41 | "ABOUT_TRANSLATION" : "*Translation*\n", 42 | "ABOUT_PRODUCTION" : "*Production*\n" 43 | } 44 | -------------------------------------------------------------------------------- /tg_bot/restapi/resources/modules/admin.py: -------------------------------------------------------------------------------- 1 | # OpenGM - Powerful Telegram group managment bot 2 | # Copyright (C) 2017 - 2019 Paul Larsen 3 | # Copyright (C) 2019 - 2020 KaratekHD 4 | # 5 | # This program is free software: you can redistribute it and/or modify 6 | # it under the terms of the GNU General Public License as published by 7 | # the Free Software Foundation, either version 3 of the License, or 8 | # (at your option) any later version. 9 | # 10 | # This program is distributed in the hope that it will be useful, 11 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | # GNU General Public License for more details. 14 | # 15 | # You should have received a copy of the GNU General Public License 16 | # along with this program. If not, see . 17 | 18 | 19 | from http import HTTPStatus 20 | 21 | from flask import request, abort 22 | from flask_restplus import Namespace, Resource 23 | from telegram import TelegramError 24 | 25 | from tg_bot import dispatcher 26 | from tg_bot.modules.sql import api_sql 27 | import tg_bot.modules.sql.users_sql as user_sql 28 | import tg_bot.modules.sql.mute as mute_sql 29 | import tg_bot.restapi.models.modules.admin as admin_model 30 | 31 | api = Namespace("admin", description="Functions designed to manage basic things inside a group.") 32 | 33 | 34 | @api.route("/") 35 | @api.param('id', 'The group identifier') 36 | @api.response(400, "Bad Request") 37 | @api.response(404, 'Chat not found.') 38 | @api.response(403, "User is not permitted to view this chat.") 39 | @api.response(401, "Unauthorized") 40 | @api.response(410, "Bot is not a member of the chat (anymore).") 41 | class Admins(Resource): 42 | @api.marshal_with(admin_model.create_chat_model(api)) 43 | @staticmethod 44 | def get(id): 45 | key = request.args.get('api_key') 46 | if not key: 47 | abort(HTTPStatus.UNAUTHORIZED, "Unauthorized") 48 | user_id = api_sql.verify_key(key) 49 | chats = [] 50 | for element in user_sql.get_chats_by_member(user_id): 51 | chats.append(element.chat) 52 | if id not in chats: 53 | abort(HTTPStatus.NOT_FOUND, "Chat not found.") 54 | user_chats = [] 55 | for element in user_sql.get_chats_by_member(user_id): 56 | user_chats.append(element.chat) 57 | if id not in user_chats: 58 | abort(HTTPStatus.FORBIDDEN, "User is not permitted to view this chat.") 59 | is_muted = mute_sql.get_muted(id) 60 | list_groups_str = request.args.get('list_groups') 61 | if list_groups_str: 62 | if list_groups_str in ("True", "true"): 63 | list_groups = True 64 | if list_groups_str in ("false", "False"): 65 | list_groups = False 66 | if list_groups_str.lower() not in ("false", "true"): 67 | abort(HTTPStatus.BAD_REQUEST, "'list_groups' is invalid.") 68 | else: 69 | list_groups = False 70 | try: 71 | groupchat = dispatcher.bot.get_chat(id) 72 | except TelegramError as excp: 73 | if excp.message == 'Chat not found': 74 | abort(HTTPStatus.GONE, "Bot is not a member of the chat (anymore).") 75 | admins = [] 76 | for admin in groupchat.get_administrators(): 77 | data = {} 78 | try: 79 | data.update({"id": admin.user.id}) 80 | chat = admin.user 81 | if chat.username: 82 | data.update({"username": chat.username}) 83 | data.update({"link": chat.link}) 84 | data.update({"first_name": chat.first_name}) 85 | if chat.last_name: 86 | data.update({"last_name": chat.last_name}) 87 | 88 | if list_groups: 89 | groups = [] 90 | for group in user_sql.get_chats_by_member(chat.id): 91 | groups.append([{"id": group.chat, "name": user_sql.get_chatname(group.chat)}]) 92 | data.update({"groups": groups}) 93 | 94 | admins.append(data) 95 | except TelegramError as excp: 96 | if excp.message == 'Chat not found': 97 | pass 98 | return {"id": id, "name" : groupchat.title, "is_muted" : is_muted, "admins" : admins}, HTTPStatus.OK 99 | -------------------------------------------------------------------------------- /tg_bot/strings/de/misc.json: -------------------------------------------------------------------------------- 1 | { 2 | "MSG_ID_WITH_FORWARD": "Der ursprüngliche Absender, {}, hat die ID `{}`.\nWeitergeleitet wurde die Nachricht von {}, mit der ID `{}`.", 3 | "MSG_ID_USER": "{}s id ist `{}`.", 4 | "MSG_YOUR_ID": "Deine ID ist `{}`.", 5 | "MSG_GROUP_ID": "Diese Gruppe hat die ID `{}`.", 6 | "ERR_CANT_EXTRACT_USER": "Ich kann keinen Benutzer daraus extrahieren.", 7 | "MSG_USER_INFO_GENERAL": "Benutzerinformationen:\nID: {}\nVorname: {}", 8 | "MSG_USER_INFO_LAST_NAME": "\nNachname: {}", 9 | "MSG_USER_INFO_USERNAME": "\nBenutzername: @{}", 10 | "MSG_USER_INFO_LINK": "\nPermanenter Benutzerlink: {}", 11 | "MSG_USER_INFO_OWNER": "\n\nDiese Person ist mein Besitzer - Ich würde nie etwas gegen ihn tun!", 12 | "MSG_USER_INFO_CO_OWNER": "\n\nDiese Person ist meine Miteigentümerin - genauso mächtig wie mein Besitzer! Sieht so aus, als ob er ihr wirklich vertraut, so werde ich es auch machen.", 13 | "MSG_USER_INFO_SUDO": "\nDiese Person ist einer meiner Privilegierten Benutzer! Fast so mächtig wie mein Besitzer - also merke sie dir.", 14 | "MSG_USER_INFO_SUPPORT": "\nDiese Person ist einer meiner Support-Benutzer! Nicht ganz ein Privilegierter-Benutzer, kann dich aber trotzdem von der Karte verschwinden lassen.", 15 | "MSG_USER_INFO_WHITELIST": "\nDiese Person steht auf der Ausnahmeliste! Das bedeutet, dass ich sie nicht bannen/kicken darf.", 16 | "MSG_BANHAMMER_TIME": "Es ist immer Banhammer-Zeit für mich!", 17 | "MSG_TIME": "Es ist {} in {}", 18 | "MSG_DELETING_DATA": "Identifizierbare Daten werden gelöscht...", 19 | "MSG_DELETING_SUCCESS": "Deine persönlichen Daten wurden gelöscht.\n\nBeachte, dass dies dich nicht von Chats entbannt, da es sich dabei um Telegram-Daten und nicht um Nemesis-Daten handelt. Überflutung, Warnungen und Gbans werden ebenfalls nicht gelöscht, siehe [hier](https://ico.org.uk/for-organisations/guide-to-data-protection/guide-to-the-general-data-protection-regulation-gdpr/individual-rights/right-to-erasure/#ib6), wo klar festgestellt wird, dass das Recht auf Löschung nicht \"für die Erfüllung einer Aufgabe im öffentlichen Interesse\" gilt, wie es bei den oben genannten Daten der Fall ist.", 20 | "MARKDOWN_HELP": "Markdown ist ein sehr leistungsstarkes Formatierungswerkzeug, das von Telegramm unterstützt wird. {} hat einige Verbesserungen, um sicherzustellen, dass die gespeicherten Nachrichten korrekt analysiert werden, und um Ihnen das Erstellen von Schaltflächen zu ermöglichen.\n\n- _kursiv_: Umbruch von Text mit '_' erzeugt kursiven Text\n- *fett*: Umverpackung mit '*' erzeugt fettgedruckten Text\n- `code`: Umverpackung von Text mit ''' erzeugt monospace-Text, auch bekannt als 'code'\n- [irgendein Text](irgendeine URL): Dies wird einen Link erstellen - die Nachricht zeigt einfach irgendein Text, und tippen Sie darauf, wird die Seite unter irgendeine URLöffnen.\nEG: [test](example.om)\n\n- [Schaltflächentext](buttonurl:someURL): Dies ist eine besondere Verbesserung, die es Benutzern erlaubt, Telegramm-Buttons in ihrer Markierung zu haben. Schaltflächentext wird angezeigt, was auf der Schaltfläche angezeigt wird, und someurl wird die URL sein, die geöffnet wird.\nEG: [Dies ist ein Button](buttonurl:example.com)\n\nWenn du mehrere Tasten in der gleichen Zeile möchtest, verwende :same wie folgt:\n[eins](buttonurl://example.com)\n[zwei](buttonurl://google.com:same)\nDies erzeugt zwei Tasten in einer einzigen Zeile, statt einer Taste pro Zeile.\nDenke daran, dass die Nachricht einen anderen Text als nur einen Knopf enthalten muss!", 21 | "MARKDOWN_HELP_FORWARD": "Versuche mir die folgende Nachricht weiterzuleiten, und du wirst es sehen!", 22 | "MARKDOWN_HELP_FORWARD_MSG": "/save Test Dies ist ein Markdown Test. _kursiv_, *fett*, `code`, [URL](example.com) [button](buttonurl:karatek.net) [button2](buttonurl://github.com:same)", 23 | "CURRENT_STATS": "Aktuelle Statistiken:", 24 | "HELP": " - /id: ruft die aktuelle Gruppen-ID auf. Wenn diese verwendet wird, indem auf eine Nachricht geantwortet wird, erhält diese Benutzer-ID.\n - /runs: antworte einen zufälligen String aus einem Array von Antworten.\n - /slap: \"schlägt\" einen Benutzer\n - /info: holt Informationen über einen Benutzer.\n - /gdpr: löscht deine Informationen aus der Datenbank des Bots. Nur private Chats.\n\n - /markdownhelp: Schnellübersicht wie Markdown im Telegramm funktioniert - kann nur in privaten Chats aufgerufen werden." 25 | } --------------------------------------------------------------------------------