Skip to content

Commit

Permalink
Activation now optional and improved management commands.
Browse files Browse the repository at this point in the history
  • Loading branch information
wunki committed Aug 4, 2011
1 parent 9a4922e commit 2de4243
Show file tree
Hide file tree
Showing 16 changed files with 140 additions and 31 deletions.
3 changes: 2 additions & 1 deletion demo_project/settings.py
Expand Up @@ -96,12 +96,12 @@
'django.contrib.sites',
'django.contrib.messages',
'django.contrib.admin',
'demo_project.profiles',
'easy_thumbnails',
'guardian',
'south',
'userena',
'userena.contrib.umessages',
'demo_project.profiles',
)

# Userena settings
Expand All @@ -112,6 +112,7 @@

USERENA_DISABLE_PROFILE_LIST = True
USERENA_MUGSHOT_SIZE = 140
USERENA_ACTIVATION_REQUIRED = False

# Test settings
TEST_RUNNER = 'django.test.simple.DjangoTestSuiteRunner'
Expand Down
12 changes: 12 additions & 0 deletions docs/faq.rst
@@ -0,0 +1,12 @@
.. _faq:

F.A.Q
=====

I get a ``Permission matching query does not exist`` exception
--------------------------------------------------------------

Sometimes Django decides not to install the default permissions for a model
and thus the ``change_profile`` permission goes missing. To fix this, run the
``check_permissions`` in :ref:`commands`. This checks all permissions and adds
those that are missing.
1 change: 1 addition & 0 deletions docs/index.rst
Expand Up @@ -52,6 +52,7 @@ Contents
settings
signals
commands
faq
api/index

Contrib: uMessages
Expand Down
7 changes: 7 additions & 0 deletions docs/installation.rst
Expand Up @@ -174,4 +174,11 @@ The above should supply you with a fully functional account management app. for
your project. You can look into the next chapter to fully customize userena to
your likings.

Permission check
~~~~~~~~~~~~~~~~

Sometimes Django decides to skip installing the default permissions for a
model. To check if all permissions are there, run the ``check_permissions`` in
the management :ref:`commands`.

.. _Github: https://github.com/lukaszb/django-guardian
6 changes: 6 additions & 0 deletions docs/settings.rst
Expand Up @@ -17,6 +17,12 @@ Default ``/accounts/%(username)s/'`` (string)
A string which defines the URI where the user will be redirected to after
signin.

USERENA_ACTIVATION_REQUIRED
~~~~~~~~~~~~~~~~~~~~~~~~~~~
Default: ``True`` (integer)

Boolean that defines if a activation is required when creating a new user.

USERENA_ACTIVATION_DAYS
~~~~~~~~~~~~~~~~~~~~~~~
Default: ``7`` (integer)
Expand Down
6 changes: 5 additions & 1 deletion userena/forms.py
Expand Up @@ -79,7 +79,11 @@ def save(self):
self.cleaned_data['email'],
self.cleaned_data['password1'])

new_user = UserenaSignup.objects.create_inactive_user(username, email, password)
new_user = UserenaSignup.objects.create_user(username,
email,
password,
not userena_settings.USERENA_ACTIVATION_REQUIRED,
userena_settings.USERENA_ACTIVATION_REQUIRED)
return new_user

class SignupFormOnlyEmail(SignupForm):
Expand Down
35 changes: 33 additions & 2 deletions userena/management/commands/check_permissions.py
@@ -1,4 +1,5 @@
from django.core.management.base import NoArgsCommand
from django.core.management.base import NoArgsCommand, BaseCommand
from optparse import make_option

from userena.models import UserenaSignup

