changeset 810:4a4fa174a0ec

Private message refactor: adding ability to report PM's. See also Bitbucket issue #57.
author Brian Neal <bgneal@gmail.com>
date Sat, 06 Sep 2014 16:58:08 -0500
parents ab3deff7672a
children 56b30c79f10e
files core/templatetags/custom_admin_tags.py messages/admin.py messages/forms.py messages/models.py messages/static/css/messages.css messages/urls.py messages/views.py sg101/templates/admin/base_site.html sg101/templates/core/admin_dashboard.html sg101/templates/messages/message.html sg101/templates/messages/report_message.html sg101/templates/messages/view_message.html
diffstat 12 files changed, 180 insertions(+), 28 deletions(-) [+]
line wrap: on
line diff
--- a/core/templatetags/custom_admin_tags.py	Mon Sep 01 17:05:30 2014 -0500
+++ b/core/templatetags/custom_admin_tags.py	Sat Sep 06 16:58:08 2014 -0500
@@ -12,6 +12,7 @@
 from news.models import PendingStory
 from weblinks.models import PendingLink, FlaggedLink
 from shoutbox.models import ShoutFlag
+from messages.models import Flag as PmFlag
 
 
 register = template.Library()
@@ -28,13 +29,14 @@
     new_downloads = PendingDownload.objects.count()
     flagged_posts = FlaggedPost.objects.count()
     event_requests = Event.objects.filter(
-                Q(status=Event.NEW) | 
-                Q(status=Event.EDIT_REQ) | 
+                Q(status=Event.NEW) |
+                Q(status=Event.EDIT_REQ) |
                 Q(status=Event.DEL_REQ)).count()
     new_stories = PendingStory.objects.count()
     new_links = PendingLink.objects.count()
     broken_links = FlaggedLink.objects.count()
     flagged_shouts = ShoutFlag.objects.count()
+    flagged_msgs = PmFlag.objects.count()
 
     return {
         'user': user,
@@ -47,4 +49,5 @@
         'new_links': new_links,
         'broken_links': broken_links,
         'flagged_shouts': flagged_shouts,
+        'flagged_msgs': flagged_msgs,
         }
--- a/messages/admin.py	Mon Sep 01 17:05:30 2014 -0500
+++ b/messages/admin.py	Sat Sep 06 16:58:08 2014 -0500
@@ -2,17 +2,53 @@
 This file contains the automatic admin site definitions for the Message models.
 """
 from django.contrib import admin
+from django.core.urlresolvers import reverse
 
-from messages.models import Message
-from messages.models import Options
+from messages.models import Flag, Message, Options
+import bio.badges
 
 
 class MessageAdmin(admin.ModelAdmin):
-    list_display = ('sender', 'receiver', 'send_date', 'subject')
-    raw_id_fields = ('sender', 'receiver')
-    exclude = ('html', )
+    list_display = ['sender', 'receiver', 'send_date', 'subject']
+    raw_id_fields = ['sender', 'receiver']
+    exclude = ['html']
     date_hierarchy = 'send_date'
-    list_display_links = ('subject', )
+    list_display_links = ['subject']
 
+
+class FlagAdmin(admin.ModelAdmin):
+    list_display = ['__unicode__', 'flag_date', 'message_link']
+    date_hierarchy = 'flag_date'
+    list_select_related = True
+    readonly_fields = ['message', 'flag_date', 'comments', 'message_text']
+    actions = ['accept_flags']
+
+    def message_link(self, obj):
+        return '<a href="{}">Message</a>'.format(
+                reverse('admin:messages_message_change', args=[obj.message.id]))
+    message_link.allow_tags = True
+    message_link.short_description = 'Message'
+
+    def message_text(self, obj):
+        return obj.message.html
+    message_text.allow_tags = True
+    message_text.short_description = 'Message text'
+
+    def accept_flags(self, request, qs):
+        """This admin action awards a security pin to the user who reported the
+        message and then deletes the flag object.
+
+        """
+        count = qs.count()
+        for flag in qs:
+            bio.badges.award_badge(bio.badges.SECURITY_PIN, flag.message.receiver)
+            flag.delete()
+
+        self.message_user(request,
+            "%s flag(s) acknowledged. You may want to mark users as spammers now." % count)
+
+    accept_flags.short_description = "Accept selected flags"
+
+admin.site.register(Flag, FlagAdmin)
 admin.site.register(Message, MessageAdmin)
 admin.site.register(Options)
--- a/messages/forms.py	Mon Sep 01 17:05:30 2014 -0500
+++ b/messages/forms.py	Sat Sep 06 16:58:08 2014 -0500
@@ -11,8 +11,7 @@
 
 from core.functions import send_mail
 from core.widgets import AutoCompleteUserInput
-from messages.models import Message
-from messages.models import Options
+from messages.models import Flag, Message, Options
 from messages import MSG_BOX_LIMIT
 
 
@@ -124,6 +123,17 @@
         fields = ['attach_signature', 'notify_email']
 
 
+class ReportForm(forms.ModelForm):
+    class Meta:
+        model = Flag
+        fields = ['comments']
+        labels = {'comments': ''}
+        widgets = {
+            'comments': forms.Textarea(attrs={
+                'placeholder': 'Enter a comment for the admin (optional).'})
+        }
+
+
 def notify_receiver(new_msg):
     """
     This function creates the notification email to notify a user of
