Skip to content

Commit

Permalink
Merge 9c25ad2 into f170c3c
Browse files Browse the repository at this point in the history
  • Loading branch information
nkonin committed Feb 8, 2017
2 parents f170c3c + 9c25ad2 commit 48632d5
Show file tree
Hide file tree
Showing 8 changed files with 229 additions and 37 deletions.
11 changes: 11 additions & 0 deletions README.rst
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,17 @@ in which you can provide which models you want to be added the view permission.
If you don't specify this setting then the view permission will be applied to
all the models.

You can also use another setting in which you can provide models which
you want to be excluded from the view permission. The view permission will be
applied to all the models except those listed in this list::

ADMIN_VIEW_PERMISSION_EXCLUDE_MODELS = [
'auth.User',
...
]

:warning: You can't use both settings at the same time.

Uninstall
---------

Expand Down
63 changes: 29 additions & 34 deletions admin_view_permission/admin.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,7 @@
from django.utils.text import capfirst
from django.utils.translation import ugettext as _

from .enums import DjangoVersion
from .utils import django_version
from admin_view_permission.utils import get_model_name


class AdminViewPermissionChangeList(ChangeList):
Expand Down Expand Up @@ -241,45 +240,41 @@ def register(self, model_or_iterable, admin_class=None, **options):
"""
SETTINGS_MODELS = getattr(settings, 'ADMIN_VIEW_PERMISSION_MODELS',
None)
SETTINGS_EXCLUDE_MODELS = \
getattr(settings, 'ADMIN_VIEW_PERMISSION_EXCLUDE_MODELS', None)

models = model_or_iterable
if not isinstance(model_or_iterable, (tuple, list)):
models = tuple([model_or_iterable])

if SETTINGS_MODELS or (SETTINGS_MODELS is not None and len(
SETTINGS_MODELS) == 0):
for model in models:
if django_version() == DjangoVersion.DJANGO_18:
model_name = '%s.%s' % (model._meta.app_label,
model._meta.object_name)
elif django_version() > DjangoVersion.DJANGO_18:
model_name = model._meta.label

for model in models:
model_name = get_model_name(model)
if SETTINGS_MODELS or (SETTINGS_MODELS is not None and len(
SETTINGS_MODELS) == 0):
if model_name in SETTINGS_MODELS:
if admin_class:
admin_class = type(
str('DynamicAdminViewPermissionModelAdmin'),
(admin_class, AdminViewPermissionModelAdmin),
dict(admin_class.__dict__))
else:
admin_class = AdminViewPermissionModelAdmin

super(AdminViewPermissionAdminSite, self).register([model],
admin_class,
**options)
else:
if admin_class:
admin_class = type(str('DynamicAdminViewPermissionModelAdmin'),
(
admin_class,
AdminViewPermissionModelAdmin),
dict(admin_class.__dict__))
else:
admin_class = AdminViewPermissionModelAdmin
admin_class = self.replace_admin_class(admin_class)

super(AdminViewPermissionAdminSite, self).register(
model_or_iterable,
admin_class, **options)
elif SETTINGS_EXCLUDE_MODELS:
if model_name not in SETTINGS_EXCLUDE_MODELS:
admin_class = self.replace_admin_class(admin_class)

else:
admin_class = self.replace_admin_class(admin_class)

super(AdminViewPermissionAdminSite, self).register([model],
admin_class,
**options)

@staticmethod
def replace_admin_class(admin_class):
if admin_class:
admin_class = type(
str('DynamicAdminViewPermissionModelAdmin'),
(admin_class, AdminViewPermissionModelAdmin),
dict(admin_class.__dict__))
else:
admin_class = AdminViewPermissionModelAdmin
return admin_class

def _build_app_dict(self, request, label=None):
"""
Expand Down
27 changes: 27 additions & 0 deletions admin_view_permission/apps.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
from django.apps import AppConfig
from django.conf import settings
from django.contrib import admin
from django.core.exceptions import ImproperlyConfigured
from django.db.models.signals import post_migrate

from .admin import AdminViewPermissionAdminSite
Expand All @@ -14,6 +15,8 @@
def update_permissions(sender, app_config, verbosity, apps=global_apps,
**kwargs):
settings_models = getattr(settings, 'ADMIN_VIEW_PERMISSION_MODELS', None)
settings_exclude_models =\
getattr(settings, 'ADMIN_VIEW_PERMISSION_EXCLUDE_MODELS', None)