Expand All @@ -8,6 +9,36 @@ class Command(NoArgsCommand):
This command checks that all permissions are correct.
"""
option_list = BaseCommand.option_list + (
make_option('--no-output',
action='store_false',
dest='output',
default=True,
help='Hide informational output.'),
make_option('--test',
action='store_true',
dest='test',
default=False,
help="Displays that it's testing management command. Don't use it yourself."),
)

help = 'Check that user permissions are correct.'
def handle_noargs(self, **options):
users = UserenaSignup.objects.check_permissions()
permissions, users, warnings = UserenaSignup.objects.check_permissions()
output = options.pop("output")
test = options.pop("test")
if test:
self.stdout.write(40 * ".")
self.stdout.write("\nChecking permission management command. Ignore output..\n\n")
if output:
for p in permissions:
self.stdout.write("Added permission: %s\n" % p)

for u in users:
self.stdout.write("Changed permissions for user: %s\n" % u)

for w in warnings:
self.stdout.write("WARNING: %s\n" %w)

if test:
self.stdout.write("\nFinished testing permissions command.. continuing..\n")
32 changes: 21 additions & 11 deletions userena/managers.py
Expand Up @@ -2,6 +2,7 @@
from django.db.models import Q
from django.contrib.auth.models import User, UserManager, Permission, AnonymousUser
from django.contrib.contenttypes.models import ContentType
from django.utils.translation import ugettext as _

from userena import settings as userena_settings
from userena.utils import generate_sha1, get_profile_model
Expand All @@ -16,7 +17,8 @@
ASSIGNED_PERMISSIONS = {
'profile':
(('view_profile', 'Can view profile'),
('change_profile', 'Can change profile')),
('change_profile', 'Can change profile'),
('delete_profile', 'Can delete profile')),
'user':
(('change_user', 'Can change user'),
('delete_user', 'Can delete user'))
Expand All @@ -25,7 +27,8 @@
class UserenaManager(UserManager):
""" Extra functionality for the Userena model. """

def create_inactive_user(self, username, email, password, send_email=True):
def create_user(self, username, email, password, active=False,
send_email=True):
"""
A simple wrapper that creates a new :class:`User`.
Expand All @@ -38,6 +41,10 @@ def create_inactive_user(self, username, email, password, send_email=True):
:param password:
String containing the password for the new user.
:param active:
Boolean that defines if the user requires activation by clicking
on a link in an e-mail. Defauts to ``True``.
:param send_email:
Boolean that defines if the user should be send an email. You could
set this to ``False`` when you want to create a user in your own
Expand All @@ -49,7 +56,7 @@ def create_inactive_user(self, username, email, password, send_email=True):
now = datetime.datetime.now()

new_user = User.objects.create_user(username, email, password)
new_user.is_active = False
new_user.is_active = active
new_user.save()

userena_profile = self.create_userena_profile(new_user)
Expand All @@ -66,7 +73,7 @@ def create_inactive_user(self, username, email, password, send_email=True):
for perm in ASSIGNED_PERMISSIONS['profile']:
assign(perm[0], new_user, new_profile)

# Give permissinos to view and change itself
# Give permissions to view and change itself
for perm in ASSIGNED_PERMISSIONS['user']:
assign(perm[0], new_user, new_user)

