Allow access control function to be replaced

The current access control function `can_translate` is not always
sufficient.  For instance, some projects require access to translation
to be controlled using a permission rather than using groups.

This change introduces a new setting `ROSETTA_ACCESS_CONTROL_FUNCTION`
that allows an alternative predicate to be specified.  The default is to
use the current function so this change is backwards compatible.
This commit is contained in:
David Winterbottom 2013-04-16 11:31:36 +01:00
parent b4ac8057cc
commit 718f9430ad
5 changed files with 60 additions and 17 deletions

View file

@ -61,6 +61,7 @@ Rosetta can be configured via the following parameters, to be defined in your pr
* ``ROSETTA_REQUIRES_AUTH``: Require authentication for all Rosetta views. Defaults to ``True``.
* ``ROSETTA_POFILE_WRAP_WIDTH``: Sets the line-length of the edited PO file. Set this to ``0`` to mimic ``makemessage``'s ``--no-wrap`` option. Defaults to ``78``.
* ``ROSETTA_STORAGE_CLASS``: See the note below on Storages. Defaults to ``rosetta.storage.CacheRosettaStorage``
* ``ROSETTA_ACCESS_CONTROL_FUNCTION``: An alternative function that determines if a given user can access the translation views.
********
Storages

36
rosetta/access.py Normal file
View file

@ -0,0 +1,36 @@
from django.conf import settings
from django.utils import importlib
def can_translate(user):
return get_access_control_function()(user)
def get_access_control_function():
"""
Return a predicate for determining if a user can access the Rosetta views
"""
fn_path = getattr(settings, 'ROSETTA_ACCESS_CONTROL_FUNCTION', None)
if fn_path is None:
return is_superuser_staff_or_in_translators_group
# Dynamically load a permissions function
perm_module, perm_func = fn_path.rsplit('.', 1)
perm_module = importlib.import_module(perm_module)
return getattr(perm_module, perm_func)
# Default access control test
def is_superuser_staff_or_in_translators_group(user):
if not getattr(settings, 'ROSETTA_REQUIRES_AUTH', True):
return True
if not user.is_authenticated():
return False
elif user.is_superuser and user.is_staff:
return True
else:
try:
from django.contrib.auth.models import Group
translators = Group.objects.get(name='translators')
return translators in user.groups.all()
except Group.DoesNotExist:
return False

View file

@ -16,6 +16,9 @@ MAIN_LANGUAGE = getattr(settings, 'ROSETTA_MAIN_LANGUAGE', None)
MESSAGES_SOURCE_LANGUAGE_CODE = getattr(settings, 'ROSETTA_MESSAGES_SOURCE_LANGUAGE_CODE', 'en')
MESSAGES_SOURCE_LANGUAGE_NAME = getattr(settings, 'ROSETTA_MESSAGES_SOURCE_LANGUAGE_NAME', 'English')
ACCESS_CONTROL_FUNCTION = getattr(
settings, 'ROSETTA_ACCESS_CONTROL_FUNCTION', None)
"""
When running WSGI daemon mode, using mod_wsgi 2.0c5 or later, this setting

View file

@ -537,3 +537,22 @@ class RosettaTestCase(TestCase):
r = self.client.post(reverse('rosetta-home'), dict(m_e48f149a8b2e8baa81b816c0edf93890='Hello, world', _next='_next'))
r = self.client.get(reverse('rosetta-home'))
self.assertTrue('Progress: 25.00%' in str(r.content))
def test_24_replace_access_control(self):
# Test default access control allows access
url = reverse('rosetta-home')
response = self.client.get(url)
self.assertEqual(200, response.status_code)
# Now replace access control, and check we get redirected
settings.ROSETTA_ACCESS_CONTROL_FUNCTION = 'rosetta.tests.no_access'
response = self.client.get(url)
self.assertEqual(302, response.status_code)
# Restore setting to default
settings.ROSETTA_ACCESS_CONTROL_FUNCTION = None
# Stubbed access control function
def no_access(user):
return False

View file

@ -13,6 +13,7 @@ from rosetta.polib import pofile
from rosetta.poutil import find_pos, pagination_range, timestamp_with_timezone
from rosetta.signals import entry_changed, post_save
from rosetta.storage import get_storage
from rosetta.access import can_translate
import re
import rosetta
import unicodedata
@ -392,20 +393,3 @@ def lang_sel(request, langid, idx):
storage.set('rosetta_i18n_write', False)
return HttpResponseRedirect(reverse('rosetta-home'))
def can_translate(user):
if not getattr(settings, 'ROSETTA_REQUIRES_AUTH', True):
return True
if not user.is_authenticated():
return False
elif user.is_superuser and user.is_staff:
return True
else:
try:
from django.contrib.auth.models import Group
translators = Group.objects.get(name='translators')
return translators in user.groups.all()
except Group.DoesNotExist:
return False