diff --git a/articles/admin.py b/articles/admin.py index 70e4c28..49e0a81 100644 --- a/articles/admin.py +++ b/articles/admin.py @@ -1,9 +1,11 @@ +import copy + from django.contrib import admin, messages from django.contrib.admin import register from django.contrib.auth.admin import UserAdmin from django.shortcuts import redirect -from .models import Article, Comment, Page, User +from .models import Article, Page, User admin.site.register(User, UserAdmin) @@ -29,7 +31,7 @@ class ArticleAdmin(admin.ModelAdmin): { "fields": [ ("title", "slug"), - ("author", "comments_allowed"), + ("author",), ("status", "published_at"), ("created_at", "updated_at"), "views_count", @@ -100,27 +102,3 @@ class PageAdmin(ArticleAdmin): article_fieldsets = ArticleAdmin.fieldsets article_fieldsets[0][1]["fields"][0] = ("title", "slug", "position") return article_fieldsets - - -@register(Comment) -class CommentAdmin(admin.ModelAdmin): - list_display = ( - "username", - "email", - "content", - "article", - "created_at", - "status", - "user_notified", - ) - list_filter = ("status",) - search_fields = ("username", "email", "content") - actions = ["approve_comments", "reject_comments"] - - def approve_comments(self, request, queryset): - count = queryset.update(status=Comment.APPROVED, user_notified=False) - messages.success(request, f"Approved {count} message(s).") - - def reject_comments(self, request, queryset): - count = queryset.update(status=Comment.REJECTED, user_notified=False) - messages.success(request, f"Rejected {count} message(s).") diff --git a/articles/forms.py b/articles/forms.py deleted file mode 100644 index 9b58638..0000000 --- a/articles/forms.py +++ /dev/null @@ -1,33 +0,0 @@ -from django import forms - -from articles.models import Comment - - -class CommentForm(forms.ModelForm): - required_css_class = "required" - error_css_class = "error" - - class Meta: - model = Comment - fields = ["username", "email", "content"] - - def as_table(self): - "Return this form rendered as HTML s -- excluding the
." - return self._html_output( - normal_row="%(label)s%(errors)s%(field)s%(help_text)s", - error_row=( - '%s' - '' - ), - row_ender="", - help_text_html='
%s', - errors_on_separate_row=False, - ) - - def __init__(self, *args, **kwargs): - defaults = { - "label_suffix": "", - } - defaults.update(kwargs) - - super().__init__(*args, **defaults) diff --git a/articles/management/commands/check_pending_comments.py b/articles/management/commands/check_pending_comments.py deleted file mode 100644 index c168215..0000000 --- a/articles/management/commands/check_pending_comments.py +++ /dev/null @@ -1,28 +0,0 @@ -from django.conf import settings -from django.core.mail import mail_admins -from django.core.management import BaseCommand -from django.urls import reverse -from django.utils.translation import ngettext - -from articles.models import Comment - - -class Command(BaseCommand): - help = "Check for pending comments and send an email to the admin." - - def handle(self, *args, **options): - count = Comment.objects.filter(status=Comment.PENDING).count() - if count: - url = reverse("admin:articles_comment_changelist") - url = (settings.BLOG["base_url"] + url).replace( - "//", "/" - ) + "?status__exact=pending" - message = ( - ngettext( - "There is %(count)d comment pending review.\n%(url)s", - "There are %(count)d comments pending review.\n%(url)s", - count, - ) - % {"count": count, "url": url} - ) - mail_admins("Comments pending review", message) diff --git a/articles/management/commands/notify_commenters.py b/articles/management/commands/notify_commenters.py deleted file mode 100644 index 2af7644..0000000 --- a/articles/management/commands/notify_commenters.py +++ /dev/null @@ -1,54 +0,0 @@ -from collections import defaultdict - -from django.conf import settings -from django.core.mail import mail_admins, send_mass_mail -from django.core.management import BaseCommand -from django.db.models import Q -from django.template import Context, Engine -from django.template.loader import render_to_string -from django.urls import reverse -from django.utils.translation import ngettext - -from articles.models import Comment - - -class Command(BaseCommand): - help = "Check for pending comments and send an email to the admin." - - def handle(self, *args, **options): - to_notify = ( - Comment.objects.filter( - Q(status=Comment.APPROVED) | Q(status=Comment.REJECTED), - user_notified=False, - ) - .exclude(email=None) - .exclude(email="") - ) - by_email = {} - for comment in to_notify: - if comment.email not in by_email: - by_email[comment.email] = {"approved": [], "rejected": []} - if comment.status == Comment.APPROVED: - by_email[comment.email]["approved"].append(comment) - elif comment.status == Comment.REJECTED: - by_email[comment.email]["rejected"].append(comment) - - email_data = [] - for email, comments in by_email.items(): - approved = comments["approved"] - rejected = comments["rejected"] - subject = ngettext( - "Your comment has been moderated.", - "Your comments have been moderated.", - len(approved) + len(rejected), - ) - blog_title = settings.BLOG["title"] - message = render_to_string( - "articles/comments_notification_email.txt", - {"approved": approved, "rejected": rejected, "blog_title": blog_title}, - ).replace("'", "'") - from_email = settings.DEFAULT_FROM_EMAIL - recipient_list = [email] - email_data.append((subject, message, from_email, recipient_list)) - send_mass_mail(tuple(email_data)) - to_notify.update(user_notified=True) diff --git a/articles/migrations/0021_auto_20201110_1623.py b/articles/migrations/0021_auto_20201110_1623.py new file mode 100644 index 0000000..488560e --- /dev/null +++ b/articles/migrations/0021_auto_20201110_1623.py @@ -0,0 +1,20 @@ +# Generated by Django 3.1.1 on 2020-11-10 15:23 + +from django.db import migrations + + +class Migration(migrations.Migration): + + dependencies = [ + ("articles", "0020_auto_20200903_2157"), + ] + + operations = [ + migrations.RemoveField( + model_name="article", + name="comments_allowed", + ), + migrations.DeleteModel( + name="Comment", + ), + ] diff --git a/articles/models.py b/articles/models.py index d17704c..85ba5d4 100644 --- a/articles/models.py +++ b/articles/models.py @@ -48,7 +48,6 @@ class Article(AdminUrlMixin, models.Model): author = models.ForeignKey(User, on_delete=models.PROTECT, default=1) views_count = models.IntegerField(default=0) slug = models.SlugField(unique=True, max_length=255) - comments_allowed = models.BooleanField(default=True) objects = models.Manager() without_pages = ArticleManager() @@ -118,47 +117,3 @@ class Page(Article): class Meta: ordering = ["position", "-published_at"] - - -class Comment(AdminUrlMixin, models.Model): - PENDING = "pending" - APPROVED = "approved" - REJECTED = "rejected" - STATUS_CHOICES = ( - (PENDING, "Pending"), - (APPROVED, "Approved"), - (REJECTED, "Rejected"), - ) - username = models.CharField( - max_length=255, help_text="Will be displayed with your comment." - ) - email = models.EmailField( - blank=True, - null=True, - help_text=( - "Not mandatory, fill only if you want me to be able to contact you. " - "It will never be displayed here nor shared with any third party." - ), - ) - content = models.TextField( - max_length=500, - help_text="Your comment, limited to 500 characters. No formatting.", - ) - article = models.ForeignKey( - Article, on_delete=models.CASCADE, related_name="comments" - ) - created_at = models.DateTimeField(auto_now_add=True) - status = models.CharField(max_length=10, choices=STATUS_CHOICES, default=PENDING) - user_notified = models.BooleanField(default=False) - - class Meta: - ordering = ["created_at"] - - def __str__(self): - return f"{self.username} - {self.content[:50]}" - - def get_absolute_url(self): - return self.article.get_absolute_url() + "#" + str(self.id) - - def get_full_absolute_url(self, request: HttpRequest = None): - return self.article.get_full_absolute_url(request) + "#" + str(self.id) diff --git a/articles/static/style.css b/articles/static/style.css index 39b911d..514d8f4 100644 --- a/articles/static/style.css +++ b/articles/static/style.css @@ -211,33 +211,6 @@ textarea, input { width: 100%; } -/* COMMENTS */ -.comment { - background-color: var(--background2); - border-radius: .5ex; - padding: .5em 1em; -} - -.comment + .comment, .comments form { - margin-top: 1em; -} - -.comment p { - margin: 0; -} - -.comment .metadata { - color: var(--main3); -} - -.comment:target { - background-color: var(--warning-background); -} - -.permalink { - font-size: 80%; -} - /* MESSAGES */ .messages p { background-color: var(--background2); diff --git a/articles/templates/articles/article_detail.html b/articles/templates/articles/article_detail.html index 78477c4..e7d425d 100644 --- a/articles/templates/articles/article_detail.html +++ b/articles/templates/articles/article_detail.html @@ -5,13 +5,19 @@ {% endblock %} {% block content %}
-

{{ article.title }}{% if article.status != article.PUBLISHED %} ({{ article.status }}){% endif %}

+

{{ article.title }}{% if article.status != article.PUBLISHED %} ( + {{ article.status }}){% endif %}

{% include "articles/metadata_snippet.html" %}
{{ article.get_formatted_content|safe }}
- {% if article.comments_allowed %} - {% include 'articles/comment_snippet.html' %} - {% endif %} +
+

Comments

+

+ Comments are hard to manage. I tried enabling them but I only got spam. + If you want to react to this article or interact with me, please head to the + about me page ðŸ˜‰. +

+
{% endblock %} diff --git a/articles/templates/articles/comment_snippet.html b/articles/templates/articles/comment_snippet.html deleted file mode 100644 index 207e644..0000000 --- a/articles/templates/articles/comment_snippet.html +++ /dev/null @@ -1,34 +0,0 @@ -
-

Comments

- {% for comment in comments %} -
- -

- {{ comment.content|linebreaksbr }} -

-
- {% empty %} -

- No reaction yet, write your own! -

- {% endfor %} -
- {% csrf_token %} - - {{ form.as_table }} -
- -

- Your comment may not be approved if it's not respectful, on topic or spammy. - If you feel I've made a mistake with your comment, please - send me a message! -

-
-
diff --git a/articles/templates/articles/comments_notification_email.txt b/articles/templates/articles/comments_notification_email.txt deleted file mode 100644 index 4fa8c8a..0000000 --- a/articles/templates/articles/comments_notification_email.txt +++ /dev/null @@ -1,20 +0,0 @@ -Hello, - -This is a quick (automated) notification about the comments you left -on {{ blog_title }}. - -{% if approved %}Approved: -{% for comment in approved %}* {{ comment.get_full_absolute_url }} -{% endfor %}{% endif %} - -{% if rejected %}Rejected: -{% for comment in rejected %}* #{{comment.id}} on {{ comment.article.get_full_absolute_url }}: -{{ comment.content }} - -{% endfor %}{% endif %} - -You received this notification because you left your email address in the -comment form. - -Cheers, -Gabriel diff --git a/articles/views/html.py b/articles/views/html.py index 9d13647..30535b9 100644 --- a/articles/views/html.py +++ b/articles/views/html.py @@ -1,14 +1,11 @@ from typing import Union from django.conf import settings -from django.contrib import messages from django.contrib.auth.mixins import LoginRequiredMixin from django.db.models import F from django.views import generic -from django.views.generic.edit import FormMixin -from articles.forms import CommentForm -from articles.models import Article, Comment, Page +from articles.models import Article, Page class ArticlesListView(generic.ListView): @@ -40,9 +37,8 @@ class DraftsListView(generic.ListView, LoginRequiredMixin): return context -class ArticleDetailView(FormMixin, generic.DetailView): +class ArticleDetailView(generic.DetailView): model = Article - form_class = CommentForm context_object_name = "article" template_name = "articles/article_detail.html" @@ -52,14 +48,6 @@ class ArticleDetailView(FormMixin, generic.DetailView): return queryset return queryset.filter(status=Article.PUBLISHED) - def get_context_data(self, **kwargs): - context = super().get_context_data(**kwargs) - article = self.object - if hasattr(article, "article"): - article = article.article - context["comments"] = article.comments.filter(status=Comment.APPROVED) - return context - def get_object(self, queryset=None) -> Union[Article, Page]: obj = super().get_object(queryset) # type: Article if hasattr(obj, "page"): @@ -69,34 +57,3 @@ class ArticleDetailView(FormMixin, generic.DetailView): obj.save(update_fields=["views_count"]) return obj - - def post(self, request, *args, **kwargs): - self.object = self.get_object() # type: Union[Article, Page] - form = self.get_form() - - if not self.object.comments_allowed: - messages.error(self.request, "Comments are disabled on this article.") - # Bypassing self.form_invalid because we don't want its error message - return super().form_invalid(form) - - if form.is_valid(): - return self.form_valid(form) - else: - return self.form_invalid(form) - - def form_invalid(self, form): - messages.error( - self.request, - 'Your comment couldn\'t be saved, see the form below.', - ) - return super().form_invalid(form) - - def form_valid(self, form): - comment = form.save(commit=False) - comment.article = self.object - comment.save() - messages.success(self.request, "Comment successfully saved, pending review.") - return super().form_valid(form) - - def get_success_url(self): - return self.object.get_absolute_url() diff --git a/blog/urls.py b/blog/urls.py index 91a76e2..527e5af 100644 --- a/blog/urls.py +++ b/blog/urls.py @@ -34,9 +34,6 @@ urlpatterns = [ path("feed/", feeds.CompleteFeed(), name="complete-feed"), path("", html.ArticleDetailView.as_view(), name="article-detail-old"), path("/", html.ArticleDetailView.as_view(), name="article-detail"), - path( - "/comment/", html.ArticleDetailView.as_view(), name="create-comment" - ), ] if settings.DEBUG: