Пример #1
0
def process_personal_chat_updates(update: Update):
    user = get_bot_user(update)
    if not user:
        return

    # check for unfinished posts
    unfinished_post = cached_post_get(update.effective_user.id)

    # found an unfinished post
    if unfinished_post:
        reply = continue_posting(update, unfinished_post, user)
        if reply:
            send_telegram_message(chat=Chat(id=update.effective_chat.id),
                                  text=reply)
        return

    # parse forwarded posts and links
    if update.message:
        reply = parse_forwarded_messages(update)
        if reply:
            send_telegram_message(chat=Chat(id=update.effective_chat.id),
                                  text=reply)
        return

    send_telegram_message(chat=Chat(id=update.effective_chat.id),
                          text="Чот непонятна 🤔")
Пример #2
0
def process_comment_reply(update: Update):
    if not update.message.reply_to_message:
        return

    user = get_bot_user(update)
    if not user:
        return

    comment_url_entity = [
        entity["url"] for entity in update.message.reply_to_message.entities if
        entity["type"] == "text_link" and COMMENT_URL_RE.match(entity["url"])
    ]
    if not comment_url_entity:
        log.info(
            f"Comment url not found in: {update.message.reply_to_message.entities}"
        )
        return

    comment_id = COMMENT_URL_RE.match(comment_url_entity[0]).group(1)
    comment = Comment.objects.filter(id=comment_id).first()
    if not comment:
        log.info(f"Comment not found: {comment_id}")
        return

    is_ok = Comment.check_rate_limits(user)
    if not is_ok:
        send_telegram_message(
            chat=Chat(id=update.effective_chat.id),
            text=
            f"🙅‍♂️ Извините, вы комментировали слишком часто и достигли дневного лимита"
        )
        return

    text = update.message.text or update.message.caption
    if not text:
        send_telegram_message(
            chat=Chat(id=update.effective_chat.id),
            text=f"😣 Сорян, я пока умею только в текстовые ответы")
        return

    # max 3 levels of comments are allowed
    reply_to_id = comment.id
    if comment.reply_to_id and comment.reply_to.reply_to_id:
        reply_to_id = comment.reply_to_id

    reply = Comment.objects.create(author=user,
                                   post=comment.post,
                                   reply_to_id=reply_to_id,
                                   text=f"@{comment.author.slug}, {text}",
                                   useragent="TelegramBot (like TwitterBot)",
                                   metadata={"telegram": update.to_dict()})
    new_comment_url = settings.APP_HOST + reverse("show_comment",
                                                  kwargs={
                                                      "post_slug":
                                                      reply.post.slug,
                                                      "comment_id": reply.id
                                                  })
    send_telegram_message(
        chat=Chat(id=update.effective_chat.id),
        text=f"➜ <a href=\"{new_comment_url}\">Отвечено</a> 👍")
Пример #3
0
def process_personal_chat_updates(update: Update):
    user = User.objects.filter(telegram_id=update.effective_user.id).first()
    if not user:
        send_telegram_message(
            chat=Chat(id=update.effective_chat.id),
            text=
            f"😐 Извините, мы не знакомы. Привяжите свой аккаунт в профиле на https://vas3k.club"
        )
        return

    # check for unfinished posts
    unfinished_post = cached_post_get(update.effective_user.id)

    # found an unfinished post
    if unfinished_post:
        reply = continue_posting(update, unfinished_post, user)
        if reply:
            send_telegram_message(chat=Chat(id=update.effective_chat.id),
                                  text=reply)
        return

    # parse forwarded posts and links
    if update.message:
        reply = parse_forwarded_messages(update)
        if reply:
            send_telegram_message(chat=Chat(id=update.effective_chat.id),
                                  text=reply)
        return

    send_telegram_message(chat=Chat(id=update.effective_chat.id),
                          text="Чот непонятна 🤔")
