Esempio n. 1
0
def notify_user_auth(user, code):
    if user.telegram_id:
        send_telegram_message(
            chat=Chat(id=user.telegram_id),
            text=
            f"<pre>{code.code}</pre> — ваш одноразовый код для входа в Клуб",
        )
Esempio n. 2
0
def notify_profile_needs_review(user, intro):
    admin_profile_url = settings.APP_HOST + reverse("admin_profile", kwargs={"user_slug": user.slug})

    send_telegram_message(
        chat=ADMIN_CHAT,
        text=render_html_message("moderator_new_member_review.html", user=user, intro=intro),
        reply_markup=telegram.InlineKeyboardMarkup([
            [
                telegram.InlineKeyboardButton("👍 Впустить", callback_data=f"approve_user:{user.id}")
            ],
            [
                telegram.InlineKeyboardButton("❌️ Плохое интро", callback_data=f"reject_user_intro:{user.id}"),
            ],
            [
                telegram.InlineKeyboardButton("❌️ Недостаточно данных", callback_data=f"reject_user_data:{user.id}"),
            ],
            [
                telegram.InlineKeyboardButton("❌️ Агрессия", callback_data=f"reject_user_aggression:{user.id}"),
            ],
            [
                telegram.InlineKeyboardButton("❌️ Слишком общее", callback_data=f"reject_user_general:{user.id}"),
            ],
            [
                telegram.InlineKeyboardButton("❌️ Плохое имя", callback_data=f"reject_user_name:{user.id}"),
            ],
            [
                telegram.InlineKeyboardButton("✏️ Написать юзеру", url=admin_profile_url),
            ]
        ])
    )
Esempio n. 3
0
def notify_post_approved(post):
    if post.author.telegram_id:
        send_telegram_message(
            chat=Chat(id=post.author.telegram_id),
            text=render_html_message("post_approved.html", post=post),
            parse_mode=telegram.ParseMode.HTML,
        )
Esempio n. 4
0
def notify_users(users, template, post):
    for username in users:
        user = User.objects.filter(slug=username).first()
        if user and user.telegram_id:
            send_telegram_message(
                chat=Chat(id=user.telegram_id),
                text=render_html_message(template, post=post),
            )
Esempio n. 5
0
def notify_admin_user_on_ban(user, days, reason):
    banned_user_profile_url = settings.APP_HOST + reverse("profile", kwargs={"user_slug": user.slug})
    send_telegram_message(
        chat=ADMIN_CHAT,
        text=f"⛔️ <b>Юзер <a href=\"{banned_user_profile_url}\">{user.full_name}</a> "
             f"({user.slug}) забанен на {days} дней</b>"
             f"\n\nПричина: <i>{reason}</i>"
    )
Esempio n. 6
0
def notify_admin_user_on_mute(user_from, user_to, comment):
    user_from_profile_url = settings.APP_HOST + reverse("profile", kwargs={"user_slug": user_from.slug})
    user_to_profile_url = settings.APP_HOST + reverse("profile", kwargs={"user_slug": user_to.slug})
    send_telegram_message(
        chat=ADMIN_CHAT,
        text=f"<b>Кого-то замьютили</b> 🤕"
             f"\n\n<a href=\"{user_from_profile_url}\">{user_from.full_name}</a> ({user_from.slug}) считает, "
             f"что <a href=\"{user_to_profile_url}\">{user_to.full_name}</a> ({user_to.slug}) не место в Клубе "
             f"и замьютил его. \n\nВот почему: <i>{comment}</i>"
    )
Esempio n. 7
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}"
        )
Esempio n. 8
0
def notify_user_profile_rejected(user: User, reason: UserRejectReason):
    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,
        )
Esempio n. 9
0
def async_label_changed(post):
    moderator_template = "moderator_label_removed.html" if post.label_code is None else "moderator_label_set.html"
    send_telegram_message(
        chat=ADMIN_CHAT,
        text=render_html_message(moderator_template, post=post),
        parse_mode=telegram.ParseMode.HTML,
    )
    if post.label_code is not None and post.label['notify'] and post.author.telegram_id:
        send_telegram_message(
            chat=Chat(id=post.author.telegram_id),
            text=render_html_message("post_label.html", post=post),
            parse_mode=telegram.ParseMode.HTML,
        )
