changeset 98:d0d779dd0832

Forums: flag posts.
author Brian Neal <bgneal@gmail.com>
date Sun, 13 Sep 2009 21:45:35 +0000
parents 96eec1ed0fd3
children 10d6182b9f6e
files gpp/comments/models.py gpp/forums/admin.py gpp/forums/models.py gpp/forums/urls.py gpp/forums/views.py gpp/templates/forums/display_post.html media/css/base.css media/js/forums.js
diffstat 8 files changed, 83 insertions(+), 3 deletions(-) [+]
line wrap: on
line diff
--- a/gpp/comments/models.py	Sun Sep 13 19:58:31 2009 +0000
+++ b/gpp/comments/models.py	Sun Sep 13 21:45:35 2009 +0000
@@ -75,7 +75,7 @@
     flag_date = models.DateTimeField(auto_now_add=True)
 
     def __unicode__(self):
-        return u'Comment ID %s flagged by %s' % (self.comment_id, self.user.username)
+        return u'Comment ID %s flagged by %s' % (self.comment.id, self.user.username)
 
     class Meta:
         ordering = ('flag_date', )
--- a/gpp/forums/admin.py	Sun Sep 13 19:58:31 2009 +0000
+++ b/gpp/forums/admin.py	Sun Sep 13 21:45:35 2009 +0000
@@ -7,6 +7,7 @@
 from forums.models import Forum
 from forums.models import Topic
 from forums.models import Post
+from forums.models import FlaggedPost
 
 
 class CategoryAdmin(admin.ModelAdmin):
@@ -43,7 +44,12 @@
     save_on_top = True
 
 
+class FlaggedPostAdmin(admin.ModelAdmin):
+    list_display = ('__unicode__', 'flag_date', 'get_post_url')
+
+
 admin.site.register(Category, CategoryAdmin)
 admin.site.register(Forum, ForumAdmin)
 admin.site.register(Topic, TopicAdmin)
 admin.site.register(Post, PostAdmin)
+admin.site.register(FlaggedPost, FlaggedPostAdmin)
--- a/gpp/forums/models.py	Sun Sep 13 19:58:31 2009 +0000
+++ b/gpp/forums/models.py	Sun Sep 13 21:45:35 2009 +0000
@@ -145,5 +145,21 @@
         if self.id == first_post_id:
             self.topic.delete()
 
+
+class FlaggedPost(models.Model):
+    """This model represents a user flagging a post as inappropriate."""
+    user = models.ForeignKey(User)
+    post = models.ForeignKey(Post)
+    flag_date = models.DateTimeField(auto_now_add=True)
+
+    def __unicode__(self):
+        return u'Post ID %s flagged by %s' % (self.post.id, self.user.username)
+
+    class Meta:
+        ordering = ('flag_date', )
+
+    def get_post_url(self):
+        return '<a href="%s">Post</a>' % self.post.get_absolute_url()
+    get_post_url.allow_tags = True
+
 # TODO: A "read" table
-# TODO: A flagged post table
--- a/gpp/forums/urls.py	Sun Sep 13 19:58:31 2009 +0000
+++ b/gpp/forums/urls.py	Sun Sep 13 21:45:35 2009 +0000
@@ -7,6 +7,7 @@
     url(r'^$', 'index', name='forums-index'),
     url(r'^new-topic-success/(?P<tid>\d+)$', 'new_topic_thanks', name='forums-new_topic_thanks'),
     url(r'^topic/(?P<id>\d+)/$', 'topic_index', name='forums-topic_index'),
+    url(r'^flag-post/$', 'flag_post', name='forums-flag_post'),
     url(r'^forum/(?P<slug>[\w\d-]+)/$', 'forum_index', name='forums-forum_index'),
     url(r'^forum/(?P<slug>[\w\d-]+)/new-topic/$', 'new_topic', name='forums-new_topic'),
     url(r'^post/(\d+)/$', 'goto_post', name='forums-goto_post'),
