changeset 347:69d0306a6fe7

Fixing #165: add a way to filter users in the admin by join date; add an admin action to approve a pending user; added a honeypot type field to the registration form.
author Brian Neal <bgneal@gmail.com>
date Wed, 02 Mar 2011 01:11:32 +0000
parents efa3b4901777
children d1b11096595b
files gpp/accounts/__init__.py gpp/accounts/admin.py gpp/accounts/forms.py gpp/accounts/views.py gpp/bio/admin.py
diffstat 5 files changed, 81 insertions(+), 24 deletions(-) [+]
line wrap: on
line diff
--- a/gpp/accounts/__init__.py	Mon Feb 28 03:53:04 2011 +0000
+++ b/gpp/accounts/__init__.py	Wed Mar 02 01:11:32 2011 +0000
@@ -0,0 +1,37 @@
+import datetime
+import logging
+
+from django.contrib.auth.models import User
+
+
+def create_new_user(pending_user, ip=None, admin_activation=False):
+    """
+    This function contains the code to create a new user from a
+    pending user. The pending user is deleted and the new user
+    is saved. A log message is produced. If admin_activation is false,
+    then ip should be the user's IP they confirmed from, if available.
+
+    """
+    new_user = User()
+
+    new_user.username = pending_user.username
+    new_user.first_name = ''
+    new_user.last_name = ''
+    new_user.email = pending_user.email
+    new_user.password = pending_user.password     # already been hashed
+    new_user.is_staff = False
+    new_user.is_active = True
+    new_user.is_superuser = False
+    new_user.last_login = datetime.datetime.now()
+    new_user.date_joined = new_user.last_login
+
+    new_user.save()
+    pending_user.delete()
+
+    if admin_activation:
+        msg = 'Accounts registration confirmed by ADMIN for %s' % new_user.username
+    else:
+        msg = 'Accounts registration confirmed by USER for %s from %s' % (
+                new_user.username, ip)
+
+    logging.info(msg)
--- a/gpp/accounts/admin.py	Mon Feb 28 03:53:04 2011 +0000
+++ b/gpp/accounts/admin.py	Wed Mar 02 01:11:32 2011 +0000
@@ -4,9 +4,23 @@
 from accounts.models import IllegalUsername
 from accounts.models import IllegalEmail
 from accounts.models import PendingUser
+from accounts import create_new_user
+
 
 class PendingUserAdmin(admin.ModelAdmin):
    list_display = ('username', 'email', 'date_joined')
+   actions = ('activate_account', )
+
+   def activate_account(self, request, qs):
+       """
+       Activate the accounts of the selected pending users.
+
+       """
+       for pending_user in qs:
+           create_new_user(pending_user, admin_activation=True)
+
+   activate_account.short_description = "Activate accounts for selected users"
+
 
 admin.site.register(IllegalUsername)
 admin.site.register(IllegalEmail)
--- a/gpp/accounts/forms.py	Mon Feb 28 03:53:04 2011 +0000
+++ b/gpp/accounts/forms.py	Wed Mar 02 01:11:32 2011 +0000
@@ -19,7 +19,7 @@
     """Form used to register with the website"""
     username = forms.RegexField(max_length=30, regex=r'^\w+$',
         error_messages={
-            'invalid': 'Your username must be 30 characters or less and ' \
+            'invalid': 'Your username must be 30 characters or less and '
                     'contain only letters, numbers and underscores.'})
     email = forms.EmailField()
     password1 = forms.CharField(label="Password", widget=forms.PasswordInput)
@@ -27,7 +27,7 @@
     agree_age = forms.BooleanField(required=True,
         label='I certify that I am over the age of 13',
         error_messages={
-            'required': 'Sorry, but you must be over the age of 13 to ' \
+            'required': 'Sorry, but you must be over the age of 13 to '
                     'register at our site.',
             })
     agree_tos = forms.BooleanField(required=True,
@@ -41,6 +41,8 @@
             'required': 'You have not agreed to our Privacy Policy.',
             })
     question1 = forms.CharField(label="What number appears in the site name?")
