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)
Esempio n. 4
0
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.")
Esempio n. 5
0
 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')
Esempio n. 6
0
 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
Esempio n. 7
0
 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)
Esempio n. 9
0
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()
Esempio n. 11
0
    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()
Esempio n. 12
0
    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()
Esempio n. 13
0
    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
Esempio n. 14
0
    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
Esempio n. 15
0
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
Esempio n. 16
0
 def __str__(self):
     return util.escape_markdown(
         self.str_no_md).encode('utf-8').decode('utf-8')
Esempio n. 17
0
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
Esempio n. 19
0
 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)
Esempio n. 20
0
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
Esempio n. 22
0
    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