├── .gitignore ├── LICENSE ├── MANIFEST.in ├── README.rst ├── rest_condition ├── __init__.py └── permissions.py ├── runtests.py ├── setup.py └── tests ├── __init__.py ├── models.py ├── settings.py ├── tests ├── __init__.py └── test_permissions.py ├── urls.py └── views.py /.gitignore: -------------------------------------------------------------------------------- 1 | *.py[cod] 2 | 3 | # C extensions 4 | *.so 5 | 6 | # Packages 7 | *.egg 8 | *.egg-info 9 | dist 10 | build 11 | eggs 12 | parts 13 | bin 14 | var 15 | sdist 16 | develop-eggs 17 | .installed.cfg 18 | lib 19 | lib64 20 | __pycache__ 21 | 22 | # Installer logs 23 | pip-log.txt 24 | 25 | # Unit test / coverage reports 26 | .coverage 27 | .tox 28 | nosetests.xml 29 | 30 | # Translations 31 | *.mo 32 | 33 | # Mr Developer 34 | .mr.developer.cfg 35 | .project 36 | .pydevproject 37 | 38 | # Virtualenv 39 | venv/ 40 | .venv/ 41 | 42 | # Some temp files 43 | .DS_Store 44 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2016 Maxim Kamenkov 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy of 6 | this software and associated documentation files (the "Software"), to deal in 7 | the Software without restriction, including without limitation the rights to 8 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of 9 | the Software, and to permit persons to whom the Software is furnished to do so, 10 | subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 17 | FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 18 | COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 19 | IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 20 | CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 21 | -------------------------------------------------------------------------------- /MANIFEST.in: -------------------------------------------------------------------------------- 1 | include README.rst LICENSE runtests.py 2 | -------------------------------------------------------------------------------- /README.rst: -------------------------------------------------------------------------------- 1 | rest\_condition 2 | =============== 3 | 4 | Complex permissions flow for `django-rest-framework`_. 5 | 6 | Installation 7 | ------------ 8 | 9 | The easiest way to install the latest version is by using 10 | pip/easy\_install to pull it from PyPI: 11 | 12 | :: 13 | 14 | pip install rest_condition 15 | 16 | You may also use Git to clone the repository from Github and install it 17 | manually: 18 | 19 | :: 20 | 21 | git clone https://github.com/caxap/rest_condition.git 22 | python setup.py install 23 | 24 | Example 25 | ------- 26 | 27 | .. code:: python 28 | 29 | from rest_framework.response import Response 30 | from rest_framework.views import APIView 31 | from rest_framework.permissions import BasePermission 32 | from rest_condition import ConditionalPermission, C, And, Or, Not 33 | 34 | 35 | class Perm1(BasePermission): 36 | 37 | def has_permission(self, request, view): 38 | # You permissions check here 39 | return True 40 | 41 | 42 | class Perm2(BasePermission): 43 | 44 | def has_permission(self, request, view): 45 | # You permissions check here 46 | return False 47 | 48 | 49 | # Example of possible expressions 50 | expr1 = Or(Perm1, Perm2) # same as: C(Perm1) | Perm2 51 | expr2 = And(Perm1, Perm2) # same as: C(Perm1) & Perm2 52 | expr3 = Not(Perm1) # same as: ~C(Perm1) 53 | expr4 = And(Not(Perm1), Or(Perm1, Not(Perm2))) # same as: ~C(Perm1) & (C(Perm1) | ~C(Perm2)) 54 | 55 | # Using expressions in API views 56 | class ExampleView(APIView): 57 | permission_classes = [Or(And(Perm1, Perm2), Not(Perm2)), ] 58 | # Or just simple: 59 | # permission_classes = [C(Perm1) & Perm2 | ~C(Perm2), ] 60 | 61 | def get(self, request, format=None): 62 | content = {'status': 'request was permitted'} 63 | return Response(content) 64 | 65 | 66 | class OtherExampleView(ExampleView): 67 | # Using ConditionalPermission class 68 | permission_classes = [ConditionalPermission, ] 69 | permission_condition = (C(Perm1) & Perm2) | (~C(Perm1) & ~C(Perm2)) 70 | 71 | License 72 | ------- 73 | 74 | The MIT License (MIT) 75 | 76 | Contributed by `Max Kamenkov`_ 77 | 78 | .. _django-rest-framework: http://django-rest-framework.org/ 79 | .. _Maxim Kamenkov: https://github.com/caxap/ 80 | -------------------------------------------------------------------------------- /rest_condition/__init__.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | 4 | from .permissions import * # noqa 5 | 6 | __title__ = 'rest_condition' 7 | __version__ = '1.0.3' 8 | __author__ = 'Maxim Kamenkov' 9 | __license__ = 'MIT' 10 | 11 | __all__ = ['ConditionalPermission', 'Condition', 'C', 'And', 'Or', 'Not'] 12 | -------------------------------------------------------------------------------- /rest_condition/permissions.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | 4 | import inspect 5 | import operator 6 | from rest_framework import permissions 7 | 8 | __all__ = ['ConditionalPermission', 'Condition', 'C', 'And', 'Or', 'Not'] 9 | 10 | _NONE = object() 11 | 12 | 13 | def _is_permission_factory(obj): 14 | return inspect.isclass(obj) or inspect.isfunction(obj) 15 | 16 | 17 | class ConditionalPermission(permissions.BasePermission): 18 | ''' 19 | Example of usage: 20 | >>> class MyView(GenericView): 21 | >>> permission_classes = (ConditionalPermission, ) 22 | >>> permission_condition = C(Perm1) | ~C(Perm2) 23 | 24 | Or you can just: 25 | >>> class MyView(GenericView): 26 | >>> permission_classes = (C(Perm1) | ~C(Perm2), ) 27 | ''' 28 | permission_condition_field = 'permission_condition' 29 | 30 | def get_permission_condition(self, view): 31 | condition = getattr(view, self.permission_condition_field, None) 32 | if condition and not isinstance(condition, Condition): 33 | condition = Condition(condition) 34 | return condition 35 | 36 | def has_object_permission(self, request, view, obj): 37 | condition = self.get_permission_condition(view) 38 | if not condition: 39 | return False 40 | return condition.has_object_permission(request, view, obj) 41 | 42 | def has_permission(self, request, view): 43 | condition = self.get_permission_condition(view) 44 | if not condition: 45 | return False 46 | return condition.has_permission(request, view) 47 | 48 | 49 | class Condition(object): 50 | ''' 51 | Provides a simple way to define complex and multi-depth 52 | (with logic operators) permissions tree. 53 | 54 | Example of usage: 55 | >>> cond = C(Perm1, Perm2) | C(Perm3, ~C(Perm4)) 56 | 57 | It's same as: 58 | >>> cond = Or(And(Perm1, Perm2), And(Perm3, Not(Perm4))) 59 | 60 | Some advanced/exotic usage, it will reject access if 3 of 4 given 61 | permission will be evaluated to `True`: 62 | >>> cond1 = C(Perm1, Perm2, Perm3, Perm4, 63 | >>> reduce_op=operator.add, lazy_until=3, negated=True) 64 | ''' 65 | @classmethod 66 | def And(cls, *perms_or_conds): 67 | return cls(reduce_op=operator.and_, lazy_until=False, *perms_or_conds) 68 | 69 | @classmethod 70 | def Or(cls, *perms_or_conds): 71 | return cls(reduce_op=operator.or_, lazy_until=True, *perms_or_conds) 72 | 73 | @classmethod 74 | def Not(cls, *perms_or_conds): 75 | return cls(negated=True, *perms_or_conds) 76 | 77 | def __init__(self, *perms_or_conds, **kwargs): 78 | self.perms_or_conds = perms_or_conds 79 | self.reduce_op = kwargs.get('reduce_op', operator.and_) 80 | self.lazy_until = kwargs.get('lazy_until', False) 81 | self.negated = kwargs.get('negated') 82 | 83 | def evaluate_permissions(self, permission_name, *args, **kwargs): 84 | reduced_result = _NONE 85 | 86 | for condition in self.perms_or_conds: 87 | if hasattr(condition, 'evaluate_permissions'): 88 | result = condition.evaluate_permissions(permission_name, *args, **kwargs) 89 | else: 90 | if _is_permission_factory(condition): 91 | condition = condition() 92 | result = getattr(condition, permission_name)(*args, **kwargs) 93 | 94 | # In some cases permission may not have explicit return statement 95 | if result is None: 96 | result = False 97 | # As well as can return Django CallableBool 98 | elif callable(result): 99 | result = result() 100 | 101 | if reduced_result is _NONE: 102 | reduced_result = result 103 | else: 104 | reduced_result = self.reduce_op(reduced_result, result) 105 | 106 | if self.lazy_until is not None and self.lazy_until is reduced_result: 107 | break 108 | 109 | if reduced_result is not _NONE: 110 | return not reduced_result if self.negated else reduced_result 111 | 112 | return False 113 | 114 | def has_object_permission(self, request, view, obj): 115 | return self.evaluate_permissions('has_object_permission', 116 | request, view, obj) 117 | 118 | def has_permission(self, request, view): 119 | return self.evaluate_permissions('has_permission', request, view) 120 | 121 | def __or__(self, perm_or_cond): 122 | return self.Or(self, perm_or_cond) 123 | 124 | def __ior__(self, perm_or_cond): 125 | return self.Or(self, perm_or_cond) 126 | 127 | def __and__(self, perm_or_cond): 128 | return self.And(self, perm_or_cond) 129 | 130 | def __iand__(self, perm_or_cond): 131 | return self.And(self, perm_or_cond) 132 | 133 | def __invert__(self): 134 | return self.Not(self) 135 | 136 | def __call__(self): 137 | return self 138 | 139 | 140 | # Define some shortcuts 141 | (C, And, Or, Not) = (Condition, Condition.And, Condition.Or, Condition.Not) 142 | -------------------------------------------------------------------------------- /runtests.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | 4 | import os 5 | import sys 6 | 7 | os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'tests.settings') 8 | 9 | import django 10 | from django.core.management import call_command 11 | 12 | 13 | if __name__ == '__main__': 14 | args = sys.argv[1:] 15 | 16 | django.setup() 17 | call_command('test', *args, verbosity=2, failfast=True) 18 | -------------------------------------------------------------------------------- /setup.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | 4 | from setuptools import setup 5 | import re 6 | import os 7 | import sys 8 | import codecs 9 | 10 | 11 | name = 'rest_condition' 12 | package = 'rest_condition' 13 | description = 'Complex permissions flow for django-rest-framework' 14 | url = 'https://github.com/caxap/rest_condition' 15 | author = 'Maxim Kamenkov' 16 | author_email = 'mkamenkov@gmail.com' 17 | license = 'MIT' 18 | keywords = 'django, rest, restframework, permissions' 19 | classifiers = [ 20 | 'Development Status :: 5 - Production/Stable', 21 | 'Framework :: Django', 22 | 'Intended Audience :: Developers', 23 | 'Natural Language :: English', 24 | 'License :: OSI Approved :: MIT License', 25 | 'Programming Language :: Python', 26 | 'Programming Language :: Python :: 2.6', 27 | 'Programming Language :: Python :: 2.7', 28 | 'Programming Language :: Python :: 3', 29 | 'Programming Language :: Python :: 3.3', 30 | 'Programming Language :: Python :: 3.4' 31 | ] 32 | 33 | install_requires = [ 34 | 'django >= 1.3', 35 | 'djangorestframework', 36 | ] 37 | 38 | 39 | def get_version(package): 40 | """ 41 | Return package version as listed in `__version__` in `init.py`. 42 | """ 43 | init_py = open(os.path.join(package, '__init__.py')).read() 44 | version = re.search("^__version__ = ['\"]([^'\"]+)['\"]", init_py, re.MULTILINE).group(1) 45 | if not version: 46 | raise RuntimeError('Cannot find version information') 47 | return version 48 | 49 | 50 | def get_readme(package): 51 | with codecs.open('README.rst', 'r', 'utf-8') as fd: 52 | return fd.read() 53 | 54 | 55 | def get_packages(package): 56 | """ 57 | Return root package and all sub-packages. 58 | """ 59 | return [dirpath 60 | for dirpath, dirnames, filenames in os.walk(package) 61 | if os.path.exists(os.path.join(dirpath, '__init__.py'))] 62 | 63 | 64 | def get_package_data(package): 65 | """ 66 | Return all files under the root package, that are not in a 67 | package themselves. 68 | """ 69 | walk = [(dirpath.replace(package + os.sep, '', 1), filenames) 70 | for dirpath, dirnames, filenames in os.walk(package) 71 | if not os.path.exists(os.path.join(dirpath, '__init__.py'))] 72 | 73 | filepaths = [] 74 | for base, filenames in walk: 75 | filepaths.extend([os.path.join(base, filename) 76 | for filename in filenames]) 77 | return {package: filepaths} 78 | 79 | 80 | if sys.argv[-1] == 'publish': 81 | os.system('python setup.py sdist upload') 82 | args = {'version': get_version(package)} 83 | print("You probably want to also tag the version now:") 84 | print(" git tag -a %(version)s -m 'version %(version)s'" % args) 85 | print(" git push --tags") 86 | sys.exit() 87 | 88 | setup( 89 | name=name, 90 | version=get_version(package), 91 | url=url, 92 | license=license, 93 | description=description, 94 | long_description=get_readme(package), 95 | author=author, 96 | author_email=author_email, 97 | packages=get_packages(package), 98 | package_data=get_package_data(package), 99 | install_requires=install_requires, 100 | classifiers=classifiers 101 | ) 102 | -------------------------------------------------------------------------------- /tests/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/caxap/rest_condition/efe44bbb74fb3fea80ef698f9331492df11174f4/tests/__init__.py -------------------------------------------------------------------------------- /tests/models.py: -------------------------------------------------------------------------------- 1 | from django.db import models 2 | 3 | # Create your models here. 4 | -------------------------------------------------------------------------------- /tests/settings.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | 4 | from django.conf.global_settings import * 5 | import os 6 | 7 | SITE_ROOT = os.path.dirname(os.path.realpath(__file__)) 8 | 9 | DEBUG = True 10 | TEMPLATE_DEBUG = True 11 | 12 | ROOT_URLCONF = 'tests.urls' 13 | 14 | SECRET_KEY = '12345678' 15 | 16 | MIDDLEWARE_CLASSES = ( 17 | 'django.middleware.common.CommonMiddleware', 18 | 'django.contrib.sessions.middleware.SessionMiddleware', 19 | 'django.middleware.csrf.CsrfViewMiddleware', 20 | 'django.contrib.auth.middleware.AuthenticationMiddleware', 21 | ) 22 | 23 | INSTALLED_APPS = [ 24 | 'django.contrib.auth', 25 | 'django.contrib.contenttypes', 26 | 'django.contrib.sessions', 27 | 'rest_condition', 28 | 'tests', 29 | ] 30 | 31 | DATABASES = { 32 | 'default': { 33 | 'ENGINE': 'django.db.backends.sqlite3', 34 | 'NAME': 'rest_condition.db', 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /tests/tests/__init__.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | 4 | -------------------------------------------------------------------------------- /tests/tests/test_permissions.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | 4 | from django.test import TestCase 5 | from django.test.client import RequestFactory 6 | from rest_framework.permissions import BasePermission 7 | from rest_framework.views import APIView 8 | from rest_condition import ConditionalPermission, C, And, Or, Not 9 | 10 | 11 | class TestView(APIView): 12 | 13 | def test_permission(self, request): 14 | from rest_framework.request import Request 15 | 16 | request = Request(request) 17 | 18 | self.request = request 19 | 20 | for permission in self.get_permissions(): 21 | if not permission.has_permission(request, self): 22 | return False 23 | 24 | return True 25 | 26 | 27 | class TruePermission(BasePermission): 28 | 29 | def has_permission(self, request, view): 30 | return True 31 | 32 | 33 | class FalsePermission(BasePermission): 34 | 35 | def has_permission(self, request, view): 36 | return False 37 | 38 | 39 | class PermissionsTestCase(TestCase): 40 | 41 | def setUp(self): 42 | self.requests = RequestFactory() 43 | 44 | def assertViewPermission(self, view_class, granted=True): 45 | view = view_class() 46 | request = self.requests.get('/') 47 | result = view.test_permission(request) 48 | if granted: 49 | self.assertTrue(result) 50 | else: 51 | self.assertFalse(result) 52 | 53 | def test_conditional_permissions_with_assigment(self): 54 | 55 | perm1 = C(TruePermission) 56 | perm1 |= ~C(TruePermission) 57 | perm1 |= FalsePermission 58 | 59 | class View1(TestView): 60 | permission_classes = [perm1] 61 | 62 | self.assertViewPermission(View1, True) 63 | 64 | perm2 = C(TruePermission) 65 | perm2 &= TruePermission 66 | perm2 &= ~C(FalsePermission) 67 | 68 | class View2(TestView): 69 | permission_classes = [perm2] 70 | 71 | self.assertViewPermission(View2, True) 72 | 73 | def test_single_conditional_permission_true(self): 74 | 75 | class View1(TestView): 76 | permission_classes = [ConditionalPermission] 77 | permission_condition = TruePermission 78 | 79 | class View2(TestView): 80 | permission_classes = [ConditionalPermission] 81 | permission_condition = C(TruePermission) 82 | 83 | class View3(TestView): 84 | permission_classes = [C(TruePermission)] 85 | 86 | class View4(TestView): 87 | permission_classes = [TruePermission] 88 | 89 | self.assertViewPermission(View1, True) 90 | self.assertViewPermission(View2, True) 91 | self.assertViewPermission(View3, True) 92 | self.assertViewPermission(View4, True) 93 | 94 | def test_single_conditional_permission_false(self): 95 | 96 | class View1(TestView): 97 | permission_classes = [ConditionalPermission] 98 | permission_condition = FalsePermission 99 | 100 | class View2(TestView): 101 | permission_classes = [ConditionalPermission] 102 | permission_condition = C(FalsePermission) 103 | 104 | class View3(TestView): 105 | permission_classes = [C(FalsePermission)] 106 | 107 | class View4(TestView): 108 | permission_classes = [FalsePermission] 109 | 110 | self.assertViewPermission(View1, False) 111 | self.assertViewPermission(View2, False) 112 | self.assertViewPermission(View3, False) 113 | self.assertViewPermission(View4, False) 114 | 115 | def test_multi_and_conditional_permission_true(self): 116 | 117 | class View1(TestView): 118 | permission_classes = [ConditionalPermission] 119 | permission_condition = (C(TruePermission) & 120 | TruePermission & 121 | TruePermission) 122 | 123 | class View2(TestView): 124 | permission_classes = [ConditionalPermission] 125 | permission_condition = And(TruePermission, 126 | TruePermission, 127 | C(TruePermission)) 128 | 129 | class View3(TestView): 130 | permission_classes = [C(TruePermission) & 131 | TruePermission & 132 | TruePermission] 133 | 134 | class View4(TestView): 135 | permission_classes = [And(TruePermission, 136 | TruePermission, 137 | C(TruePermission))] 138 | 139 | self.assertViewPermission(View1, True) 140 | self.assertViewPermission(View2, True) 141 | self.assertViewPermission(View3, True) 142 | self.assertViewPermission(View4, True) 143 | 144 | def test_multi_and_conditional_permission_false(self): 145 | 146 | class View1(TestView): 147 | permission_classes = [ConditionalPermission] 148 | permission_condition = (C(TruePermission) & 149 | FalsePermission & 150 | TruePermission) 151 | 152 | class View2(TestView): 153 | permission_classes = [ConditionalPermission] 154 | permission_condition = And(TruePermission, 155 | FalsePermission, 156 | C(TruePermission)) 157 | 158 | class View3(TestView): 159 | permission_classes = [C(FalsePermission) & 160 | TruePermission & 161 | TruePermission] 162 | 163 | class View4(TestView): 164 | permission_classes = [And(FalsePermission, 165 | TruePermission, 166 | C(TruePermission))] 167 | 168 | self.assertViewPermission(View1, False) 169 | self.assertViewPermission(View2, False) 170 | self.assertViewPermission(View3, False) 171 | self.assertViewPermission(View4, False) 172 | 173 | def test_multi_or_conditional_permission_true(self): 174 | 175 | class View1(TestView): 176 | permission_classes = [ConditionalPermission] 177 | permission_condition = (C(TruePermission) | 178 | FalsePermission | 179 | TruePermission) 180 | 181 | class View2(TestView): 182 | permission_classes = [ConditionalPermission] 183 | permission_condition = Or(TruePermission, 184 | FalsePermission, 185 | TruePermission) 186 | 187 | class View3(TestView): 188 | permission_classes = [C(FalsePermission) | 189 | TruePermission | 190 | TruePermission] 191 | 192 | class View4(TestView): 193 | permission_classes = [Or(FalsePermission, 194 | TruePermission, 195 | C(TruePermission))] 196 | 197 | self.assertViewPermission(View1, True) 198 | self.assertViewPermission(View2, True) 199 | self.assertViewPermission(View3, True) 200 | self.assertViewPermission(View4, True) 201 | 202 | def test_multi_or_conditional_permission_false(self): 203 | 204 | class View1(TestView): 205 | permission_classes = [ConditionalPermission] 206 | permission_condition = (C(FalsePermission) | 207 | FalsePermission | 208 | FalsePermission) 209 | 210 | class View2(TestView): 211 | permission_classes = [ConditionalPermission] 212 | permission_condition = Or(FalsePermission, 213 | FalsePermission, 214 | FalsePermission) 215 | 216 | class View3(TestView): 217 | permission_classes = [C(FalsePermission) | 218 | FalsePermission | 219 | FalsePermission] 220 | 221 | class View4(TestView): 222 | permission_classes = [Or(FalsePermission, 223 | FalsePermission, 224 | C(FalsePermission))] 225 | 226 | self.assertViewPermission(View1, False) 227 | self.assertViewPermission(View2, False) 228 | self.assertViewPermission(View3, False) 229 | self.assertViewPermission(View4, False) 230 | 231 | def test_not_conditional_permission_true(self): 232 | 233 | class View1(TestView): 234 | permission_classes = [ConditionalPermission] 235 | permission_condition = ~C(FalsePermission) 236 | 237 | class View2(TestView): 238 | permission_classes = [ConditionalPermission] 239 | permission_condition = Not(FalsePermission) 240 | 241 | class View3(TestView): 242 | permission_classes = [~C(FalsePermission)] 243 | 244 | class View4(TestView): 245 | permission_classes = [Not(FalsePermission)] 246 | 247 | self.assertViewPermission(View1, True) 248 | self.assertViewPermission(View2, True) 249 | self.assertViewPermission(View3, True) 250 | self.assertViewPermission(View4, True) 251 | 252 | def test_not_conditional_permission_false(self): 253 | 254 | class View1(TestView): 255 | permission_classes = [ConditionalPermission] 256 | permission_condition = ~C(TruePermission) 257 | 258 | class View2(TestView): 259 | permission_classes = [ConditionalPermission] 260 | permission_condition = Not(TruePermission) 261 | 262 | class View3(TestView): 263 | permission_classes = [~C(TruePermission)] 264 | 265 | class View4(TestView): 266 | permission_classes = [Not(TruePermission)] 267 | 268 | self.assertViewPermission(View1, False) 269 | self.assertViewPermission(View2, False) 270 | self.assertViewPermission(View3, False) 271 | self.assertViewPermission(View4, False) 272 | 273 | def test_conditional_permission_true(self): 274 | 275 | class View1(TestView): 276 | permission_classes = [ConditionalPermission] 277 | permission_condition = (C(TruePermission) & 278 | ~C(FalsePermission) | 279 | TruePermission) 280 | 281 | class View2(TestView): 282 | permission_classes = [ConditionalPermission] 283 | permission_condition = And(Or(TruePermission, 284 | Not(FalsePermission)), 285 | TruePermission) 286 | 287 | class View3(TestView): 288 | permission_classes = [C(TruePermission) & 289 | ~C(FalsePermission) | 290 | TruePermission] 291 | 292 | class View4(TestView): 293 | permission_classes = [And(Or(TruePermission, 294 | Not(FalsePermission)), 295 | TruePermission)] 296 | 297 | self.assertViewPermission(View1, True) 298 | self.assertViewPermission(View2, True) 299 | self.assertViewPermission(View3, True) 300 | self.assertViewPermission(View4, True) 301 | -------------------------------------------------------------------------------- /tests/urls.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | 4 | try: 5 | from django.conf.urls import include, patterns, url 6 | except ImportError: 7 | from django.conf.urls.defaults import include, patterns, url 8 | 9 | urlpatterns = patterns('', ) 10 | -------------------------------------------------------------------------------- /tests/views.py: -------------------------------------------------------------------------------- 1 | # Create your views here. 2 | --------------------------------------------------------------------------------