# TODO: Maybe look at the registry not in all models
for app in apps.get_app_configs():
Expand All @@ -33,6 +36,19 @@ def update_permissions(sender, app_config, verbosity, apps=global_apps,
model._meta.permissions += (
(view_permission,
'Can view %s' % model._meta.model_name),)
elif settings_exclude_models:
if django_version() == DjangoVersion.DJANGO_18:
model_name = '%s.%s' % (model._meta.app_label,
model._meta.object_name)
elif django_version() > DjangoVersion.DJANGO_18:
model_name = model._meta.label

if (model_name not in settings_exclude_models and
view_permission not in
[perm[0] for perm in model._meta.permissions]):
model._meta.permissions += (
(view_permission,
'Can view %s' % model._meta.model_name),)
else:
if view_permission not in [perm[0] for perm in
model._meta.permissions]:
Expand All @@ -45,6 +61,17 @@ class AdminViewPermissionConfig(AppConfig):
name = 'admin_view_permission'

def ready(self):
SETTINGS_MODELS = \
getattr(settings, 'ADMIN_VIEW_PERMISSION_MODELS', None)
SETTINGS_EXCLUDE_MODELS = \
getattr(settings, 'ADMIN_VIEW_PERMISSION_EXCLUDE_MODELS', None)
if SETTINGS_MODELS is not None \
and SETTINGS_EXCLUDE_MODELS is not None:
raise ImproperlyConfigured(
"ADMIN_VIEW_PERMISSION_MODELS "
"and ADMIN_VIEW_PERMISSION_EXCLUDE_MODELS "
"can't be defined at the same time")

if not isinstance(admin.site, AdminViewPermissionAdminSite):
admin.site = AdminViewPermissionAdminSite('admin')
admin.sites.site = admin.site
Expand Down
9 changes: 9 additions & 0 deletions admin_view_permission/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,3 +12,12 @@ def django_version():
return DjangoVersion.DJANGO_18
elif django.get_version().startswith('1.10'):
return DjangoVersion.DJANGO_110


def get_model_name(model):
if django_version() == DjangoVersion.DJANGO_18:
model_name = '%s.%s' % (model._meta.app_label,
model._meta.object_name)
elif django_version() > DjangoVersion.DJANGO_18:
model_name = model._meta.label
return model_name
22 changes: 20 additions & 2 deletions docs/configuration.rst
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,24 @@ Example
::

ADMIN_VIEW_PERMISSION_MODELS = [
auth.User,
'auth.User',
...
]
]

ADMIN_VIEW_PERMISSION_EXCLUDE_MODELS
------------------------------------

You can also use another setting in which you can provide models which
you want to be excluded from the view permission. The view permission will be
applied to all the models except those listed in this list.

Example
~~~~~~~
::

ADMIN_VIEW_PERMISSION_EXCLUDE_MODELS = [
'auth.User',
...
]

:warning: You can't use both settings at the same time.
34 changes: 34 additions & 0 deletions tests/test_admin.py
Original file line number Diff line number Diff line change
Expand Up @@ -831,3 +831,37 @@ def test_register_6(self):
self.admin_site.register(TestModel1)
assert not isinstance(self.admin_site._registry[TestModel1],
AdminViewPermissionModelAdmin)

@override_settings(ADMIN_VIEW_PERMISSION_EXCLUDE_MODELS=[])
def test_register_7(self):
self.admin_site.register(TestModel1)
assert isinstance(self.admin_site._registry[TestModel1],
AdminViewPermissionModelAdmin)

@override_settings(ADMIN_VIEW_PERMISSION_EXCLUDE_MODELS=())
def test_register_8(self):
self.admin_site.register(TestModel1)
assert isinstance(self.admin_site._registry[TestModel1],
AdminViewPermissionModelAdmin)

@override_settings(ADMIN_VIEW_PERMISSION_EXCLUDE_MODELS=None)
def test_register_9(self):
self.admin_site.register(TestModel1)
assert isinstance(self.admin_site._registry[TestModel1],
AdminViewPermissionModelAdmin)

@override_settings(
ADMIN_VIEW_PERMISSION_EXCLUDE_MODELS=['test_app.TestModel1', ]
)
def test_register_10(self):
self.admin_site.register(TestModel1)
assert not isinstance(self.admin_site._registry[TestModel1],
AdminViewPermissionModelAdmin)

@override_settings(
ADMIN_VIEW_PERMISSION_EXCLUDE_MODELS=['test_app.TestModel2', ]
)
def test_register_11(self):
self.admin_site.register(TestModel1)
assert isinstance(self.admin_site._registry[TestModel1],
AdminViewPermissionModelAdmin)
60 changes: 60 additions & 0 deletions tests/test_apps.py
Original file line number Diff line number Diff line change
Expand Up @@ -90,3 +90,63 @@ def test_ready_with_other_permissions_and_with_none(self):
self.model3._meta.permissions,
((u'copy_apptestmodel3', u'Can copy apptestmodel3'), )
)

