ISSUE-6
Showing 7 of 13 files from the diff.
django_view_permissions/access.py
changed.
Other files ignored by Codecov
requirements/test.txt
has changed.
django_view_permissions/tests/test_middleware.py
was deleted.
requirements/compatibility.txt
has changed.
requirements/dev.txt
has changed.
requirements/test.in
has changed.
requirements/docs.txt
has changed.
@@ -1,3 +1,39 @@
Loading
1 | 1 | """ |
|
2 | 2 | Test Module for django-view-permissions. |
|
3 | 3 | """ |
|
4 | + | from unittest.mock import PropertyMock, patch |
|
5 | + | ||
6 | + | from django.contrib.auth.models import User |
|
7 | + | from django.test.testcases import TestCase |
|
8 | + | from django.urls import reverse |
|
9 | + | ||
10 | + | from django_view_permissions.tests.test_app.permissions import AllowAccess, RejectAccess |
|
11 | + | ||
12 | + | ||
13 | + | class BaseTestClass(TestCase): |
|
14 | + | """ |
|
15 | + | View Permission Middleware Tests |
|
16 | + | """ |
|
17 | + | ||
18 | + | def setUp(self): |
|
19 | + | super(BaseTestClass, self).setUp() |
|
20 | + | self.user = User.objects.create_user(username='test') |
|
21 | + | self.client.force_login(self.user) |
|
22 | + | ||
23 | + | def call_view_and_assert_response(self, view, request_method, status_code): |
|
24 | + | """ |
|
25 | + | Calls the View, checks the response. |
|
26 | + | """ |
|
27 | + | if request_method == 'GET': |
|
28 | + | response = self.client.get(reverse(view)) |
|
29 | + | else: |
|
30 | + | response = self.client.post(reverse(view)) |
|
31 | + | ||
32 | + | self.assertEqual(response.status_code, status_code) |
|
33 | + | if status_code == 200: |
|
34 | + | self.assertEqual(response.content.decode('utf-8'), 'ok!') |
|
35 | + | ||
36 | + | def tearDown(self): |
|
37 | + | super(BaseTestClass, self).tearDown() |
|
38 | + | self.client.logout() |
|
39 | + | self.user.delete() |
@@ -0,0 +1,88 @@
Loading
1 | + | """ |
|
2 | + | Tests the functionality of Attribute based permissions. |
|
3 | + | """ |
|
4 | + | from unittest.mock import PropertyMock, patch |
|
5 | + | ||
6 | + | from ddt import data, ddt, unpack |
|
7 | + | ||
8 | + | from django_view_permissions.tests import BaseTestClass |
|
9 | + | ||
10 | + | ||
11 | + | @ddt |
|
12 | + | class AttrBasedPermissionsTests(BaseTestClass): |
|
13 | + | """ |
|
14 | + | Tests the functionality of Attribute Based Permissions. |
|
15 | + | """ |
|
16 | + | @unpack |
|
17 | + | @data( |
|
18 | + | # ........................................................ |
|
19 | + | ( |
|
20 | + | [('attr', 'is_staff', True)], |
|
21 | + | 'GET', |
|
22 | + | 200 |
|
23 | + | ), |
|
24 | + | ( |
|
25 | + | [('attr', 'is_staff', False)], |
|
26 | + | 'GET', |
|
27 | + | 404 |
|
28 | + | ), |
|
29 | + | ( |
|
30 | + | [('attr', 'is_staff', True)], |
|
31 | + | 'POST', |
|
32 | + | 200 |
|
33 | + | ), |
|
34 | + | ( |
|
35 | + | [('attr', 'is_staff', False)], |
|
36 | + | 'POST', |
|
37 | + | 404 |
|
38 | + | ), |
|
39 | + | # ........................................................ |
|
40 | + | ( |
|
41 | + | [('attr', 'is_staff', True, ('GET'))], |
|
42 | + | 'GET', |
|
43 | + | 200 |
|
44 | + | ), |
|
45 | + | ( |
|
46 | + | [('attr', 'is_staff', False, ('GET'))], |
|
47 | + | 'GET', |
|
48 | + | 404 |
|
49 | + | ), |
|
50 | + | ( |
|
51 | + | [('attr', 'is_staff', True, ('GET'))], |
|
52 | + | 'POST', |
|
53 | + | 404 |
|
54 | + | ), |
|
55 | + | ( |
|
56 | + | [('attr', 'is_staff', False, ('GET'))], |
|
57 | + | 'POST', |
|
58 | + | 404 |
|
59 | + | ), |
|
60 | + | # ........................................................ |
|
61 | + | ( |
|
62 | + | [('attr', 'is_staff', True, ())], |
|
63 | + | 'GET', |
|
64 | + | 404 |
|
65 | + | ), |
|
66 | + | ( |
|
67 | + | [('attr', 'is_staff', True, ('GET', 'POST'))], |
|
68 | + | 'GET', |
|
69 | + | 200 |
|
70 | + | ), |
|
71 | + | ( |
|
72 | + | [('attr', 'is_staff', False, ('GET', 'POST'))], |
|
73 | + | 'POST', |
|
74 | + | 404 |
|
75 | + | ), |
|
76 | + | ) |
|
77 | + | def test_attribute_based_permissions(self, permissions, request_method, return_value): |
|
78 | + | """ |
|
79 | + | Tests the functionality of user attr based permissions. |
|
80 | + | """ |
|
81 | + | with patch( |
|
82 | + | 'django_view_permissions.tests.test_app.views.TestView.permissions', |
|
83 | + | new_callable=PropertyMock, |
|
84 | + | return_value=permissions |
|
85 | + | ): |
|
86 | + | self.user.is_staff = True |
|
87 | + | self.user.save() |
|
88 | + | self.call_view_and_assert_response('test-view', request_method, return_value) |
@@ -0,0 +1,88 @@
Loading
1 | + | """ |
|
2 | + | Tests the functionality of Class based permissions. |
|
3 | + | """ |
|
4 | + | from unittest.mock import PropertyMock, patch |
|
5 | + | ||
6 | + | from ddt import data, ddt, unpack |
|
7 | + | ||
8 | + | from django_view_permissions.tests import BaseTestClass |
|
9 | + | from django_view_permissions.tests.test_app.permissions import AllowAccess, RejectAccess |
|
10 | + | ||
11 | + | ||
12 | + | @ddt |
|
13 | + | class ClassBasedPermissionsTests(BaseTestClass): |
|
14 | + | """ |
|
15 | + | Tests the functionality of Class Based Permissions. |
|
16 | + | """ |
|
17 | + | @unpack |
|
18 | + | @data( |
|
19 | + | # ........................................................ |
|
20 | + | ( |
|
21 | + | [('class', AllowAccess)], |
|
22 | + | 'GET', |
|
23 | + | 200 |
|
24 | + | ), |
|
25 | + | ( |
|
26 | + | [('class', RejectAccess)], |
|
27 | + | 'GET', |
|
28 | + | 404 |
|
29 | + | ), |
|
30 | + | ( |
|
31 | + | [('class', AllowAccess)], |
|
32 | + | 'POST', |
|
33 | + | 200 |
|
34 | + | ), |
|
35 | + | ( |
|
36 | + | [('class', RejectAccess)], |
|
37 | + | 'POST', |
|
38 | + | 404 |
|
39 | + | ), |
|
40 | + | # ........................................................ |
|
41 | + | ( |
|
42 | + | [('class', AllowAccess, ('GET'))], |
|
43 | + | 'GET', |
|
44 | + | 200 |
|
45 | + | ), |
|
46 | + | ( |
|
47 | + | [('class', RejectAccess, ('GET'))], |
|
48 | + | 'GET', |
|
49 | + | 404 |
|
50 | + | ), |
|
51 | + | ( |
|
52 | + | [('class', AllowAccess, ('GET'))], |
|
53 | + | 'POST', |
|
54 | + | 404 |
|
55 | + | ), |
|
56 | + | ( |
|
57 | + | [('class', RejectAccess, ('GET'))], |
|
58 | + | 'POST', |
|
59 | + | 404 |
|
60 | + | ), |
|
61 | + | # ........................................................ |
|
62 | + | ( |
|
63 | + | [('class', AllowAccess, ())], |
|
64 | + | 'GET', |
|
65 | + | 404 |
|
66 | + | ), |
|
67 | + | ( |
|
68 | + | [('class', AllowAccess, ('GET', 'POST'))], |
|
69 | + | 'GET', |
|
70 | + | 200 |
|
71 | + | ), |
|
72 | + | ( |
|
73 | + | [('class', RejectAccess, ('GET', 'POST'))], |
|
74 | + | 'POST', |
|
75 | + | 404 |
|
76 | + | ), |
|
77 | + | ) |
|
78 | + | def test_class_based_permissions(self, permissions, request_method, return_value): |
|
79 | + | """ |
|
80 | + | Tests the class based permissions functionality. |
|
81 | + | """ |
|
82 | + | ||
83 | + | with patch( |
|
84 | + | 'django_view_permissions.tests.test_app.views.TestView.permissions', |
|
85 | + | new_callable=PropertyMock, |
|
86 | + | return_value=permissions |
|
87 | + | ): |
|
88 | + | self.call_view_and_assert_response('test-view', request_method, return_value) |
@@ -9,7 +9,13 @@
Loading
9 | 9 | # pylint: disable=no-self-use, unused-argument |
|
10 | 10 | def get(self, request): |
|
11 | 11 | """ |
|
12 | - | Test Get Method |
|
12 | + | Test GET Method |
|
13 | + | """ |
|
14 | + | return HttpResponse("ok!") |
|
15 | + | ||
16 | + | def post(self, request): |
|
17 | + | """ |
|
18 | + | Test POST Method |
|
13 | 19 | """ |
|
14 | 20 | return HttpResponse("ok!") |
|
15 | 21 |
@@ -0,0 +1,27 @@
Loading
1 | + | """ |
|
2 | + | Tests the functionality of middleware. |
|
3 | + | """ |
|
4 | + | from ddt import data, ddt |
|
5 | + | ||
6 | + | from django_view_permissions.tests import BaseTestClass |
|
7 | + | ||
8 | + | ||
9 | + | @ddt |
|
10 | + | class GeneralTests(BaseTestClass): |
|
11 | + | """ |
|
12 | + | Genral Test cases of Permissions |
|
13 | + | """ |
|
14 | + | @data('GET', 'POST') |
|
15 | + | def test_empty_view(self, request_method): |
|
16 | + | """ |
|
17 | + | Check empty view without permissions attribute works normaly. |
|
18 | + | """ |
|
19 | + | self.call_view_and_assert_response('empty-view', request_method, 200) |
|
20 | + | ||
21 | + | @data('GET', 'POST') |
|
22 | + | def test_empty_permissions_reject_all_requests(self, request_method): |
|
23 | + | """ |
|
24 | + | Tests if view permissions attr is empty all requests |
|
25 | + | are rejected. |
|
26 | + | """ |
|
27 | + | self.call_view_and_assert_response('test-view', request_method, 404) |
@@ -1,4 +1,8 @@
Loading
1 | 1 | """Checks view access for Permissions""" |
|
2 | + | METHODS = ( |
|
3 | + | 'GET', |
|
4 | + | 'POST', |
|
5 | + | ) |
|
2 | 6 | ||
3 | 7 | ||
4 | 8 | # pylint: disable=too-few-public-methods |
@@ -14,29 +18,54 @@
Loading
14 | 18 | """ |
|
15 | 19 | Checks if any of the permission is true for request. |
|
16 | 20 | """ |
|
17 | - | method_based = tuple(filter( |
|
18 | - | lambda x: x[0] == 'method', |
|
19 | - | self.permissions |
|
20 | - | )) |
|
21 | - | class_based = tuple(filter( |
|
22 | - | lambda x: x[0] == 'class', |
|
23 | - | self.permissions |
|
24 | - | )) |
|
25 | - | attr_based = tuple(filter( |
|
26 | - | lambda x: x[0] == 'attr', |
|
27 | - | self.permissions |
|
28 | - | )) |
|
21 | + | method_based = tuple( |
|
22 | + | filter( |
|
23 | + | lambda x: bool(x[1](self.request)), |
|
24 | + | tuple( |
|
25 | + | filter( |
|
26 | + | lambda x: x[0] == 'method', |
|
27 | + | self.permissions |
|
28 | + | ) |
|
29 | + | ) |
|
30 | + | ) |
|
31 | + | ) |
|
29 | 32 | ||
30 | - | if any( |
|
31 | - | p[1](self.request) for p in method_based |
|
32 | - | ): |
|
33 | - | return True |
|
34 | - | if any( |
|
35 | - | p[1](self.request)() for p in class_based |
|
36 | - | ): |
|
37 | - | return True |
|
38 | - | if any( |
|
39 | - | p[2] == getattr(self.request.user, p[1]) for p in attr_based |
|
40 | - | ): |
|
33 | + | class_based = tuple( |
|
34 | + | filter( |
|
35 | + | lambda x: bool(x[1](self.request)()), |
|
36 | + | tuple( |
|
37 | + | filter( |
|
38 | + | lambda x: x[0] == 'class', |
|
39 | + | self.permissions |
|
40 | + | ) |
|
41 | + | ) |
|
42 | + | ) |
|
43 | + | ) |
|
44 | + | attr_based = tuple( |
|
45 | + | filter( |
|
46 | + | lambda x: x[2] == getattr(self.request.user, x[1]), |
|
47 | + | tuple( |
|
48 | + | filter( |
|
49 | + | lambda x: x[0] == 'attr', |
|
50 | + | self.permissions |
|
51 | + | ) |
|
52 | + | ) |
|
53 | + | ) |
|
54 | + | ) |
|
55 | + | ||
56 | + | allowed_permissions = tuple( |
|
57 | + | filter( |
|
58 | + | lambda x: self.request.method in (x[3] if len(x) == 4 else METHODS), |
|
59 | + | attr_based |
|
60 | + | ) |
|
61 | + | ) + tuple( |
|
62 | + | filter( |
|
63 | + | lambda x: self.request.method in (x[2] if len(x) == 3 else METHODS), |
|
64 | + | method_based + class_based |
|
65 | + | ) |
|
66 | + | ) |
|
67 | + | ||
68 | + | if any(allowed_permissions): |
|
41 | 69 | return True |
|
70 | + | ||
42 | 71 | return False |
@@ -0,0 +1,87 @@
Loading
1 | + | """ |
|
2 | + | Tests the functionality of Method based permissions. |
|
3 | + | """ |
|
4 | + | from unittest.mock import PropertyMock, patch |
|
5 | + | ||
6 | + | from ddt import data, ddt, unpack |
|
7 | + | ||
8 | + | from django_view_permissions.tests import BaseTestClass |
|
9 | + | ||
10 | + | ||
11 | + | @ddt |
|
12 | + | class MethodBasedPermissionsTests(BaseTestClass): |
|
13 | + | """ |
|
14 | + | Tests the functionality of Method Based Permissions. |
|
15 | + | """ |
|
16 | + | ||
17 | + | @unpack |
|
18 | + | @data( |
|
19 | + | # ........................................................ |
|
20 | + | ( |
|
21 | + | [('method', lambda request: True)], |
|
22 | + | 'GET', |
|
23 | + | 200 |
|
24 | + | ), |
|
25 | + | ( |
|
26 | + | [('method', lambda request: False)], |
|
27 | + | 'GET', |
|
28 | + | 404 |
|
29 | + | ), |
|
30 | + | ( |
|
31 | + | [('method', lambda request: True)], |
|
32 | + | 'POST', |
|
33 | + | 200 |
|
34 | + | ), |
|
35 | + | ( |
|
36 | + | [('method', lambda request: False)], |
|
37 | + | 'POST', |
|
38 | + | 404 |
|
39 | + | ), |
|
40 | + | # ........................................................ |
|
41 | + | ( |
|
42 | + | [('method', lambda request: True, ('GET'))], |
|
43 | + | 'GET', |
|
44 | + | 200 |
|
45 | + | ), |
|
46 | + | ( |
|
47 | + | [('method', lambda request: False, ('GET'))], |
|
48 | + | 'GET', |
|
49 | + | 404 |
|
50 | + | ), |
|
51 | + | ( |
|
52 | + | [('method', lambda request: True, ('GET'))], |
|
53 | + | 'POST', |
|
54 | + | 404 |
|
55 | + | ), |
|
56 | + | ( |
|
57 | + | [('method', lambda request: False, ('GET'))], |
|
58 | + | 'POST', |
|
59 | + | 404 |
|
60 | + | ), |
|
61 | + | # ........................................................ |
|
62 | + | ( |
|
63 | + | [('method', lambda request: True, ())], |
|
64 | + | 'GET', |
|
65 | + | 404 |
|
66 | + | ), |
|
67 | + | ( |
|
68 | + | [('method', lambda request: True, ('GET', 'POST'))], |
|
69 | + | 'GET', |
|
70 | + | 200 |
|
71 | + | ), |
|
72 | + | ( |
|
73 | + | [('method', lambda request: False, ('GET', 'POST'))], |
|
74 | + | 'POST', |
|
75 | + | 404 |
|
76 | + | ), |
|
77 | + | ) |
|
78 | + | def test_method_based_permissions(self, permissions, request_method, return_value): |
|
79 | + | """ |
|
80 | + | Tests the method based permissions functionality. |
|
81 | + | """ |
|
82 | + | with patch( |
|
83 | + | 'django_view_permissions.tests.test_app.views.TestView.permissions', |
|
84 | + | new_callable=PropertyMock, |
|
85 | + | return_value=permissions |
|
86 | + | ): |
|
87 | + | self.call_view_and_assert_response('test-view', request_method, return_value) |
Files | Coverage |
---|---|
django_view_permissions | 100.00% |
Project Totals (11 files) | 100.00% |
68.12
TRAVIS_PYTHON_VERSION=3.7 TRAVIS_OS_NAME=linux
68.13
TRAVIS_PYTHON_VERSION=3.7 TRAVIS_OS_NAME=linux
68.11
TRAVIS_PYTHON_VERSION=3.7 TRAVIS_OS_NAME=linux
68.14
TRAVIS_PYTHON_VERSION=3.7 TRAVIS_OS_NAME=linux
68.16
TRAVIS_PYTHON_VERSION=3.8 TRAVIS_OS_NAME=linux
68.15
TRAVIS_PYTHON_VERSION=3.8 TRAVIS_OS_NAME=linux
68.19
TRAVIS_PYTHON_VERSION=3.8 TRAVIS_OS_NAME=linux
68.17
TRAVIS_PYTHON_VERSION=3.8 TRAVIS_OS_NAME=linux
68.18
TRAVIS_PYTHON_VERSION=3.8 TRAVIS_OS_NAME=linux
68.5
TRAVIS_PYTHON_VERSION=3.6 TRAVIS_OS_NAME=linux
68.3
TRAVIS_PYTHON_VERSION=3.5 TRAVIS_OS_NAME=linux
68.4
TRAVIS_PYTHON_VERSION=3.5 TRAVIS_OS_NAME=linux
68.2
TRAVIS_PYTHON_VERSION=3.5 TRAVIS_OS_NAME=linux
68.7
TRAVIS_PYTHON_VERSION=3.6 TRAVIS_OS_NAME=linux
68.1
TRAVIS_PYTHON_VERSION=3.5 TRAVIS_OS_NAME=linux
68.9
TRAVIS_PYTHON_VERSION=3.6 TRAVIS_OS_NAME=linux
68.8
TRAVIS_PYTHON_VERSION=3.6 TRAVIS_OS_NAME=linux
68.6
TRAVIS_PYTHON_VERSION=3.6 TRAVIS_OS_NAME=linux