Expand Down Expand Up @@ -196,6 +203,11 @@ def check_permissions(self):
:return: A set of users whose permissions was wrong.
"""
# Variable to supply some feedback
changed_permissions = []
changed_users = []
warnings = []

# Check that all the permissions are available.
for model, perms in ASSIGNED_PERMISSIONS.items():
if model == 'profile':
Expand All @@ -207,20 +219,18 @@ def check_permissions(self):
Permission.objects.get(codename=perm[0],
content_type=model_content_type)
except Permission.DoesNotExist:
print "Creating permission: %s" % perm[1]
changed_permissions.append(perm[1])
Permission.objects.create(name=perm[1],
codename=perm[0],
content_type=model_content_type)
else: print "Found permission: %s" % perm[1]

# Check permission for every user.
changed_users = set()
for user in User.objects.all():
if not user.username == 'AnonymousUser':
try:
user_profile = user.get_profile()
except get_profile_model().DoesNotExist:
print "WARNING: No profile found for %s" % user.username
warnings.append(_("No profile found for %(username)s") \
% {'username': user.username})
else:
all_permissions = get_perms(user, user.get_profile()) + get_perms(user, user)

Expand All @@ -232,9 +242,9 @@ def check_permissions(self):
for perm in perms:
if perm[0] not in all_permissions:
assign(perm[0], user, perm_object)
changed_users.add(user)
changed_users.append(user)

return changed_users
return (changed_permissions, changed_users, warnings)

class UserenaBaseProfileManager(models.Manager):
""" Manager for :class:`UserenaProfile` """
Expand Down
2 changes: 0 additions & 2 deletions userena/models.py
Expand Up @@ -21,8 +21,6 @@

PROFILE_PERMISSIONS = (
('view_profile', 'Can view profile'),
('change_profile', 'Can change profile'),
('delete_profile', 'Can delete profile'),
)

def upload_to_mugshot(instance, filename):
Expand Down
4 changes: 4 additions & 0 deletions userena/settings.py
Expand Up @@ -14,6 +14,10 @@
'USERENA_SIGNIN_REDIRECT_URL',
'/accounts/%(username)s/')

USERENA_ACTIVATION_REQUIRED = getattr(settings,
'USERENA_ACTIVATION_REQUIRED',
True)

USERENA_ACTIVATION_DAYS = getattr(settings,
'USERENA_ACTIVATION_DAYS',
7)
Expand Down
8 changes: 7 additions & 1 deletion userena/templates/userena/signup_complete.html
Expand Up @@ -7,6 +7,12 @@

{% block content %}
<p>{% trans "Thank you for signing up with us!" %}</p>

{% if userena_activation_required %}
<p>{% blocktrans %}You have been send an e-mail with an activation link to the supplied email.{% endblocktrans %}</p>
<p>{% blocktrans %}We will store your signup information for {{ userena_activation_days }} days on our server. {% endblocktrans %}</p>
<p>{% blocktrans %}We will store your signup information for {{
userena_activation_days }} days on our server. {% endblocktrans %}</p>
{% else %}
<p>{% blocktrans %}You can now use the supplied credentials to signin.{% endblocktrans %}</p>
{% endif %}
{% endblock %}
21 changes: 17 additions & 4 deletions userena/tests/commands.py
Expand Up @@ -25,7 +25,7 @@ def test_clean_expired(self):
"""
# Create an account which is expired.
user = UserenaSignup.objects.create_inactive_user(**self.user_info)
user = UserenaSignup.objects.create_user(**self.user_info)
user.date_joined -= datetime.timedelta(days=userena_settings.USERENA_ACTIVATION_DAYS + 1)
user.save()

Expand All @@ -44,7 +44,7 @@ class CheckPermissionTests(TestCase):

def test_check_permissions(self):
# Create a new account.
user = UserenaSignup.objects.create_inactive_user(**self.user_info)
user = UserenaSignup.objects.create_user(**self.user_info)
user.save()

# Remove all permissions
Expand All @@ -64,7 +64,7 @@ def test_check_permissions(self):
self.fail()

# Check it again should do nothing
call_command('check_permissions')
call_command('check_permissions', test=True)

def test_incomplete_permissions(self):
# Delete the neccesary permissions
Expand Down Expand Up @@ -92,7 +92,7 @@ def test_incomplete_permissions(self):
else: self.fail("Found %s: " % perm)

# Repair them
call_command('check_permissions')
call_command('check_permissions', test=True)

# Check if they are they are back
for model, perms in ASSIGNED_PERMISSIONS.items():
Expand All @@ -105,3 +105,16 @@ def test_incomplete_permissions(self):
content_type=content_type)
except Permission.DoesNotExist:
self.fail()

