Add task to notify commenters once their comment has been moderated.

This commit is contained in:
Gabriel Augendre 2020-08-20 16:22:15 +02:00
parent 23985a3263
commit f6d6d7b850
7 changed files with 132 additions and 2 deletions

View file

@ -116,7 +116,15 @@ class PageAdmin(ArticleAdmin):
@register(Comment) @register(Comment)
class CommentAdmin(admin.ModelAdmin): class CommentAdmin(admin.ModelAdmin):
list_display = ("username", "email", "content", "article", "created_at", "status") list_display = (
"username",
"email",
"content",
"article",
"created_at",
"status",
"user_notified",
)
list_filter = ("status",) list_filter = ("status",)
search_fields = ("username", "email", "content") search_fields = ("username", "email", "content")
actions = ["approve_comments", "reject_comments"] actions = ["approve_comments", "reject_comments"]

View file

@ -0,0 +1,54 @@
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)

View file

@ -0,0 +1,18 @@
# Generated by Django 3.1 on 2020-08-20 13:42
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
("articles", "0015_auto_20200818_2138"),
]
operations = [
migrations.AddField(
model_name="comment",
name="user_notified",
field=models.BooleanField(default=False),
),
]

View file

@ -0,0 +1,16 @@
# Generated by Django 3.1 on 2020-08-20 14:06
from django.db import migrations
class Migration(migrations.Migration):
dependencies = [
("articles", "0016_comment_user_notified"),
]
operations = [
migrations.AlterModelOptions(
name="comment", options={"ordering": ["-created_at"]},
),
]

View file

@ -1,9 +1,11 @@
import re import re
import markdown import markdown
from django.conf import settings
from django.contrib.auth.models import AbstractUser from django.contrib.auth.models import AbstractUser
from django.contrib.contenttypes.models import ContentType from django.contrib.contenttypes.models import ContentType
from django.db import models from django.db import models
from django.http import HttpRequest
from django.template.defaultfilters import slugify from django.template.defaultfilters import slugify
from django.urls import reverse from django.urls import reverse
from django.utils import timezone from django.utils import timezone
@ -64,6 +66,13 @@ class Article(AdminUrlMixin, models.Model):
def get_absolute_url(self): def get_absolute_url(self):
return reverse("article-detail", kwargs={"slug": self.slug}) return reverse("article-detail", kwargs={"slug": self.slug})
def get_full_absolute_url(self, request: HttpRequest = None):
url = self.get_absolute_url()
if request:
return request.build_absolute_uri(url)
else:
return (settings.BLOG["base_url"] + url).replace("//", "/")
def get_abstract(self): def get_abstract(self):
html = self.get_formatted_content() html = self.get_formatted_content()
return html.split("<!--more-->")[0] return html.split("<!--more-->")[0]
@ -130,12 +139,16 @@ class Comment(AdminUrlMixin, models.Model):
) )
created_at = models.DateTimeField(auto_now_add=True) created_at = models.DateTimeField(auto_now_add=True)
status = models.CharField(max_length=10, choices=STATUS_CHOICES, default=PENDING) status = models.CharField(max_length=10, choices=STATUS_CHOICES, default=PENDING)
user_notified = models.BooleanField(default=False)
class Meta: class Meta:
ordering = ["created_at"] ordering = ["-created_at"]
def __str__(self): def __str__(self):
return f"{self.username} - {self.content[:50]}" return f"{self.username} - {self.content[:50]}"
def get_absolute_url(self): def get_absolute_url(self):
return self.article.get_absolute_url() + "#" + str(self.id) 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)

View file

@ -0,0 +1,20 @@
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

View file

@ -162,6 +162,7 @@ else:
AUTH_USER_MODEL = "articles.User" AUTH_USER_MODEL = "articles.User"
BLOG = { BLOG = {
"title": "Gab's Notes",
"description": "My take on tech-related subjects (but not only)", "description": "My take on tech-related subjects (but not only)",
"base_url": os.getenv("BLOG_BASE_URL", "https://gabnotes.org/"), "base_url": os.getenv("BLOG_BASE_URL", "https://gabnotes.org/"),
} }