Esempio n. 10
0
def notify_post_rejected(post, reason):
    try:
        text = render_html_message(f"post_rejected/{reason.value}.html",
                                   post=post)
    except TemplateDoesNotExist:
        text = render_html_message(f"post_rejected/draft.html", post=post)

    if post.author.telegram_id:
        send_telegram_message(
            chat=Chat(id=post.author.telegram_id),
            text=text,
            parse_mode=telegram.ParseMode.HTML,
        )
Esempio n. 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):
        if username == settings.MODERATOR_USERNAME:
            send_telegram_message(
                chat=ADMIN_CHAT,
                text=render_html_message("moderator_mention.html",
                                         comment=comment),
            )
            continue

        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)
Esempio n. 12
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,
        )
Esempio n. 13
0
    def handle(self, *args, **options):
        new_posts = Post.visible_objects()\
            .filter(
                is_approved_by_moderator=True,
                published_at__gte=datetime.utcnow() - timedelta(hours=24),
            )\
            .exclude(type=Post.TYPE_INTRO)\
            .order_by("-upvotes")[:6]

        send_telegram_message(
            chat=ADMIN_CHAT,
            text=render_html_message("good_morning.html",
                                     posts=new_posts,
                                     greetings=random.choice(DUMB_GREETINGS)),
        )

        self.stdout.write("Done 🥙")
Esempio n. 14
0
def announce_in_club_channel(post, announce_text=None, image=None):
    if not announce_text:
        announce_text = render_html_message("channel_post_announce.html",
                                            post=post)

    if image:
        send_telegram_image(
            chat=CLUB_CHANNEL,
            image_url=image,
            text=announce_text,
        )
    else:
        send_telegram_message(
            chat=CLUB_CHANNEL,
            text=announce_text,
            disable_preview=False,
            parse_mode=telegram.ParseMode.HTML,
        )
Esempio n. 15
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(f"❌ {title}", callback_data=f"reject_post_{reason}:{post.id}")]
                    for reason, title in REJECT_POST_REASONS.get(post.type) or []
                ],
                [
                    telegram.InlineKeyboardButton("❌ В черновики", callback_data=f"reject_post:{post.id}"),
                    telegram.InlineKeyboardButton("😕 Так себе", callback_data=f"forgive_post:{post.id}"),
                ],
                [
                    telegram.InlineKeyboardButton("👍 Одобрить", callback_data=f"approve_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,
    )

    # only for newly created posts
    if post.is_visible and (is_created or "is_visible" in post.changed_fields):
        notified_user_ids = set()

        # parse @nicknames and notify mentioned users
        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)

        # notify friends about new posts
        friends = Friend.friends_for_user(post.author)
        for friend in friends:
            if friend.user_from.telegram_id \
                    and friend.is_subscribed_to_posts \
                    and friend.user_from.id not in notified_user_ids:
                send_telegram_message(
                    chat=Chat(id=friend.user_from.telegram_id),
                    text=render_html_message("friend_post.html", post=post),
                )
                notified_user_ids.add(friend.user_from.id)