def test_no_profile(self):
""" Check for warning when there is no profile """
# TODO: Dirty! Currently we check for the warning by getting a 100%
# test coverage, meaning that it dit output some warning.
user = UserenaSignup.objects.create_user(**self.user_info)

# remove the profile of this user
get_profile_model().objects.get(user=user).delete()

# run the command to check for the warning.
call_command('check_permissions', test=True)

8 changes: 4 additions & 4 deletions userena/tests/managers.py
Expand Up @@ -30,7 +30,7 @@ def test_create_inactive_user(self):
"""
# Check that the fields are set.
new_user = UserenaSignup.objects.create_inactive_user(**self.user_info)
new_user = UserenaSignup.objects.create_user(**self.user_info)
self.assertEqual(new_user.username, self.user_info['username'])
self.assertEqual(new_user.email, self.user_info['email'])
self.failUnless(new_user.check_password(self.user_info['password']))
Expand All @@ -56,7 +56,7 @@ def test_activation_valid(self):
the setting ``USERENA_ACTIVATED``.
"""
user = UserenaSignup.objects.create_inactive_user(**self.user_info)
user = UserenaSignup.objects.create_user(**self.user_info)
active_user = UserenaSignup.objects.activate_user(user.username,
user.userena_signup.activation_key)

Expand Down Expand Up @@ -93,7 +93,7 @@ def test_activation_expired(self):
``UserenaSignup.objects.activation_user`` return ``False``.
"""
user = UserenaSignup.objects.create_inactive_user(**self.user_info)
user = UserenaSignup.objects.create_user(**self.user_info)

# Set the date that the key is created a day further away than allowed
user.date_joined -= datetime.timedelta(days=userena_settings.USERENA_ACTIVATION_DAYS + 1)
Expand Down Expand Up @@ -153,7 +153,7 @@ def test_delete_expired_users(self):
Test if expired users are deleted from the database.
"""
expired_user = UserenaSignup.objects.create_inactive_user(**self.user_info)
expired_user = UserenaSignup.objects.create_user(**self.user_info)
expired_user.date_joined -= datetime.timedelta(days=userena_settings.USERENA_ACTIVATION_DAYS + 1)
expired_user.save()

Expand Down
8 changes: 4 additions & 4 deletions userena/tests/models.py
Expand Up @@ -61,7 +61,7 @@ def test_activation_expired_account(self):
``USERENA_ACTIVATION_DAYS``.
"""
user = UserenaSignup.objects.create_inactive_user(**self.user_info)
user = UserenaSignup.objects.create_user(**self.user_info)
user.date_joined -= datetime.timedelta(days=userena_settings.USERENA_ACTIVATION_DAYS + 1)
user.save()

Expand All @@ -74,7 +74,7 @@ def test_activation_used_account(self):
already used.
"""
user = UserenaSignup.objects.create_inactive_user(**self.user_info)
user = UserenaSignup.objects.create_user(**self.user_info)
activated_user = UserenaSignup.objects.activate_user(user.username,
user.userena_signup.activation_key)
self.failUnless(activated_user.userena_signup.activation_key_expired())
Expand All @@ -85,7 +85,7 @@ def test_activation_unexpired_account(self):
``activation_key_created`` is within the defined timeframe.``
"""
user = UserenaSignup.objects.create_inactive_user(**self.user_info)
user = UserenaSignup.objects.create_user(**self.user_info)
self.failIf(user.userena_signup.activation_key_expired())

def test_activation_email(self):
Expand All @@ -94,7 +94,7 @@ def test_activation_email(self):
by ``UserenaSignup.send_activation_email``.
"""
new_user = UserenaSignup.objects.create_inactive_user(**self.user_info)
new_user = UserenaSignup.objects.create_user(**self.user_info)
self.failUnlessEqual(len(mail.outbox), 1)
self.assertEqual(mail.outbox[0].to, [self.user_info['email']])

Expand Down

0 comments on commit 2de4243

Please sign in to comment.