def cmd_all(bot, update, chat=None): subscriptions = list( Subscription.select().where(Subscription.tg_chat == chat)) if len(subscriptions) == 0: return bot.reply(update, 'You have no subscriptions, so no tweets to show!') text = "" for sub in subscriptions: if sub.last_tweet is None: text += "\n{screen_name}: <no tweets yet>".format( screen_name=escape_markdown(sub.tw_user.screen_name), ) else: text += ("\n{screen_name}:\n{text} " "[link](https://twitter.com/{screen_name}/status/{tw_id})" ).format( text=markdown_twitter_usernames( escape_markdown(sub.last_tweet.text)), tw_id=sub.last_tweet.tw_id, screen_name=escape_markdown(sub.tw_user.screen_name), ) bot.reply(update, text, disable_web_page_preview=True, parse_mode=telegram.ParseMode.MARKDOWN)
def cmd_all(bot, update, chat=None): subscriptions = list(Subscription.select().where( Subscription.tg_chat == chat)) if len(subscriptions) == 0: return bot.reply(update, 'You have no subscriptions, so no tweets to show!') text = "" for sub in subscriptions: if sub.last_tweet is None: text += "\n{screen_name}: <no tweets yet>".format( screen_name=escape_markdown(sub.tw_user.screen_name), ) else: text += ("\n{screen_name}:\n{text} " "[link](https://twitter.com/{screen_name}/status/{tw_id})").format( text=markdown_twitter_usernames(escape_markdown(sub.last_tweet.text)), tw_id=sub.last_tweet.tw_id, screen_name=escape_markdown(sub.tw_user.screen_name), ) bot.reply(update, text, disable_web_page_preview=True, parse_mode=telegram.ParseMode.MARKDOWN)
def cmd_all(update: telegram.Update, context: CallbackContext) -> None: bot = context.bot chat, _created = TelegramChat.get_or_create( chat_id=update.message.chat.id, tg_type=update.message.chat.type, ) subscriptions = list( Subscription.select().where(Subscription.tg_chat == chat)) if len(subscriptions) == 0: return bot.reply(update, 'You have no subscriptions, so no tweets to show!') text = "" for sub in subscriptions: if sub.last_tweet is None: text += "\n{screen_name}: <no tweets yet>".format( screen_name=escape_markdown(sub.tw_user.screen_name), ) else: text += ("\n{screen_name}:\n{text} " "[link](https://twitter.com/{screen_name}/status/{tw_id})" ).format( text=markdown_twitter_usernames( escape_markdown(sub.last_tweet.text)), tw_id=sub.last_tweet.tw_id, screen_name=escape_markdown(sub.tw_user.screen_name), ) bot.reply(update, text, disable_web_page_preview=True, parse_mode=telegram.ParseMode.MARKDOWN)
def set_text_property(bot, update, chat_data, property_name, to_edit=None): uid = util.uid_from_update(update) user = User.from_update(update) if check_suggestion_limit(bot, update, user): return if to_edit: text = (util.escape_markdown(getattr(to_edit, property_name)) + "\n\n" if getattr(to_edit, property_name) else '') text += mdformat.action_hint( messages.SET_BOTPROPERTY.format( property_name, util.escape_markdown(to_edit.username), CLEAR_QUERY)) if property_name == 'description': text += ', markdown enabled.' update.effective_message.reply_text( text, reply_markup=ForceReply(selective=True), parse_mode=ParseMode.MARKDOWN) chat_data['edit_bot'] = to_edit elif update.message: value = None text = update.message.text to_edit = chat_data.get('edit_bot', None) def too_long(n): bot.formatter.send_failure( uid, "Your {} text is too long, it must be shorter " "than {} characters. Please try again.".format( property_name, n)) util.wait(bot, update) return admin.edit_bot(bot, update, chat_data, to_edit) # Validation if property_name == 'description' and len(text) > 300: return too_long(300) if property_name == 'username': value = helpers.validate_username(text) if value: to_edit = chat_data.get('edit_bot', None) else: bot.formatter.send_failure( uid, "The username you entered is not valid. Please try again..." ) return admin.edit_bot(bot, update, chat_data, to_edit) if not value: value = text if to_edit: if _is_clear_query(text): Suggestion.add_or_update(user, property_name, to_edit, None) else: Suggestion.add_or_update(user, property_name, to_edit, value) admin.edit_bot(bot, update, chat_data, to_edit) else: bot.formatter.send_failure(uid, "An unexpected error occured.")
def markdown_short(self): displayname = '' if self.first_name: displayname = util.escape_markdown(self.first_name) if self.username: text = '[👤 {}](https://t.me/{})'.format(displayname, util.escape_markdown(self.username)) else: text = displayname return text.encode('utf-8').decode('utf-8')
def detail_text(self): from model import Keyword keywords = Keyword.select().where(Keyword.entity == self) txt = '{}'.format(self.__str__()) txt += '\n_{}_'.format(util.escape_markdown( self.name)) if self.name else '' txt += '\n\n{}'.format(self.description) if self.description else '' txt += util.escape_markdown('\n\nKeywords: {}'.format(', '.join( [str(k) for k in keywords])) if keywords else '') return txt
def send_notification(self, message, **kwargs): self.send_message(settings.BOTLIST_NOTIFICATIONS_ID, util.escape_markdown(message), parse_mode='markdown', timeout=20, **kwargs) log.info(message)
def accept_suggestion(bot, update, suggestion: Suggestion): user = User.from_telegram_object(update.effective_user) suggestion.apply() if suggestion.action == 'offline': suggestion_text = '{} went {}.'.format( suggestion.subject.str_no_md, 'offline' if suggestion.subject.offline else 'online') else: suggestion_text = str(suggestion) suggestion_text = suggestion_text[0].upper() + suggestion_text[1:] suggestion_text += '\nApproved by ' + user.markdown_short bot.send_message(settings.BOTLIST_NOTIFICATIONS_ID, suggestion_text, parse_mode='markdown', disable_web_page_preview=True) if user != suggestion.user.chat_id: submittant_notification = '*Thank you* {}, your suggestion has been accepted:' \ '\n\n{}'.format(util.escape_markdown(suggestion.user.first_name), str(suggestion)) try: bot.send_message(suggestion.user.chat_id, submittant_notification, parse_mode='markdown', disable_web_page_preview=True) except BadRequest: update.effective_message.reply_text("Could not contact {}.".format( suggestion.user.markdown_short), parse_mode='markdown', disable_web_page_preview=True)
def set_keywords(bot, update, chat_data, to_edit): chat_id = util.uid_from_update(update) keywords = Keyword.select().where(Keyword.entity == to_edit) chat_data['edit_bot'] = to_edit set_keywords_msgid = chat_data.get('set_keywords_msg') kw_remove_buttons = [ InlineKeyboardButton('{} ✖️'.format(x), callback_data=util.callback_for_action( CallbackActions.REMOVE_KEYWORD, { 'id': to_edit.id, 'kwid': x.id })) for x in keywords ] buttons = util.build_menu( kw_remove_buttons, 2, header_buttons=[ InlineKeyboardButton(captions.DONE, callback_data=util.callback_for_action( CallbackActions.ABORT_SETTING_KEYWORDS, {'id': to_edit.id})) ]) reply_markup = InlineKeyboardMarkup(buttons) msg = util.send_or_edit_md_message( bot, chat_id, util.action_hint( 'Send me the keywords for {} one by one...\n\n{}'.format( util.escape_markdown(to_edit.username), messages.KEYWORD_BEST_PRACTICES)), to_edit=set_keywords_msgid, reply_markup=reply_markup) chat_data['set_keywords_msg'] = msg.message_id return BotStates.SENDING_KEYWORDS
def send_tweet(self, chat, tweet): try: self.logger.debug("Sending tweet {} to chat {}...".format( tweet.tw_id, chat.chat_id )) ''' Use a soft-hyphen to put an invisible link to the first image in the tweet, which will then be displayed as preview ''' photo_url = '' if tweet.photo_url: photo_url = '[\xad](%s)' % tweet.photo_url created_dt = utc.localize(tweet.created_at) if chat.timezone_name is not None: tz = timezone(chat.timezone_name) created_dt = created_dt.astimezone(tz) created_at = created_dt.strftime('%Y-%m-%d %H:%M:%S %Z') self.sendMessage( chat_id=chat.chat_id, disable_web_page_preview=not photo_url, text=""" {link_preview}*{name}* ([@{screen_name}](https://twitter.com/{screen_name})) at {created_at}: {text} -- [Link to this Tweet](https://twitter.com/{screen_name}/status/{tw_id}) """ .format( link_preview=photo_url, text=prepare_tweet_text(tweet.text), name=escape_markdown(tweet.name), screen_name=tweet.screen_name, created_at=created_at, tw_id=tweet.tw_id, ), parse_mode=telegram.ParseMode.MARKDOWN) except TelegramError as e: self.logger.info("Couldn't send tweet {} to chat {}: {}".format( tweet.tw_id, chat.chat_id, e.message )) delet_this = None if e.message == 'Bad Request: group chat was migrated to a supergroup chat': delet_this = True if e.message == "Unauthorized": delet_this = True if delet_this: self.logger.info("Marking chat for deletion") chat.delete_soon = True chat.save()
def send_tweet(self, chat, tweet): try: self.logger.debug("Sending tweet {} to chat {}...".format( tweet.tw_id, chat.chat_id )) ''' Use a soft-hyphen to put an invisible link to the first image in the tweet, which will then be displayed as preview ''' photo_url = '' if tweet.photo_url: photo_url = '[\xad](%s)' % tweet.photo_url created_dt = utc.localize(tweet.created_at) if chat.timezone_name is not None: tz = timezone(chat.timezone_name) created_dt = created_dt.astimezone(tz) created_at = created_dt.strftime('%Y-%m-%d %H:%M:%S %Z') self.sendMessage( chat_id=chat.chat_id, disable_web_page_preview=not photo_url, text=""" {link_preview}*{name}* ([@{screen_name}](https://twitter.com/{screen_name})) : {text} """ # -- [Enllaç a la piulada original](https://twitter.com/{screen_name}/status/{tw_id}) .format( link_preview=photo_url, text=prepare_tweet_text(tweet.text), name=escape_markdown(tweet.name), screen_name=tweet.screen_name, # created_at=created_at, # tw_id=tweet.tw_id, ), parse_mode=telegram.ParseMode.MARKDOWN) except TelegramError as e: self.logger.info("Couldn't send tweet {} to chat {}: {}".format( tweet.tw_id, chat.chat_id, e.message )) delet_this = None if e.message == 'Bad Request: group chat was migrated to a supergroup chat': delet_this = True if e.message == "Unauthorized": delet_this = True if delet_this: self.logger.info("Marking chat for deletion") chat.delete_soon = True chat.save()
def send_tweet(self, chat, tweet: Tweet): try: self.logger.debug("Sending tweet {} to chat {}...".format( tweet.id, chat.chat_id)) ''' Use a soft-hyphen to put an invisible link to the first image in the tweet, which will then be displayed as preview ''' media_url = '' if len(tweet.media_list) == 1: media_url = '[\xad](%s)' % tweet.media_list[0].url elif tweet.link_url: media_url = '[\xad](%s)' % tweet.link_url self.sendMessage(chat_id=chat.chat_id, disable_web_page_preview=not media_url, text=self.MESSAGE_TEMPLATE.format( link_preview=media_url, text=prepare_tweet_text(tweet.text), name=escape_markdown(tweet.user_name), screen_name=tweet.user_screen_name, id=tweet.id, ), parse_mode=telegram.ParseMode.MARKDOWN) if len(tweet.media_list) > 1: self.sendMediaGroup( chat_id=chat.chat_id, media=map(self.create_input_media, tweet.media_list), ) except TelegramError as e: self.logger.info("Couldn't send tweet {} to chat {}: {}".format( tweet.id, chat.chat_id, e.message)) delete_this = None if e.message == 'Bad Request: group chat was migrated to a supergroup chat': delete_this = True if e.message == "Unauthorized": delete_this = True if delete_this: self.logger.info("Marking chat for deletion") chat.delete_soon = True chat.save()
def _md_plaintext(self): uname = util.escape_markdown(self.subject.username) value = self.value text = '' if self.action == 'category': from models import Category try: cat = Category.get(id=self.value) text += "move {} ➜ {}".format(uname, cat.name) except Category.DoesNotExist: raise AttributeError("Category to change to does not exist.") elif self.action == 'name': text += "set name {} ➜ {}".format(uname, str(value)) elif self.action == 'username': text += "set username {} ➜ {}".format(uname, str(value)) elif self.action == 'description': text += "change description text of {}".format(uname) elif self.action == 'extra': text += "change extra text {}".format(uname) elif self.action == 'country': text += "change country {} ➜ ".format(uname) if self._value == 'None' or self._value is None: text += "None" else: from models import Country try: con = Country.get(id=self._value) text += str(con) except Country.DoesNotExist: raise AttributeError( "Country to change to does not exist.") elif self.action == 'inlinequeries': text += "toggle inlinequeries {} ➜ {}".format(uname, str(value)) elif self.action == 'official': text += "toggle official {} ➜ {}".format(uname, str(value)) elif self.action == 'offline': text += "set {} {}".format('💤' if bool(value) else 'online', uname) elif self.action == 'spam': text += "mark {} as spammy".format(uname) elif self.action == 'add_keyword': text += "add keyword #{} to {}".format(str(value), uname) elif self.action == 'remove_keyword': text += "remove keyword #{} from {}".format(str(value), uname) return text
def value(self): # cast types from models import Category from models import Country if self._value == 'None': return None if self.action in self.BOOLEAN_ACTIONS: return bool(self._value) elif self.action == 'category': return Category.get(id=self._value) elif self.action == 'country': if self._value is None: return None return Country.get(id=self._value) else: return util.escape_markdown(str( self._value)) if self._value else None
def search_query(bot, update, chat_data, query, send_errors=True): cid = update.effective_chat.id results = search.search_bots(query) is_admin = cid in settings.MODERATORS reply_markup = ReplyKeyboardMarkup( basic.main_menu_buttons(is_admin), resize_keyboard=True) if util.is_private_message(update) else None if results: if len(results) == 1: return send_bot_details(bot, update, chat_data, results[0]) too_many_results = len(results) > settings.MAX_SEARCH_RESULTS bots_list = '' if cid in settings.MODERATORS: # append edit buttons bots_list += '\n'.join([ "{} — /edit{} 🛃".format(b, b.id) for b in list(results)[:100] ]) else: bots_list += '\n'.join( [str(b) for b in list(results)[:settings.MAX_SEARCH_RESULTS]]) bots_list += '\n…' if too_many_results else '' bots_list = messages.SEARCH_RESULTS.format( bots=bots_list, num_results=len(results), plural='s' if len(results) > 1 else '', query=query) msg = update.message.reply_text(bots_list, parse_mode=ParseMode.MARKDOWN, reply_markup=reply_markup) else: if send_errors: update.message.reply_text(util.failure( "Sorry, I couldn't find anything related " "to *{}* in the @BotList. /search".format( util.escape_markdown(query))), parse_mode=ParseMode.MARKDOWN, reply_markup=reply_markup) return ConversationHandler.END
def __str__(self): return util.escape_markdown( self.str_no_md).encode('utf-8').decode('utf-8')
def callback_router(bot, update, chat_data, user_data, job_queue): obj = json.loads(str(update.callback_query.data)) user = User.from_update(update) try: if "a" in obj: action = obj["a"] # BOTLISTCHAT if action == CallbackActions.DELETE_CONVERSATION: botlistchat.delete_conversation(bot, update, chat_data) # HELP elif action == CallbackActions.HELP: help.help(bot, update) elif action == CallbackActions.CONTRIBUTING: help.contributing(bot, update) elif action == CallbackActions.EXAMPLES: help.examples(bot, update) # BASIC QUERYING elif action == CallbackActions.SELECT_CATEGORY: select_category(bot, update, chat_data) elif action == CallbackActions.SELECT_BOT_FROM_CATEGORY: category = Category.get(id=obj["id"]) send_category(bot, update, chat_data, category) elif action == CallbackActions.SEND_BOT_DETAILS: item = Bot.get(id=obj["id"]) send_bot_details(bot, update, chat_data, item) # FAVORITES elif action == CallbackActions.TOGGLE_FAVORITES_LAYOUT: value = obj["v"] favorites.toggle_favorites_layout(bot, update, value) elif action == CallbackActions.ADD_FAVORITE: favorites.add_favorite_handler(bot, update) elif action == CallbackActions.REMOVE_FAVORITE_MENU: favorites.remove_favorite_menu(bot, update) elif action == CallbackActions.REMOVE_FAVORITE: to_remove = Favorite.get(id=obj["id"]) bot_details = to_remove.bot to_remove.delete_instance() if obj.get("details"): send_bot_details(bot, update, chat_data, bot_details) else: favorites.remove_favorite_menu(bot, update) elif action == CallbackActions.SEND_FAVORITES_LIST: favorites.send_favorites_list(bot, update) elif action == CallbackActions.ADD_ANYWAY: favorites.add_custom(bot, update, obj["u"]) elif action == CallbackActions.ADD_TO_FAVORITES: details = obj.get("details") discreet = obj.get("discreet", False) or details item = Bot.get(id=obj["id"]) favorites.add_favorite(bot, update, item, callback_alert=discreet) if details: send_bot_details(bot, update, chat_data, item) # ACCEPT/REJECT BOT SUBMISSIONS elif action == CallbackActions.APPROVE_REJECT_BOTS: custom_approve_list = [Bot.get(id=obj["id"])] admin.approve_bots(bot, update, override_list=custom_approve_list) elif action == CallbackActions.ACCEPT_BOT: to_accept = Bot.get(id=obj["id"]) admin.edit_bot_category(bot, update, to_accept, CallbackActions.BOT_ACCEPTED) # Run in x minutes, giving the moderator enough time to edit bot details job_queue.run_once( lambda b, job: botlistchat. notify_group_submission_accepted(b, job, to_accept), settings.BOT_ACCEPTED_IDLE_TIME * 60, ) elif action == CallbackActions.RECOMMEND_MODERATOR: bot_in_question = Bot.get(id=obj["id"]) admin.recommend_moderator(bot, update, bot_in_question, obj["page"]) elif action == CallbackActions.SELECT_MODERATOR: bot_in_question = Bot.get(id=obj["bot_id"]) moderator = User.get(id=obj["uid"]) admin.share_with_moderator(bot, update, bot_in_question, moderator) admin.approve_bots(bot, update, obj["page"]) elif action == CallbackActions.REJECT_BOT: to_reject = Bot.get(id=obj["id"]) notification = obj.get("ntfc", True) admin.reject_bot_submission( bot, update, None, to_reject, verbose=False, notify_submittant=notification, ) admin.approve_bots(bot, update, obj["page"]) elif action == CallbackActions.BOT_ACCEPTED: to_accept = Bot.get(id=obj["bid"]) category = Category.get(id=obj["cid"]) admin.accept_bot_submission(bot, update, to_accept, category) elif action == CallbackActions.COUNT_THANK_YOU: new_count = obj.get("count", 1) basic.count_thank_you(bot, update, new_count) # ADD BOT # elif action == CallbackActions.ADD_BOT_SELECT_CAT: # category = Category.get(id=obj['id']) # admin.add_bot(bot, update, chat_data, category) # EDIT BOT elif action == CallbackActions.EDIT_BOT: to_edit = Bot.get(id=obj["id"]) admin.edit_bot(bot, update, chat_data, to_edit) elif action == CallbackActions.EDIT_BOT_SELECT_CAT: to_edit = Bot.get(id=obj["id"]) admin.edit_bot_category(bot, update, to_edit) elif action == CallbackActions.EDIT_BOT_CAT_SELECTED: to_edit = Bot.get(id=obj["bid"]) cat = Category.get(id=obj["cid"]) botproperties.change_category(bot, update, to_edit, cat) admin.edit_bot(bot, update, chat_data, to_edit) elif action == CallbackActions.EDIT_BOT_COUNTRY: to_edit = Bot.get(id=obj["id"]) botproperties.set_country_menu(bot, update, to_edit) elif action == CallbackActions.SET_COUNTRY: to_edit = Bot.get(id=obj["bid"]) if obj["cid"] == "None": country = None else: country = Country.get(id=obj["cid"]) botproperties.set_country(bot, update, to_edit, country) admin.edit_bot(bot, update, chat_data, to_edit) elif action == CallbackActions.EDIT_BOT_DESCRIPTION: to_edit = Bot.get(id=obj["id"]) botproperties.set_text_property(bot, update, chat_data, "description", to_edit) elif action == CallbackActions.EDIT_BOT_EXTRA: to_edit = Bot.get(id=obj["id"]) # SAME IS DONE HERE, but manually botproperties.set_text_property(bot, update, chat_data, "extra", to_edit) elif action == CallbackActions.EDIT_BOT_NAME: to_edit = Bot.get(id=obj["id"]) botproperties.set_text_property(bot, update, chat_data, "name", to_edit) elif action == CallbackActions.EDIT_BOT_USERNAME: to_edit = Bot.get(id=obj["id"]) botproperties.set_text_property(bot, update, chat_data, "username", to_edit) # elif action == CallbackActions.EDIT_BOT_KEYWORDS: # to_edit = Bot.get(id=obj['id']) # botproperties.set_keywords_init(bot, update, chat_data, to_edit) elif action == CallbackActions.APPLY_ALL_CHANGES: to_edit = Bot.get(id=obj["id"]) admin.apply_all_changes(bot, update, chat_data, to_edit) elif action == CallbackActions.EDIT_BOT_INLINEQUERIES: to_edit = Bot.get(id=obj["id"]) value = bool(obj["value"]) botproperties.toggle_value(bot, update, "inlinequeries", to_edit, value) admin.edit_bot(bot, update, chat_data, to_edit) elif action == CallbackActions.EDIT_BOT_OFFICIAL: to_edit = Bot.get(id=obj["id"]) value = bool(obj["value"]) botproperties.toggle_value(bot, update, "official", to_edit, value) admin.edit_bot(bot, update, chat_data, to_edit) elif action == CallbackActions.EDIT_BOT_OFFLINE: to_edit = Bot.get(id=obj["id"]) value = bool(obj["value"]) botproperties.toggle_value(bot, update, "offline", to_edit, value) admin.edit_bot(bot, update, chat_data, to_edit) elif action == CallbackActions.EDIT_BOT_SPAM: to_edit = Bot.get(id=obj["id"]) value = bool(obj["value"]) botproperties.toggle_value(bot, update, "spam", to_edit, value) admin.edit_bot(bot, update, chat_data, to_edit) elif action == CallbackActions.CONFIRM_DELETE_BOT: to_delete = Bot.get(id=obj["id"]) botproperties.delete_bot_confirm(bot, update, to_delete) elif action == CallbackActions.DELETE_BOT: to_edit = Bot.get(id=obj["id"]) botproperties.delete_bot(bot, update, to_edit) # send_category(bot, update, chat_data, to_edit.category) elif action == CallbackActions.ACCEPT_SUGGESTION: suggestion = Suggestion.get(id=obj["id"]) components.botproperties.accept_suggestion( bot, update, suggestion) admin.approve_suggestions(bot, update, page=obj["page"]) elif action == CallbackActions.REJECT_SUGGESTION: suggestion = Suggestion.get(id=obj["id"]) suggestion.delete_instance() admin.approve_suggestions(bot, update, page=obj["page"]) elif action == CallbackActions.CHANGE_SUGGESTION: suggestion = Suggestion.get(id=obj["id"]) botproperties.change_suggestion(bot, update, suggestion, page_handover=obj["page"]) elif action == CallbackActions.SWITCH_SUGGESTIONS_PAGE: page = obj["page"] admin.approve_suggestions(bot, update, page) elif action == CallbackActions.SWITCH_APPROVALS_PAGE: admin.approve_bots(bot, update, page=obj["page"]) elif action == CallbackActions.SET_NOTIFICATIONS: set_notifications(bot, update, obj["value"]) elif action == CallbackActions.NEW_BOTS_SELECTED: show_new_bots(bot, update, chat_data, back_button=True) elif action == CallbackActions.ABORT_SETTING_KEYWORDS: to_edit = Bot.get(id=obj["id"]) admin.edit_bot(bot, update, chat_data, to_edit) # SENDING BOTLIST elif action == CallbackActions.SEND_BOTLIST: silent = obj.get("silent", False) re_send = obj.get("re", False) botlist.send_botlist(bot, update, resend=re_send, silent=silent) elif action == CallbackActions.RESEND_BOTLIST: botlist.send_botlist(bot, update, resend=True) # BROADCASTING elif action == "send_broadcast": broadcasts.send_broadcast(bot, update, user_data) elif action == "pin_message": broadcasts.pin_message(bot, update, obj["mid"]) elif action == "add_thank_you": basic.add_thank_you_button(bot, update, obj["cid"], obj["mid"]) # EXPLORING elif action == CallbackActions.EXPLORE_NEXT: explore.explore(bot, update, chat_data) except Exception as e: traceback.print_exc() # get the callback action in plaintext actions = dict(CallbackActions.__dict__) a = next(k for k, v in actions.items() if v == obj.get("a")) util.send_md_message( bot, settings.DEVELOPER_ID, "Exception in callback query for {}:\n{}\n\nWith CallbackAction {}\n\nWith data:\n{}" .format( user.markdown_short, util.escape_markdown(e), util.escape_markdown(a), util.escape_markdown(str(obj)), ), ) finally: bot.answerCallbackQuery(update.callback_query.id) return ConversationHandler.END
def send_tweet(self, chat, tweet): try: self.logger.debug('Sending tweet {} to chat {}...'.format( tweet.tw_id, chat.chat_id)) ''' Use a soft-hyphen to put an invisible link to the first image in the tweet, which will then be displayed as preview ''' photo_url = '' if tweet.photo_url: photo_url = '[\xad](%s)' % tweet.photo_url created_dt = utc.localize(tweet.created_at) if chat.timezone_name is not None: tz = timezone(chat.timezone_name) created_dt = created_dt.astimezone(tz) created_at = created_dt.strftime('%Y-%m-%d %H:%M:%S %Z') retweet_text = '' if tweet.original_name: retweet_text = 'retweeted from *{}* '.format( tweet.original_name) self.sendMessage(chat_id=chat.chat_id, disable_web_page_preview=not photo_url, text=''' {link_preview}*{name}* ([@{screen_name}](https://twitter.com/{screen_name})) {retweet_text}at {created_at}: {text} — [Link to this Tweet](https://twitter.com/{screen_name}/status/{tw_id}) '''.format( link_preview=photo_url, text=prepare_tweet_text(tweet.text), name=escape_markdown(tweet.name), screen_name=tweet.screen_name, created_at=created_at, tw_id=tweet.tw_id, retweet_text=retweet_text, ), parse_mode=telegram.ParseMode.MARKDOWN) return True except TelegramError as e: self.logger.info('Couldn\'t send tweet {} to chat {}: {}'.format( tweet.tw_id, chat.chat_id, e.message)) #self.logger.debug('\ttweet text: {}'.format(prepare_tweet_text(tweet.text))) delet_this = None if e.message == 'Forbidden: bot was blocked by the user': delet_this = True if e.message == 'Bad Request: group chat was migrated to a supergroup chat': delet_this = True if e.message == 'Unauthorized': delet_this = True if delet_this: self.logger.info('Marking chat for deletion') chat.delete_soon = True chat.save() return False
def __format_entity(self): if self.action == 'command': return '/' + self.entity if self.action == 'menu': return util.escape_markdown(self.entity.title()) return util.escape_markdown(self.entity)
def approve_bots(bot, update, page=0, override_list=None): chat_id = util.uid_from_update(update) if override_list: unapproved = override_list else: unapproved = Bot.select().where(Bot.approved == False).order_by( Bot.date_added) if page < 0: page = 0 last_page = int((len(unapproved) - 1) / settings.PAGE_SIZE_BOT_APPROVAL) if page * settings.PAGE_SIZE_BOT_APPROVAL >= len(unapproved): # old item deleted, list now too small page = last_page start = page * settings.PAGE_SIZE_BOT_APPROVAL end = start + settings.PAGE_SIZE_BOT_APPROVAL has_prev_page = page > 0 has_next_page = (page + 1) * settings.PAGE_SIZE_BOT_APPROVAL < len(unapproved) unapproved = unapproved[start:end] if len(unapproved) == 0: bot.formatter.send_or_edit(chat_id, "No more unapproved bots available. " "Good job! (Is this the first time? 😂)", to_edit=util.mid_from_update(update)) return buttons = list() for x in unapproved: first_row = [ InlineKeyboardButton(x.username, url="http://t.me/{}".format(x.username[1:])) ] second_row = [ InlineKeyboardButton('👍', callback_data=util.callback_for_action( CallbackActions.ACCEPT_BOT, {'id': x.id})), InlineKeyboardButton('👎', callback_data=util.callback_for_action( CallbackActions.REJECT_BOT, { 'id': x.id, 'page': page, 'ntfc': True })), InlineKeyboardButton('🗑', callback_data=util.callback_for_action( CallbackActions.REJECT_BOT, { 'id': x.id, 'page': page, 'ntfc': False })), InlineKeyboardButton('👥🔀', callback_data=util.callback_for_action( CallbackActions.RECOMMEND_MODERATOR, { 'id': x.id, 'page': page })) ] if len(unapproved) > 1: buttons.append(first_row) buttons.append(second_row) page_arrows = list() if has_prev_page: page_arrows.append( InlineKeyboardButton('⏮', callback_data=util.callback_for_action( CallbackActions.SWITCH_APPROVALS_PAGE, {'page': -1}))) page_arrows.append( InlineKeyboardButton(Emoji.LEFTWARDS_BLACK_ARROW, callback_data=util.callback_for_action( CallbackActions.SWITCH_APPROVALS_PAGE, {'page': page - 1}))) if has_prev_page or has_next_page: page_arrows.append( InlineKeyboardButton('·{}·'.format(page + 1), callback_data=util.callback_for_action( CallbackActions.SWITCH_APPROVALS_PAGE, {'page': page}))) if has_next_page: page_arrows.append( InlineKeyboardButton(Emoji.BLACK_RIGHTWARDS_ARROW, callback_data=util.callback_for_action( CallbackActions.SWITCH_APPROVALS_PAGE, {'page': page + 1}))) page_arrows.append( InlineKeyboardButton('⏭', callback_data=util.callback_for_action( CallbackActions.SWITCH_APPROVALS_PAGE, {'page': last_page}))) buttons.append(page_arrows) reply_markup = InlineKeyboardMarkup(buttons) text = "What to do with {}?".format( util.escape_markdown(unapproved[0].username)) if len( unapproved ) == 1 else "Please select a bot you want to accept for the BotList" bot.formatter.send_or_edit(chat_id, util.action_hint(text), reply_markup=reply_markup, to_edit=util.mid_from_update(update)) return CallbackStates.APPROVING_BOTS
def search_query(bot, update: Update, chat_data, query, send_errors=True): cid: int = update.effective_chat.id user: User = User.from_update(update) is_admin: bool = cid in settings.MODERATORS replied_to_message_id: Optional[int] = util.original_reply_id(update) results = search.search_bots(query) reply_markup = ( ReplyKeyboardMarkup(basic.main_menu_buttons(is_admin), resize_keyboard=True) if util.is_private_message(update) else None ) if results: if len(results) == 1: update.effective_message.delete() header = f"{user.markdown_short} found the following bot for you:" return send_bot_details(bot, update, chat_data, results[0], header_msg=header) too_many_results = len(results) > settings.MAX_SEARCH_RESULTS bots_list = "" if cid in settings.MODERATORS: # private chat with moderator # append edit buttons bots_list += "\n".join( ["{} — /edit{} 🛃".format(b, b.id) for b in list(results)[:100]] ) else: bots_list += "\n".join( [str(b) for b in list(results)[: settings.MAX_SEARCH_RESULTS]] ) bots_list += "\n…" if too_many_results else "" bots_list = messages.SEARCH_RESULTS.format( bots=bots_list, num_results=len(results), plural="s" if len(results) > 1 else "", query=query, ) if util.is_group_message(update) and not update.message.reply_to_message: try: bot.formatter.send_message( update.effective_user.id, bots_list, reply_markup=reply_markup, disable_web_page_preview=True, ) reply_markup, callback = botlistchat.append_restricted_delete_button( update, chat_data, InlineKeyboardMarkup([[]]) ) msg = bot.formatter.send_message( update.effective_chat.id, f"Hey {user.plaintext}, let's not annoy the others. I sent you the search results " f"[in private chat](https://t.me/{settings.SELF_BOT_NAME}).", disable_web_page_preview=True, reply_markup=reply_markup, ) callback(msg) update.effective_message.delete() except TelegramError: hint_msg, hint_reply_markup, _ = get_hint_data("#private") bot.formatter.send_message( update.effective_chat.id, hint_msg, reply_markup=hint_reply_markup, reply_to_message_id=update.effective_message.id, disable_web_page_preview=True, ) return ConversationHandler.END if replied_to_message_id: bots_list = f"{user.markdown_short} suggests to search and {bots_list}" bot.formatter.send_message( update.effective_chat.id, bots_list, parse_mode=ParseMode.MARKDOWN, reply_markup=reply_markup, disable_web_page_preview=True, reply_to_message_id=replied_to_message_id, ) update.effective_message.delete() else: if send_errors: callback = None if util.is_group_message(update): reply_markup, callback = botlistchat.append_restricted_delete_button( update, chat_data, InlineKeyboardMarkup([[]]) ) msg = update.message.reply_text( util.failure( "Sorry, I couldn't find anything related " "to *{}* in the @BotList. /search".format( util.escape_markdown(query) ) ), parse_mode=ParseMode.MARKDOWN, reply_markup=reply_markup, ) if callback: callback(msg) return ConversationHandler.END
def send_tweet(self, chat, tweet, sub_kind): try: if sub_kind == 1: if tweet.text[0:1] == 'RT': return elif sub_kind == 2: if tweet.text[0] == '@': return elif sub_kind == 3: if len(eval(tweet.photo_url)) == 0: return self.logger.debug("Sending tweet {} to chat {}...".format( tweet.tw_id, chat.chat_id)) ''' Use a soft-hyphen to put an invisible link to the first image in the tweet, which will then be displayed as preview ''' photo_url = '' video_url = '' if len(eval(tweet.photo_url)) != 0: photo_url = '[\xad](%s)' % eval(tweet.photo_url)[0] if tweet.video_url: video_url = tweet.video_url created_dt = utc.localize(tweet.created_at) #created_dt = tweet.created_at if chat.timezone_name is not None: tz = timezone(chat.timezone_name) created_dt = created_dt.astimezone(tz) created_at = created_dt.strftime('%Y-%m-%d %H:%M:%S %Z') self.sendMessage(chat_id=chat.chat_id, disable_web_page_preview=not photo_url, text=""" {link_preview}*{name}* ([@{screen_name}](https://twitter.com/{screen_name})) at {created_at}: {text} -- [Link to this Tweet](https://twitter.com/{screen_name}/status/{tw_id}) """.format( link_preview=photo_url, text=prepare_tweet_text(tweet.text), name=escape_markdown(tweet.name), screen_name=tweet.screen_name, created_at=created_at, tw_id=tweet.tw_id, ), parse_mode=telegram.ParseMode.MARKDOWN) if video_url: try: self.sendVideo(chat_id=chat.chat_id, video=tweet.video_url) except TelegramError as e: self.logger.warning( "Sending tweet {} video failed, video url is {}, error is {}" .format(tweet.tw_id, tweet.video_url, e)) file = open("video_url.txt", "a") file.write('\n') file.write(str(video_url)) file.write('\n') file.write(str(tweet.video_url)) file.close() else: try: if photo_url: for img in eval(tweet.photo_url): self.sendPhoto(chat_id=chat.chat_id, photo=img) except TelegramError as e: self.logger.warning( "Sending tweet {} img failed, img url is {}, error is {}" .format(tweet.tw_id, tweet.photo_url, e)) file = open("photo_url.txt", "a") file.write('\n') file.write(str(photo_url)) file.write('\n') file.write(str(tweet.photo_url)) file.close() except TelegramError as e: self.logger.info("Couldn't send tweet {} to chat {}: {}".format( tweet.tw_id, chat.chat_id, e.message)) delet_this = None if e.message == 'Bad Request: group chat was migrated to a supergroup chat': delet_this = True if e.message == "Unauthorized": delet_this = True if delet_this: self.logger.info("Marking chat for deletion") chat.delete_soon = True chat.save()
def set_keywords(bot, update, chat_data, to_edit): chat_id = util.uid_from_update(update) keywords = Keyword.select().where(Keyword.entity == to_edit) chat_data['edit_bot'] = to_edit set_keywords_msgid = chat_data.get('set_keywords_msg') pending = Suggestion.select().where( Suggestion.executed == False, Suggestion.subject == to_edit, Suggestion.action << ['add_keyword', 'remove_keyword']) pending_removal = [y for y in pending if y.action == 'remove_keyword'] # Filter keywords by name to not include removal suggestions # We don't need to do this for add_keyword suggestions, because duplicates are not allowed. keywords = [ k for k in keywords if k.name not in [s.value for s in pending_removal] ] kw_remove_buttons = [ InlineCallbackButton('{} ✖️'.format(x), callback_action=CallbackActions.REMOVE_KEYWORD, params={ 'id': to_edit.id, 'kwid': x.id }) for x in keywords ] kw_remove_buttons.extend([ InlineKeyboardButton('#{} 👓✖️'.format(x.value), callback_data=util.callback_for_action( CallbackActions.DELETE_KEYWORD_SUGGESTION, { 'id': to_edit.id, 'suggid': x.id })) for x in [y for y in pending if y.action == 'add_keyword'] ]) kw_remove_buttons.extend([ InlineKeyboardButton('#{} 👓❌'.format(x.value), callback_data=util.callback_for_action( CallbackActions.DELETE_KEYWORD_SUGGESTION, { 'id': to_edit.id, 'suggid': x.id })) for x in pending_removal ]) buttons = util.build_menu( kw_remove_buttons, 2, header_buttons=[ InlineKeyboardButton(captions.DONE, callback_data=util.callback_for_action( CallbackActions.ABORT_SETTING_KEYWORDS, {'id': to_edit.id})) ]) reply_markup = InlineKeyboardMarkup(buttons) msg = util.send_or_edit_md_message( bot, chat_id, util.action_hint( 'Send me the keywords for {} one by one...\n\n{}'.format( util.escape_markdown(to_edit.username), messages.KEYWORD_BEST_PRACTICES)), to_edit=set_keywords_msgid, reply_markup=reply_markup) if msg: # message might not have been edited if the user adds an already-existing keyword # TODO: should the user be notified about this? chat_data['set_keywords_msg'] = msg.message_id return BotStates.SENDING_KEYWORDS