def setvotes_command(bot, message): report_botan(message, 'slave_setvotes_cmd') yield bot.send_message(pgettext('New required votes count request', 'Set new amount of required votes'), reply_to_message=message, reply_markup=ForceReply(True)) return True
def ban_command(bot, callback_query, user_id): report_botan(callback_query, 'slave_ban_cmd') if int(user_id) == bot.owner_id: yield bot.answer_callback_query( callback_query['id'], pgettext('Somebody trying to ban the owner', 'It\'s not allowed to ban the bot owner')) return None if int(user_id) == callback_query['from']['id']: yield bot.answer_callback_query( callback_query['id'], pgettext('Somebody trying to ban himself', 'It\'s not allowed to ban yourself')) return None cur = yield bot.db.execute( 'SELECT banned_at FROM users WHERE bot_id = %s AND user_id = %s', (bot.bot_id, user_id)) row = cur.fetchone() if row and row[0]: yield bot.answer_callback_query( callback_query['id'], pgettext('User already banned', 'User already banned')) return None msg = pgettext('Ban reason request', 'Please enter a ban reason for the user, @{moderator_username}')\ .format(moderator_username=callback_query['from']['username']) yield bot.send_message(msg, chat_id=bot.moderator_chat_id, reply_markup=ForceReply(True)) yield bot.answer_callback_query(callback_query['id']) return {'user_id': user_id}
def check_votes_failures(self): vote_timeout = datetime.now() - timedelta( hours=self.settings.get('vote_timeout', 24)) cur = yield self.db.execute( 'SELECT message,' '(SELECT SUM(vote_yes::INT) FROM votes_history vh WHERE vh.message_id = im.id ' ' AND vh.original_chat_id = im.original_chat_id)' 'FROM incoming_messages im WHERE bot_id = %s AND ' 'is_voting_success = FALSE AND is_voting_fail = FALSE AND created_at <= %s', (self.bot_id, vote_timeout)) for message, yes_votes in cur.fetchall(): if yes_votes is None: yes_votes = 0 report_botan(message, 'slave_verification_failed') try: yield self.decline_message(message, yes_votes) except: logging.exception( '[bot #%d] Got exception while declining message', self.bot_id) if not self._finished.is_set(): IOLoop.current().add_timeout(timedelta(minutes=10), self.check_votes_failures)
def change_start_command(bot, message, **kwargs): report_botan(message, 'boterator_change_start_cmd') yield bot.send_message(pgettext( '/setstart response', 'Ok, I\'m listening to you. How I should say hello to your authors?'), reply_to_message=message) return True
def publish_message(self, message, moderation_message_id): report_botan(message, 'slave_publish') try: conn = yield self.db.getconn() with self.db.manage(conn): try: yield conn.execute('BEGIN') cur = yield conn.execute( 'UPDATE incoming_messages SET is_published = TRUE WHERE id = %s AND original_chat_id = %s AND ' 'is_published = FALSE', (message['message_id'], message['chat']['id'])) if cur.rowcount == 0: yield conn.execute('ROLLBACK') return yield conn.execute('UPDATE registered_bots SET last_channel_message_at = NOW() WHERE id = %s', (self.bot_id,)) yield self.api.forward_message(self.target_channel, message['chat']['id'], message['message_id']) yield conn.execute('COMMIT') except: yield conn.execute('ROLLBACK') raise msg, keyboard = yield self.get_verification_message(message['message_id'], message['chat']['id'], True) yield self.edit_message_text(msg, chat_id=self.moderator_chat_id, message_id=moderation_message_id, reply_markup=keyboard) except: logging.exception('Message forwarding failed (#%s from %s)', message['message_id'], message['chat']['id'])
def publish_message(self, message, moderation_message_id): report_botan(message, 'slave_publish') try: conn = yield self.db.getconn() with self.db.manage(conn): try: yield conn.execute('BEGIN') cur = yield conn.execute( 'UPDATE incoming_messages SET is_published = TRUE WHERE id = %s AND original_chat_id = %s AND ' 'is_published = FALSE', (message['message_id'], message['chat']['id'])) if cur.rowcount == 0: yield conn.execute('ROLLBACK') return yield conn.execute('UPDATE registered_bots SET last_channel_message_at = NOW() WHERE id = %s', (self.bot_id,)) yield self.api.forward_message(self.target_channel, message['chat']['id'], message['message_id']) yield conn.execute('COMMIT') except: yield conn.execute('ROLLBACK') raise msg, keyboard = yield self.get_verification_message(message['message_id'], message['chat']['id'], True) yield self.edit_message_text(msg, chat_id=self.moderator_chat_id, message_id=moderation_message_id, reply_markup=keyboard) except: logging.exception('[bot #%d] Message forwarding failed (#%s from %s)', self.bot_id, message['message_id'], message['chat']['id'])
def ban_command(bot, callback_query, user_id, chat_id=None, message_id=None): report_botan(callback_query, 'slave_ban_cmd') if int(user_id) == callback_query['from']['id']: yield bot.answer_callback_query(callback_query['id'], pgettext('Somebody trying to ban himself', 'It\'s not allowed to ban yourself')) return None if int(user_id) == bot.owner_id: yield bot.answer_callback_query(callback_query['id'], pgettext('Somebody trying to ban the owner', 'It\'s not allowed to ban the bot owner')) return None cur = yield bot.db.execute('SELECT banned_at FROM users WHERE bot_id = %s AND user_id = %s', (bot.bot_id, user_id)) row = cur.fetchone() if row and row[0]: yield bot.answer_callback_query(callback_query['id'], pgettext('User already banned', 'User already banned')) return None msg = pgettext('Ban reason request', 'Please enter a ban reason for the user, @{moderator_username}')\ .format(moderator_username=callback_query['from']['username']) if chat_id and message_id: fwd_id = yield bot.get_message_fwd_id(chat_id, message_id) else: fwd_id = None yield bot.send_message(msg, chat_id=bot.moderator_chat_id, reply_markup=ForceReply(True), reply_to_message_id=fwd_id) yield bot.answer_callback_query(callback_query['id']) return { 'user_id': user_id }
def vote_old(bot, message, original_chat_id, message_id, vote_type): report_botan(message, 'slave_vote_yes') yield __vote(bot, message_id, original_chat_id, vote_type == 'yes', message=message)
def vote_new(bot, callback_query, original_chat_id, message_id, vote_type): report_botan(callback_query, 'slave_vote_yes') yield __vote(bot, message_id, original_chat_id, vote_type == 'yes', callback_query=callback_query)
def plaintext_reject_handler(bot, message, chat_id, message_id): msg = message['text'].strip() if len(msg) < 10: report_botan(message, 'slave_reply_short_msg') yield bot.send_message(pgettext( 'Reject message is too short', 'Reject message is too short (10 symbols required), try ' 'again or send /cancel'), reply_to_message=message, reply_markup=ForceReply(True)) else: yield bot.decline_message( { 'chat': { 'id': chat_id }, 'message_id': message_id }, 0, False) try: yield bot.send_message(pgettext( 'Message to user in case of rejection', "Your post has been rejected. " "Reason:\n> {reject_reason}").format(reject_reason=msg), chat_id=chat_id, reply_to_message_id=message_id) yield bot.send_message(pgettext('Rejection delivery confirmation', 'Message sent and post rejected'), reply_to_message=message) except Exception as e: yield bot.send_message( pgettext('Rejection failed', 'Message sending failed: {reason}').format(reason=str(e)), reply_to_message=message) return True
def setdelay_command(bot, message): report_botan(message, 'slave_setdelay_cmd') yield bot.send_message(pgettext( 'New delay request', 'Set new delay value for messages posting (in minutes)'), reply_to_message=message, reply_markup=ForceReply(True)) return True
def new_chat(bot, message): if message['new_chat_member']['id'] == bot.bot_id and message['chat'][ 'id'] == bot.moderator_chat_id: report_botan(message, 'slave_renew_chat') yield bot.db.execute( 'UPDATE registered_bots SET active = TRUE WHERE id = %s', (bot.bot_id, )) else: return False
def settimeout_command(bot, message): report_botan(message, 'slave_settimeout_cmd') yield bot.send_message(pgettext( 'New voting duration request', 'Set new voting duration value (in hours, only a ' 'digits)'), reply_to_message=message, reply_markup=ForceReply(True)) return True
def change_allowed_command(bot, message): report_botan(message, 'slave_change_allowed_cmd') yield bot.send_message(pgettext( '/changeallowed response', 'You can see current status on keyboard, just click on ' 'content type to change it\'s status'), reply_to_message=message, reply_markup=build_contenttype_keyboard(bot)) return True
def unban_command(bot, message, user_id): report_botan(message, 'slave_unban_cmd') yield bot.db.execute('UPDATE users SET banned_at = NULL, ban_reason = NULL WHERE user_id = %s AND ' 'bot_id = %s', (user_id, bot.id)) yield bot.send_message(pgettext('Unban confirmation', 'User unbanned'), reply_to_message=message) try: yield bot.send_message(pgettext('User notification in case of unban', 'Access restored'), chat_id=user_id) except: pass
def toggletagpolls_command(bot, message): report_botan(message, 'slave_toggletagpolls_cmd') if bot.settings.get('tag_polls'): yield bot.update_settings(message['from']['id'], tag_polls=False) yield bot.send_message(pgettext('Polls tagging disabled', 'State tags shall not pass.'), reply_to_message=message) else: yield bot.update_settings(message['from']['id'], tag_polls=True) yield bot.send_message(pgettext('Polls tagging enabled', 'State tags will be added to future polls.'), reply_to_message=message)
def reject_command(bot, callback_query, chat_id, message_id): report_botan(callback_query, 'slave_reject_cmd') msg = pgettext('Reject message request', 'Please enter a reject reason, @{moderator_username}?') \ .format(moderator_username=callback_query['from'].get('username', callback_query['from']['id'])) yield bot.send_message(msg, chat_id=bot.moderator_chat_id, reply_markup=ForceReply(True)) yield bot.answer_callback_query(callback_query['id']) return { 'chat_id': chat_id, 'message_id': message_id, }
def togglevoteswitch_command(bot, message): report_botan(message, 'slave_togglevoteswitch_cmd') if bot.settings.get('allow_vote_switch'): yield bot.update_settings(message['from']['id'], allow_vote_switch=False) yield bot.send_message(pgettext('Vote switching disabled', 'From now Moderators can NOT switch their votes'), reply_to_message=message) else: yield bot.update_settings(message['from']['id'], allow_vote_switch=True) yield bot.send_message(pgettext('Vote switching enabled', 'From now Moderators can switch their votes'), reply_to_message=message)
def togglepower_command(bot, message): report_botan(message, 'slave_togglepower_cmd') if bot.settings.get('power'): yield bot.update_settings(message['from']['id'], power=False) yield bot.send_message(pgettext('Power mode disabled', 'From now other chat users can not modify bot settings'), reply_to_message=message) else: yield bot.update_settings(message['from']['id'], power=True) yield bot.send_message(pgettext('Power mode enabled', 'From now other chat users can modify bot settings (only ' 'inside moderators chat)'), reply_to_message=message)
def help_command(bot, message): report_botan(message, 'slave_help') delay_str = npgettext('Delay between channel messages', '{delay} minute', '{delay} minutes', bot.settings['delay']) timeout_str = npgettext('Voting timeout', '{timeout} hour', '{timeout} hours', bot.settings['vote_timeout']) power_state = 'on' if bot.settings.get('power') else 'off' power_state_str = pgettext('Boolean settings', power_state) public_vote_state = 'on' if bot.settings.get('public_vote') else 'off' public_vote_state_str = pgettext('Boolean settings', public_vote_state) selfvote_state = 'on' if bot.settings.get('selfvote') else 'off' selfvote_state_str = pgettext('Boolean settings', selfvote_state) start_web_preview_state = 'on' if bot.settings.get( 'start_web_preview') else 'off' start_web_preview_state_str = pgettext('Boolean settings', start_web_preview_state) voteswitch_state = 'on' if bot.settings.get('allow_vote_switch') else 'off' voteswitch_state_str = pgettext('Boolean settings', voteswitch_state) tag_polls_state = 'on' if bot.settings.get('tag_polls') else 'off' tag_polls_state_str = pgettext('Boolean settings', tag_polls_state) if bot.settings.get('msg_freq_limit'): fl = bot.settings['msg_freq_limit'] freq_limit_msg_str = npgettext('Messages count', '{msg} message', '{msg} messages', fl[0]).format(msg=fl[0]) freq_limit_days_str = npgettext('Days', '{n} day', '{n} days', fl[1]).format(n=fl[1]) freq_limit_str = pgettext('Frequency limit', '{messages_str} per {days_str}') \ .format(messages_str=freq_limit_msg_str, days_str=freq_limit_days_str) else: freq_limit_str = pgettext('No frequency limit', 'unlimited') msg = pgettext('/help command response', 'bot.help.response') \ .format(current_delay_with_minutes=delay_str.format(delay=bot.settings['delay']), current_votes_required=bot.settings['votes'], current_timeout_with_hours=timeout_str.format(timeout=bot.settings['vote_timeout']), thumb_up_sign=Emoji.THUMBS_UP_SIGN, thumb_down_sign=Emoji.THUMBS_DOWN_SIGN, current_start_message=bot.settings['start'], power_state=power_state_str, public_vote_state=public_vote_state_str, current_text_limit={'min': bot.settings['text_min'], 'max': bot.settings['text_max']}, selfvote_state=selfvote_state_str, start_web_preview_state=start_web_preview_state_str, current_freqlimit=freq_limit_str, voteswitch_state=voteswitch_state_str, tag_polls_state=tag_polls_state_str) try: yield bot.send_message(msg, reply_to_message=message, parse_mode=bot.PARSE_MODE_MD, disable_web_page_preview=True) except: yield bot.send_message(msg, reply_to_message=message, disable_web_page_preview=True)
def plaintext_ban_handler(bot, message, user_id): chat_id = message['chat']['id'] cur = yield bot.db.execute( 'SELECT banned_at FROM users WHERE bot_id = %s AND user_id = %s', (bot.bot_id, user_id)) row = cur.fetchone() if row and row[0]: yield bot.send_message(pgettext( 'Somebody banned a user faster than another one', 'Somebody already banned the user. Be faster next time.'), reply_to_message=message) return True msg = message['text'].strip() if len(msg) < 5: report_botan(message, 'slave_ban_short_msg') yield bot.send_message(pgettext( 'Ban reason too short', 'Reason is too short (5 symbols required), ' 'try again or send /cancel'), reply_to_message=message, reply_markup=ForceReply(True)) else: report_botan(message, 'slave_ban_success') yield bot.send_chat_action(chat_id, bot.CHAT_ACTION_TYPING) try: yield bot.send_message(pgettext( 'Message to user in case of ban', "You've been banned from further communication with this bot. " "Reason:\n> {ban_reason}").format(ban_reason=msg), chat_id=user_id) except: pass cur = yield bot.db.execute( 'SELECT message FROM incoming_messages WHERE bot_id = %s AND owner_id = %s AND ' 'is_voting_success = FALSE AND is_voting_fail = FALSE AND is_published = FALSE', ( bot.id, user_id, )) while True: row = cur.fetchone() if not row: break yield bot.decline_message(row[0], 0, False) yield bot.db.execute( 'UPDATE users SET banned_at = NOW(), ban_reason = %s WHERE user_id = %s AND ' 'bot_id = %s', (msg, user_id, bot.id)) yield bot.send_message(pgettext('Ban confirmation', 'User banned'), reply_to_message=message) return True
def toggleselfvote_command(bot, message): report_botan(message, 'slave_toggleselfvote_cmd') if bot.settings.get('selfvote'): yield bot.update_settings(message['from']['id'], selfvote=False) yield bot.send_message(pgettext('Self-vote disabled', 'From now moderators WILL NOT be able to vote for own ' 'messages.'), reply_to_message=message) else: yield bot.update_settings(message['from']['id'], selfvote=True) yield bot.send_message(pgettext('Self-vote enabled', 'From now moderators WILL BE able to vote for own ' 'messages.'), reply_to_message=message)
def reply_command(bot, callback_query, chat_id, message_id): report_botan(callback_query, 'slave_reply_cmd') msg = pgettext('Reply message request', 'What message should I send to user, @{moderator_username}?') \ .format(moderator_username=callback_query['from'].get('username', callback_query['from']['id'])) fwd_id = yield bot.get_message_fwd_id(chat_id, message_id) yield bot.send_message(msg, chat_id=bot.moderator_chat_id, reply_markup=ForceReply(True), reply_to_message_id=fwd_id) yield bot.answer_callback_query(callback_query['id']) return { 'chat_id': chat_id, 'message_id': message_id, }
def toggle_start_web_preview_command(bot, message): report_botan(message, 'slave_toggle_start_web_preview_cmd') if bot.settings.get('start_web_preview'): yield bot.update_settings(message['from']['id'], start_web_preview=False) yield bot.send_message(pgettext('Web preview disabled in /start', 'From now web previews WILL NOT BE generated ' 'for links in /start message.'), reply_to_message=message) else: yield bot.update_settings(message['from']['id'], start_web_preview=True) yield bot.send_message(pgettext('Web preview enabled in /start', 'From now web previews WILL BE generated for ' 'links in /start message.'), reply_to_message=message)
def plaintext_timeout_handler(bot, message): if message['text'].isdigit() and int(message['text']) > 0: report_botan(message, 'slave_settimeout') yield bot.update_settings(message['from']['id'], vote_timeout=int(message['text'])) yield bot.send_message(pgettext('Voting duration successfully changed', 'Voting duration updated'), reply_to_message=message) return True else: report_botan(message, 'slave_settimeout_invalid') yield bot.send_message(pgettext('Invalid voting duration value', 'Invalid voting duration value. Try again or ' 'type /cancel'), reply_to_message=message, reply_markup=ForceReply(True))
def togglevote_command(bot, message): report_botan(message, 'slave_togglevote_cmd') if bot.settings.get('public_vote'): yield bot.update_settings(message['from']['id'], public_vote=False) yield bot.send_message(pgettext('Vote status displaying disabled', 'From now other chat users WILL NOT see ' 'current votes distribution.'), reply_to_message=message) else: yield bot.update_settings(message['from']['id'], public_vote=True) yield bot.send_message(pgettext('Vote status displaying enabled', 'From now other chat users WILL see current ' 'votes distribution.'), reply_to_message=message)
def plaintext_startmessage_handler(bot, message): if message['text'] and len(message['text'].strip()) > 10: report_botan(message, 'slave_setstartmessage') yield bot.update_settings(message['from']['id'], start=message['text'].strip()) yield bot.send_message(pgettext('Start message successfully changed', 'Start message updated'), reply_to_message=message) return True else: report_botan(message, 'slave_setstartmessage_invalid') yield bot.send_message(pgettext('Too short start message entered', 'Invalid start message, you should write at ' 'least 10 symbols. Try again or type ' '/cancel'), reply_to_message=message, reply_markup=ForceReply(True))
def plaintext_votes_handler(bot, message): if message['text'].isdigit() and int(message['text']) > 0: report_botan(message, 'slave_setvotes') yield bot.update_settings(message['from']['id'], votes=int(message['text'])) yield bot.send_message(pgettext('Required votes count successfully changed', 'Required votes ' 'amount updated'), reply_to_message=message) return True else: report_botan(message, 'slave_setvotes_invalid') yield bot.send_message(pgettext('Invalid votes amount value', 'Invalid votes amount value. Try again or type ' '/cancel'), reply_to_message=message, reply_markup=ForceReply(True))
def toggletagpolls_command(bot, message): report_botan(message, 'slave_toggletagpolls_cmd') if bot.settings.get('tag_polls'): yield bot.update_settings(message['from']['id'], tag_polls=False) yield bot.send_message(pgettext('Polls tagging disabled', 'State tags shall not pass.'), reply_to_message=message) else: yield bot.update_settings(message['from']['id'], tag_polls=True) yield bot.send_message(pgettext( 'Polls tagging enabled', 'State tags will be added to future polls.'), reply_to_message=message)
def plaintext_set_start_message(bot, message, **kwargs): text = message['text'].strip() if len(text) >= 10: report_botan(message, 'boterator_change_start_success') yield bot.send_message(pgettext('/start message updated', 'Ok, noted, now tell me the channel name'), reply_to_message=message) kwargs['settings']['start'] = text return { 'settings': kwargs['settings'] } else: report_botan(message, 'boterator_change_start_short') yield bot.send_message(pgettext('/start message is too short', 'Hey, you should write at least 10 symbols'), reply_to_message=message)
def reply_command(bot, callback_query, chat_id, message_id): report_botan(callback_query, 'slave_reply_cmd') msg = pgettext('Reply message request', 'What message should I send to user, @{moderator_username}?') \ .format(moderator_username=callback_query['from'].get('username', callback_query['from']['id'])) fwd_id = yield bot.get_message_fwd_id(chat_id, message_id) yield bot.send_message(msg, chat_id=bot.moderator_chat_id, reply_markup=ForceReply(True), reply_to_message_id=fwd_id) yield bot.answer_callback_query(callback_query['id']) return { 'chat_id': chat_id, 'message_id': message_id, }
def togglepower_command(bot, message): report_botan(message, 'slave_togglepower_cmd') if bot.settings.get('power'): yield bot.update_settings(message['from']['id'], power=False) yield bot.send_message(pgettext( 'Power mode disabled', 'From now other chat users can not modify bot settings'), reply_to_message=message) else: yield bot.update_settings(message['from']['id'], power=True) yield bot.send_message(pgettext( 'Power mode enabled', 'From now other chat users can modify bot settings (only ' 'inside moderators chat)'), reply_to_message=message)
def plaintext_reply_handler(bot, message, chat_id, message_id): msg = message['text'].strip() if len(msg) < 10: report_botan(message, 'slave_reply_short_msg') yield bot.send_message(pgettext('Reply message is too short', 'Message is too short (10 symbols required), try ' 'again or send /cancel'), reply_to_message=message, reply_markup=ForceReply(True)) else: try: yield bot.send_message(msg, chat_id=chat_id, reply_to_message_id=message_id) yield bot.send_message(pgettext('Reply delivery confirmation', 'Message sent'), reply_to_message=message) except Exception as e: yield bot.send_message(pgettext('Reply failed', 'Failed: {reason}').format(reason=str(e)), reply_to_message=message) return True
def plaintext_set_start_message(bot, message, **kwargs): text = message['text'].strip() if len(text) >= 10: report_botan(message, 'boterator_change_start_success') yield bot.send_message(pgettext( '/start message updated', 'Ok, noted, now tell me the channel name'), reply_to_message=message) kwargs['settings']['start'] = text return {'settings': kwargs['settings']} else: report_botan(message, 'boterator_change_start_short') yield bot.send_message(pgettext( '/start message is too short', 'Hey, you should write at least 10 symbols'), reply_to_message=message)
def toggleselfvote_command(bot, message): report_botan(message, 'slave_toggleselfvote_cmd') if bot.settings.get('selfvote'): yield bot.update_settings(message['from']['id'], selfvote=False) yield bot.send_message(pgettext( 'Self-vote disabled', 'From now moderators WILL NOT be able to vote for own ' 'messages.'), reply_to_message=message) else: yield bot.update_settings(message['from']['id'], selfvote=True) yield bot.send_message(pgettext( 'Self-vote enabled', 'From now moderators WILL BE able to vote for own ' 'messages.'), reply_to_message=message)
def plaintext_delay_handler(bot, message): if message['text'].isdigit() and int(message['text']) >= 0: report_botan(message, 'slave_setdelay') yield bot.update_settings(message['from']['id'], delay=int(message['text'])) yield bot.send_message(pgettext('Messages delay successfully changed', 'Delay value updated'), reply_to_message=message) return True else: report_botan(message, 'slave_setdelay_invalid') yield bot.send_message(pgettext( 'Invalid delay value', 'Invalid delay value. Try again or type /cancel'), reply_to_message=message, reply_markup=ForceReply(True))
def plaintext_timeout_handler(bot, message): if message['text'].isdigit() and int(message['text']) > 0: report_botan(message, 'slave_settimeout') yield bot.update_settings(message['from']['id'], vote_timeout=int(message['text'])) yield bot.send_message(pgettext('Voting duration successfully changed', 'Voting duration updated'), reply_to_message=message) return True else: report_botan(message, 'slave_settimeout_invalid') yield bot.send_message(pgettext( 'Invalid voting duration value', 'Invalid voting duration value. Try again or ' 'type /cancel'), reply_to_message=message, reply_markup=ForceReply(True))
def start_command(bot, message): report_botan(message, 'slave_start') username = message['from'].get('username', message['from']['first_name']) if message['from'].get('first_name', '').strip(): username = message['from']['first_name'].strip() if message['from'].get('last_name', '').strip(): username += ' ' + message['from']['last_name'].strip() username = username.replace('_', r'\_').replace('*', r'\*').replace('`', r'\`').replace('[', r'\[') msg = bot.settings['start'].replace('%user%', username) try: yield bot.send_message(msg, reply_to_message=message, parse_mode=bot.PARSE_MODE_MD, disable_web_page_preview=not bot.settings['start_web_preview']) except: yield bot.send_message(msg, reply_to_message=message, disable_web_page_preview=not bot.settings['start_web_preview'])
def reg_command(bot, message): report_botan(message, 'boterator_reg') yield bot.send_message(pgettext('/reg response', 'Ok, please tell me the token, which you\'ve received from ' '@BotFather'), reply_to_message=message) slave_settings = deepcopy(DEFAULT_SLAVE_SETTINGS) slave_settings['locale'] = bot.get_settings(message['from']['id']).get('locale', 'en_US') locale = tornado.locale.get(slave_settings['locale']) slave_settings['hello'].locale = locale slave_settings['hello'] = str(slave_settings['hello']) slave_settings['start'].locale = locale slave_settings['start'] = str(slave_settings['start']) return { 'settings': slave_settings, 'owner_id': message['from']['id'], }
def toggle_start_web_preview_command(bot, message): report_botan(message, 'slave_toggle_start_web_preview_cmd') if bot.settings.get('start_web_preview'): yield bot.update_settings(message['from']['id'], start_web_preview=False) yield bot.send_message(pgettext( 'Web preview disabled in /start', 'From now web previews WILL NOT BE generated ' 'for links in /start message.'), reply_to_message=message) else: yield bot.update_settings(message['from']['id'], start_web_preview=True) yield bot.send_message(pgettext( 'Web preview enabled in /start', 'From now web previews WILL BE generated for ' 'links in /start message.'), reply_to_message=message)
def plaintext_votes_handler(bot, message): if message['text'].isdigit() and int(message['text']) > 0: report_botan(message, 'slave_setvotes') yield bot.update_settings(message['from']['id'], votes=int(message['text'])) yield bot.send_message(pgettext( 'Required votes count successfully changed', 'Required votes ' 'amount updated'), reply_to_message=message) return True else: report_botan(message, 'slave_setvotes_invalid') yield bot.send_message(pgettext( 'Invalid votes amount value', 'Invalid votes amount value. Try again or type ' '/cancel'), reply_to_message=message, reply_markup=ForceReply(True))
def plaintext_contenttype_handler(bot, message): try: split = message['text'].split(' ') action_type, content_type = split[0], ' '.join(split[1:]) if action_type == Emoji.MEDIUM_SMALL_WHITE_CIRCLE: action_type = True elif action_type == Emoji.CIRCLED_BULLET: action_type = False else: raise ValueError() updated_content_type = content_type[0].upper( ) + content_type[1:].lower() content_status = bot.settings['content_status'] translations = types_translations(bot) content_types_list = dict( zip(translations.values(), translations.keys())) if updated_content_type in content_types_list: content_type_raw = content_types_list[updated_content_type] content_status[content_type_raw] = action_type yield bot.update_settings(message['from']['id'], content_status=content_status) else: raise ValueError() action_text = 'enable' if action_type else 'disable' report_botan(message, 'slave_content_' + content_type_raw + '_' + action_text) msg = content_type_raw[0].upper( ) + content_type_raw[1:] + 's ' + action_text + 'd' yield bot.send_message(pgettext('Content type enabled/disabled', msg), reply_to_message=message, reply_markup=build_contenttype_keyboard(bot)) except: yield bot.send_message(pgettext('Invalid user response', 'Wrong input'), reply_to_message=message)
def help_command(bot, message): report_botan(message, 'slave_help') delay_str = npgettext('Delay between channel messages', '{delay} minute', '{delay} minutes', bot.settings['delay']) timeout_str = npgettext('Voting timeout', '{timeout} hour', '{timeout} hours', bot.settings['vote_timeout']) power_state = 'on' if bot.settings.get('power') else 'off' power_state_str = pgettext('Boolean settings', power_state) public_vote_state = 'on' if bot.settings.get('public_vote') else 'off' public_vote_state_str = pgettext('Boolean settings', public_vote_state) selfvote_state = 'on' if bot.settings.get('selfvote') else 'off' selfvote_state_str = pgettext('Boolean settings', selfvote_state) start_web_preview_state = 'on' if bot.settings.get('start_web_preview') else 'off' start_web_preview_state_str = pgettext('Boolean settings', start_web_preview_state) voteswitch_state = 'on' if bot.settings.get('allow_vote_switch') else 'off' voteswitch_state_str = pgettext('Boolean settings', voteswitch_state) tag_polls_state = 'on' if bot.settings.get('tag_polls') else 'off' tag_polls_state_str = pgettext('Boolean settings', tag_polls_state) if bot.settings.get('msg_freq_limit'): fl = bot.settings['msg_freq_limit'] freq_limit_msg_str = npgettext('Messages count', '{msg} message', '{msg} messages', fl[0]).format(msg=fl[0]) freq_limit_days_str = npgettext('Days', '{n} day', '{n} days', fl[1]).format(n=fl[1]) freq_limit_str = pgettext('Frequency limit', '{messages_str} per {days_str}') \ .format(messages_str=freq_limit_msg_str, days_str=freq_limit_days_str) else: freq_limit_str = pgettext('No frequency limit', 'unlimited') msg = pgettext('/help command response', 'bot.help.response') \ .format(current_delay_with_minutes=delay_str.format(delay=bot.settings['delay']), current_votes_required=bot.settings['votes'], current_timeout_with_hours=timeout_str.format(timeout=bot.settings['vote_timeout']), thumb_up_sign=Emoji.THUMBS_UP_SIGN, thumb_down_sign=Emoji.THUMBS_DOWN_SIGN, current_start_message=bot.settings['start'], power_state=power_state_str, public_vote_state=public_vote_state_str, current_text_limit={'min': bot.settings['text_min'], 'max': bot.settings['text_max']}, selfvote_state=selfvote_state_str, start_web_preview_state=start_web_preview_state_str, current_freqlimit=freq_limit_str, voteswitch_state=voteswitch_state_str, tag_polls_state=tag_polls_state_str) try: yield bot.send_message(msg, reply_to_message=message, parse_mode=bot.PARSE_MODE_MD, disable_web_page_preview=True) except: yield bot.send_message(msg, reply_to_message=message, disable_web_page_preview=True)
def cbq_message_review(bot, callback_query, sent_message): user_id = callback_query['from']['id'] report_botan(callback_query, 'slave_confirm') yield bot.db.execute(""" INSERT INTO incoming_messages (id, original_chat_id, owner_id, bot_id, created_at, message) VALUES (%s, %s, %s, %s, NOW(), %s) """, (sent_message['message_id'], sent_message['chat']['id'], user_id, bot.bot_id, dumps(sent_message))) bot.send_moderation_request(sent_message['chat']['id'], sent_message['message_id']) yield bot.db.execute('UPDATE registered_bots SET last_moderation_message_at = NOW() WHERE id = %s', (bot.bot_id,)) yield bot.edit_message_text(pgettext('Message sent for verification', 'Okay, I\'ve sent your message for ' 'verification. Fingers crossed!'), callback_query['message']) yield bot.answer_callback_query(callback_query['id']) return True
def check_votes_failures(self): vote_timeout = datetime.now() - timedelta(hours=self.settings.get('vote_timeout', 24)) cur = yield self.db.execute('SELECT message,' '(SELECT SUM(vote_yes::INT) FROM votes_history vh WHERE vh.message_id = im.id ' ' AND vh.original_chat_id = im.original_chat_id)' 'FROM incoming_messages im WHERE bot_id = %s AND ' 'is_voting_success = FALSE AND is_voting_fail = FALSE AND created_at <= %s', (self.bot_id, vote_timeout)) for message, yes_votes in cur.fetchall(): if yes_votes is None: yes_votes = 0 report_botan(message, 'slave_verification_failed') try: yield self.decline_message(message, yes_votes) except: logging.exception('[bot #%d] Got exception while declining message', self.bot_id) if not self._finished.is_set(): IOLoop.current().add_timeout(timedelta(minutes=10), self.check_votes_failures)
def plaintext_ban_handler(bot, message, user_id): chat_id = message['chat']['id'] cur = yield bot.db.execute('SELECT banned_at FROM users WHERE bot_id = %s AND user_id = %s', (bot.bot_id, user_id)) row = cur.fetchone() if row and row[0]: yield bot.send_message(pgettext('Somebody banned a user faster than another one', 'Somebody already banned the user. Be faster next time.'), reply_to_message=message) return True msg = message['text'].strip() if len(msg) < 5: report_botan(message, 'slave_ban_short_msg') yield bot.send_message(pgettext('Ban reason too short', 'Reason is too short (5 symbols required), ' 'try again or send /cancel'), reply_to_message=message, reply_markup=ForceReply(True)) else: report_botan(message, 'slave_ban_success') yield bot.send_chat_action(chat_id, bot.CHAT_ACTION_TYPING) try: yield bot.send_message(pgettext('Message to user in case of ban', "You've been banned from further communication with this bot. " "Reason:\n> {ban_reason}").format(ban_reason=msg), chat_id=user_id) except: pass cur = yield bot.db.execute('SELECT message FROM incoming_messages WHERE bot_id = %s AND owner_id = %s AND ' 'is_voting_success = FALSE AND is_voting_fail = FALSE AND is_published = FALSE', (bot.id, user_id,)) while True: row = cur.fetchone() if not row: break yield bot.decline_message(row[0], 0, False) yield bot.db.execute('UPDATE users SET banned_at = NOW(), ban_reason = %s WHERE user_id = %s AND ' 'bot_id = %s', (msg, user_id, bot.id)) yield bot.send_message(pgettext('Ban confirmation', 'User banned'), reply_to_message=message) return True
def plaintext_post_handler(bot, message): if bot.settings['content_status']['text'] is False: yield bot.bot.send_message(pgettext('User send text message for verification while texts is disabled', 'Accepting text messages are disabled'), reply_to_message=message) return mes = message['text'] if mes.strip() != '': if bot.settings['text_min'] <= len(mes) <= bot.settings['text_max']: yield _request_message_confirmation(bot, message) report_botan(message, 'slave_message') return { 'sent_message': message } else: report_botan(message, 'slave_message_invalid') yield bot.send_message(pgettext('Incorrect text message received', 'Sorry, but we can proceed only ' 'messages with length between ' '{min_msg_length} and {max_msg_length} ' 'symbols.') .format(min_msg_length=format_number(bot.settings['text_min'], bot.language), max_msg_length=format_number(bot.settings['text_max'], bot.language)), reply_to_message=message) else: report_botan(message, 'slave_message_empty') yield bot.send_message(pgettext('User sent empty message', 'Seriously??? 8===3'), reply_to_message=message)
def ban_list_command(bot, message): chat_id = message['chat']['id'] report_botan(message, 'slave_ban_list_cmd') yield bot.send_chat_action(chat_id, bot.CHAT_ACTION_TYPING) cur = yield bot.db.execute('SELECT user_id, first_name, last_name, username, banned_at, ban_reason ' 'FROM users WHERE bot_id = %s AND ' 'banned_at IS NOT NULL ORDER BY banned_at DESC', (bot.bot_id,)) bans = cur.fetchall() msg = '{}\n' * len(bans) if len(bans) > 0 else '' msg = msg.strip() data = [] for row_id, (user_id, first_name, last_name, username, banned_at, ban_reason) in enumerate(bans): if first_name and last_name: user = first_name + ' ' + last_name elif first_name: user = first_name else: user = '******' % user_id data.append(pgettext('Ban user item', '{row_id}. {user} - {ban_reason} (banned {ban_date}) {unban_cmd}') \ .format(row_id=row_id + 1, user=user, ban_reason=ban_reason, ban_date=banned_at.strftime('%Y-%m-%d'), unban_cmd='/unban_%s' % (user_id,))) msg = msg.format(*data) if msg: yield bot.send_message(msg, reply_to_message=message) if chat_id != bot.moderator_chat_id: yield bot.send_message(pgettext('Bot owner notification', 'You can use /unban command only in moderators ' 'group'), reply_to_message=message) else: yield bot.send_message(pgettext('Ban list is empty', 'No banned users yet'), reply_to_message=message)
def multimedia_post_handler(bot, message): if 'sticker' in message and bot.settings['content_status']['sticker'] is False: yield bot.send_message(pgettext('User sent a sticker for verification while stickers are disabled', 'Accepting stickers is disabled'), reply_to_message=message) return elif 'audio' in message and bot.settings['content_status']['audio'] is False: yield bot.send_message(pgettext('User sent an audio for verification while audios are disabled', 'Accepting audios is disabled'), reply_to_message=message) return elif 'voice' in message and bot.settings['content_status']['voice'] is False: yield bot.send_message(pgettext('User sent a voice for verification while voices are disabled', 'Accepting voice is disabled'), reply_to_message=message) return elif 'video' in message and bot.settings['content_status']['video'] is False: yield bot.send_message(pgettext('User sent a video for verification while videos are disabled', 'Accepting videos is disabled'), reply_to_message=message) return elif 'photo' in message and bot.settings['content_status']['photo'] is False: yield bot.send_message(pgettext('User sent a photo for verification while photos are disabled', 'Accepting photos is disabled'), reply_to_message=message) return elif 'document' in message and bot.settings['content_status']['document'] is False and \ message['document'].get('mime_type') != 'video/mp4': yield bot.send_message(pgettext('User sent a document for verification while documents are disabled', 'Accepting documents is disabled'), reply_to_message=message) return elif 'document' in message and bot.settings['content_status']['gif'] is False and \ message['document'].get('mime_type') == 'video/mp4': yield bot.send_message(pgettext('User sent a gif for verification while gifs are disabled', 'Accepting gifs is disabled'), reply_to_message=message) return report_botan(message, 'slave_message_multimedia') yield _request_message_confirmation(bot, message) return { 'sent_message': message }
def plaintext_contenttype_handler(bot, message): try: split = message['text'].split(' ') action_type, content_type = split[0], ' '.join(split[1:]) if action_type == Emoji.MEDIUM_SMALL_WHITE_CIRCLE: action_type = True elif action_type == Emoji.CIRCLED_BULLET: action_type = False else: raise ValueError() updated_content_type = content_type[0].upper() + content_type[1:].lower() content_status = bot.settings['content_status'] translations = types_translations(bot) content_types_list = dict(zip(translations.values(), translations.keys())) if updated_content_type in content_types_list: content_type_raw = content_types_list[updated_content_type] content_status[content_type_raw] = action_type yield bot.update_settings(message['from']['id'], content_status=content_status) else: raise ValueError() action_text = 'enable' if action_type else 'disable' report_botan(message, 'slave_content_' + content_type_raw + '_' + action_text) msg = content_type_raw[0].upper() + content_type_raw[1:] + 's ' + action_text + 'd' yield bot.send_message(pgettext('Content type enabled/disabled', msg), reply_to_message=message, reply_markup=build_contenttype_keyboard(bot)) except: yield bot.send_message(pgettext('Invalid user response', 'Wrong input'), reply_to_message=message)
def settimeout_command(bot, message): report_botan(message, 'slave_settimeout_cmd') yield bot.send_message(pgettext('New voting duration request', 'Set new voting duration value (in hours, only a ' 'digits)'), reply_to_message=message, reply_markup=ForceReply(True)) return True
def change_start_command(bot, message, **kwargs): report_botan(message, 'boterator_change_start_cmd') yield bot.send_message(pgettext('/setstart response', 'Ok, I\'m listening to you. How I should say hello to your authors?'), reply_to_message=message) return True
def plaintext_token(bot, message, **kwargs): token = message['text'].strip() if token == '': report_botan(message, 'boterator_token_empty') yield bot.send_message(pgettext('Empty token entered', 'I guess you forgot to enter the token :)'), reply_to_message=message) else: if len(token.split(':')) != 2 or not token.split(':')[0].isdigit(): report_botan(message, 'boterator_token_invalid') yield bot.send_message(pgettext('Non-well formatted token', 'Token is incorrect. And I can do nothing with ' 'that.'), reply_to_message=message) return yield bot.send_chat_action(message['chat']['id'], bot.CHAT_ACTION_TYPING) try: new_bot_info = yield queue_request(bot.queue, QUEUE_SLAVEHOLDER_GET_BOT_INFO, token=token, timeout=10) except: yield bot.send_message(pgettext('Unable to validate token', 'Unable to validate token right now, please ' 'try again later'), reply_to_message=message) return if new_bot_info.get('error'): if new_bot_info['error'] == 'duplicate': report_botan(message, 'boterator_token_duplicate') yield bot.send_message(pgettext('Provided token is already registered and alive', 'It seems like this bot is already registered. Try to create another ' 'one'), reply_to_message=message) return else: report_botan(message, 'boterator_token_failure') yield bot.send_message(pgettext('Token check failed', 'Unable to get bot info: {}') \ .format(new_bot_info['error']), reply_to_message=message) return msg = pgettext('Token received', "Ok, I\'ve got basic information for @{bot_username_escaped}\n" 'Now add him to a group of moderators (or copy and paste `/attach@{bot_username}` to the ' 'group, in case you\'ve already added him), where I should send messages for verification, or ' 'type /cancel') bot_username_escaped = new_bot_info['username'].replace('_', r'\_') kwargs['settings']['hello'] = kwargs['settings']['hello'].format(bot_username=new_bot_info['username']) msg.format(bot_username_escaped=bot_username_escaped, bot_username=new_bot_info['username']) yield bot.send_message(msg, reply_to_message=message, parse_mode=bot.PARSE_MODE_MD) report_botan(message, 'boterator_token') try: chat = yield queue_request(bot.queue, QUEUE_SLAVEHOLDER_GET_MODERATION_GROUP, token=token, timeout=600) except: try: yield bot.send_message(pgettext('Unable to receive moderation group', 'Unable to receive moderation group. Send me bot`s token if you would ' 'like to try again.'), reply_to_message=message) except: pass return yield bot.send_chat_action(message['chat']['id'], bot.CHAT_ACTION_TYPING) if chat['type'] == 'private': chat['title'] = '@' + chat['sender']['username'] kwargs['settings']['votes'] = 1 elif not chat['title']: chat['title'] = '<no title>' msg = pgettext('Slave attached to moderator`s channel', "Ok, I'll be sending moderation requests to {chat_type} {chat_title}\n" "Now you need to add your bot (@{bot_username_escaped}) to a channel as administrator and tell " "me the channel name (e.g. @mobilenewsru)\n" "As soon as I will receive the channel name I'll send a message with following text:\n> " "{current_hello}\n" "You can change the message, if you mind, just send me /sethello.\n" "Also there is 'start' message for your new bot:\n> {current_start}\n" "You can change it with /setstart.") msg.format(chat_type=chat['type'], chat_title=chat['title'], bot_username_escaped=bot_username_escaped, current_hello=kwargs['settings']['hello'], current_start=kwargs['settings']['start']) try: yield bot.send_message(msg, reply_to_message=message, parse_mode=bot.PARSE_MODE_MD) except: yield bot.send_message(msg, reply_to_message=message) report_botan(message, 'boterator_slave_attached_to_channel') return { 'id': new_bot_info['id'], 'moderator_chat_id': chat['id'], 'chat': chat, 'token': token, 'settings': kwargs['settings'], 'bot_info': new_bot_info, }
def new_chat(bot, message): if message['new_chat_member']['id'] == bot.bot_id and message['chat']['id'] == bot.moderator_chat_id: report_botan(message, 'slave_renew_chat') yield bot.db.execute('UPDATE registered_bots SET active = TRUE WHERE id = %s', (bot.bot_id,)) else: return False
def setstartmessage_command(bot, message): report_botan(message, 'slave_setstartmessage_cmd') yield bot.send_message(pgettext('New start message request', 'Set new start message'), reply_to_message=message, reply_markup=ForceReply(True)) return True