├── requirements.txt ├── .gitignore ├── config.ini ├── bot ├── creator.py ├── block.py ├── group.py ├── chating.py ├── helpers.py └── settings.py ├── main.py ├── README.md └── Data └── language ├── he_IL.json └── en_US.json /requirements.txt: -------------------------------------------------------------------------------- 1 | pyrogram 2 | tgcrypto 3 | apscheduler 4 | pony 5 | plate -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | /venv/ 2 | /*.session 3 | /Data/bot.log 4 | /Data/*_data.json 5 | -------------------------------------------------------------------------------- /config.ini: -------------------------------------------------------------------------------- 1 | [init] 2 | session_name = # your session name 3 | creator = # the Telegram ID of the creator 4 | 5 | [pyrogram] 6 | api_id = # your app api id 7 | api_hash = # your app api hash 8 | bot_token = # your bot token 9 | 10 | [plugins] 11 | root = bot -------------------------------------------------------------------------------- /bot/creator.py: -------------------------------------------------------------------------------- 1 | from pyrogram import StopPropagation 2 | from bot.helpers import * 3 | from main import CREATOR 4 | 5 | _logger = logging.getLogger(__name__) 6 | 7 | 8 | @Client.on_message(filters.command(COMMANDS['demote'] + COMMANDS['promote']) & 9 | filters.chat(CREATOR)) 10 | async def set_admins(_, m: Message): 11 | """ 12 | Handler function to promote / demote admins in the bot. 13 | (only for the CREATOR) 14 | :param _: pyrogram Client, unused argument 15 | :param m: the message. 16 | """ 17 | if not m.reply_to_message and len(m.command) == 2: 18 | uid = m.command[1] 19 | try: 20 | if not get_user(int(uid)): 21 | return _logger.debug("couldn't find a user") 22 | except ValueError: 23 | return _logger.debug("couldn't find a user, using wrong ID") 24 | elif not m.reply_to_message: 25 | return _logger.debug('not replayed to a message') 26 | else: 27 | uid = get_id(m) 28 | if not uid: 29 | return _logger.debug("couldn't find a user in the message") 30 | 31 | state = m.command[0] in COMMANDS['promote'] 32 | with db_session: 33 | get_user(uid).is_admin = state 34 | await m.reply( 35 | format_message('success_add_admin' if state else 'success_remove_admin', 36 | get_user(uid), lang=get_user(m.from_user.id).language 37 | ), disable_web_page_preview=True) 38 | raise StopPropagation() 39 | -------------------------------------------------------------------------------- /main.py: -------------------------------------------------------------------------------- 1 | from configparser import ConfigParser 2 | import re 3 | 4 | from apscheduler.schedulers.background import BackgroundScheduler 5 | from bot.helpers import * 6 | 7 | # Creat logger # 8 | _logger = logging.getLogger('main') 9 | _format = '%(asctime)s - %(levelname)s - %(name)s - %(funcName)s : %(message)s' 10 | logging.basicConfig(format=_format, filename=f'Data{os.sep}bot.log') 11 | 12 | # Config # 13 | _config = ConfigParser(inline_comment_prefixes=('#',)) 14 | _config.read('config.ini') 15 | _session = _config['init']['session_name'] 16 | if not _session or re.search(r'[/:*?"<>|~&#%+{}\\]', _session) or len(_session) > 244: 17 | msg = r'The session_name can not contain: \ / : * ? " < > | ~ & # % + { }' 18 | _logger.error(msg) 19 | raise NameError(msg) 20 | 21 | CREATOR = _config['init'].getint('creator') 22 | 23 | # set scheduler and Telegram client # 24 | _scheduler = BackgroundScheduler() 25 | bot = Client(_session, api_id=_config['pyrogram'].getint('api_id'), 26 | api_hash=_config['pyrogram']['api_hash'], 27 | bot_token=_config['pyrogram']['bot_token'], 28 | plugins=dict(_config['plugins'])) 29 | 30 | # Defining data files name depending the session name # 31 | DATA_FILE = f"Data{os.sep}{_session}" 32 | 33 | # Import data # 34 | if os.path.isfile(f'{DATA_FILE}_data.json'): 35 | with open(f'{DATA_FILE}_data.json', 'r', encoding='utf-8') as f: 36 | data = json.load(f, parse_int=int) 37 | else: 38 | data = {'start_msg': '', 'group': None, 'non_participant': '', 'ban': list()} 39 | 40 | 41 | def main(db_type: str, **db_kwargs): 42 | """ 43 | Setup and run the bot 44 | """ 45 | DB.bind(provider=db_type, **db_kwargs) 46 | DB.generate_mapping(create_tables=True) 47 | add_user(CREATOR, admin=True) 48 | _scheduler.add_job(clean_cash, trigger='interval', days=1) 49 | _scheduler.start() 50 | _logger.warning(f'Start running. PID: {os.getpid()}') 51 | bot.run() 52 | 53 | 54 | if __name__ == '__main__': 55 | main(db_type='sqlite', filename=f"{DATA_FILE}_DB.sqlite", create_db=True) 56 | -------------------------------------------------------------------------------- /bot/block.py: -------------------------------------------------------------------------------- 1 | from pyrogram.errors import PeerIdInvalid, UserIsBlocked 2 | from bot.helpers import * 3 | 4 | _logger = logging.getLogger(__name__) 5 | 6 | 7 | @db_session 8 | def report_to_admins(admin: User, user: User, c: Client, message: str): 9 | """ 10 | Function to report the admins that admin blocked / released user. 11 | :param admin: the admin that blocked / released the user. 12 | :param user: the user that was blocked / released. 13 | :param c: pyrogram.Client to send the message. 14 | :param message: the key of which message to send to the admins. 15 | """ 16 | for k, v in get_admins().items(): 17 | if k != admin.uid: 18 | try: 19 | c.send_message( 20 | k, 21 | format_message(message, user, admin=admin.link(), lang=v.language), 22 | disable_web_page_preview=True 23 | ) 24 | except PeerIdInvalid: 25 | _logger.error(f"Wasn't allow to send message to {v.name}") 26 | 27 | 28 | @Client.on_message(is_admin & filters.reply & filters.private & 29 | filters.command(COMMANDS['block'])) 30 | def block(c: Client, m: Message): 31 | """ 32 | Function to block a user from using the bot. 33 | :param c: reference to the Client. 34 | :param m: the message. 35 | """ 36 | user = get_id(m) 37 | if not user: 38 | return _logger.debug("couldn't find user ID in the message") 39 | user = get_user(user) 40 | if user.is_admin: 41 | return 42 | admin = get_user(m.from_user.id) 43 | if str(user.uid) not in data['ban']: 44 | data['ban'].append(str(user.uid)) 45 | m.reply(format_message('user_block', user, lang=admin.language), quote=True, 46 | disable_web_page_preview=True) 47 | save_data() 48 | else: 49 | return m.reply( 50 | format_message('already_blocked', user, lang=admin.language), quote=True) 51 | report_to_admins(admin, user, c, 'user_block_admin') 52 | 53 | 54 | @Client.on_message(is_admin & filters.reply & filters.private & 55 | filters.command(COMMANDS['unblock'])) 56 | def unblock(c: Client, m: Message): 57 | """ 58 | Unblock users, allow user to use the bot again. This function tell the user 59 | that he is not blocked. 60 | :param c: reference to the Client. 61 | :param m: the message. 62 | """ 63 | user = get_id(m) 64 | if not user: 65 | return _logger.debug("couldn't find user ID in the message") 66 | user = get_user(user) 67 | if user.is_admin: 68 | return 69 | admin = get_user(m.from_user.id) 70 | if str(user.uid) in data['ban']: 71 | data['ban'].remove(str(user.uid)) 72 | m.reply(format_message('user_unblock', user, lang=admin.language), quote=True, 73 | disable_web_page_preview=True) 74 | save_data() 75 | try: 76 | c.send_message(user.uid, MSG('unban_msg', user.language)) 77 | except UserIsBlocked: 78 | with db_session: 79 | delete(u for u in User if u.uid == user.uid) 80 | else: 81 | return m.reply(format_message('not_blocked', user, lang=admin.language), 82 | quote=True) 83 | report_to_admins(admin, user, c, 'user_unblock_admin') 84 | -------------------------------------------------------------------------------- /bot/group.py: -------------------------------------------------------------------------------- 1 | from pyrogram.enums.chat_member_status import ChatMemberStatus 2 | from bot.helpers import * 3 | 4 | 5 | @Client.on_message(is_admin & ~filters.private & filters.command(COMMANDS['group'])) 6 | def set_group(_, m: Message): 7 | """ 8 | Handler function to limit the bot to a group. 9 | Only the group members will be allowed to use the bot. 10 | :param _: pyrogram Client, unused argument 11 | :param m: command message. 12 | """ 13 | if data['group']: 14 | return m.chat.leave() 15 | if m.chat.get_member(m.from_user.id).status in [ChatMemberStatus.OWNER, 16 | ChatMemberStatus.ADMINISTRATOR]: 17 | privileges = m.chat.get_member('me').privileges 18 | if privileges and privileges.can_delete_messages and privileges.can_restrict_members: 19 | data['group'] = m.chat.id 20 | save_data() 21 | return m.reply(MSG('group_added', get_user(m.from_user.id).language, 22 | title=m.chat.title)) 23 | m.reply(MSG('bot_promote', add_user(tg_user=m.from_user).language)) 24 | data['group'] = None 25 | save_data() 26 | m.chat.leave() 27 | 28 | 29 | @Client.on_message( 30 | (is_admin & ~filters.private & filters.command(COMMANDS['remove_group'])) | 31 | filters.left_chat_member) 32 | def unset_group(c, m: Message): 33 | """ 34 | Handler function to unlimited the bot to a group. 35 | All the users will be allowed to use the bot. 36 | :param c: reference to the Client. 37 | :param m: command message. 38 | """ 39 | if not data['group']: 40 | return 41 | if m.left_chat_member and m.left_chat_member.is_self: 42 | data['group'] = None 43 | save_data() 44 | elif m.chat.get_member(m.from_user.id).status in [ChatMemberStatus.OWNER, 45 | ChatMemberStatus.ADMINISTRATOR]: 46 | data['group'] = None 47 | c.send_message( 48 | m.from_user.id, 49 | MSG('group_removed', get_user(m.from_user.id).language, 50 | title=m.chat.title)) 51 | save_data() 52 | 53 | 54 | @Client.on_message(filters.new_chat_members) 55 | async def joined_group(_, m: Message): 56 | """ 57 | Check permissions on joining the group. If someone added the bot, the bot 58 | will check its permissions immediately and after 5 minutes if necessary. 59 | :param _: pyrogram Client, unused argument 60 | :param m: join message. 61 | """ 62 | if data['group'] and str(m.chat.id) != data['group']: 63 | await m.chat.leave() 64 | for i in m.new_chat_members: 65 | if i.is_self: 66 | me = await m.chat.get_member('me') 67 | if me.status in [ChatMemberStatus.OWNER, ChatMemberStatus.ADMINISTRATOR]\ 68 | and me.privileges.can_delete_messages \ 69 | and me.privileges.can_restrict_members: 70 | return 71 | await m.reply( 72 | MSG('bot_promote', add_user(tg_user=m.from_user).language)) 73 | await asyncio.sleep(300) 74 | break 75 | me = await m.chat.get_member('me') 76 | if me.status in [ChatMemberStatus.OWNER, ChatMemberStatus.ADMINISTRATOR]: 77 | if me.privileges.can_delete_messages and me.privileges.can_restrict_members: 78 | return 79 | data['group'] = None 80 | save_data() 81 | await m.chat.leave() 82 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # TGanonymusChatBot 2 | 3 | This robot's purpose is to create a chat between an admin or several admins (which could stay anonymous if would like) and users. 4 | 5 | ## About 6 | 7 | The robot can function as a mail box so users from all over the world send messages to the bot and are received in one place, 8 | The users don't have the ability to see other user's messages, although the admin can. 9 | The robot was created using [pyrogram + tgcrypto](https://github.com/pyrogram), [ponyorm](https://github.com/ponyorm), [apscheduler](https://github.com/agronholm/apscheduler) and [plate](https://github.com/delivrance/plate). 10 | 11 | ### usage examples 12 | 13 | * You as a channel admin are able to give people a referral to that chatting bot so people can write messages, complaints or spamming and you can remain anonymous. 14 | * You can allow people who has been muted or spammed by telegram write and contact you even tho they are muted by telegram (due to spam or some thing). 15 | * You as an admin of a telegram group can tell people of some curtain group to message to you by the robot only, you can also give an order to the robot to receive messages from people from a curtain group so it saves him the time and effort of and moving from chat to another. 16 | 17 | ### benefits 18 | 19 | * People who send you messages through the robot can't erase them so you don't lose any messages that has been sent by someone, but if the admin erases a message he sent then it erases for the user too. 20 | * The admin and the user are able to edit an image, messages, video, GIF, also the admin can edit an image or a message and the user will see the editing too. **(editing can be done up to a day)**. 21 | * You can nominate people to be admins too. 22 | * You can block specific user from sending you messages. 23 | 24 | ## Setup 25 | 26 | 1. clone the bot 27 | `git clone https://github.com/idokar/TGanonymusChatBot.git` 28 | 2. Navigate to the folder 29 | `cd TGanonymusChatBot` 30 | 3. Install [requirements.txt](https://github.com/idokar/TGanonymusChatBot/blob/master/requirements.txt) 31 | `pip3 install -U -r requirements.txt` 32 | 4. Enter to the [config.ini](https://github.com/idokar/TGanonymusChatBot/blob/master/config.ini) file and edit the empty fields: 33 | 1. Create telegram app here: https://core.telegram.org/api/obtaining_api_id for getting `api_id` and `api_hash` 34 | 2. [Create bot token](https://core.telegram.org/bots#3-how-do-i-create-a-bot) using [BotFather](https://t.me/botfather) 35 | 3. Enter the `api_id`, `api_hash` and the `bot_token` to the [`config.ini`](https://github.com/idokar/TGanonymusChatBot/blob/master/config.ini) file (without using "" around the strings). 36 | ##### Example 37 | ``` 38 | api_id = 12345 39 | api_hash = 0123456789abcdef0123456789abcdef 40 | bot_token = 123456:ABC-DEF1234ghIkl-zyx57W2v1u123ew11 41 | ``` 42 | 4. Enter the `session_name` and the `creator` Telegram ID 43 | ##### Example 44 | ``` 45 | session_name = My_bot 46 | creator = 123456789 47 | ``` 48 | 5. Run the bot. 49 | 50 | ## Bot commands 51 | 52 | * `/start` - **admins and users command**. for admins its a permanent message and for users it is a editable using `/set welcome` command. 53 | * `/help` - **admins and users command**. for users it gives the ability to change language and get info about the bot. and for admins, it gives info about all the commands. 54 | * `/set welcome` - **admins only command**. allows to set a welcome message for the users. 55 | * `/settings` - **admins only command**. allows to choose language, to remove the welcome message and to see the blocked and admins lists. 56 | * `/block` and `/unblock` - **admins only command**. to block and unlock users. 57 | * `/set group` and `/unset group` - **admins only command**. to limit the incoming messages from a curtain group only. 58 | * `/promote` and `/demote` - **creator only command**. to promote and demote users and admins. 59 | 60 | **for more information use `/help` (as admin) in the bot.** 61 | 62 | ## todo 63 | - [ ] add bot factory to create instances of this bot. 64 | - [ ] add admins group (to receive messages there) 65 | -------------------------------------------------------------------------------- /Data/language/he_IL.json: -------------------------------------------------------------------------------- 1 | { 2 | "en_US": "🇺🇸 English (אנגלית)", 3 | "he_IL": "🇮🇱 Hebrew (עברית)", 4 | 5 | "block": "חסום", 6 | "unblock": "הסר חסימה", 7 | "promote": "הפוך למנהל", 8 | "demote": "הסר מנהל", 9 | "welcome": "ברוך הבא", 10 | "group": "הגדר קבוצה", 11 | "remove_group": "הסר קבוצה", 12 | "settings": "הגדרות", 13 | 14 | "ban_msg": "⛔️ **נחסמת** ⛔️\n**כעת אין ביכולתך לשלוח הודעות דרך צ'אט זה**", 15 | "admin_welcome": "ברוך הבא {name}\nאתה מנהל כעת ברובוט הזה, שלח /help בכדי לראות את רשימת הפקודות", 16 | "forwarded": "**לא ניתן להעביר הודעות לרובוט זה**", 17 | "edited": "ההודעה נערכה ✏️\n", 18 | "edit_expired": "לא הצלחתי לערוך את ההודעה עבור המשתמש", 19 | "user_not_found": "לא מצאתי לאיזה משתמש להגיב,\nאנא השב להודעת המשתמש או להודעה שאומרת \"השב להודעה זו\"", 20 | "pic": "תמונה 🖼", 21 | "reply": "{uid}\n**השב למשתמש**: {link}\n **השב להודעה זו כדי לענות למשתמש**", 22 | "admin_ans": "המנהל {admin} השיב ל {link} עם ההודעה:\n\n`{msg}`", 23 | "admin_edit_ans": "המנהל {admin} ערך את ההודעה שהשיב ל {link} עם ההודעה:\n\n`{msg}`", 24 | "blocked": "לא הצלחתי לשלוח את ההודעה, כנראה המשתמש חסם את הרובוט", 25 | "user_block": "המשתמש {link} ({uid}) נחסם בהצלחה", 26 | "user_block_admin": "המנהל {admin} חסם את המשתמש {link} ({uid})", 27 | "user_unblock_admin": "המנהל {admin} שחרר את חסימת המשתמש {link} ({uid})", 28 | "already_blocked": "המשתמש הזה כבר חסום", 29 | "not_blocked": "המשתמש הזה לא היה חסום", 30 | "user_unblock": "השתחררה חסימת המשתמש {link} ({uid}), משתמש זה אינו חסום יותר.", 31 | "unban_msg": "**מזל טוב! אתה כבר לא חסום!**\nכעת אתה יכול להשתמש שוב ברובוט זה", 32 | "block_list": "**רשימת משתמשים חסומים:**\n\n", 33 | "admin_list": "**רשימת מנהלים:**\n\n", 34 | "format_err": "פורמט ההודעה שגוי, אנא נסה שנית", 35 | "success_welcome": "**הודעת הפתיחה הוגדרה בהצלחה.**", 36 | "success_add_admin": "{link} ({uid}) הוגדר כמנהל בהצלחה.", 37 | "success_remove_admin": "**כעת {link} ({uid}) אינו מנהל**", 38 | "bot_promote": "אני חייב להיות מנהל של קבוצה זו עם ההראשות הבאות:\n\t▪️מחיקת הודעות (Delete Messages)\n\t▪️חסימת משתמשים (Ban Users)", 39 | "group_added": "\uD83D\uDD17הקבוצה `{title}` נוספה בהצלחה.\nכעת **רק חברי קבוצה זו** יוכלו לשלוח הודעות דרך הבוט", 40 | "group_removed": "הקבוצה {title} הוסרה בהצלחה.\nכעת **כולם** יוכלו לשלוח הודעות דרך הבוט", 41 | "settings_msg": "**הגדרות הרובוט:**\nכאן תוכל לשנות את שפת הבוט, להסיר את הודעת הפתיחה (כדי להגדיר מחדש את הודעת הפתיחה השתמש בפקודה: `/ברוך הבא`) ולצפות ברשימת המנהלים והמשתמשים החסומים.", 42 | "chang_lang": "כאן תוכל לשנות את שפת הבוט.\n**בחר/י את השפה שלך:**", 43 | "explain_welcome": "כדי לבטל את הודעת הפתיחה הקש על ✅.\n\nמסמל הודעה מבוטלת:\t\t☑️\nמסמל הודעה מופעלת:\t\t✅", 44 | "welcome_removed": "**הודעת הפתיחה הוסרה.**\nכדי להגדיר מחדש את הודעת הפיחה השתמש/י בפקודה: `/ברוך הבא`, לעזרה נוספת שלח/י את הפקודה: `/help`", 45 | "users_help": "בעזרת הבוט הזה תוכלו ליצור קשר עם המנהל/ים של הבוט.\nניתן גם לשנות את שפת הבוט לשפות נתמכות אחרות.\n\nהבוט הזה הוא פרויקט קוד פתוח, אם ברצונך להוסיף שפות נוספות לרובוט או להציע לו שיפורים או ליצור לעצמך רובוט שכזה, תוכל/י [ליצור קשר עם יוצר הבוט](https://t.me/ido1234) או לחלופין לשלוח הצעות ב[דף הבוט ב- GitHub](https://github.com/idokar/TGanonymusChatBot)", 46 | "admins_help": "באמצעות בוט זה משתמשים יכולים ליצור איתך קשר ועם עוד מנהלים ברובוט זה (ראה את הכפתור 'הגדרת מנהלים' למטה), אתה יכול גם להגביל את הבוט לקבוצה מסוימת, לחסום משתמשים משימוש בבוט, להגדיר הודעת פתיחה ולשנות את שפת הרובוט.\n\nהבוט הזה הוא פרויקט קוד פתוח, אם ברצונך להוסיף שפות נוספות לרובוט או להציע לו שיפורים או ליצור לעצמך רובוט שכזה, תוכל/י [ליצור קשר עם יוצר הבוט](https://t.me/ido1234) או לחלופין לשלוח הצעות ב[דף הבוט ב- GitHub](https://github.com/idokar/TGanonymusChatBot)", 47 | "help_block": "באמצעות הפקודה `/חסום` ניתן להגביל משתמשים מלהשתמש בבוט זה.\nאם ברצונך לחסום משתמש משימוש ברובוט, עליך להשיב להודעת המשתמש (או להודעה העוקבת אחר הודעת המשתמש שאומרת \"השב להודעה זו\") באמצעות הפקודה `/חסום`.\n\nאם ברצונך לשחרר משתמש חסום עליך להשיב להודעת המשתמש (או להודעה העוקבת אחר הודעת המשתמש שאומרת \"השב להודעה זו\") באמצעות הפקודה `/הסר חסימה`.\n\nבשביל לראות את כל המשתמשים החסומים ניתן להשתמש בפקודה `/הגדרות` ואז ללחוץ על 'רשימת חסומים'.", 48 | "help_admins": "**רק יוצר הרובוט** יכול להוסיף או להסיר מנהלים מהבוט.\nמנהלים בבוט זה יכולים: ליצור קשר עם המשתמשים, יכולים להגדיר לשנות או להסיר את הודעת הפתיחה, יכולים להגביל את הרובוט לענות רק למשתמשים מקבוצה מסויימת (ראה 'הגדרות קבוצה' מטה) ולחסום או לבטל חסימה של משתמשים משימוש בבוט.\n\nאם ברצונך להפוך משתמש להיות מנהל, עליך להשיב להודעת המשתמש (או להודעה העוקבת אחר הודעת המשתמש שאומרת \"השב להודעה זו\") באמצעות הפקודה `/הפוך למנהל` **או לחילופין** לשלוח את הפקודה '/הפוך למנהל' עם ה-ID של המשתמש (מבלי להשיב להודעה) למשל: `/הפוך למנהל 123456789`.\n\nאם ברצונך להסיר מנהל ניתן לעשות את אותו הדבר בדיוק, אך במקום להשתמש בפקודה '/הפוך למנהל' **צריך להשתמש בפקודה** '/הסר מנהל',\nלמשל: `/הסר מנהל 123456789`. או בתשובה להודעה.\n\nבמקרה וברצונך לראות את הרשימה של כל המנהלים ניתן להשתמש בפקודה `/הגדרות` ואז ללחוץ על 'רשימת מנהלים'.", 49 | "help_welcome": "אפשר להגדיר לרובוט לשלוח הודעת ברוך הבא מותאמת אישית למשתמשים כאשר משתמש שולח `/start` לרובוט.\nאם ברצונך ליצור הודעת ברוך הבא תוכל להשתמש בפקודה '/ברוך הבא' ואחריה ההודעה עצמה, למשל. `/ברוך הבא שלום $name ברוך הבא לבוט שלי`\n\nכמו כן ניתן גם לעצב את ההודעה שלך באמצעות פרמטרים או טקסט מעוצב.\nפרמטרים:\n `$id` - ה-ID של המשתמש בטלגרם.\n `$first_name` - השם הפרטי של המשתמש.\n `$last_name` - שם המשפחה של המשתמש (לא תמיד קיים)\n `$username` - היוזרניים של המשתמש בטלגרם (לא תמיד קיים)\n `$name` - השם המלא של המשתמש\n\nעבור **טקסט מודגש** השתמש ב- `*` (משני צידי הטקסט), עבור __טקסט נטוי__ השתמש ב- `_` (משני צידי הטקסט), עבור ~~קו חוצה~~ השתמש ב- `~` (משני צידי הטקסט), עבור ||ספויילר|| השתמש ב- `|` (משני צידי הטקסט), עבור --קו תחתון-- השתמש ב- `-` (משני צידי הטקסט) ובשביל [קישור מוטמע בטקסט](https://example.com) תוכל להשתמש ב- `[טקסט](קישור URL)`.\n\nאם ברצונך להשתמש באחת מהתווים הללו מבלי לעצב את הטקסט, תוכל 'לחלץ' אותם באמצעות `\\\\` (למשל `\\\\_` או `\\\\-` וכו...).\n\nכדי להסיר את הודעת הפתיחה שלח `/הגדרות` ואז לחץ על ✅\n**שים לב**: פעולה זו אינה הפיכה ולאחר ביצועה לא ניתן יהיה לשחזר את הודעת הפתיחה, לכן אם ברצונך להחזיר את הודעת הפתיחה הקודמת, עליך ליצור אותה מחדש עם הפקודה '/ברוך הבא'.", 50 | "help_group": "ניתן להגביל את הבוט להגיב רק למשתמשים מקבוצה מסוימת. אם אתה מנהל של הקבוצה G ואליס היא חברה בקבוצה שלך אבל בוב לא חבר בה, אז ברגע שאליס תשלח הודעה לבוט ההודעה תועבר כצפוי, אך כאשר בוב ישלח הודעה, הרובוט לא יגיב לו כלל.\n\nכדי להגדיר קבוצה עליך להיות מנהל/ת בקבוצה, הבוט צריך להיות מנהל גם, עם הרשאה למחיקת הודעות ולחסום משתמשים. שלח/י את הפקודה `/הגדר קבוצה` **בקבוצה שאת/ה רוצה להגדיר**.\n\nכדי לבטל את הגדרת הקבוצה ניתן להסיר את הבוט מהקבוצה או להשתמש בפקודה '/הסר קבוצה'", 51 | "button_block": "משתמשים חסומים", 52 | "button_admins": "הגדרת מנהלים", 53 | "button_welcome": "הודעת פתיחה", 54 | "button_group": "הגדרת קבוצה", 55 | "button_admin_list": "רשימת מנהלים", 56 | "button_block_list": "רשימת חסומים", 57 | "button_remove_welcome": "הודעת פתיחה", 58 | "button_back": "הקודם ↩️", 59 | "button_lang": "\uD83C\uDF10 שינוי שפה \uD83C\uDF10" 60 | } -------------------------------------------------------------------------------- /bot/chating.py: -------------------------------------------------------------------------------- 1 | import time 2 | 3 | from pyrogram.errors import PeerIdInvalid, UserIsBlocked, FloodWait,\ 4 | MessageEditTimeExpired, MessageIdInvalid 5 | from pyrogram.types import InputMediaAnimation, InputMediaAudio, \ 6 | InputMediaDocument, InputMediaVideo, InputMediaPhoto 7 | 8 | from bot.helpers import * 9 | from main import CREATOR 10 | 11 | _logger = logging.getLogger(__name__) 12 | 13 | 14 | async def forward_to_admins(m: Message, user: User, message): 15 | """ 16 | Forward the users messages to the admins. 17 | :param m: message to forward. 18 | :param user: the user who send the message. 19 | :param message: the key of which message to send to the admins. 20 | ['reply', 'edited'] 21 | """ 22 | for k in get_admins().keys(): 23 | try: 24 | try: 25 | msg = await m.forward(k) 26 | except FloodWait as flood: 27 | time.sleep(flood.value + 3) 28 | msg = await m.forward(k) 29 | with db_session: 30 | admin = get_user(k) 31 | if not admin: 32 | continue 33 | admin_lang = admin.language 34 | admin_name = admin.name 35 | if not msg.forward_from or m.sticker: 36 | await msg.reply(format_message(message, user, lang=admin_lang), 37 | quote=True, disable_web_page_preview=True) 38 | else: 39 | if m.edit_date: 40 | await msg.reply(MSG('edited', admin_lang), quote=True) 41 | except PeerIdInvalid: 42 | _logger.error(f"Wasn't allow to send message to {admin_name}") 43 | except UserIsBlocked: 44 | _logger.error(f'The Admin {admin_name} blocked the bot') 45 | with db_session: 46 | if k != CREATOR: 47 | delete(u for u in User if u.uid == k) 48 | commit() 49 | 50 | 51 | async def edit_message(m: Message): 52 | """ 53 | Edit any type of pyrogram message using the messages dict. 54 | :param m: pyrogram.Message to edit. 55 | """ 56 | if m.text: 57 | messages[m.date] = await messages[m.date].edit(m.text, entities=m.entities) 58 | elif m.caption and m.caption != messages[m.date].caption: 59 | messages[m.date] = await messages[m.date].edit_caption( 60 | m.caption, caption_entities=m.caption_entities) 61 | elif m.media: 62 | caption = {'caption': m.caption + '\n', 63 | 'caption_entities': m.caption_entities} if m.caption else {} 64 | if m.photo and m.photo != messages[m.date].photo: 65 | messages[m.date] = await messages[m.date].edit_media( 66 | InputMediaPhoto(m.photo.file_id, m.photo.file_unique_id, 67 | **caption)) 68 | elif m.video and m.video != messages[m.date].video: 69 | messages[m.date] = await messages[m.date].edit_media( 70 | InputMediaVideo(m.video.file_id, m.video.file_unique_id, **caption)) 71 | elif m.document and m.document != messages[m.date].document: 72 | messages[m.date] = await messages[m.date].edit_media( 73 | InputMediaDocument(m.document.file_id, m.document.file_unique_id, 74 | **caption)) 75 | elif m.animation and m.animation != messages[m.date].animation: 76 | messages[m.date] = await messages[m.date].edit_media( 77 | InputMediaAnimation(m.animation.file_id, 78 | m.animation.file_unique_id, **caption)) 79 | elif m.audio and m.audio != messages[m.date].audio: 80 | messages[m.date] = await messages[m.date].edit_media( 81 | InputMediaAudio(m.audio.file_id, m.audio.file_unique_id, **caption)) 82 | 83 | 84 | @Client.on_message(filters.private & filters.command('start')) 85 | async def start(c, m): 86 | """ 87 | Handler for the `/start` command. 88 | :param c: reference to the Client. 89 | :param m: the message. 90 | """ 91 | user = add_user(tg_user=m.from_user) 92 | if user.is_admin: 93 | return await m.reply( 94 | format_message('admin_welcome', user, lang=user.language)) 95 | elif await user.member(c): 96 | if str(user.uid) in data['ban']: 97 | return await m.reply(MSG('ban_msg', user.language), quote=True) 98 | if data['start_msg']: 99 | await m.reply(format_message( 100 | data['start_msg'], user).replace('{{', '{').replace('}}', '}')) 101 | await forward_to_admins(m, user, 'reply') 102 | else: 103 | if data['non_participant']: 104 | return await m.reply(format_message(data['non_participant'], user)) 105 | 106 | 107 | @Client.on_message(filters.private & ~filters.me & ~is_admin & ~is_command, group=1) 108 | @Client.on_edited_message(filters.private & ~filters.me & ~is_admin & ~is_command, group=1) 109 | async def get_messages(c, m): 110 | """ 111 | Handler for getting messages from the users. 112 | :param c: reference to the Client. 113 | :param m: the message. 114 | """ 115 | user = add_user(m.from_user.id) 116 | if not await user.member(c): 117 | return 118 | if str(user.uid) in data['ban']: 119 | return await m.reply(MSG('ban_msg', user.language), quote=True) 120 | elif m.forward_date: 121 | return await m.reply(MSG('forwarded', user.language)) 122 | await forward_to_admins(m, user, 'edited' if m.edit_date else 'reply') 123 | 124 | 125 | @Client.on_message(is_admin & filters.private & filters.reply & ~is_command, group=1) 126 | @Client.on_edited_message(is_admin & filters.private & filters.reply & ~is_command, group=1) 127 | async def return_message(c, m): 128 | """ 129 | Handler for return messages to the users. 130 | :param c: reference to the Client. 131 | :param m: the message. 132 | """ 133 | uid = get_id(m) 134 | admin = add_user(tg_user=m.from_user) 135 | if not uid: 136 | return _logger.debug(f'not a valid ID in the message {m}') 137 | if get_user(uid) is None: 138 | return await m.reply(MSG('blocked', admin.language), quote=True) 139 | elif get_user(uid).is_admin: 140 | return _logger.debug('user is admin') 141 | try: 142 | if m.edit_date: 143 | await edit_message(m) 144 | else: 145 | messages[m.date] = await m.copy(uid) 146 | except UserIsBlocked: 147 | await m.reply(MSG('blocked', admin.language), quote=True) 148 | with db_session: 149 | delete(u for u in User if u.uid == uid) 150 | except (KeyError, MessageEditTimeExpired, MessageIdInvalid): 151 | await m.reply(MSG('edit_expired', admin.language), quote=True) 152 | else: 153 | with db_session: 154 | for k, v in get_admins().items(): 155 | try: 156 | if k != m.from_user.id: 157 | await c.send_message( 158 | k, 159 | format_message( 160 | 'admin_edit_ans' if m.edit_date else 'admin_ans', 161 | get_user(uid), 162 | lang=v.language, 163 | admin=admin.link(), 164 | msg=m.text or MSG('pic', v.language) 165 | ), 166 | disable_web_page_preview=True) 167 | except (PeerIdInvalid, UserIsBlocked): 168 | _logger.error(f"Wasn't allow to send message to {v.name}") 169 | -------------------------------------------------------------------------------- /Data/language/en_US.json: -------------------------------------------------------------------------------- 1 | { 2 | "en_US": "🇺🇸 English (אנגלית)", 3 | "he_IL": "🇮🇱 Hebrew (עברית)", 4 | 5 | "block": "block", 6 | "unblock": "unblock", 7 | "promote": "promote", 8 | "demote": "demote", 9 | "welcome": "set welcome", 10 | "group": "set group", 11 | "remove_group": "unset group", 12 | "settings": "settings", 13 | 14 | "ban_msg": "⛔️ **You are blocked** ⛔️\n**This chat is not currently available for you**", 15 | "admin_welcome": "Welcome {name}\nyou are an admin on this bot, use /help to see all the commands list", 16 | "forwarded": "**You can't forward messages to this bot!**", 17 | "edited": "The message was edited ✏️\n", 18 | "edit_expired": "I was unable to edit the message for the user", 19 | "user_not_found": "I couldn't find a user to reply to,\nPlease reply to the user message or the message that says \"reply to this message\"", 20 | "pic": "picture 🖼", 21 | "reply": "{uid}\n**reply to the user**: {link}\n\n**reply to this message to reply to the user message**", 22 | "admin_ans": "The admin {admin} reply to {link} with the message:\n\n`{msg}`", 23 | "admin_edit_ans": "The admin {admin} edited the message to {link} with the message:\n\n`{msg}`", 24 | "blocked": "I couldn't send the message, apparently the user blocked the robot", 25 | "user_block": "The user {link} ({uid}) has been blocked successfully", 26 | "user_block_admin": "The admin {admin} blocked the user {link} ({uid})", 27 | "user_unblock_admin": "The admin {admin} unblocked the user {link} ({uid})", 28 | "already_blocked": "This user is already blocked", 29 | "not_blocked": "This user wasn't blocked", 30 | "user_unblock": "The user {link} ({uid}) has been released, The user is no longer blocked", 31 | "unban_msg": "**Congratulations! you have been released from the block**\nYou can now use the bot again", 32 | "block_list": "**blocked users List:**\n\n", 33 | "admin_list": "**Admin list:**\n\n", 34 | "format_err": "The message format is incorrect, please try again", 35 | "success_welcome": "**Success**\nWelcome message has been set up correctly.", 36 | "success_add_admin": "**Success**\nNow {link} ({uid}) is admin", 37 | "success_remove_admin": "**Success**\nNow {link} ({uid}) is not admin anymore", 38 | "bot_promote": "I must be an admin in this group with the following permissions:\n\t▪️Delete Messages\n\t▪️Ban Users", 39 | "group_added": "\uD83D\uDD17The group `{title}` was successfully added.\nNow only this group members will be able to send messages through the bot", 40 | "group_removed": "The Group {title} was successfully removed.\nNow everyone will be able to send messages through the bot", 41 | "settings_msg": "**Bot settings:**\nHere you can change the bot language, remove the Welcome message (to reset the welcome message use: `/set welcome` command), see the admin list and the blocked users.", 42 | "chang_lang": "Here you can change the bot language.\n**Select your language:**", 43 | "explain_welcome": "To disable the welcome message press on ✅.\n\nDisabled:\t\t☑️\nEnabled:\t\t✅", 44 | "welcome_removed": "**The welcome message has been removed.**\nTo reset the welcome message use: `/set welcome` command, for more help use `/help`", 45 | "users_help": "With this bot you can contact the admin/s of this bot.\nYou can also change the bot language.\n\nThe bot is an open source project, if you want to add additional languages to the bot or offer it improvements or create one for yourself as well, you can [contact the creator of the bot](https://t.me/ido1234) or alternatively send suggestions on the [bot page in GitHub](https://github.com/idokar/TGanonymusChatBot)", 46 | "admins_help": "With this bot, users can contact you and more admins of this bot (see the 'Admins' button below), you can also limit the bot for a specific group, block users from using the bot, set a welcome message and change the bot language.\n\nThe bot is an open source project, if you want to add additional languages to the bot or offer it improvements or create one for yourself as well, you can [contact the creator of the bot](https://t.me/ido1234) or alternatively send suggestions on the [bot page in GitHub](https://github.com/idokar/TGanonymusChatBot)", 47 | "help_block": "With the command `/block` you can restrict users from using this bot.\nIf you want to block a user from using the bot, you have to reply the user message (or the message that follow the user message that says \"reply to this message\") with the command `/block`.\n\nIf you want to release a blocked user you have to reply the user message (or the message that follow the user message that says \"reply to this message\") with the command `/unblock`.\n\nIn case you want to see all the blocked user you can use the command `/settings` and then press on 'Blocked list'.", 48 | "help_admins": "**Only the creator of the bot** can promote or demote admins on this bot.\nAdmins on this bot can: contact with the users, can change set or remove the welcome message, can set a group of users (see 'Group settings' below) and block or unblock users from using the bot.\n\nIf you want to promote user to be an admin you have to reply the user message (or the message that follow the user message that says \"reply to this message\") with the command `/promote` **or** send the command `/promote` withe the user ID (without replying a message) e.g: `/promote 123456789`.\n\nIf you want to demote admin you can do the same but instead of using the command `/promote` **use the command** `/demote`,\ne.g: `/demote 123456789`. or in a reply to a message.\n\nIn case you want to see a list of the admins you can use the command `/settings` and then press on 'Admins list'.", 49 | "help_welcome": "If you wish, you can make the bot to send a custom welcome message to the users when a user send /start to the bot.\nIf you want to create a welcome message you can use the command `/set welcome` followed by the message itself, e.g. `/set welcome hello $name welcome to my bot`\n\nif you wish you can also format your message with parameters or text formatting.\nparameters:\n `$id` - the user telegram ID.\n `$first_name` - the first name of the user.\n `$last_name` - the last name of the user (not always exist)\n `$username` - the telegram username of the user (not always exist)\n `$name` - the full name of the user (first + last)\n\nFor **bold text** use `*` (from both sides of the text), for __italic__ use `_` (from both sides of the text), for ~~strikethrough~~ use `~` (from both sides of the text), for ||spoiler|| use `|` (from both sides of the text), for --underline-- use `-` (from both sides of the text) and for [text link](https://example.com) you can use `[Text](url link)`.\n\nIf you want to use one of this characters without formatting the text, you can escape them with `\\\\` (e.g. '\\\\_' or '\\\\-'...).\n\nTo remove the welcome message send `/settings` and then press on ✅\n**Attention**: this operation is not reversible and once performed it won't be possible to restore the welcome message, so if you want to return the previous welcome message, you should recreate it with `/set welcome`.", 50 | "help_group": "If you want, you can limit the bot to respond only to users from a specific group. If you are the admin of some group and Alice is member in your group but Bob isn't a member, so if Alice will send message to the bot its will work as expected but when Bob will send a message, the robot won't respond to him.\n\nTo set a group you must be an admin in this group, the bot must be admin too with the permission to delete and to ban users. send the command `/set group` **in the group**.\n\nTo unset the group you can remove the bot from the group or use the command `/unset group`", 51 | "button_block": "Blocking users", 52 | "button_admins": "Admins", 53 | "button_welcome": "Welcome message", 54 | "button_group": "Group settings", 55 | "button_admin_list": "Admins list", 56 | "button_block_list": "Blocked list", 57 | "button_remove_welcome": "Welcome message", 58 | "button_back": "Back ↩️", 59 | "button_lang": "\uD83C\uDF10 Chang language \uD83C\uDF10" 60 | } -------------------------------------------------------------------------------- /bot/helpers.py: -------------------------------------------------------------------------------- 1 | import asyncio 2 | import json 3 | import logging 4 | import os 5 | import sys 6 | from typing import Union, Dict 7 | 8 | from pony.orm import * 9 | from plate import Plate 10 | from pyrogram import filters, Client 11 | from pyrogram.errors import RPCError 12 | from pyrogram.types import Message 13 | from pyrogram.enums.chat_member_status import ChatMemberStatus 14 | from main import DATA_FILE, data 15 | 16 | sys.path.append(os.path.dirname(os.path.dirname(os.path.abspath(__file__)))) 17 | __logger = logging.getLogger(__name__) 18 | 19 | messages = dict() 20 | DB = Database() 21 | MSG = Plate(f'.{os.sep}Data{os.sep}language') 22 | COMMANDS = {c: [MSG(c, i) for i in MSG.locales.keys()] for c in ( 23 | 'block', 'unblock', 24 | 'promote', 'demote', 25 | 'group', 'remove_group', 26 | 'welcome', 'settings' 27 | )} 28 | 29 | 30 | # ==================================== DB ==================================== 31 | class User(DB.Entity): 32 | """ 33 | User entity type to represent Telegram user 34 | """ 35 | uid = PrimaryKey(int, size=64) 36 | is_admin = Required(bool) 37 | language = Required(str) 38 | first_name = Optional(str) 39 | last_name = Optional(str) 40 | username = Optional(str) 41 | 42 | @property 43 | def name(self) -> str: 44 | """ 45 | Full name of a user 46 | :return: the user first and last name if existed. 47 | """ 48 | if self.first_name and self.last_name: 49 | return f'{self.first_name} {self.last_name}' 50 | elif self.first_name and not self.last_name: 51 | return self.first_name 52 | return self.last_name or '' 53 | 54 | async def member(self, c: Client) -> bool: 55 | """ 56 | Check if a user is a group member. 57 | :param c: reference to the Client. 58 | :return: rather the user is member or not. 59 | """ 60 | if data['group'] is None: 61 | return True 62 | try: 63 | user = await c.get_chat_member(data['group'], self.uid) 64 | return bool(user.status not in [ChatMemberStatus.RESTRICTED, 65 | ChatMemberStatus.LEFT, 66 | ChatMemberStatus.BANNED]) 67 | except RPCError: 68 | return False 69 | 70 | def link(self) -> str: 71 | """ 72 | Function to get a link to the user 73 | :return: Markdown hyperlink to the user 74 | """ 75 | if self.username: 76 | return f'[{self.name or self.uid}](https://t.me/{self.username[1:]})' 77 | return f'[{self.name or self.uid}](tg://user?id={self.uid})' 78 | 79 | 80 | @db_session 81 | def get_user(user_id: int) -> Union[User, None]: 82 | """ 83 | Getter function for getting users from the database by user id. 84 | :param user_id: the user telegram ID. 85 | :return: the user on None in case the user is not in DB. 86 | """ 87 | try: 88 | return User[user_id] 89 | except ObjectNotFound: 90 | return __logger.debug(f'the ID {user_id} is not found') 91 | 92 | 93 | @db_session 94 | def add_user(uid=None, tg_user=None, admin=False, language='en_US', 95 | first_name='', last_name='', username='') -> User: 96 | """ 97 | Function to add a new user to the database. 98 | In case the user is already exist in the DB the user will be returned. 99 | 100 | Required: uid or message 101 | :param uid: the user telegram ID. 102 | :type uid: int 103 | :param tg_user: a Telegram user type as represented in pyrogram. 104 | :type tg_user: pyrogram.types.User 105 | 106 | Optional arguments: 107 | :param admin: boolean value if the user is admin 108 | :param language: the user language. One of: ('en_US', 'he_IL') 109 | :arg first_name: user first name as string 110 | :arg last_name: user last name as string 111 | :arg username: the telegram user username 112 | :return: a new user, or the user from the DB in case the user already exist. 113 | """ 114 | if tg_user: 115 | if not get_user(tg_user.id): 116 | return User( 117 | uid=tg_user.id, 118 | is_admin=admin, 119 | language=language, 120 | first_name=tg_user.first_name or '', 121 | last_name=tg_user.last_name or '', 122 | username=f'@{tg_user.username}' if tg_user.username else '' 123 | ) 124 | User[tg_user.id].first_name = tg_user.first_name or '' 125 | User[tg_user.id].last_name = tg_user.last_name or '' 126 | User[tg_user.id].username = f'@{tg_user.username}' if tg_user.username else '' 127 | 128 | elif uid and not get_user(uid): 129 | return User( 130 | uid=uid, 131 | is_admin=admin, 132 | language=language, 133 | first_name=first_name, 134 | last_name=last_name, 135 | username=username 136 | ) 137 | return User[uid or tg_user.id] 138 | 139 | 140 | @db_session 141 | def get_admins() -> Dict[int, User]: 142 | """ 143 | Getter to the admin list. 144 | :return: dict[(admin ID: dataBase user),...] 145 | """ 146 | return dict(select((u.uid, u) for u in User if u.is_admin)) 147 | 148 | 149 | def save_data(): 150 | """ 151 | Save the data to json that contains the welcome message, group and blocked 152 | list. 153 | """ 154 | with open(f'{DATA_FILE}_data.json', 'w', buffering=1) as file: 155 | json.dump(data, file, indent=4) 156 | __logger.info('the data was saved') 157 | 158 | 159 | def clean_cash(message_date=None): 160 | """ 161 | Delete all the messages sent from the admins or a specific one. 162 | :param message_date: the pyrogram.types.Message.date (a none zero number) 163 | """ 164 | global messages 165 | if message_date: 166 | message = messages.pop(message_date) 167 | if message: 168 | message.delete(True) 169 | else: 170 | del messages 171 | messages = dict() 172 | __logger.info('All the messages were clean') 173 | 174 | 175 | # ============================ pyrogram functions ============================ 176 | def format_message(message: str, user: User, **kwargs) -> str: 177 | """ 178 | Function to format messages. 179 | The message can contain one (or more) of this tags: 180 | {uid} (the user ID), 181 | {first} (the user first name), 182 | {last} (the user last name), 183 | {username} (the user telegram username), 184 | {name} (the full name of the user) 185 | {link} (link to the user (not always exists)) 186 | 187 | :param message: a message to format or key of message if 'lang' in kwargs 188 | :param user: User as represents in the database 189 | :param kwargs: more optional arguments to the message 190 | :return: the formatted message. 191 | """ 192 | if 'lang' in kwargs.keys(): 193 | return MSG( 194 | message, 195 | kwargs.pop('lang'), 196 | uid=user.uid, 197 | first=user.first_name or '', 198 | last=user.last_name or '', 199 | username=user.username or '', 200 | name=user.name, 201 | link=user.link(), 202 | **kwargs 203 | ) 204 | return message.format( 205 | uid=user.uid, 206 | first=user.first_name or '', 207 | last=user.last_name or '', 208 | username=user.username or '', 209 | name=user.name, 210 | link=user.link(), 211 | **kwargs 212 | ) 213 | 214 | 215 | def get_id(message: Message) -> Union[int, None]: 216 | """ 217 | Function to cathe the use ID from the given message. 218 | :return the user ID or None in case of filer. 219 | """ 220 | if message.reply_to_message.forward_from: 221 | uid = message.reply_to_message.forward_from.id 222 | else: 223 | uid = message.reply_to_message.text.split("\n")[0] 224 | if isinstance(uid, str) and uid.isdigit(): 225 | uid = int(uid) 226 | if not isinstance(uid, int): 227 | message.reply(MSG('user_not_found', 228 | add_user(tg_user=message.from_user).language)) 229 | return 230 | return uid 231 | 232 | 233 | async def _is_admin(_, __, m: Message) -> bool: 234 | return bool(m.from_user and m.from_user.id in get_admins().keys()) 235 | 236 | 237 | async def _is_command(_, __, m: Message) -> bool: 238 | return bool(m.command) 239 | 240 | is_admin = filters.create(_is_admin) 241 | """filter for filtering admins messages.""" 242 | is_command = filters.create(_is_command) 243 | """filter for filtering command messages.""" 244 | -------------------------------------------------------------------------------- /bot/settings.py: -------------------------------------------------------------------------------- 1 | from re import sub 2 | 3 | from pyrogram.types import InlineKeyboardButton, InlineKeyboardMarkup, CallbackQuery 4 | from pyrogram.errors import MessageNotModified 5 | 6 | from bot.helpers import * 7 | from main import CREATOR 8 | 9 | 10 | def block_list(lang: str) -> str: 11 | """ 12 | Generate the blocked users list. 13 | :param lang: user language like in the keys of 'languages' 14 | """ 15 | msg = MSG('block_list', lang) 16 | for i in data['ban']: 17 | user = get_user(int(i)) 18 | msg += format_message('{link} ({uid})\n', user) if user else i 19 | msg += '**~empty~**' if not data['ban'] else '' 20 | return msg 21 | 22 | 23 | @db_session 24 | def admin_list(lang: str) -> str: 25 | """ 26 | Generate the admins list. 27 | :param lang: user language like in the keys of 'languages' 28 | """ 29 | msg = '' 30 | for admin in get_admins().values(): 31 | if admin.uid == CREATOR: 32 | msg = format_message('🎖 {link} ({uid})\n', admin) + msg 33 | else: 34 | msg += format_message('🥇 {link} ({uid})\n', admin) 35 | return MSG('admin_list', lang) + msg 36 | 37 | 38 | def get_settings_keyboard(lang: str) -> InlineKeyboardMarkup: 39 | """ 40 | Generate the admins settings keyboard. 41 | :param lang: user language like in the keys of 'languages' 42 | """ 43 | return InlineKeyboardMarkup([ 44 | [InlineKeyboardButton(MSG('button_lang', lang), callback_data='lang')], 45 | [ 46 | InlineKeyboardButton(MSG('button_remove_welcome', lang), 47 | callback_data='explain_welcome'), 48 | InlineKeyboardButton('✅' if data['start_msg'] else '☑️', 49 | callback_data='on_welcome'), 50 | ], 51 | [InlineKeyboardButton(MSG('button_block_list', lang), 52 | callback_data='block_list')], 53 | [InlineKeyboardButton(MSG('button_admin_list', lang), 54 | callback_data='admin_list')] 55 | ]) 56 | 57 | 58 | def get_admin_help_keyboard(lang: str) -> InlineKeyboardMarkup: 59 | """ 60 | Generate the admins help keyboard. 61 | :param lang: user language like in the keys of 'languages' 62 | """ 63 | return InlineKeyboardMarkup([ 64 | [InlineKeyboardButton(MSG('button_block', lang), 'block'), 65 | InlineKeyboardButton(MSG('button_admins', lang), 'admins')], 66 | [InlineKeyboardButton(MSG('button_welcome', lang), 'welcome'), 67 | InlineKeyboardButton(MSG('button_group', lang), 'group')] 68 | ]) 69 | 70 | 71 | @Client.on_message(is_admin & filters.private & filters.text & 72 | filters.command(COMMANDS['welcome'])) 73 | @Client.on_edited_message(is_admin & filters.private & filters.text & 74 | filters.command(COMMANDS['welcome'])) 75 | def start_msg(_, m: Message): 76 | """ 77 | Handler function to set or update the start message. 78 | [read more about format text](https://core.telegram.org/bots/api#formatting-options) 79 | :param _: pyrogram Client, unused argument 80 | :param m: the command message. 81 | message arguments: 82 | `$id` - replaced with the user Telegram id 83 | `$first_name` - replaced with the user Telegram first name 84 | `$last_name` - replaced with the user Telegram last name 85 | `$username` - replaced with the user Telegram username 86 | `$name` - replaced with the full name of the user 87 | """ 88 | text = m.text[len(m.command[0]) + 2:].replace('{', '{{').replace('}', '}}') 89 | text = text.replace('$id', '{uid}').replace('$first_name', "{first}") 90 | text = text.replace('$last_name', '{last}').replace('$username', '{username}') 91 | text = text.replace('$name', '{name}').replace(r'|', '||') 92 | text = sub(r'~', '~~', sub(r'_', '__', sub(r'-', '--', text))) 93 | text = sub(r'\\--', '-', sub(r'\\__', '_', sub(r'\*', '**', text))) 94 | text = sub(r'\\~~', '~', sub(r'\\\|\|', r'|', sub(r'\\\*\*', '*', text))) 95 | try: 96 | m.reply(format_message(text, get_user(m.from_user.id))).delete() 97 | except RPCError: 98 | return m.reply(MSG('format_err', get_user(m.from_user.id).language)) 99 | data['start_msg'] = text 100 | save_data() 101 | m.reply(MSG('success_welcome', get_user(m.from_user.id).language), 102 | quote=True) 103 | 104 | 105 | @Client.on_message(filters.command('help') & filters.private) 106 | def info_and_help(_, m: Message): 107 | """ 108 | Send the help message. 109 | :param _: pyrogram Client, unused argument 110 | :param m: the `/help` command message. 111 | """ 112 | user = get_user(m.from_user.id) 113 | lang = user.language 114 | if user.is_admin: 115 | return m.reply(MSG('admins_help', lang), disable_web_page_preview=True, 116 | reply_markup=get_admin_help_keyboard(lang)) 117 | else: 118 | return m.reply( 119 | MSG('users_help', lang), disable_web_page_preview=True, 120 | reply_markup=InlineKeyboardMarkup( 121 | [[InlineKeyboardButton(MSG('button_lang', lang), 'help_lang')]] 122 | )) 123 | 124 | 125 | @Client.on_message(filters.command(COMMANDS['settings']) & is_admin & filters.private) 126 | def settings_keyboard(_, m: Message): 127 | """ 128 | Send the settings keyboard on a command 129 | :param _: pyrogram Client, unused argument 130 | :param m: the command message. 131 | """ 132 | m.reply(MSG('settings_msg', get_user(m.from_user.id).language), 133 | reply_markup=get_settings_keyboard( 134 | get_user(m.from_user.id).language)) 135 | 136 | 137 | @Client.on_callback_query(is_admin) 138 | def refresh_admin_keyboards(_, query: CallbackQuery): 139 | """ 140 | Refreshing the settings and the help keyboards. 141 | :param _: pyrogram Client, unused argument 142 | :param query: when the user press the keyboard 143 | the query returns to this function. 144 | :type query: pyrogram.types.CallbackQuery 145 | """ 146 | lang = get_user(query.from_user.id).language 147 | keyboard = InlineKeyboardMarkup( 148 | [[InlineKeyboardButton(text=MSG('button_back', lang), 149 | callback_data='back')]]) 150 | try: 151 | if query.data == 'lang': 152 | for k in MSG.locales.keys(): 153 | keyboard.inline_keyboard.append( 154 | [InlineKeyboardButton(text=MSG(k), callback_data=k)]) 155 | return query.message.edit(MSG('chang_lang', lang), 156 | reply_markup=keyboard) 157 | elif query.data == 'explain_welcome': 158 | return query.answer(MSG('explain_welcome', lang), show_alert=True, 159 | cache_time=60) 160 | elif query.data == 'on_welcome': 161 | if data['start_msg']: 162 | data['start_msg'] = '' 163 | save_data() 164 | query.answer(MSG('welcome_removed', lang), show_alert=True) 165 | return query.message.edit_reply_markup(get_settings_keyboard(lang)) 166 | elif query.data == 'admin_list': 167 | return query.message.edit(admin_list(lang), disable_web_page_preview=True, 168 | reply_markup=keyboard) 169 | elif query.data == 'block_list': 170 | return query.message.edit(block_list(lang), disable_web_page_preview=True, 171 | reply_markup=keyboard) 172 | elif query.data == 'back': 173 | return query.message.edit(MSG('settings_msg', lang), 174 | reply_markup=get_settings_keyboard(lang)) 175 | elif query.data in ['block', 'admins', 'welcome', 'group']: 176 | return query.message.edit(MSG(f'help_{query.data}', lang), 177 | disable_web_page_preview=True, 178 | reply_markup=get_admin_help_keyboard(lang)) 179 | except MessageNotModified: 180 | query.message.delete() 181 | 182 | 183 | @Client.on_callback_query(group=1) 184 | def change_lang_keyboard(_, query: CallbackQuery): 185 | """ 186 | Refreshing the user help keyboard by change the language or the 187 | settings. 188 | :param _: pyrogram Client, unused argument. 189 | :param query: when the user press the keyboard the query returns to this 190 | function. 191 | :type query: pyrogram.types.CallbackQuery 192 | """ 193 | if query.data == 'help_lang': 194 | keyboard = [[InlineKeyboardButton(text=MSG(lang), callback_data=lang 195 | )] for lang in MSG.locales.keys()] 196 | return query.message.edit( 197 | MSG('chang_lang', get_user(query.from_user.id).language), 198 | reply_markup=InlineKeyboardMarkup(keyboard)) 199 | elif query.data in MSG.locales.keys(): 200 | with db_session: 201 | get_user(query.from_user.id).language = query.data 202 | if get_user(query.from_user.id).is_admin: 203 | return query.edit_message_text( 204 | MSG('settings_msg', query.data), 205 | reply_markup=get_settings_keyboard(query.data)) 206 | else: 207 | return query.edit_message_text( 208 | MSG('users_help', query.data), disable_web_page_preview=True, 209 | reply_markup=InlineKeyboardMarkup( 210 | [[InlineKeyboardButton(MSG('button_lang', query.data), 'help_lang')]] 211 | )) 212 | --------------------------------------------------------------------------------