from __future__ import annotations from django.conf import settings from django.contrib import messages from django.core.cache import cache from django.core.exceptions import ValidationError from django.http import HttpResponse from django.shortcuts import get_object_or_404, redirect from django.views import View from apps.blog.models import ArticlePage from apps.comments.forms import CommentForm from apps.comments.models import Comment def client_ip_from_request(request) -> str: remote_addr = request.META.get("REMOTE_ADDR", "").strip() trusted_proxies = getattr(settings, "TRUSTED_PROXY_IPS", []) x_forwarded_for = request.META.get("HTTP_X_FORWARDED_FOR", "") if remote_addr in trusted_proxies and x_forwarded_for: return x_forwarded_for.split(",")[0].strip() return remote_addr class CommentCreateView(View): def post(self, request): ip = client_ip_from_request(request) key = f"comment-rate:{ip}" count = cache.get(key, 0) if count >= 3: return HttpResponse(status=429) cache.set(key, count + 1, timeout=60) form = CommentForm(request.POST) article = get_object_or_404(ArticlePage, pk=request.POST.get("article_id")) if not article.comments_enabled: return HttpResponse(status=404) if form.is_valid(): if form.cleaned_data.get("honeypot"): return redirect(f"{article.url}?commented=1") comment = form.save(commit=False) comment.article = article parent_id = form.cleaned_data.get("parent_id") if parent_id: comment.parent = Comment.objects.filter(pk=parent_id, article=article).first() comment.ip_address = ip or None try: comment.full_clean() except ValidationError: messages.error(request, "Reply depth exceeds the allowed limit") return redirect(article.url) comment.save() messages.success(request, "Your comment is awaiting moderation") return redirect(f"{article.url}?commented=1") messages.error(request, "Please correct the form errors") return redirect(article.url)