Пример #4
0
def process_auth(update: Update):
    user = None
    if update.message and update.message.text:
        user = User.objects.filter(
            secret_hash=str(update.message.text).strip()).first()

    if not user:
        send_telegram_message(
            chat=Chat(id=update.effective_chat.id),
            text=
            "Привет. Мы пока не знакомы. Привяжи меня на сайте или пришли мне секретный код 👇"
        )
        return

    user.telegram_id = update.effective_user.id
    user.telegram_data = {
        "id": update.effective_user.id,
        "username": update.effective_user.username,
        "first_name": update.effective_user.first_name,
        "last_name": update.effective_user.last_name,
        "language_code": update.effective_user.language_code,
    }
    user.save()

    send_telegram_message(chat=Chat(id=update.effective_chat.id),
                          text=f"Отлично! Приятно познакомиться, {user.slug}")
    cache.delete("bot:telegram_user_ids")
Пример #5
0
def parse_forwarded_messages(update: Update):
    started_post = {
        "title": None,
        "type": Post.TYPE_POST,
        "text": update.message.text or update.message.caption,
        "url": None,
        "is_visible": True,
        "is_public": True,
    }
    for entity, text in update.message.parse_entities().items():
        if entity.type == "url":
            started_post["url"] = text
        elif entity.type == "bold":
            started_post["title"] = text

    # save it to user cache
    cached_post_set(update.effective_user.id, started_post)

    if started_post["url"]:
        # looks like a link
        send_telegram_message(
            chat=Chat(id=update.effective_chat.id),
            text=
            f"Выглядит как ссылка. Хотите поделиться ей в Клубе? Как будем постить?",
            reply_markup=telegram.InlineKeyboardMarkup(
                [[
                    telegram.InlineKeyboardButton("🔗 Ссылкой",
                                                  callback_data=f"link"),
                    telegram.InlineKeyboardButton("📝 Как пост",
                                                  callback_data=f"post"),
                ],
                 [
                     telegram.InlineKeyboardButton("❌ Отмена",
                                                   callback_data=f"nope"),
                 ]]))
    else:
        # looks like a text post
        if len(started_post["text"] or "") < 120:
            return "Напиши или форвардни мне нормальный пост или ссылку!"

        send_telegram_message(
            chat=Chat(id=update.effective_chat.id),
            text=f"Хотите поделиться этим в Клубе? Как будем постить?",
            reply_markup=telegram.InlineKeyboardMarkup(
                [[
                    telegram.InlineKeyboardButton("📝 Как пост",
                                                  callback_data=f"post"),
                    telegram.InlineKeyboardButton("❔ Вопросом",
                                                  callback_data=f"question"),
                ],
                 [
                     telegram.InlineKeyboardButton("❌ Отмена",
                                                   callback_data=f"nope"),
                 ]]))
Пример #6
0
def process_comment_reply(update: Update):
    if not update.message.reply_to_message:
        return

    user = User.objects.filter(telegram_id=update.effective_user.id).first()
    if not user:
        send_telegram_message(
            chat=Chat(id=update.effective_user.id),
            text=f"😐 Извините, мы не знакомы. Привяжите свой аккаунт в профиле на https://vas3k.club"
        )
        return

    comment_url_entity = [
        entity["url"] for entity in update.message.reply_to_message.entities
        if entity["type"] == "text_link" and COMMENT_URL_RE.match(entity["url"])
    ]
    if not comment_url_entity:
        log.info(f"Comment url not found in: {update.message.reply_to_message.entities}")
        return

    reply_to_id = COMMENT_URL_RE.match(comment_url_entity[0]).group(1)
    reply = Comment.objects.filter(id=reply_to_id).first()
    if not reply:
        log.info(f"Reply not found: {reply_to_id}")
        return

    is_ok = Comment.check_rate_limits(user)
    if not is_ok:
        send_telegram_message(
            chat=Chat(id=update.effective_chat.id),
            text=f"🙅‍♂️ Извините, вы комментировали слишком часто и достигли дневного лимита"
        )
        return

    comment = Comment.objects.create(
        author=user,
        post=reply.post,
        reply_to=Comment.find_top_comment(reply),
        text=update.message.text,
        useragent="TelegramBot (like TwitterBot)",
        metadata={
            "telegram": update.to_dict()
        }
    )
    new_comment_url = settings.APP_HOST + reverse("show_comment", kwargs={
        "post_slug": comment.post.slug,
        "comment_id": comment.id
    })
    send_telegram_message(
        chat=Chat(id=update.effective_chat.id),
        text=f"➜ [Отвечено]({new_comment_url}) 👍"
    )