--- a/messages/models.py	Mon Sep 01 17:05:30 2014 -0500
+++ b/messages/models.py	Sat Sep 06 16:58:08 2014 -0500
@@ -101,3 +101,22 @@
         verbose_name_plural = "Options"
 
 
+class Flag(models.Model):
+    """The Flag model is used to represent when a receiver of a private message
+    has flagged the message for spam or abuse.
+
+    """
+    message = models.OneToOneField(Message)
+    flag_date = models.DateTimeField()
+    comments = models.TextField(blank=True)
+
+    def __unicode__(self):
+        msg = self.message
+        return "{} has flagged a PM from {}".format(msg.receiver.username,
+                msg.sender.username)
+
+    def save(self, *args, **kwargs):
+        if not self.id:
+            self.flag_date = datetime.datetime.now()
+        super(Flag, self).save(*args, **kwargs)
+
--- a/messages/static/css/messages.css	Mon Sep 01 17:05:30 2014 -0500
+++ b/messages/static/css/messages.css	Sat Sep 06 16:58:08 2014 -0500
@@ -90,3 +90,9 @@
 table.pm td {
    background-color: #EDF7F6;
 }
+#report_form textarea {
+   width: 90%;
+   margin-left: auto;
+   margin-right: auto;
+   height: 10em;
+}
--- a/messages/urls.py	Mon Sep 01 17:05:30 2014 -0500
+++ b/messages/urls.py	Sat Sep 06 16:58:08 2014 -0500
@@ -30,7 +30,7 @@
     url(r'^view/(\d+)/$',
         'messages.views.view',
         name='messages-view'),
-#   url(r'^report/(\d+)/$',
-#       'messages.views.report',
-#       name='messages-report'),
+    url(r'^report/(\d+)/$',
+        'messages.views.report',
+        name='messages-report'),
 )
--- a/messages/views.py	Mon Sep 01 17:05:30 2014 -0500
+++ b/messages/views.py	Sat Sep 06 16:58:08 2014 -0500
@@ -12,8 +12,8 @@
 from django.shortcuts import get_object_or_404
 from django.shortcuts import render, redirect
 
-from messages.models import Message, Options
-from messages.forms import OptionsForm, ComposeForm
+from messages.models import Flag, Message, Options
+from messages.forms import OptionsForm, ComposeForm, ReportForm
 from messages.utils import reply_subject
 from messages import MSG_BOX_LIMIT
 from core.functions import quote_message
@@ -184,9 +184,15 @@
 
         form = ComposeForm(request.user, initial=initial_data)
 
+    try:
+        msg_flag = msg.flag
+    except Flag.DoesNotExist:
+        msg_flag = None
+
     return render(request, 'messages/view_message.html', {
         'msg': msg,
         'form': form,
+        'msg_flag': msg_flag,
         })
 
 
@@ -295,3 +301,38 @@
 
     url = reverse('messages-trash') + '?page={}'.format(page)
     return redirect(url)
+
+
+@login_required
+def report(request, msg_id):
+    """This view is for reporting a PM as spam or abuse.
+
+    """
+    msg = get_object_or_404(Message.objects.select_related(), pk=msg_id)
+    if msg.receiver != request.user:
+        django_messages.error(request, "You can't report this message.")
+        return redirect('messages-inbox')
+    try:
+        msg.flag
+    except Flag.DoesNotExist:
+        pass
+    else:
+        django_messages.error(request, "This message has already been reported.")
+        return redirect('messages-inbox')
+
+    if request.method == 'POST':
+        form = ReportForm(request.POST)
+        if form.is_valid():
+            flag = form.save(commit=False)
+            flag.message = msg
+            flag.save()
+            django_messages.success(request,
+                    'Message reported. An admin will be notified. Thank you.')
+            return redirect('messages-inbox')
+    else:
+        form = ReportForm()
+
+    return render(request, 'messages/report_message.html', {
+        'msg': msg,
+        'form': form,
+        })
--- a/sg101/templates/admin/base_site.html	Mon Sep 01 17:05:30 2014 -0500
+++ b/sg101/templates/admin/base_site.html	Sat Sep 06 16:58:08 2014 -0500
@@ -9,9 +9,8 @@
    }
    #dashboard-list li {
       float: left;
+      display: inline;
       list-style: square inside none;