# test ADMIN_VIEW_PERMISSION_EXCLUDE_MODELS

@override_settings(
ADMIN_VIEW_PERMISSION_EXCLUDE_MODELS=['test_app.AppTestModel2', ]
)
def test_ready_with_one_excluded_model(self):
self.trigger_signal()
self.assertEqual(self.model1._meta.permissions,
[('view_apptestmodel1', 'Can view apptestmodel1'), ])
self.assertEqual(self.model2._meta.permissions, [])

@override_settings(
ADMIN_VIEW_PERMISSION_EXCLUDE_MODELS=[]
)
def test_ready_without_excluded_model_list(self):
self.trigger_signal()
self.assertEqual(self.model1._meta.permissions,
[('view_apptestmodel1', 'Can view apptestmodel1'), ])
self.assertEqual(self.model2._meta.permissions,
[('view_apptestmodel2', 'Can view apptestmodel2'), ])

@override_settings(
ADMIN_VIEW_PERMISSION_EXCLUDE_MODELS=()
)
def test_ready_without_excluded_model_tuple(self):
self.trigger_signal()
self.assertEqual(self.model1._meta.permissions,
[('view_apptestmodel1', 'Can view apptestmodel1'), ])
self.assertEqual(self.model2._meta.permissions,
[('view_apptestmodel2', 'Can view apptestmodel2'), ])

@override_settings(
ADMIN_VIEW_PERMISSION_EXCLUDE_MODELS=None
)
def test_ready_excluded_with_none(self):
self.trigger_signal()
self.assertEqual(self.model1._meta.permissions,
[('view_apptestmodel1', 'Can view apptestmodel1'), ])
self.assertEqual(self.model2._meta.permissions,
[('view_apptestmodel2', 'Can view apptestmodel2'), ])

@override_settings(
ADMIN_VIEW_PERMISSION_EXCLUDE_MODELS=['test_app.AppTestModel3', ]
)
def test_ready_excluded_with_other_permissions(self):
self.trigger_signal()
self.assertEqual(
self.model3._meta.permissions,
((u'copy_apptestmodel3', u'Can copy apptestmodel3'), )
)

@override_settings(
ADMIN_VIEW_PERMISSION_EXCLUDE_MODELS=[]
)
def test_ready_excluded_with_other_permissions_and_with_none(self):
self.trigger_signal()
self.assertEqual(self.model3._meta.permissions,
((u'copy_apptestmodel3', u'Can copy apptestmodel3'),
(u'view_apptestmodel3', u'Can view apptestmodel3')))
40 changes: 39 additions & 1 deletion tests/test_others.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,11 @@
from __future__ import unicode_literals

from django.apps import apps
from django.conf import UserSettingsHolder, settings
from django.contrib import admin
from django.test import SimpleTestCase
from django.core.exceptions import ImproperlyConfigured
from django.core.signals import setting_changed
from django.test import SimpleTestCase, override_settings

from admin_view_permission.admin import AdminViewPermissionModelAdmin

Expand All @@ -13,3 +17,37 @@ def test_testapp_modeladmin_override_1(self):
assert isinstance(admin.site._registry[model],
AdminViewPermissionModelAdmin)
assert isinstance(admin.site._registry[model], admin.ModelAdmin)


# noinspection PyPep8Naming
class reload_apps(override_settings):

def enable(self):
override = UserSettingsHolder(settings._wrapped)
for key, new_value in self.options.items():
setattr(override, key, new_value)
self.wrapped = settings._wrapped
settings._wrapped = override
for key, new_value in self.options.items():
setting_changed.send(sender=settings._wrapped.__class__,
setting=key, value=new_value, enter=True)
if 'INSTALLED_APPS' in self.options:
try:
apps.set_installed_apps(self.options['INSTALLED_APPS'])
except Exception:
apps.unset_installed_apps()
raise


class TestImproperlyConfigured(SimpleTestCase):

def test_improperly_configured(self):
try:
with reload_apps(ADMIN_VIEW_PERMISSION_MODELS=[],
ADMIN_VIEW_PERMISSION_EXCLUDE_MODELS=[],
INSTALLED_APPS=['admin_view_permission']):
pass
except ImproperlyConfigured:
pass
else:
raise AssertionError

0 comments on commit 48632d5

Please sign in to comment.