changeset 138:7ea842744a57

Ticket #15, add a way to report user profiles.
author Brian Neal <bgneal@gmail.com>
date Fri, 27 Nov 2009 21:55:32 +0000
parents c7d75cdfea21
children e04d91babfcf
files gpp/bio/admin.py gpp/bio/models.py gpp/bio/urls.py gpp/bio/views.py gpp/templates/bio/view_profile.html media/js/bio.js
diffstat 6 files changed, 103 insertions(+), 19 deletions(-) [+]
line wrap: on
line diff
--- a/gpp/bio/admin.py	Fri Nov 27 04:11:12 2009 +0000
+++ b/gpp/bio/admin.py	Fri Nov 27 21:55:32 2009 +0000
@@ -4,12 +4,17 @@
 
 from django.contrib import admin
 from bio.models import UserProfile
+from bio.models import UserProfileFlag
 
 class UserProfileAdmin(admin.ModelAdmin):
-    search_fields = ('user__username', 'user__first_name', 'user__last_name', 'user__email')
+    search_fields = ('user__username', 'user__first_name', 'user__last_name',
+            'user__email')
     exclude = ('profile_html', 'signature_html')
 
+
+class UserProfileFlagAdmin(admin.ModelAdmin):
+    list_display = ('__unicode__', 'flag_date', 'get_profile_url')
+
+
 admin.site.register(UserProfile, UserProfileAdmin)
-
-
-# vim: ts=4 sw=4
+admin.site.register(UserProfileFlag, UserProfileFlagAdmin)
--- a/gpp/bio/models.py	Fri Nov 27 04:11:12 2009 +0000
+++ b/gpp/bio/models.py	Fri Nov 27 21:55:32 2009 +0000
@@ -52,3 +52,25 @@
         self.signature_html = sm.convert(self.signature)
         super(UserProfile, self).save(*args, **kwargs)
         cache.delete('avatar_' + self.user.username)
+
+    @models.permalink
+    def get_absolute_url(self):
+        return ('bio-view_profile', (), {'username': self.user.username})
+
+
+class UserProfileFlag(models.Model):
+    """This model represents a user flagging a profile as inappropriate."""
+    user = models.ForeignKey(auth.models.User)
+    profile = models.ForeignKey(UserProfile)
+    flag_date = models.DateTimeField(auto_now_add=True)
+
+    def __unicode__(self):
+        return u"%s's profile flagged by %s" % (self.profile.user.username,
+                self.user.username)
+
+    class Meta:
+        ordering = ('flag_date', )
+
+    def get_profile_url(self):
+        return '<a href="%s">Profile</a>' % self.profile.get_absolute_url()
+    get_profile_url.allow_tags = True
--- a/gpp/bio/urls.py	Fri Nov 27 04:11:12 2009 +0000
+++ b/gpp/bio/urls.py	Fri Nov 27 21:55:32 2009 +0000
@@ -10,6 +10,7 @@
     url(r'^edit/$', 'edit_profile', name='bio-edit_profile'),
     url(r'^edit/elsewhere/$', 'edit_elsewhere', name='bio-edit_elsewhere'),
     url(r'^avatar/$', 'change_avatar', name='bio-change_avatar'),
+    url(r'^flag/(\d+)/$', 'flag_profile', name='bio-flag_profile'),
 )
 
 urlpatterns += patterns('django.views.generic.simple',
@@ -19,5 +20,3 @@
         name='bio-members'),
 )
 
-
-# vim: ts=4 sw=4
--- a/gpp/bio/views.py	Fri Nov 27 04:11:12 2009 +0000
+++ b/gpp/bio/views.py	Fri Nov 27 21:55:32 2009 +0000
@@ -6,20 +6,25 @@
 from django.shortcuts import get_object_or_404
 from django.template import RequestContext
 from django.contrib import auth
+from django.http import HttpResponse
+from django.http import HttpResponseBadRequest
 from django.http import HttpResponseRedirect
 from django.core.paginator import InvalidPage
 from django.core.urlresolvers import reverse
 from django.contrib.auth.decorators import login_required
+from django.views.decorators.http import require_POST
 
 from elsewhere.models import SocialNetworkForm
 from elsewhere.models import InstantMessengerForm
 from elsewhere.models import WebsiteForm
 
 from bio.models import UserProfile