Esempio n. 16
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)
Esempio n. 17
0
def do_user_admin_actions(request, user, data):
    if not request.me.is_moderator:
        raise AccessDenied()

    # Roles
    if data["role"] and is_role_manageable_by_user(data["role"], request.me):
        role = data["role"]
        if data["role_action"] == "add" and role not in user.roles:
            user.roles.append(role)
            user.save()
        if data["role_action"] == "delete" and role in user.roles:
            user.roles.remove(role)
            user.save()

    # Hats
    if data["remove_hat"]:
        user.hat = None
        user.save()

    if data["add_hat"]:
        if data["new_hat"]:
            hat = HATS.get(data["new_hat"])
            if hat:
                user.hat = {"code": data["new_hat"], **hat}
                user.save()
        else:
            user.hat = {
                "code": "custom",
                "title": data["new_hat_name"],
                "icon": data["new_hat_icon"],
                "color": data["new_hat_color"],
            }
            user.save()

    # Achievements
    if data["new_achievement"]:
        achievement = Achievement.objects.filter(
            code=data["new_achievement"]).first()
        if achievement:
            UserAchievement.objects.get_or_create(
                user=user,
                achievement=achievement,
            )

    # Ban
    if data["is_banned"]:
        if not user.is_god:
            user.is_banned_until = datetime.utcnow() + timedelta(
                days=data["ban_days"])
            user.save()
            if data["ban_days"] > 0:
                send_banned_email(user,
                                  days=data["ban_days"],
                                  reason=data["ban_reason"])
                notify_admin_user_on_ban(user,
                                         days=data["ban_days"],
                                         reason=data["ban_reason"])

    # Unmoderate
    if data["is_rejected"]:
        user.moderation_status = User.MODERATION_STATUS_REJECTED
        user.save()
        send_unmoderated_email(user)
        notify_admin_user_unmoderate(user)

    # Delete account
    if data["delete_account"] and request.me.is_god:
        user.membership_expires_at = datetime.utcnow()
        user.is_banned_until = datetime.utcnow() + timedelta(days=5000)

        # cancel recurring payments
        cancel_all_stripe_subscriptions(user.stripe_id)

        # mark user for deletion
        user.deleted_at = datetime.utcnow()
        user.save()

        # remove sessions
        Session.objects.filter(user=user).delete()

        # notify user
        send_delete_account_confirm_email(user=user, )

        # notify admins
        send_telegram_message(
            chat=ADMIN_CHAT,
            text=
            f"💀 Юзер был удален админами: {settings.APP_HOST}/user/{user.slug}/",
        )

    # Ping
    if data["ping"]:
        send_ping_email(user, message=data["ping"])
        notify_user_ping(user, message=data["ping"])
        notify_admin_user_ping(user, message=data["ping"])

    # Add more days of membership
    if data["add_membership_days"] and int(data["add_membership_days"]) > 0:
        gift_membership_days(
            days=data["add_membership_days"],
            from_user=request.me,
            to_user=user,
            deduct_from_original_user=False,
        )

        send_telegram_message(
            chat=ADMIN_CHAT,
            text=
            f"🎁 <b>Юзеру {user.slug} добавили {data['add_membership_days']} дней членства</b>",
        )

    return redirect("profile", user.slug)
Esempio n. 18
0
def notify_admin_user_unmoderate(user):
    send_telegram_message(
        chat=ADMIN_CHAT,
        text=f"💣 <b>Юзера {user.slug} размодерировали</b>"
    )
Esempio n. 19
0
def notify_admin_user_ping(user, message):
    send_telegram_message(
        chat=ADMIN_CHAT,
        text=f"🛎 <b>Юзера {user.slug} пинганули:</b> {message}"
    )
Esempio n. 20
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}"
        )
Esempio n. 21
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:
            # respect subscription type (i.e. all comments vs top level only)
            if post_subscriber.type == PostSubscription.TYPE_ALL_COMMENTS \
                    or (post_subscriber.type == PostSubscription.TYPE_TOP_LEVEL_ONLY and not comment.reply_to_id):
                send_telegram_message(
                    chat=Chat(id=post_subscriber.user.telegram_id),
                    text=render_html_message("comment_to_post.html",
                                             comment=comment),
                )
                notified_user_ids.add(post_subscriber.user.id)

    # notify thread author on reply (note: 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 and comment.post.is_visible and comment.post.is_visible_in_feeds:
        send_telegram_message(
            chat=CLUB_ONLINE,
            text=render_html_message("comment_to_post.html", comment=comment),
        )

    # notify friends about your comments (not replies)
    if not comment.reply_to:
        friends = Friend.friends_for_user(comment.author)
        for friend in friends:
            if friend.user_from.telegram_id \
                    and friend.is_subscribed_to_comments \
                    and friend.user_from.id not in notified_user_ids:
                send_telegram_message(
                    chat=Chat(id=friend.user_from.telegram_id),
                    text=render_html_message("friend_comment.html",
                                             comment=comment),
                )
                notified_user_ids.add(friend.user_from.id)

    # parse @nicknames and notify their users
    for username in USERNAME_RE.findall(comment.text):
        if username == settings.MODERATOR_USERNAME:
            send_telegram_message(
                chat=ADMIN_CHAT,
                text=render_html_message("moderator_mention.html",
                                         comment=comment),
            )
            continue

        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)