Пример #7
0
def async_create_or_update_achievement(user_achievement: UserAchievement):
    user = user_achievement.user
    achievement = user_achievement.achievement

    # messages
    if user.is_club_member and user.telegram_id:
        if achievement.image:
            send_telegram_image(
                chat=Chat(id=user.telegram_id),
                image_url=achievement.image,
                text=render_html_message("achievement.html",
                                         user=user,
                                         achievement=achievement),
            )

    # emails
    if not user.is_email_unsubscribed:
        email_template = loader.get_template("emails/achievement.html")
        send_club_email(
            recipient=user.email,
            subject=f"🎖 Вас наградили бейджиком «{achievement.name}»",
            html=email_template.render({
                "user": user,
                "achievement": achievement
            }),
            tags=["achievement"])
Пример #8
0
def notify_post_author_rejected(post):
    if post.author.telegram_id:
        send_telegram_message(
            chat=Chat(id=post.author.telegram_id),
            text=render_html_message("post_rejected.html", post=post),
            parse_mode=telegram.ParseMode.HTML,
        )
Пример #9
0
def async_create_or_update_comment(comment, is_created):
    # notify admins
    send_telegram_message(
        chat=ADMIN_CHAT,
        text=render_html_message("moderator_comment.html", comment=comment),
        parse_mode=telegram.ParseMode.HTML,
    )

    # notify post author
    post_author = comment.post.author
    if post_author.telegram_id and comment.author != post_author:
        send_telegram_message(
            chat=Chat(id=comment.post.author.telegram_id),
            text=render_html_message("comment_to_post.html", comment=comment),
            parse_mode=telegram.ParseMode.HTML,
        )

    # on reply — notify thread author (do not notify yourself)
    thread_author = None
    if comment.reply_to:
        thread_author = comment.reply_to.author
        if comment.reply_to_id and thread_author.telegram_id and comment.author != thread_author:
            send_telegram_message(
                chat=Chat(id=comment.reply_to.author.telegram_id),
                text=render_html_message("comment_to_thread.html",
                                         comment=comment),
                parse_mode=telegram.ParseMode.HTML,
            )

    # post first level comments to club chat
    # if not comment.reply_to:
    #     send_telegram_message(
    #         chat=CLUB_CHAT,
    #         text=render_html_message("comment_to_post_announce.html", comment=comment),
    #         parse_mode=telegram.ParseMode.HTML,
    #     )

    # parse @nicknames and notify their users
    for username in USERNAME_RE.findall(comment.text):
        user = User.objects.filter(slug=username).first()
        if user and user.telegram_id and user != post_author and user != thread_author:
            send_telegram_message(
                chat=Chat(id=user.telegram_id),
                text=render_html_message("comment_mention.html",
                                         comment=comment),
                parse_mode=telegram.ParseMode.HTML,
            )
Пример #10
0
def notify_user_profile_approved(user):
    user_profile_url = settings.APP_HOST + reverse(
        "profile", kwargs={"user_slug": user.slug})

    if user.telegram_id:
        send_telegram_message(
            chat=Chat(id=user.telegram_id),
            text=f"🚀 Подравляем, вы прошли модерацию. Добро пожаловать в Клуб!"
            f"\n\nМожно пойти заполнить другие смешные поля в профиле:"
            f"\n\n{user_profile_url}")
