diff --git a/CHANGELOG.md b/CHANGELOG.md index 0dd197b..aef7a61 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,14 @@ +## [0.0.11] + +- отображение одобренности заявки на кнопке +- разрешения по умолчанию для unmute_member +- исправлены ошибки перепроверки заявок на старте +- фильтрация вступления в чат обратной связи +- исправлен kick/approve на старте +- сообщение во все чаты, если отменили все одобрения +- ответы учитываются только от админов FEEDBACK-чата + + ## [0.0.10] - добавлено фото к заявке пользователя, если есть diff --git a/tgbot/api.py b/tgbot/api.py index d7aaf30..23b6986 100644 --- a/tgbot/api.py +++ b/tgbot/api.py @@ -22,7 +22,7 @@ def delete_message(cid: str, mid: str): # https://core.telegram.org/bots/api#sendmessage def send_message(cid: str, body, reply_to=None, reply_markup=None): - url = apiBase + f"sendMessage?chat_id={cid}&text={body}" + url = f"sendMessage?chat_id={cid}&text={body}" if reply_to: url += f'&reply_to_message_id={reply_to}' if reply_markup: @@ -30,12 +30,13 @@ def send_message(cid: str, body, reply_to=None, reply_markup=None): reply_markup = requests.utils.quote(reply_markup) url += f'&reply_markup={reply_markup}' url += f'&parse_mode=html' - r = requests.post(url) + print(url) + r = requests.post(apiBase + url) return r.json() # https://core.telegram.org/bots/api#sendphoto def send_photo(cid: str, file_id: str, caption="", reply_to=None, reply_markup=None): - url = apiBase + f"sendPhoto?chat_id={cid}&photo={file_id}" + url = f"sendPhoto?chat_id={cid}&photo={file_id}&caption={caption}" if reply_to: url += f'&reply_to_message_id={reply_to}' if reply_markup: @@ -43,7 +44,8 @@ def send_photo(cid: str, file_id: str, caption="", reply_to=None, reply_markup=N reply_markup = requests.utils.quote(reply_markup) url += f'&reply_markup={reply_markup}' url += f'&parse_mode=html' - r = requests.post(url) + print(url) + r = requests.post(apiBase + url) return r.json() @@ -88,8 +90,21 @@ def mute_member(chat_id, member_id): # https://core.telegram.org/bots/api#restrictchatmember -def unmute_member(chat_id, member_id): - chat_permissions = json.dumps({ "can_send_messages": True }) +def unmute_member(chat_id, member_id, chat_permissions=None): + if not chat_permissions: + chat_permissions = json.dumps({ + "can_send_messages": True, + "can_send_photos": True, + "can_send_other_messages": True, + "can_send_polls": True, + "can_add_web_page_previews": True, + "can_send_audios": True, + "can_invite_users": True, + "can_send_voice_notes": True, + "can_send_video_notes": True, + "can_send_videos": True, + "can_send_documents": True + }) chat_permissions = requests.utils.quote(chat_permissions) url = apiBase + f'restrictChatMember?chat_id={chat_id}' + \ f'&user_id={member_id}&permissions={chat_permissions}' + \ @@ -145,4 +160,27 @@ def get_member(chat_id, member_id): def get_userphotos(user_id): url = apiBase + f"getUserProfilePhotos?user_id={user_id}" r = requests.get(url) + return r.json() + +# https://core.telegram.org/bots/api#editmessagereplymarkup +def edit_replymarkup(cid, mid, reply_markup): + url = apiBase + f"editMessageText?chat_id={cid}&message_id={mid}&reply_markup={text}" + r = requests.post(url) + return r.json() + + +# https://core.telegram.org/bots/api#getchat +def get_chat(cid): + url = apiBase + f"getChat?chat_id={cid}" + r = requests.get(url) + return r.json() + + +# https://core.telegram.org/bots/api#banchatmember +def kick_member(chat_id, member_id): + url = f"banChatSenderChat?chat_id={cid}&user_id={member_id}" + r = requests.post(apiBase + url) + print(r.json()) + url = f"unbanChatSenderChat?chat_id={cid}&user_id={member_id}&only_if_banned=1" + r = requests.post(apiBase + url) return r.json() \ No newline at end of file diff --git a/tgbot/handlers/callback_unlink.py b/tgbot/handlers/callback_unlink.py index 83a3573..9fa1e08 100644 --- a/tgbot/handlers/callback_unlink.py +++ b/tgbot/handlers/callback_unlink.py @@ -1,5 +1,6 @@ -from tgbot.api import send_message, delete_message +from tgbot.api import send_message, delete_message, kick_member from tgbot.handlers.command_my import handle_command_my +from tgbot.utils.mention import userdata_extract from tgbot.storage import Profile # remove link of callback sender @@ -29,7 +30,14 @@ def handle_unlink(callback_query): if len(actor['children']) > 0: handle_command_my(callback_query) - # если больше никто не поручился - мьютим + # если больше никто не поручился - kick out if len(linked['parents']) == 0: + lang = callback_query['from'].get('language_code', 'ru') for chat_id in linked['chats']: - mute_member(chat_id, linked_id) \ No newline at end of file + r = kick_member(chat_id, linked_id) + print(r) + if r['ok']: + _, identity, username = userdata_extract(linked['result']['user']) + body = ('Участник %s%s был удалён' if lang == 'ru' else 'Member %s%s was deleted') % (identity, username) + r = send_message(chat_id, body) + print(r) \ No newline at end of file diff --git a/tgbot/handlers/callback_vouch.py b/tgbot/handlers/callback_vouch.py index 219fb55..45ae8f3 100644 --- a/tgbot/handlers/callback_vouch.py +++ b/tgbot/handlers/callback_vouch.py @@ -1,5 +1,6 @@ -from tgbot.api import send_message, forward_message, delete_message, approve_chat_join_request, unmute_member -from tgbot.storage import Profile +from tgbot.api import send_message, forward_message, delete_message, \ + approve_chat_join_request, unmute_member, edit_replymarkup, get_chat +from tgbot.storage import Profile, storage def handle_button(callback_query): @@ -38,7 +39,27 @@ def handle_button(callback_query): r = approve_chat_join_request(chat_id, newcomer_id) print(r) - if not r.get('ok'): + print('update reply markup') + prevmsg_id = storage.get(f'btn-{chat_id}-{newcomer_id}').decode('utf-8') + amount = len(newcomer['parents']) + 1 + rm = { + "inline_keyboard": [ + [ + { + "text": '❤️' + f'({amount})', + "callback_data": 'vouch' + newcomer_id + } + ] + ] + } + r = edit_replymarkup(chat_id, premsg_id, reply_markup=rm) + print(r) + + if not r.get('ok'): + print('getting chat permissions') + r = get_chat(chat_id) + print(r) + perms = r['result']['permissions'] print('try to unmute newcomer') - r = unmute_member(chat_id, newcomer_id) + r = unmute_member(chat_id, newcomer_id, chat_permissions=perms) print(r) \ No newline at end of file diff --git a/tgbot/handlers/handle_feedback.py b/tgbot/handlers/handle_feedback.py index fcf069b..1bac75c 100644 --- a/tgbot/handlers/handle_feedback.py +++ b/tgbot/handlers/handle_feedback.py @@ -27,7 +27,11 @@ def handle_feedback(msg): def handle_answer(msg): answered_msg = msg['reply_to_message'] - if answered_msg['from']['is_bot']: + r = get_chat_administrators(msg['chat']['id']) + print(r) + for a in r['result']: + admins.append(a['user']['id']) + if answered_msg['from']['is_bot'] and msg['from']['id'] in admins: support_msg_id = str(answered_msg['message_id']) # получение сохраненного информации о сообщении для ответа stored_feedback = storage.get(f'fbk-{support_msg_id}') diff --git a/tgbot/handlers/handle_members_change.py b/tgbot/handlers/handle_members_change.py index 6722f16..536a231 100644 --- a/tgbot/handlers/handle_members_change.py +++ b/tgbot/handlers/handle_members_change.py @@ -1,6 +1,7 @@ from tgbot.handlers.send_button import show_request_msg from tgbot.api import unmute_member, mute_member, delete_message from tgbot.storage import Profile, storage +from tgbot.config import FEEDBACK_CHAT_ID def handle_join(msg): chat_id = str(msg['chat']['id']) @@ -10,7 +11,7 @@ def handle_join(msg): newcomer_id = str(msg['new_chat_member']['id']) if from_id == newcomer_id: - if len(actor['parents']) == 0: + if len(actor['parents']) == 0 and chat_id != FEEDBACK_CHAT_ID: # показываем сообщение с кнопкой "поручиться" show_request_msg(msg) @@ -43,7 +44,7 @@ def handle_left(msg): # удаление сообщения с кнопкой в этом чате prev_msg = storage.get(f'btn-{chat_id}-{member_id}') - if prev_msg_id: + if prev_msg: r = delete_message(chat_id, prev_msg['id']) print(r) storage.remove(f'btn-{chat_id}-{member_id}') diff --git a/tgbot/handlers/handle_startup.py b/tgbot/handlers/handle_startup.py index 8dfda91..b990028 100644 --- a/tgbot/handlers/handle_startup.py +++ b/tgbot/handlers/handle_startup.py @@ -1,18 +1,27 @@ from tgbot.storage import scan, Profile +from tgbot.api import approve_chat_join_request, kick_member +from tgbot.utils.mention import userdata_extract # устанавливает соответствие данных def handle_startup(): btn_ids, btns = scan(match='btn-*', count=100) for btnid in btn_ids: # для каждой ранее созданной кнопки - try: - btnid_str = btnid.decode("utf-8") - chat_id, member_id = btnid_str[3:].split('-') - - newcomer = Profile.get(member_id) - if len(newcomer.get('parents', [])) > 0: - # принять заявку если её нажимали - r = approve_chat_join_request(chat_id, member_id) - print(r) - except: - print(f'error {btnid}') \ No newline at end of file + btnid_str = btnid.decode("utf-8").replace("btn-", "") + parts = btnid_str.split('-') + print(parts) + _, chat_id, member_id = parts + chat_id = "-" + chat_id + newcomer = Profile.get(member_id) + if len(newcomer.get('parents', [])) > 0: + # принять заявку если её нажимали + r = approve_chat_join_request(chat_id, member_id) + print(r) + elif len(newcomer.get('parents', [])) == 0: + r = kick_member(chat_id, member_id) + print(r) + if r['ok']: + _, identity, username = userdata_extract(newcomer['result']['user']) + body = ('Участник %s%s был удалён' if lang == 'ru' else 'Member %s%s was deleted') % (identity, username) + r = send_message(chat_id, body) + print(r) \ No newline at end of file diff --git a/tgbot/handlers/send_button.py b/tgbot/handlers/send_button.py index 45d370f..3866f8d 100644 --- a/tgbot/handlers/send_button.py +++ b/tgbot/handlers/send_button.py @@ -1,5 +1,5 @@ from tgbot.api import send_message, send_photo, get_userphotos -from tgbot.utils.mention import mention +from tgbot.utils.mention import mention, userdata_extract from tgbot.storage import storage def show_request_msg(msg): @@ -10,7 +10,7 @@ def show_request_msg(msg): "inline_keyboard": [ [ { - "text": 'Моё одобрение' if lang == 'ru' else 'My connection', + "text": '❤️', "callback_data": 'vouch' + from_id } ] @@ -21,15 +21,18 @@ def show_request_msg(msg): r = get_userphotos(user_id=from_id) print(r) if r['ok'] and r['result']['total_count'] > 0: + print('show button with photo') file_id = r['result']['photos'][0][0]['file_id'] + _uid, identity, username = userdata_extract(msg['from']) r = send_photo( chat_id, file_id, - caption=newcomer_message + mention(msg['from']), + caption=newcomer_message + f'{identity}{username}', reply_to=msg.get('message_id', ''), reply_markup=reply_markup ) else: + print('show button without photo') r = send_photo( chat_id, newcomer_message + mention(msg['from']),