def create_badge_for_comment(request, comment_id): comment = get_object_or_404(Comment, id=comment_id) if comment.is_deleted: raise BadRequest( title="😵 Комментарий удалён", message="Нельзя выдавать награды за удалённые комменты") if comment.author.deleted_at: raise BadRequest(title="😵 Пользователь удалился", message="Нельзя выдавать награды удалённым юзерам") if comment.author == request.me: raise BadRequest(title="😵 Это же ты", message="Нельзя выдавать награды самому себе") if request.method != "POST": if request.me.membership_days_left( ) < settings.MIN_DAYS_TO_GIVE_BADGES: return render(request, "badges/messages/insufficient_funds.html") return render(request, "badges/create.html", { "comment": comment, "badges": Badge.visible_objects().all(), }) badge_code = request.POST.get("badge_code") badge = Badge.objects.filter(code=badge_code).first() if not badge or not badge.is_visible: raise BadRequest(title="🙅♀️ Бейджик недоступен", message="Данную награду пока нельзя выдавать") note = (request.POST.get("note") or "")[:1000] user_badge = UserBadge.create_user_badge( badge=badge, from_user=request.me, to_user=comment.author, comment=comment, note=note, ) # bump post on home page by updating its last_activity_at Post.objects.filter(id=comment.post_id).update( last_activity_at=datetime.utcnow()) # show insufficient funds warning if < 3 months show_funds_warning = request.me.membership_days_left() - \ user_badge.badge.price_days < settings.MIN_DAYS_TO_GIVE_BADGES * 3 return render(request, "badges/messages/success.html", { "user_badge": user_badge, "show_funds_warning": show_funds_warning, })
def create_user_badge(cls, badge, from_user, to_user, post=None, comment=None, note=None): if from_user == to_user: raise BadRequest( title="🛑 Нельзя дарить награды самому себе", message="Это что такое-то вообще!" ) if badge.price_days >= from_user.membership_days_left(): raise InsufficientFunds( title="💸 Недостаточно средств :(", message=f"Вы не можете подарить юзеру эту награду, " f"так как у вас осталось {math.floor(from_user.membership_days_left())} дней членства, " f"а награда стоит {badge.price_days}. " f"Продлите членство в настройках своего профиля." ) with transaction.atomic(): # save user badge into the database try: user_badge = UserBadge.objects.create( badge=badge, from_user=from_user, to_user=to_user, post=post, comment=comment, note=note, ) except IntegrityError: raise ContentDuplicated( title="🛑 Вы уже дарили награду за этот пост или комментарий", message="Повторно награды дарить нельзя. Но вы можете подарить другую награду." ) # deduct days balance from profile User.objects\ .filter(id=from_user.id)\ .update( membership_expires_at=F("membership_expires_at") - timedelta(days=badge.price_days) ) # add badge to post/comment metadata (for caching purposes) comment_or_post = comment or post metadata = comment_or_post.metadata or {} badges = metadata.get("badges") or {} if badge.code not in badges: # add new badge badges[badge.code] = { "title": badge.title, "description": badge.description, "count": 1, } else: # if badge exists, increment badge count badges[badge.code]["count"] += 1 # update metadata only (do not use .save(), it saves all fields and can cause side-effects) metadata["badges"] = badges type(comment_or_post).objects.filter(id=comment_or_post.id).update(metadata=metadata) return user_badge
def request_delete_account(request, user_slug): if request.method != "POST": return redirect("edit_account", user_slug, permanent=False) user = get_object_or_404(User, slug=user_slug) if user.id != request.me.id and not request.me.is_god: raise Http404() confirmation_string = request.POST.get("confirm") if confirmation_string != settings.GDPR_DELETE_CONFIRMATION: raise BadRequest( title="Неправильная строка подтверждения", message= f"Вы должны в точности написать \"{settings.GDPR_DELETE_CONFIRMATION}\" " f"чтобы запустить процедуру удаления аккаунта") DataRequests.register_forget_request(user) code = Code.create_for_user(user=user, recipient=user.email, length=settings.GDPR_DELETE_CODE_LENGTH) async_task(send_delete_account_request_email, user=user, code=code) return render(request, "users/messages/delete_account_requested.html", {"user": user})
def gift_membership_days(days, from_user, to_user, deduct_from_original_user=True): if days <= 0: raise BadRequest(message="Количество дней должно быть больше 0") amount = timedelta(days=days) if deduct_from_original_user and from_user.membership_expires_at - amount <= datetime.utcnow( ): raise InsufficientFunds() with transaction.atomic(): if to_user.membership_expires_at <= datetime.utcnow(): to_user.membership_expires_at = datetime.utcnow() to_user.membership_expires_at += amount to_user.membership_platform_type = User.MEMBERSHIP_PLATFORM_DIRECT to_user.save() if deduct_from_original_user: from_user.membership_expires_at -= amount from_user.save() return to_user.membership_expires_at
def create_badge_for_post(request, post_slug): post = get_object_or_404(Post, slug=post_slug) if post.deleted_at: raise BadRequest(title="😵 Пост удалён", message="Нельзя давать награды за удалённые посты") if request.method != "POST": if request.me.membership_days_left( ) < settings.MIN_DAYS_TO_GIVE_BADGES: return render(request, "badges/messages/insufficient_funds.html") return render(request, "badges/create.html", { "post": post, "badges": Badge.visible_objects().all(), }) badge_code = request.POST.get("badge_code") badge = Badge.objects.filter(code=badge_code).first() if not badge or not badge.is_visible: raise BadRequest(title="🙅♀️ Бейджик недоступен", message="Данную награду пока нельзя выдавать") note = (request.POST.get("note") or "")[:1000] user_badge = UserBadge.create_user_badge( badge=badge, from_user=request.me, to_user=post.author, post=post, note=note, ) # bump post on home page by updating its last_activity_at Post.objects.filter(id=post.id).update(last_activity_at=datetime.utcnow()) # show insufficient funds warning if < 3 months show_funds_warning = request.me.membership_days_left() - \ user_badge.badge.price_days < settings.MIN_DAYS_TO_GIVE_BADGES * 3 return render(request, "badges/messages/success.html", { "user_badge": user_badge, "show_funds_warning": show_funds_warning, })
def save(self, *args, **kwargs): if self.reply_to and self.reply_to.reply_to and self.reply_to.reply_to.reply_to_id: raise BadRequest(message="3 уровня комментариев это максимум") self.updated_at = datetime.utcnow() return super().save(*args, **kwargs)