+    question2 = forms.CharField(label='', required=False,
+        widget=forms.TextInput(attrs={'style': 'display: none;'}))
 
     def __init__(self, *args, **kwargs):
         self.ip = kwargs.pop('ip', '?')
@@ -101,6 +103,15 @@
             self._validation_error("Incorrect answer to our anti-spam question.", answer)
         return answer
 
+    def clean_question2(self):
+        """
+        Honeypot field should be empty.
+        """
+        answer = self.cleaned_data.get('question2')
+        if answer:
+            self._validation_error('Wrong answer #2: %s' % answer)
+        return answer
+
     def save(self):
         pending_user = PendingUser.objects.create_pending_user(self.cleaned_data['username'],
                 self.cleaned_data['email'],
--- a/gpp/accounts/views.py	Mon Feb 28 03:53:04 2011 +0000
+++ b/gpp/accounts/views.py	Wed Mar 02 01:11:32 2011 +0000
@@ -12,6 +12,7 @@
 
 from accounts.models import PendingUser
 from accounts.forms import RegisterForm
+from accounts import create_new_user
 
 
 #######################################################################
@@ -69,23 +70,8 @@
             },
             context_instance = RequestContext(request))
 
-    new_user = User()
+    create_new_user(pending_user, ip)
 
-    new_user.username = pending_user.username
-    new_user.first_name = ''
-    new_user.last_name = ''
-    new_user.email = pending_user.email
-    new_user.password = pending_user.password     # already been hashed
-    new_user.is_staff = False
-    new_user.is_active = True
-    new_user.is_superuser = False
-    new_user.last_login = datetime.datetime.now()
-    new_user.date_joined = new_user.last_login
-
-    new_user.save()
-    pending_user.delete()
-
-    logging.info('Accounts register_confirm [%s]: success: %s', ip, username)
     return render_to_response('accounts/register_success.html', {
         'username': username,
         },
--- a/gpp/bio/admin.py	Mon Feb 28 03:53:04 2011 +0000
+++ b/gpp/bio/admin.py	Wed Mar 02 01:11:32 2011 +0000
@@ -5,6 +5,9 @@
 
 from django.contrib import admin
 
+import django.contrib.auth.models
+import django.contrib.auth.admin
+
 import bio.models
 import bio.badges
 from comments.models import Comment
@@ -26,7 +29,7 @@
     date_hierarchy = 'status_date'
     inlines = (BadgeOwnerInline, )
     actions = (
-        'mark_active', 
+        'mark_active',
         'mark_resigned',
         'mark_removed',
         'mark_suspended',
@@ -40,8 +43,8 @@
 
     def mark_user_status(self, request, qs, status):
         """
-        Common code for the admin actions. Updates the status field in the 
-        profiles to 'status'. Updates the status_date.  Sets the is_active 
+        Common code for the admin actions. Updates the status field in the
+        profiles to 'status'. Updates the status_date.  Sets the is_active
         field to True if the status is STA_ACTIVE and False otherwise.
         """
         now = datetime.datetime.now()
@@ -120,14 +123,20 @@
     accept_flags.short_description = "Accept selected flagged profiles"
 
 
-
-
-
 class BadgeAdmin(admin.ModelAdmin):
     list_display = ('name', 'html', 'order', 'numeric_id', 'description')
     list_editable = ('order', 'numeric_id')
 
 
+# We like the User admin but would like a date hierarcy on date_joined.
+class UserAdmin(django.contrib.auth.admin.UserAdmin):
+    date_hierarchy = 'date_joined'
+
+
 admin.site.register(bio.models.UserProfile, UserProfileAdmin)
 admin.site.register(bio.models.UserProfileFlag, UserProfileFlagAdmin)
 admin.site.register(bio.models.Badge, BadgeAdmin)
+
+# Unregister existing ModelAdmin for User, then register ours
+admin.site.unregister(django.contrib.auth.models.User)
+admin.site.register(django.contrib.auth.models.User, UserAdmin)