-      margin-right: 1.5em;
-      margin-bottom: 0.5em;
       margin: 0.5em 1.0em 0.5em 1.5em;
    }
 </style>
--- a/sg101/templates/core/admin_dashboard.html	Mon Sep 01 17:05:30 2014 -0500
+++ b/sg101/templates/core/admin_dashboard.html	Sat Sep 06 16:58:08 2014 -0500
@@ -1,5 +1,5 @@
 {% if user.is_staff %}
-{% if flagged_posts or flagged_comments or flagged_profiles or event_requests or new_stories or new_downloads or new_links or flagged_shouts or broken_links %}
+{% if flagged_posts or flagged_comments or flagged_profiles or event_requests or new_stories or new_downloads or new_links or flagged_shouts or broken_links or flagged_msgs %}
 <ul id="dashboard-list">
 {% if flagged_posts %}
 <li><a href="/admin/forums/flaggedpost/">Posts</a>: {{ flagged_posts }}</li>
@@ -28,6 +28,9 @@
 {% if broken_links %}
 <li><a href="/admin/weblinks/flaggedlink/">Broken Links</a>: {{ broken_links }}</li>
 {% endif %}
+{% if flagged_msgs %}
+<li><a href="/admin/messages/flag/">PM's</a>: {{ flagged_msgs }}</li>
+{% endif %}
 </ul>
 {% endif %}
 {% endif %}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sg101/templates/messages/message.html	Sat Sep 06 16:58:08 2014 -0500
@@ -0,0 +1,10 @@
+{% load bio_tags %}
+<table class="pm">
+   <tr><th>From:</th><td>{% profile_link msg.sender.username %}</td></tr>
+   <tr><th>To:</th><td>{% profile_link msg.receiver.username %}</td></tr>
+   <tr><th>Send Date:</th><td>{{ msg.send_date }}</td></tr>
+   <tr><th>Read Date:</th><td>{{ msg.read_date }}</td></tr>
+   <tr><th>Reply Date:</th><td>{{ msg.reply_date }}</td></tr>
+   <tr><th>Subject:</th><td>{{ msg.subject }}</td></tr>
+   <tr><td colspan="2">{{ msg.html|safe }}</td></tr>
+</table>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sg101/templates/messages/report_message.html	Sat Sep 06 16:58:08 2014 -0500
@@ -0,0 +1,23 @@
+{% extends 'messages/messages_base.html' %}
+{% block messages_content %}
+<h3>Report Private Message</h3>
+<p>
+You have asked to report this private message for spam or abuse. If you wish to
+proceed, please submit the form below. You may also add an optional note or clarification
+for the admin.
+</p>
+<p>
+If you submit the form an admin will be notified and the message will be
+reviewed and possibly deleted.
+</p>
+{% include "messages/message.html" %}
+
+<form action="." method="post" id="report_form">{% csrf_token %}
+<fieldset>
+<legend>Report Message</legend>
+{{ form.as_p }}
+<input type="submit" name="submit" value="Submit Report" />
+</fieldset>
+</form>
+<p><a href="{% url "messages-view" msg.id %}">Cancel report and return to message</a></p>
+{% endblock %}
--- a/sg101/templates/messages/view_message.html	Mon Sep 01 17:05:30 2014 -0500
+++ b/sg101/templates/messages/view_message.html	Sat Sep 06 16:58:08 2014 -0500
@@ -1,5 +1,4 @@
 {% extends 'messages/messages_base.html' %}
-{% load bio_tags %}
 {% load core_tags %}
 {% load script_tags %}
 {% block custom_js %}
@@ -10,15 +9,18 @@
 {% endblock %}
 {% block messages_content %}
 <h3>View Private Message</h3>
-<table class="pm">
-   <tr><th>From:</th><td>{% profile_link msg.sender.username %}</td></tr>
-   <tr><th>To:</th><td>{% profile_link msg.receiver.username %}</td></tr>
-   <tr><th>Send Date:</th><td>{{ msg.send_date }}</td></tr>
-   <tr><th>Read Date:</th><td>{{ msg.read_date }}</td></tr>
-   <tr><th>Reply Date:</th><td>{{ msg.reply_date }}</td></tr>
-   <tr><th>Subject:</th><td>{{ msg.subject }}</td></tr>
-   <tr><td colspan="2">{{ msg.html|safe }}</td></tr>
-</table>
+{% include "messages/message.html" %}
+
+{% if msg_flag %}
+<div class="error">
+   You reported this message to the admin on {{ msg_flag.flag_date|date:"F d, Y" }}.
+</div>
+{% else %}
+<div class="notice">
+   <img src="{{ STATIC_URL }}icons/flag_red.png" alt="Report this message" />
+   <a href="{% url "messages-report" msg.id %}">Report this message for spam or abuse</a>.
+</div>
+{% endif %}
 
 {% if form %}
 <form action="." method="post" id="msg_compose_form">{% csrf_token %}