+from bio.models import UserProfileFlag
 from bio.forms import UploadAvatarForm
 from bio.forms import EditUserForm
 from bio.forms import EditUserProfileForm
 from core.paginator import DiggPaginator
+from core.functions import email_admins
 
 #######################################################################
 
@@ -142,6 +147,32 @@
 
 #######################################################################
 
+@require_POST
+def flag_profile(request, profile_id):
+    """
+    This function handles the flagging of profiles 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 profile.')
+
+    try:
+        profile = UserProfile.objects.get(pk=profile_id)
+    except UserProfile.DoesNotExist:
+        return HttpResponseBadRequest("That profile doesn't exist.")
+
+    flag = UserProfileFlag(user=request.user, profile=profile)
+    flag.save()
+    email_admins('A Profile Has Been Flagged', """Hello,
+
+A user has flagged a profile for review.
+""")
+    return HttpResponse('The profile was flagged. A moderator will review the' \
+        ' profile shortly. Thanks for helping to improve the content on this ' \
+        'site.')
+
+#######################################################################
+
 @login_required
 def edit_elsewhere(request):
     im_id = 'id_im_%s'  # to prevent duplicate ID in HTML output
--- a/gpp/templates/bio/view_profile.html	Fri Nov 27 04:11:12 2009 +0000
+++ b/gpp/templates/bio/view_profile.html	Fri Nov 27 21:55:32 2009 +0000
@@ -10,6 +10,7 @@
       $('#bio_profile tr:even').addClass('even');
    });
 </script>
+<script type="text/javascript" src="{{ MEDIA_URL }}js/bio.js"></script>
 {% endblock %}
 {% block content %}
 <div class="user_profile">
@@ -62,11 +63,11 @@
 </ul>
 {% else %}
 {% if user.is_authenticated %}
-<p>
-<a href="{% url messages-compose_to subject.username %}">
-   <img src="{{ MEDIA_URL }}icons/note.png" alt="PM" title="Send Private Message" /></a>
-<a href="{% url messages-compose_to subject.username %}">Send a private message to {{ subject.username }}</a>
-</p>
+<ul class="icon-list">
+   <li><a href="{% url messages-compose_to subject.username %}"><img src="{{ MEDIA_URL }}icons/note.png" alt="PM" title="Send Private Message" /></a> <a href="{% url messages-compose_to subject.username %}">Send a private message to {{ subject.username }}</a></li>
+   <li><img src="{{ MEDIA_URL }}icons/flag_red.png" alt="Flag" />
+      <a href="#" class="profile-flag" id="fp-{{ profile.id }}">Report this profile</a></li>
+</ul>
 {% endif %}
 {% endif %}
 {% endblock %}
--- a/media/js/bio.js	Fri Nov 27 04:11:12 2009 +0000
+++ b/media/js/bio.js	Fri Nov 27 21:55:32 2009 +0000
@@ -1,10 +1,36 @@
-
 $(document).ready(function() {
-    $('#id_birthday').datepicker({changeMonth: true, 
-       changeYear: true,
-       dateFormat: 'yy-mm-dd',
-       defaultDate: '-30y',
-       minDate: new Date(1909, 0, 1),
-       maxDate: new Date(),
-       yearRange: '-100:+0'});
+   var bday = $('#id_birthday');
+   // jquery ui may not always be loaded
+   if (bday.length) {
+      bday.datepicker({changeMonth: true, 
+         changeYear: true,
+         dateFormat: 'yy-mm-dd',
+         defaultDate: '-30y',
+         minDate: new Date(1909, 0, 1),
+         maxDate: new Date(),
+         yearRange: '-100:+0'});
+   }
+   $('a.profile-flag').click(function() {
+      var id = this.id;
+      if (id.match(/fp-(\d+)/)) {
+         id = RegExp.$1;
+         if (confirm('Only report a profile if you feel it is spam, abuse, ' +
+                 'violates site rules, or is not appropriate. ' +
+                 'A moderator will be notified and will review the profile. ' +
+                 'Are you sure you want to report this profile?')) {
+             $.ajax({
+               url: '/profile/flag/' + id + '/',
+               type: 'POST',
+               dataType: 'text',
+               success: function (response, textStatus) {
+                  alert(response);
+               },
+               error: function (xhr, textStatus, ex) {
+                  alert('Oops, an error occurred: ' + xhr.statusText + ' - ' + xhr.responseText);
+               }
+             });
+         }
+     }
+     return false;
+   });
 });