Пример #11
0
def async_create_or_update_comment(comment):
    notified_user_ids = set()

    # notify post subscribers
    post_subscribers = PostSubscription.post_subscribers(comment.post)
    for post_subscriber in post_subscribers:
        if post_subscriber.user.telegram_id and comment.author != post_subscriber.user:
            template = "comment_to_post.html" if post_subscriber.user == comment.post.author else "comment_to_post_announce.html"
            send_telegram_message(
                chat=Chat(id=post_subscriber.user.telegram_id),
                text=render_html_message(template, comment=comment),
            )
            notified_user_ids.add(post_subscriber.user.id)

    # on reply — notify thread author (do not notify yourself)
    if comment.reply_to:
        thread_author = comment.reply_to.author
        if thread_author.telegram_id and comment.author != thread_author and thread_author.id not in notified_user_ids:
            send_telegram_message(
                chat=Chat(id=thread_author.telegram_id),
                text=render_html_message("comment_to_thread.html",
                                         comment=comment),
            )
            notified_user_ids.add(thread_author.id)

    # post top level comments to online channel
    if not comment.reply_to:
        send_telegram_message(
            chat=CLUB_ONLINE,
            text=render_html_message("comment_to_post_announce.html",
                                     comment=comment),
        )

    # parse @nicknames and notify their users
    for username in USERNAME_RE.findall(comment.text):
        user = User.objects.filter(slug=username).first()
        if user and user.telegram_id and user.id not in notified_user_ids:
            send_telegram_message(
                chat=Chat(id=user.telegram_id),
                text=render_html_message("comment_mention.html",
                                         comment=comment),
            )
            notified_user_ids.add(user.id)
Пример #12
0
def get_bot_user(update):
    user = User.objects.filter(telegram_id=update.effective_user.id).first()
    if not user:
        send_telegram_message(
            chat=Chat(id=update.effective_chat.id),
            text=
            f"😐 Извините, мы не знакомы. Привяжите свой аккаунт в профиле на https://vas3k.club"
        )
        return None

    if user.is_banned:
        send_telegram_message(
            chat=Chat(id=update.effective_user.id),
            text=
            f"😐 Извините, вы забанены до {user.is_banned_until.strftime('%d %B %Y')} и пока не можете писать"
        )
        return None

    return user
Пример #13
0
def notify_user_profile_rejected(user: User, reason: RejectReason):
    try:
        text = render_html_message(f"rejected/{reason.value}.html", user=user)
    except TemplateDoesNotExist:
        text = render_html_message(f"rejected/intro.html", user=user)

    if user.telegram_id:
        send_telegram_message(
            chat=Chat(id=user.telegram_id),
            text=text,
        )
Пример #14
0
def notify_user_profile_rejected(user):
    user_profile_url = settings.APP_HOST + reverse("profile", kwargs={"user_slug": user.slug})

    if user.telegram_id:
        send_telegram_message(
            chat=Chat(id=user.telegram_id),
            text=f"😐 К сожалению, ваш профиль не прошел модерацию. Но это не конец света и всё можно исправить."
                 f"Вот популярные причины почему так бывает:\n"
                 f"- Плохо написано #intro. Одного предложения обычно мало, нам же надо как-то познакомиться\n"
                 f"- Вымышленное имя или профессия\n"
                 f"- Много незаполненных полей\n"
                 f"\n\nВот ссылка чтобы податься на ревью еще раз: {user_profile_url}"
        )
