From a12e1b97cd07646c5809eb49f92c27a2bbd44be1 Mon Sep 17 00:00:00 2001
From: Dave Page
Date: Tue, 19 Mar 2024 14:52:24 +0000
Subject: [PATCH] Add the ability to include moderator notes on feeds.
---
hamnadmin/hamnadmin/register/admin.py | 7 +-
.../migrations/0007_moderatornotes.py | 31 ++++++
hamnadmin/hamnadmin/register/models.py | 15 +++
.../hamnadmin/register/templates/edit.html | 34 ++++++-
.../register/templates/moderate.html | 20 ++++
hamnadmin/hamnadmin/register/views.py | 98 ++++++++++---------
6 files changed, 157 insertions(+), 48 deletions(-)
create mode 100644 hamnadmin/hamnadmin/register/migrations/0007_moderatornotes.py
diff --git a/hamnadmin/hamnadmin/register/admin.py b/hamnadmin/hamnadmin/register/admin.py
index 7ca4a1f..7dde100 100644
--- a/hamnadmin/hamnadmin/register/admin.py
+++ b/hamnadmin/hamnadmin/register/admin.py
@@ -1,6 +1,6 @@
from django.contrib import admin
-from hamnadmin.register.models import Blog, Team, Post, AggregatorLog
+from hamnadmin.register.models import Blog, Team, Post, AggregatorLog, ModeratorNotes
class TeamAdmin(admin.ModelAdmin):
@@ -29,7 +29,12 @@ class AggregatorLogAdmin(admin.ModelAdmin):
list_display = ['ts', 'success', 'feed', 'info']
+class ModeratorNotesAdmin(admin.ModelAdmin):
+ list_display = ['ts', 'user', 'feed', 'note']
+
+
admin.site.register(Team, TeamAdmin)
admin.site.register(Blog, BlogAdmin)
admin.site.register(Post, PostAdmin)
admin.site.register(AggregatorLog, AggregatorLogAdmin)
+admin.site.register(ModeratorNotes, ModeratorNotesAdmin)
diff --git a/hamnadmin/hamnadmin/register/migrations/0007_moderatornotes.py b/hamnadmin/hamnadmin/register/migrations/0007_moderatornotes.py
new file mode 100644
index 0000000..cbc28a8
--- /dev/null
+++ b/hamnadmin/hamnadmin/register/migrations/0007_moderatornotes.py
@@ -0,0 +1,31 @@
+# Generated by Django 3.2.16 on 2024-03-19 14:51
+
+from django.conf import settings
+from django.db import migrations, models
+import django.db.models.deletion
+
+
+class Migration(migrations.Migration):
+
+ dependencies = [
+ migrations.swappable_dependency(settings.AUTH_USER_MODEL),
+ ('register', '0006_blog_lastsuccess'),
+ ]
+
+ operations = [
+ migrations.CreateModel(
+ name='ModeratorNotes',
+ fields=[
+ ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
+ ('ts', models.DateTimeField(auto_now=True)),
+ ('note', models.TextField()),
+ ('feed', models.ForeignKey(db_column='feed', on_delete=django.db.models.deletion.CASCADE, to='register.blog')),
+ ('user', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL)),
+ ],
+ options={
+ 'verbose_name_plural': 'Moderator notes',
+ 'db_table': 'moderatornotes',
+ 'ordering': ['-ts'],
+ },
+ ),
+ ]
diff --git a/hamnadmin/hamnadmin/register/models.py b/hamnadmin/hamnadmin/register/models.py
index 1ce886d..a06c7a0 100644
--- a/hamnadmin/hamnadmin/register/models.py
+++ b/hamnadmin/hamnadmin/register/models.py
@@ -136,3 +136,18 @@ class AggregatorLog(models.Model):
def __str__(self):
return "Log entry for %s (%s)" % (self.feed.name, self.ts)
+
+
+class ModeratorNotes(models.Model):
+ ts = models.DateTimeField(auto_now=True)
+ user = models.ForeignKey(User, null=False, blank=False, on_delete=models.CASCADE)
+ feed = models.ForeignKey(Blog, null=False, blank=False, db_column='feed', on_delete=models.CASCADE)
+ note = models.TextField()
+
+ class Meta:
+ db_table = 'moderatornotes'
+ verbose_name_plural = 'Moderator notes'
+ ordering = ['-ts']
+
+ def __str__(self):
+ return "Note for %s by %s at %s" % (self.feed.name, self.user, self.ts)
diff --git a/hamnadmin/hamnadmin/register/templates/edit.html b/hamnadmin/hamnadmin/register/templates/edit.html
index 190dbd2..d39bc20 100644
--- a/hamnadmin/hamnadmin/register/templates/edit.html
+++ b/hamnadmin/hamnadmin/register/templates/edit.html
@@ -30,8 +30,40 @@
automatically submitted for approval.
{% endif %}{#has_entries#}
{% endif %}{#approved#}
+
{% endif %}{#not new#}
-
+
+ {% if user.is_superuser %}
+ Moderator Notes
+ {% if notes %}
+
+
+ Note |
+ Moderator |
+ Date/Time |
+
+ {% for n in notes %}
+
+ {{ n.note }} |
+ {{ n.user }} |
+ {{ n.ts|date:"Y-m-d H:i:s" }} |
+
+ {% endfor %}
+
+ {% endif %}
+
+
+ {% endif %}
{% if messages %}
Results
diff --git a/hamnadmin/hamnadmin/register/templates/moderate.html b/hamnadmin/hamnadmin/register/templates/moderate.html
index 4dbe38a..1efb582 100644
--- a/hamnadmin/hamnadmin/register/templates/moderate.html
+++ b/hamnadmin/hamnadmin/register/templates/moderate.html
@@ -38,6 +38,26 @@
{% if blog.authorfilter %}
Author filter: {{ blog.authorfilter }}{% endif %}
+
+ {% if user.is_superuser and blog.moderatornotes_set.all %}
+
+
+
Moderator notes
+
+
+ Notes | Moderator | Date/Time |
+ {% for n in blog.moderatornotes_set.all %}
+
+ {{ n.note }} |
+ {{ n.user }} |
+ {{ n.ts|date:"Y-m-d H:i:s" }} |
+
+ {% endfor %}
+
+
+
+ {% endif %}
+
Posts
diff --git a/hamnadmin/hamnadmin/register/views.py b/hamnadmin/hamnadmin/register/views.py
index 299be79..f5d38af 100644
--- a/hamnadmin/hamnadmin/register/views.py
+++ b/hamnadmin/hamnadmin/register/views.py
@@ -6,7 +6,7 @@ from django.db import transaction
from django.db.models import Count, Max, Q, Subquery, OuterRef, Exists, FilteredRelation
from django.contrib import messages
-from hamnadmin.register.models import Post, Blog, Team, AggregatorLog, AuditEntry
+from hamnadmin.register.models import Post, Blog, Team, AggregatorLog, AuditEntry, ModeratorNotes
from hamnadmin.mailqueue.util import send_simple_mail
from hamnadmin.util.varnish import purge_url, purge_xkey, purge_root_and_feeds
@@ -87,51 +87,56 @@ def edit(request, id=None):
blog = Blog(user=request.user, name="{0} {1}".format(request.user.first_name, request.user.last_name))
if request.method == 'POST':
- saved_url = blog.feedurl
- saved_filter = blog.authorfilter
- saved_team = blog.team
- form = BlogEditForm(request, data=request.POST, instance=blog)
- if form.is_valid():
- if id:
- # This is an existing one. If we change the URL of the blog, it needs to be
- # de-moderated if it was previously approved.
- if blog.approved:
- if saved_url != form.cleaned_data['feedurl'] or saved_filter != form.cleaned_data['authorfilter']:
- obj = form.save()
- obj.approved = False
- obj.save(update_fields=['approved'])
-
- send_simple_mail(
- settings.EMAIL_SENDER,
- settings.NOTIFICATION_RECEIVER,
- "A blog was edited on Planet PostgreSQL",
- "The blog at {0}\nwas edited by {1} in a way that needs new moderation.\n\nTo moderate: https://planet.postgresql.org/register/moderate/\n\n".format(blog.feedurl, blog.user),
- sendername="Planet PostgreSQL",
- receivername="Planet PostgreSQL Moderators",
- )
-
- messages.warning(request, "Blog has been resubmitted for moderation, and is temporarily disabled.")
-
- purge_root_and_feeds()
- purge_url('/feeds.html')
-
- return HttpResponseRedirect("/register/edit/{0}/".format(obj.id))
-
- obj = form.save()
-
- if obj.team and obj.team != saved_team:
- # We allow anybody to join a team by default, and will just send a notice
- # so the team manager can undo it.
- send_simple_mail(settings.EMAIL_SENDER,
- obj.team.manager.email,
- "A blog joined your team on Planet PostgreSQL",
- "The blog at {0} by {1} {2}\nhas been added to your team {3} on Planet PostgreSQL\n\nIf this is correct, you do not need to do anything.\n\nIf this is incorrect, please go to\n\nhttps://planet.postgresql.org/register/\n\nand click the button to remove the blog from your team.\nWe apologize if this causes work for you.\n\n".format(
- obj.feedurl,
- obj.user.first_name, obj.user.last_name,
- obj.team.name),
- sendername="Planet PostgreSQL",
- receivername="{0} {1}".format(obj.team.manager.first_name, obj.team.manager.last_name),
- )
+ if 'note' in request.POST:
+ form = BlogEditForm(request, instance=blog)
+ note = ModeratorNotes(feed=blog, note=request.POST['note'], user=request.user)
+ note.save()
+ else:
+ saved_url = blog.feedurl
+ saved_filter = blog.authorfilter
+ saved_team = blog.team
+ form = BlogEditForm(request, data=request.POST, instance=blog)
+ if form.is_valid():
+ if id:
+ # This is an existing one. If we change the URL of the blog, it needs to be
+ # de-moderated if it was previously approved.
+ if blog.approved:
+ if saved_url != form.cleaned_data['feedurl'] or saved_filter != form.cleaned_data['authorfilter']:
+ obj = form.save()
+ obj.approved = False
+ obj.save(update_fields=['approved'])
+
+ send_simple_mail(
+ settings.EMAIL_SENDER,
+ settings.NOTIFICATION_RECEIVER,
+ "A blog was edited on Planet PostgreSQL",
+ "The blog at {0}\nwas edited by {1} in a way that needs new moderation.\n\nTo moderate: https://planet.postgresql.org/register/moderate/\n\n".format(blog.feedurl, blog.user),
+ sendername="Planet PostgreSQL",
+ receivername="Planet PostgreSQL Moderators",
+ )
+
+ messages.warning(request, "Blog has been resubmitted for moderation, and is temporarily disabled.")
+
+ purge_root_and_feeds()
+ purge_url('/feeds.html')
+
+ return HttpResponseRedirect("/register/edit/{0}/".format(obj.id))
+
+ obj = form.save()
+
+ if obj.team and obj.team != saved_team:
+ # We allow anybody to join a team by default, and will just send a notice
+ # so the team manager can undo it.
+ send_simple_mail(settings.EMAIL_SENDER,
+ obj.team.manager.email,
+ "A blog joined your team on Planet PostgreSQL",
+ "The blog at {0} by {1} {2}\nhas been added to your team {3} on Planet PostgreSQL\n\nIf this is correct, you do not need to do anything.\n\nIf this is incorrect, please go to\n\nhttps://planet.postgresql.org/register/\n\nand click the button to remove the blog from your team.\nWe apologize if this causes work for you.\n\n".format(
+ obj.feedurl,
+ obj.user.first_name, obj.user.last_name,
+ obj.team.name),
+ sendername="Planet PostgreSQL",
+ receivername="{0} {1}".format(obj.team.manager.first_name, obj.team.manager.last_name),
+ )
return HttpResponseRedirect("/register/edit/{0}/".format(obj.id))
else:
@@ -142,6 +147,7 @@ def edit(request, id=None):
'form': form,
'blog': blog,
'log': AggregatorLog.objects.filter(feed=blog).order_by('-ts')[:30],
+ 'notes': ModeratorNotes.objects.filter(feed=blog).order_by('-ts'),
'posts': Post.objects.filter(feed=blog).order_by('-dat')[:10],
'title': 'Edit blog: %s' % blog.name,
})
--
2.39.5