Esempio n. 22
0
    def handle(self, *args, **options):
        # render digest using a special html endpoint
        try:
            digest = generate_weekly_digest()
        except NotFound:
            log.error("Weekly digest is empty")
            return

        # get a version without "unsubscribe" footer for posting on home page
        digest_without_footer = generate_weekly_digest(no_footer=True)

        # save digest as a post
        issue = (datetime.utcnow() - settings.LAUNCH_DATE).days // 7
        year, week, _ = (datetime.utcnow() - timedelta(days=7)).isocalendar()
        post, _ = Post.objects.update_or_create(
            slug=f"{year}_{week}",
            type=Post.TYPE_WEEKLY_DIGEST,
            defaults=dict(
                author=User.objects.filter(slug="vas3k").first(),
                title=f"Клубный журнал. Итоги недели. Выпуск #{issue}",
                html=digest_without_footer,
                text=digest_without_footer,
                is_pinned_until=datetime.utcnow() + timedelta(days=1),
                is_visible=True,
                is_public=False,
            ))

        # make it searchable
        SearchIndex.update_post_index(post)

        # sending emails
        subscribed_users = User.objects\
            .filter(
                is_email_verified=True,
                membership_expires_at__gte=datetime.utcnow() - timedelta(days=14),
                moderation_status=User.MODERATION_STATUS_APPROVED,
            )\
            .exclude(email_digest_type=User.EMAIL_DIGEST_TYPE_NOPE)\
            .exclude(is_email_unsubscribed=True)

        for user in subscribed_users:
            self.stdout.write(f"Sending to {user.email}...")

            if not options.get("production") and user.email not in dict(
                    settings.ADMINS).values():
                self.stdout.write(
                    "Test mode. Use --production to send the digest to all users"
                )
                continue

            try:
                digest = digest\
                    .replace("%username%", user.slug)\
                    .replace("%user_id%", str(user.id))\
                    .replace("%secret_code%", base64.b64encode(user.secret_hash.encode("utf-8")).decode())

                send_club_email(
                    recipient=user.email,
                    subject=f"🤘 Клубный журнал. Итоги недели. Выпуск #{issue}",
                    html=digest,
                    tags=["weekly_digest", f"weekly_digest_{issue}"])
            except Exception as ex:
                self.stdout.write(f"Sending to {user.email} failed: {ex}")
                log.exception(f"Error while sending an email to {user.email}")
                continue

        if options.get("production"):
            # flush digest intro and title for next time
            GodSettings.objects.update(digest_intro=None, digest_title=None)

        send_telegram_message(
            chat=CLUB_CHANNEL,
            text=render_html_message("weekly_digest_announce.html", post=post),
            disable_preview=False,
            parse_mode=telegram.ParseMode.HTML,
        )

        self.stdout.write("Done 🥙")