Пример #15
0
def async_create_or_update_comment(comment, is_created):
    # notify post author
    post_author = comment.post.author
    if post_author.telegram_id and comment.author != post_author:
        send_telegram_message(
            chat=Chat(id=comment.post.author.telegram_id),
            text=render_html_message("comment_to_post.html", comment=comment),
        )

    # on reply — notify thread author (do not notify yourself)
    thread_author = None
    if comment.reply_to:
        thread_author = comment.reply_to.author
        if comment.reply_to_id and thread_author.telegram_id and comment.author != thread_author:
            send_telegram_message(
                chat=Chat(id=comment.reply_to.author.telegram_id),
                text=render_html_message("comment_to_thread.html",
                                         comment=comment),
            )

    # post top level comments to online channel
    if not comment.reply_to:
        send_telegram_message(
            chat=CLUB_ONLINE,
            text=render_html_message("comment_to_post_announce.html",
                                     comment=comment),
        )

    # parse @nicknames and notify their users
    for username in USERNAME_RE.findall(comment.text):
        user = User.objects.filter(slug=username).first()
        if user and user.telegram_id and user != post_author and user != thread_author:
            send_telegram_message(
                chat=Chat(id=user.telegram_id),
                text=render_html_message("comment_mention.html",
                                         comment=comment),
            )
Пример #16
0
def announce_in_club_chats(post):
    if post.topic and post.topic.chat_id:
        # announce to the topic chat
        send_telegram_message(
            chat=Chat(id=post.topic.chat_id),
            text=render_html_message("channel_post_announce.html", post=post),
            parse_mode=telegram.ParseMode.HTML,
            disable_preview=True,
        )
    else:
        # announce to public chat
        send_telegram_message(
            chat=CLUB_CHAT,
            text=render_html_message("channel_post_announce.html", post=post),
            parse_mode=telegram.ParseMode.HTML,
            disable_preview=True,
        )
Пример #17
0
def notify_user_profile_rejected(user):
    user_profile_url = settings.APP_HOST + reverse("profile", kwargs={"user_slug": user.slug})

    if user.telegram_id:
        send_telegram_message(
            chat=Chat(id=user.telegram_id),
            text=f"😐 К сожалению, ваш профиль не прошел модерацию. Вот популярные причины почему так бывает:\n\n"
                 f"- 📝 Маленькое #intro. Допишите еще хотя бы пару абзацев. Для примера посмотрите чужие, "
                 f"там есть ссылочки. <a href=\"https://vas3k.club/docs/about/#rules\">Наши правила</a>, "
                 f"с которыми вы согласились, запрещают анонимусов в Клубе.\n"
                 f"- 🤔 Много незаполненных полей. Мы не поняли кто вы. Профиль без фамилии или компании вряд "
                 f"ли пройдет модерацию.\n"
                 f"- 🤪 Вымышленное имя или профессия (например, Олег).\n"
                 f"- 🙅‍♀️ Наличие фраз типа «не скажу», «не люблю писать о себе», «потом заполню». "
                 f"Потом так потом, мы не торопимся :)\n"
                 f"- 💨 Душность, глупость или желание обмануть модераторов.\n\n"
                 f"\n\nВот ссылка чтобы исправить недочёты и податься на ревью еще раз: {user_profile_url}"
        )
Пример #18
0
def async_create_or_update_post(post, is_created):
    if not post.is_approved_by_moderator:
        send_telegram_message(
            chat=ADMIN_CHAT,
            text=render_html_message("moderator_new_post_review.html",
                                     post=post),
            reply_markup=telegram.InlineKeyboardMarkup(
                [[
                    telegram.InlineKeyboardButton(
                        "👍 Одобрить", callback_data=f"approve_post:{post.id}"),
                    telegram.InlineKeyboardButton(
                        "😕 Так себе", callback_data=f"forgive_post:{post.id}"),
                ],
                 [
                     telegram.InlineKeyboardButton(
                         "❌ В черновики",
                         callback_data=f"delete_post:{post.id}"),
                 ]]))

    # post to online channel
    send_telegram_message(
        chat=CLUB_ONLINE,
        text=render_html_message("channel_post_announce.html", post=post),
        parse_mode=telegram.ParseMode.HTML,
        disable_preview=True,
    )

    # parse @nicknames and notify mentioned users (only if post is visible)
    if post.is_visible and (is_created or "is_visible" in post.changed_fields):
        notified_user_ids = set()
        for username in USERNAME_RE.findall(post.text):
            user = User.objects.filter(slug=username).first()
            if user and user.telegram_id and user.id not in notified_user_ids:
                send_telegram_message(
                    chat=Chat(id=user.telegram_id),
                    text=render_html_message("post_mention.html", post=post),
                )
                notified_user_ids.add(user.id)