--- a/gpp/forums/views.py	Sun Sep 13 19:58:31 2009 +0000
+++ b/gpp/forums/views.py	Sun Sep 13 21:45:35 2009 +0000
@@ -3,6 +3,7 @@
 """
 from django.contrib.auth.decorators import login_required
 from django.http import Http404
+from django.http import HttpResponse
 from django.http import HttpResponseBadRequest
 from django.http import HttpResponseForbidden
 from django.http import HttpResponseRedirect
@@ -15,9 +16,11 @@
 from django.views.decorators.http import require_POST
 
 from core.paginator import DiggPaginator
+from core.functions import email_admins
 from forums.models import Forum
 from forums.models import Topic
 from forums.models import Post
+from forums.models import FlaggedPost
 from forums.forms import NewTopicForm
 from forums.forms import PostForm
 
@@ -182,3 +185,30 @@
         '?page=%s#p%s' % (page, post.id)
     return HttpResponseRedirect(url)
 
+
+@require_POST
+def flag_post(request):
+    """
+    This function handles the flagging of posts by users. This function should
+    be the target of an AJAX post.
+    """
+    if not request.user.is_authenticated():
+        return HttpResponse('Please login or register to flag a post.')
+
+    id = request.POST.get('id')
+    if id is None:
+        return HttpResponseBadRequest('No post id')
+
+    try:
+        post = Post.objects.get(pk=id)
+    except Post.DoesNotExist:
+        return HttpResponseBadRequest('No post with id %s' % id)
+
+    flag = FlaggedPost(user=request.user, post=post)
+    flag.save()
+    email_admins('A Post Has Been Flagged', """Hello,
+
+A user has flagged a forum post for review.
+""")
+    return HttpResponse('The post was flagged. A moderator will review the post shortly. ' \
+            'Thanks for helping to improve the discussions on this site.')
--- a/gpp/templates/forums/display_post.html	Sun Sep 13 19:58:31 2009 +0000
+++ b/gpp/templates/forums/display_post.html	Sun Sep 13 21:45:35 2009 +0000
@@ -10,11 +10,16 @@
    </td>
    <td class="forum-post-body">
       <div class="forum-post-info quiet">
-         <a href="{{ post.get_absolute_url }}"><img src="{{ MEDIA_URL }}icons/link.png" alt="Link" title="Link to this post" /></a>
+      <a href="{{ post.get_absolute_url }}"><img src="{{ MEDIA_URL }}icons/link.png" alt="Link" title="Link to this post" /></a>
          Posted on {{ post.creation_date|date:"M d, Y H:i" }}
       </div>
       <div class="forum-post-body">
          {{ post.html|safe }}
       </div>
+      <div class="forum-post-info-tools">
+      <a href="#" class="post-flag" id="fp-{{ post.id }}" 
+         title="Flag this post as spam, abuse, or a violation of site rules.">
+         <img src="{{ MEDIA_URL }}icons/flag_red.png" alt="Flag" /></a>
+      </div>
    </td>
 </tr>
--- a/media/css/base.css	Sun Sep 13 19:58:31 2009 +0000
+++ b/media/css/base.css	Sun Sep 13 21:45:35 2009 +0000
@@ -206,6 +206,7 @@
    border-right: 1px solid #ccc;
    border-bottom: 1px solid black;
    vertical-align: top;
+   font-size: x-small;
 }
 td.forum-post-body {
    vertical-align: top;
@@ -217,11 +218,17 @@
    font-size:.8em;
    border-bottom: 1px solid #ccc;
    margin-bottom: 5px;
+   padding-bottom: 5px;
 }
 div.forum-post-info img {
    float: left;
    margin-right: 5px;
 }
+div.forum-post-info-tools {
+   border-top: 1px solid #ccc;
+   padding-top: 5px;
+   text-align: right;
+}
 .forums-post-navigation {
    text-align: right;
 }
--- a/media/js/forums.js	Sun Sep 13 19:58:31 2009 +0000
+++ b/media/js/forums.js	Sun Sep 13 21:45:35 2009 +0000
@@ -31,5 +31,20 @@
          });
       return false;
    });
+   $('a.post-flag').click(function () {
+      var id = this.id;
+      if (id.match(/fp-(\d)/)) {
+         id = RegExp.$1;
+         if (confirm('Only flag a post if you feel it is spam, abuse, violates site rules, ' +
+                 'or is not appropriate. ' +
+                 'A moderator will be notified and will review the post. ' +
+                 'Are you sure you want to flag this post?')) {
+             $.post('/forums/flag-post/', { id : id }, function(response) {
+                 alert(response);
+                 }, 'text');
+         }
+     }
+     return false;
+   });
    $('#id_body').markItUp(mySettings);
 });