Esempio n. 23
0
    def handle(self, *args, **options):
        # render digest using a special html endpoint
        digest_url = "https://vas3k.club" + reverse("render_weekly_digest")
        self.stdout.write(f"Generating digest: {digest_url}")

        digest_html_response = requests.get(digest_url)
        if digest_html_response.status_code > 400:
            log.error("Weekly digest error: bad status code",
                      extra={"html": digest_html_response.text})
            return

        digest_html = digest_html_response.text

        no_footer_digest_response = requests.get(digest_url,
                                                 params={"no_footer": 1})
        if no_footer_digest_response.status_code > 400:
            log.error("Weekly digest without footer error: bad status code",
                      extra={"html": no_footer_digest_response.text})
            return

        no_footer_digest_html = no_footer_digest_response.text

        # save digest as a post
        issue = (datetime.utcnow() - settings.LAUNCH_DATE).days // 7
        year, week, _ = (datetime.utcnow() - timedelta(days=7)).isocalendar()
        post, _ = Post.objects.update_or_create(
            slug=f"{year}_{week}",
            type=Post.TYPE_WEEKLY_DIGEST,
            defaults=dict(
                author=User.objects.filter(slug="vas3k").first(),
                title=f"Клубный журнал. Итоги недели. Выпуск #{issue}",
                html=no_footer_digest_html,
                text=no_footer_digest_html,
                is_pinned_until=datetime.utcnow() + timedelta(days=1),
                is_visible=True,
                is_public=False,
            ))

        SearchIndex.update_post_index(post)

        # sending emails
        subscribed_users = User.objects\
            .filter(
                is_email_verified=True,
                membership_expires_at__gte=datetime.utcnow() - timedelta(days=14),
                moderation_status=User.MODERATION_STATUS_APPROVED
            )\
            .exclude(email_digest_type=User.EMAIL_DIGEST_TYPE_NOPE)\
            .exclude(is_email_unsubscribed=True)

        for user in subscribed_users:
            self.stdout.write(f"Sending to {user.email}...")

            if not options.get("production") and user.email != "*****@*****.**":
                self.stdout.write(
                    "Test mode. Use --production to send the digest to all users"
                )
                continue

            try:
                user_digest_html = str(digest_html)
                user_digest_html = user_digest_html\
                    .replace("%username%", user.slug)\
                    .replace("%user_id%", str(user.id))\
                    .replace("%secret_code%", base64.b64encode(user.secret_hash.encode("utf-8")).decode())

                send_club_email(
                    recipient=user.email,
                    subject=f"🤘 Клубный журнал. Итоги недели. Выпуск #{issue}",
                    html=user_digest_html,
                    tags=["weekly_digest", f"weekly_digest_{issue}"])
            except Exception as ex:
                self.stdout.write(f"Sending to {user.email} failed: {ex}")
                log.exception(f"Error while sending an email to {user.email}")
                continue

        if options.get("production"):
            # flush digest intro for next time
            GodSettings.objects.update(digest_intro=None)

        send_telegram_message(
            chat=CLUB_CHANNEL,
            text=render_html_message("weekly_digest_announce.html", post=post),
            disable_preview=True,
            parse_mode=telegram.ParseMode.HTML,
        )

        self.stdout.write("Done 🥙")
Esempio n. 24
0
def do_user_admin_actions(request, user, data):
    if not request.me.is_moderator:
        raise AccessDenied()

    # Hats
    if data["remove_hat"]:
        user.hat = None
        user.save()

    if data["add_hat"]:
        if data["new_hat"]:
            hat = HATS.get(data["new_hat"])
            if hat:
                user.hat = {"code": data["new_hat"], **hat}
                user.save()
        else:
            user.hat = {
                "code": "custom",
                "title": data["new_hat_name"],
                "icon": data["new_hat_icon"],
                "color": data["new_hat_color"],
            }
            user.save()

    # Achievements
    if data["new_achievement"]:
        achievement = Achievement.objects.filter(
            code=data["new_achievement"]).first()
        if achievement:
            UserAchievement.objects.get_or_create(
                user=user,
                achievement=achievement,
            )

    # Ban
    if data["is_banned"]:
        if not user.is_god:
            user.is_banned_until = datetime.utcnow() + timedelta(
                days=data["ban_days"])
            user.save()
            if data["ban_days"] > 0:
                send_banned_email(user,
                                  days=data["ban_days"],
                                  reason=data["ban_reason"])

    # Unban
    if data["is_unbanned"]:
        user.is_banned_until = None
        user.save()

    # Unmoderate
    if data["is_rejected"]:
        user.moderation_status = User.MODERATION_STATUS_REJECTED
        user.save()
        send_unmoderated_email(user)
        notify_admin_user_unmoderate(user)

    # Delete account
    if data["delete_account"] and request.me.is_god:
        user.membership_expires_at = datetime.utcnow()
        user.is_banned_until = datetime.utcnow() + timedelta(days=5000)

        # cancel recurring payments
        cancel_all_stripe_subscriptions(user.stripe_id)

        # mark user for deletion
        user.deleted_at = datetime.utcnow()
        user.save()

        # remove sessions
        Session.objects.filter(user=user).delete()

        # notify user
        send_delete_account_confirm_email(user=user, )

        # notify admins
        send_telegram_message(
            chat=ADMIN_CHAT,
            text=
            f"💀 Юзер был удален админами: {settings.APP_HOST}/user/{user.slug}/",
        )

    # Ping
    if data["ping"]:
        send_ping_email(user, message=data["ping"])
        notify_user_ping(user, message=data["ping"])
        notify_admin_user_ping(user, message=data["ping"])

    return redirect("profile", user.slug)