def create_or_edit(request, post_type, post=None, mode="create"): FormClass = POST_TYPE_MAP.get(post_type) or PostTextForm # show blank form on GET if request.method != "POST": form = FormClass(instance=post) return render(request, f"posts/compose/{post_type}.html", { "mode": mode, "post_type": post_type, "form": form, }) # validate form on POST form = FormClass(request.POST, request.FILES, instance=post) if form.is_valid(): if not request.me.is_moderator: if Post.check_duplicate(user=request.me, title=form.cleaned_data["title"], ignore_post_id=post.id if post else None): raise ContentDuplicated() is_ok = Post.check_rate_limits(request.me) if not is_ok: raise RateLimitException( title="🙅♂️ Слишком много постов", message= "В последнее время вы создали слишком много постов. Потерпите, пожалуйста." ) post = form.save(commit=False) if not post.author_id: post.author = request.me post.type = post_type post.html = None # flush cache post.save() if mode == "create" or not post.is_visible: PostSubscription.subscribe(request.me, post, type=PostSubscription.TYPE_ALL_COMMENTS) if post.is_visible: if post.topic: post.topic.update_last_activity() SearchIndex.update_post_index(post) LinkedPost.create_links_from_text(post, post.text) action = request.POST.get("action") if action == "publish": post.publish() LinkedPost.create_links_from_text(post, post.text) return redirect("show_post", post.type, post.slug) return render(request, f"posts/compose/{post_type}.html", { "mode": mode, "post_type": post_type, "form": form, })
def create_comment(request, post_slug): post = get_object_or_404(Post, slug=post_slug) if not post.is_commentable and not request.me.is_moderator: raise AccessDenied(title="Комментарии к этому посту закрыты") if request.POST.get("reply_to_id"): ProperCommentForm = ReplyForm elif post.type == Post.TYPE_BATTLE: ProperCommentForm = BattleCommentForm else: ProperCommentForm = CommentForm if request.method == "POST": form = ProperCommentForm(request.POST) if form.is_valid(): is_ok = Comment.check_rate_limits(request.me) if not is_ok: raise RateLimitException( title="🙅♂️ Вы комментируете слишком часто", message= "Подождите немного, вы достигли нашего лимита на комментарии в день. " "Можете написать нам в саппорт, пожаловаться об этом.") comment = form.save(commit=False) comment.post = post if not comment.author: comment.author = request.me comment.ipaddress = parse_ip_address(request) comment.useragent = parse_useragent(request) comment.save() # update the shitload of counters :) request.me.update_last_activity() Comment.update_post_counters(post) PostView.increment_unread_comments(comment) PostView.register_view( request=request, user=request.me, post=post, ) SearchIndex.update_comment_index(comment) LinkedPost.create_links_from_text(post, comment.text) return redirect("show_comment", post.slug, comment.id) else: log.error(f"Comment form error: {form.errors}") return render( request, "error.html", { "title": "Какая-то ошибка при публикации комментария 🤷♂️", "message": f"Мы уже получили оповещение и скоро пофиксим. " f"Ваш коммент мы сохранили чтобы вы могли скопировать его и запостить еще раз:", "data": form.cleaned_data.get("text") }) raise Http404()
def compose_type(request, post_type): if post_type not in dict(Post.TYPES): raise Http404() FormClass = POST_TYPE_MAP.get(post_type) or PostTextForm if request.method == "POST": form = FormClass(request.POST, request.FILES) if form.is_valid(): if not request.me.is_moderator: if Post.check_duplicate(user=request.me, title=form.cleaned_data["title"]): raise ContentDuplicated() is_ok = Post.check_rate_limits(request.me) if not is_ok: raise RateLimitException( title="🙅♂️ Слишком много постов", message= "В последнее время вы создали слишком много постов. Потерпите, пожалуйста." ) post = form.save(commit=False) post.author = request.me post.type = post_type post.save() PostSubscription.subscribe(request.me, post) if post.is_visible: if post.topic: post.topic.update_last_activity() SearchIndex.update_post_index(post) LinkedPost.create_links_from_text(post, post.text) if post.is_visible or request.POST.get("show_preview"): return redirect("show_post", post.type, post.slug) else: return redirect("compose") else: form = FormClass() return render(request, f"posts/compose/{post_type}.html", { "mode": "create", "form": form })
def create_for_user(cls, user, recipient, length=6): recipient = recipient.lower() last_codes_count = Code.objects.filter( recipient=recipient, created_at__gte=datetime.utcnow() - settings.AUTH_MAX_CODE_TIMEDELTA, ).count() if last_codes_count > settings.AUTH_MAX_CODE_COUNT: raise RateLimitException(title="Вы запросили слишком много кодов") return Code.objects.create( recipient=recipient, user=user, code=random_number(length), created_at=datetime.utcnow(), expires_at=datetime.utcnow() + settings.AUTH_CODE_EXPIRATION_TIMEDELTA, )
def register_archive_request(cls, user): latest_request = DataRequests.objects\ .filter(user=user, type=DataRequests.TYPE_ARCHIVE)\ .order_by("-created_at")\ .first() if latest_request and latest_request.created_at > datetime.utcnow( ) - settings.GDPR_ARCHIVE_REQUEST_TIMEDELTA: raise RateLimitException( title="Вы уже запрашивали архив совсем недавно", message="Генерация архива — сложная задача, " "потому нам приходится ограничивать количество запросов в день. " "Приходите завтра!") return DataRequests.objects.create( user=user, type=DataRequests.TYPE_ARCHIVE, )
def check_code(cls, recipient, code): recipient = recipient.lower() last_code = Code.objects.filter(recipient=recipient).order_by("-created_at").first() if not last_code: raise InvalidCode() if last_code.attempts >= settings.AUTH_MAX_CODE_ATTEMPTS: raise RateLimitException( title="Вы ввели код неправильно несколько раз. Придётся запросить его заново", message="Все прошлые коды больше недействительны ради защиты от перебора" ) if last_code.is_expired() or last_code.code != code: last_code.attempts += 1 last_code.save() raise InvalidCode() Code.objects.filter(recipient=recipient).delete() return last_code.user