Пример #19
0
def continue_posting(update: Update, started_post: dict, user: User):
    if update.callback_query:
        if update.callback_query.data == "nope":
            # cancel posting
            cached_post_delete(update.effective_user.id)
            return "Ок, забыли 👌"

        elif update.callback_query.data in {"post", "link", "question"}:
            # ask for title
            started_post["type"] = update.callback_query.data
            cached_post_set(update.effective_user.id, started_post)
            return f"Отлично. Теперь надо придумать заголовок, чтобы всем было понятно о чем это. " \
                   f"Подумайте и пришлите его следующим сообщением 👇"

        elif update.callback_query.data == "go":
            # go-go-go, post the post
            FormClass = POST_TYPE_MAP.get(started_post["type"]) or PostTextForm

            form = FormClass(started_post)
            if not form.is_valid():
                return f"🤦‍♂️ Что-то пошло не так. Пришлите нам багрепорт. " \
                       f"Вот ошибка:\n```{str(form.errors)}```"

            if Post.check_duplicate(user=user,
                                    title=form.cleaned_data["title"]):
                return "🤔 Выглядит как дубликат вашего прошлого поста. " \
                       "Проверьте всё ли в порядке и пришлите ниже другой заголовок 👇"

            is_ok = Post.check_rate_limits(user)
            if not is_ok:
                return "🙅‍♂️ Извините, вы сегодня запостили слишком много постов. Попробуйте попозже"

            post = form.save(commit=False)
            post.author = user
            post.type = started_post["type"]
            post.meta = {"telegram": update.to_json()}
            post.save()

            post_url = settings.APP_HOST + reverse("show_post",
                                                   kwargs={
                                                       "post_type": post.type,
                                                       "post_slug": post.slug
                                                   })
            cached_post_delete(update.effective_user.id)
            return f"Запостили 🚀🚀🚀\n\n{post_url}"

    if update.message:
        started_post["title"] = str(update.message.text
                                    or update.message.caption
                                    or "").strip()[:128]
        if len(started_post["title"]) < 7:
            send_telegram_message(
                chat=Chat(id=update.effective_chat.id),
                text=f"Какой-то короткий заголовок. Пришлите другой, подлинее",
                reply_markup=telegram.InlineKeyboardMarkup([[
                    telegram.InlineKeyboardButton("❌ Отменить всё",
                                                  callback_data=f"nope"),
                ]]))
            return

        cached_post_set(update.effective_user.id, started_post)
        emoji = Post.TYPE_TO_EMOJI.get(started_post["type"]) or "🔥"
        send_telegram_message(
            chat=Chat(id=update.effective_chat.id),
            text=f"Заголовок принят. Теперь пост выглядит как-то так:\n\n"
            f"{emoji} <b>{started_post['title']}</b>\n\n"
            f"{started_post['text'] or ''}\n\n"
            f"{started_post['url'] or ''}\n\n"
            f"<b>Будем постить?</b> (после публикации его можно будет подредактировать на сайте)",
            reply_markup=telegram.InlineKeyboardMarkup([
                [
                    telegram.InlineKeyboardButton("✅ Поехали",
                                                  callback_data=f"go"),
                    telegram.InlineKeyboardButton("❌ Отмена",
                                                  callback_data=f"nope"),
                ],
            ]))
Пример #20
0
def notify_user_auth(user, code):
    if user.telegram_id:
        send_telegram_message(
            chat=Chat(id=user.telegram_id),
            text=f"<b>{code.code}</b> — ваш одноразовый код для входа в Клуб")
Пример #21
0
def notify_user_ping(user, message):
    if user.telegram_id:
        send_telegram_message(
            chat=Chat(id=user.telegram_id),
            text=f"👋 <b>Вам письмо от модераторов Клуба:</b> {message}")