Add task to notify commenters once their comment has been moderated.
This commit is contained in:
parent
23985a3263
commit
f6d6d7b850
7 changed files with 132 additions and 2 deletions
|
@ -116,7 +116,15 @@ class PageAdmin(ArticleAdmin):
|
|||
|
||||
@register(Comment)
|
||||
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",)
|
||||
search_fields = ("username", "email", "content")
|
||||
actions = ["approve_comments", "reject_comments"]
|
||||
|
|
54
articles/management/commands/notify_commenters.py
Normal file
54
articles/management/commands/notify_commenters.py
Normal 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)
|
18
articles/migrations/0016_comment_user_notified.py
Normal file
18
articles/migrations/0016_comment_user_notified.py
Normal 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),
|
||||
),
|
||||
]
|
16
articles/migrations/0017_auto_20200820_1606.py
Normal file
16
articles/migrations/0017_auto_20200820_1606.py
Normal 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"]},
|
||||
),
|
||||
]
|
|
@ -1,9 +1,11 @@
|
|||
import re
|
||||
|
||||
import markdown
|
||||
from django.conf import settings
|
||||
from django.contrib.auth.models import AbstractUser
|
||||
from django.contrib.contenttypes.models import ContentType
|
||||
from django.db import models
|
||||
from django.http import HttpRequest
|
||||
from django.template.defaultfilters import slugify
|
||||
from django.urls import reverse
|
||||
from django.utils import timezone
|
||||
|
@ -64,6 +66,13 @@ class Article(AdminUrlMixin, models.Model):
|
|||
def get_absolute_url(self):
|
||||
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):
|
||||
html = self.get_formatted_content()
|
||||
return html.split("<!--more-->")[0]
|
||||
|
@ -130,12 +139,16 @@ class Comment(AdminUrlMixin, models.Model):
|
|||
)
|
||||
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"]
|
||||
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)
|
||||
|
|
20
articles/templates/articles/comments_notification_email.txt
Normal file
20
articles/templates/articles/comments_notification_email.txt
Normal 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
|
|
@ -162,6 +162,7 @@ else:
|
|||
AUTH_USER_MODEL = "articles.User"
|
||||
|
||||
BLOG = {
|
||||
"title": "Gab's Notes",
|
||||
"description": "My take on tech-related subjects (but not only)",
|
||||
"base_url": os.getenv("BLOG_BASE_URL", "https://gabnotes.org/"),
|
||||
}
|
||||
|
|
Reference in a new issue