From 60fc78ee6a43a482e7ebae0fa7230c6a36635ede Mon Sep 17 00:00:00 2001 From: ju5t Date: Thu, 23 Aug 2018 20:16:17 +0200 Subject: [PATCH 01/22] Store htmlcov artifcat for 2 days --- .gitlab-ci.yml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 0e8ced4..983c1e8 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -5,6 +5,10 @@ - python -V - pip install tox coverage: '/TOTAL.+ ([0-9]{1,3}%)/' + artifacts: + paths: + - htmlcov + expire_in: 2 days test:python27: <<: *test-commands From 83c34c2c1b40d00395b6269180f21a2ddf3bb50e Mon Sep 17 00:00:00 2001 From: ju5t Date: Thu, 23 Aug 2018 20:22:22 +0200 Subject: [PATCH 02/22] Implement is_demo as standalone method It doesn't add much functionality having it as part of the SimplePermissions-class. It's cleaner to have it on its own. --- drf_simplepermissions/__init__.py | 2 +- drf_simplepermissions/permissions.py | 52 +++++++++---------- .../tests/test_permissions.py | 21 ++++---- 3 files changed, 38 insertions(+), 37 deletions(-) diff --git a/drf_simplepermissions/__init__.py b/drf_simplepermissions/__init__.py index 90ea53d..a82c9e8 100644 --- a/drf_simplepermissions/__init__.py +++ b/drf_simplepermissions/__init__.py @@ -2,4 +2,4 @@ __version__ = '0.0.1' -__all__ = ['SimplePermissions'] +__all__ = ['SimplePermissions', 'is_demo'] diff --git a/drf_simplepermissions/permissions.py b/drf_simplepermissions/permissions.py index 5a0824a..c56802d 100644 --- a/drf_simplepermissions/permissions.py +++ b/drf_simplepermissions/permissions.py @@ -20,36 +20,36 @@ def has_permission(self, request, view): return False - @staticmethod - def is_demo(user, demo_group='demo', demo_mode=None): - '''is_demo checks if a user is added to a demo group or groups. If a - list of groups is supplied, it will try to match against any group and - if a match is found, it will return true. - This allows you to setup demo accounts that are restricted in what they - can do or what they can see. Keep in mind that it is not intended to - be used as a permission_classes' class.''' +def is_demo(user, demo_group='demo', demo_mode=None): + '''is_demo checks if a user is added to a demo group or groups. If a + list of groups is supplied, it will try to match against any group and + if a match is found, it will return true. - try: - basestring - except NameError: - basestring = str + This allows you to setup demo accounts that are restricted in what they + can do or what they can see. Keep in mind that it is not intended to + be used as a permission_classes' class.''' - if not isinstance(user, User): - raise Exception('user is not a valid User object') + try: + basestring + except NameError: + basestring = str - if demo_mode is not None: - if isinstance(demo_mode, bool): - return demo_mode - else: - raise Exception('demo_mode {0} is unsupported'.format( - demo_mode, - )) + if not isinstance(user, User): + raise Exception('user is not a valid User object') - if isinstance(demo_group, basestring): - return user.groups.filter(name=demo_group).exists() + if demo_mode is not None: + if isinstance(demo_mode, bool): + return demo_mode + else: + raise Exception('demo_mode {0} is unsupported'.format( + demo_mode, + )) - if isinstance(demo_group, (list)): - return user.groups.filter(name__in=demo_group).exists() + if isinstance(demo_group, basestring): + return user.groups.filter(name=demo_group).exists() - return False + if isinstance(demo_group, (list)): + return user.groups.filter(name__in=demo_group).exists() + + return False diff --git a/drf_simplepermissions/tests/test_permissions.py b/drf_simplepermissions/tests/test_permissions.py index fbe5144..e4c23a1 100644 --- a/drf_simplepermissions/tests/test_permissions.py +++ b/drf_simplepermissions/tests/test_permissions.py @@ -4,6 +4,7 @@ from django.contrib.auth.models import Permission from django.contrib.contenttypes.models import ContentType from drf_simplepermissions import SimplePermissions +from drf_simplepermissions import is_demo class View: @@ -72,28 +73,28 @@ def setUp(self): self.user = User.objects.create_user('foo', password='bar') def test_demo_default(self): - self.assertEqual(SimplePermissions.is_demo(user=self.user), False) # noqa + self.assertEqual(is_demo(user=self.user), False) # noqa def test_demo_mode_true(self): - self.assertEqual(SimplePermissions.is_demo(user=self.user, demo_mode=True), True) # noqa + self.assertEqual(is_demo(user=self.user, demo_mode=True), True) # noqa def test_demo_mode_false(self): - self.assertEqual(SimplePermissions.is_demo(user=self.user, demo_mode=False), False) # noqa + self.assertEqual(is_demo(user=self.user, demo_mode=False), False) # noqa def test_demo_group_default_name(self): group = Group.objects.create(name='demo') group.user_set.add(self.user) - self.assertEqual(SimplePermissions.is_demo(user=self.user), True) + self.assertEqual(is_demo(user=self.user), True) def test_demo_group_custom_name(self): group = Group.objects.create(name='foobar') group.user_set.add(self.user) - self.assertEqual(SimplePermissions.is_demo(user=self.user, demo_group='foobar'), True) # noqa + self.assertEqual(is_demo(user=self.user, demo_group='foobar'), True) # noqa def test_demo_group_custom_name_with_default_group(self): group = Group.objects.create(name='demo') group.user_set.add(self.user) - self.assertEqual(SimplePermissions.is_demo(user=self.user, demo_group='foobar'), False) # noqa + self.assertEqual(is_demo(user=self.user, demo_group='foobar'), False) # noqa def test_demo_multiple_groups_true(self): groups = ['group1', 'group2'] @@ -101,14 +102,14 @@ def test_demo_multiple_groups_true(self): group = Group.objects.create(name=group_name) group.user_set.add(self.user) - self.assertEqual(SimplePermissions.is_demo(user=self.user, demo_group=groups), True) # noqa + self.assertEqual(is_demo(user=self.user, demo_group=groups), True) # noqa def test_demo_group_unsupported_object(self): unsupported_group = type('demo_group', (), {})() - self.assertEqual(SimplePermissions.is_demo(user=self.user, demo_group=unsupported_group), False) # noqa + self.assertEqual(is_demo(user=self.user, demo_group=unsupported_group), False) # noqa def test_demo_group_unsupported_demo_mode(self): - self.assertRaises(Exception, SimplePermissions.is_demo, demo_group=True) # noqa + self.assertRaises(Exception, is_demo, demo_group=True) # noqa def test_demo_unsupported_user_object(self): - self.assertRaises(Exception, SimplePermissions.is_demo, user=True) + self.assertRaises(Exception, is_demo, user=True) From 7a1480e6b520298948ac997f92c4b597cf1d9e9d Mon Sep 17 00:00:00 2001 From: ju5t Date: Thu, 23 Aug 2018 20:26:49 +0200 Subject: [PATCH 03/22] Remove unnecessary if-statement --- drf_simplepermissions/permissions.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drf_simplepermissions/permissions.py b/drf_simplepermissions/permissions.py index c56802d..93ee0a4 100644 --- a/drf_simplepermissions/permissions.py +++ b/drf_simplepermissions/permissions.py @@ -39,13 +39,13 @@ def is_demo(user, demo_group='demo', demo_mode=None): raise Exception('user is not a valid User object') if demo_mode is not None: - if isinstance(demo_mode, bool): - return demo_mode - else: + if not isinstance(demo_mode, bool): raise Exception('demo_mode {0} is unsupported'.format( demo_mode, )) + return demo_mode + if isinstance(demo_group, basestring): return user.groups.filter(name=demo_group).exists() From b178e3f8514031340320ad490074b6cdae5ab240 Mon Sep 17 00:00:00 2001 From: ju5t Date: Thu, 23 Aug 2018 20:37:42 +0200 Subject: [PATCH 04/22] Add custom exceptions test_demo_group_unsupported_demo_mode was expected to raise an exception. It did, but as we were catching generic exceptions the test didn't show the actual problem. --- drf_simplepermissions/exceptions.py | 6 ++++++ drf_simplepermissions/permissions.py | 6 ++++-- drf_simplepermissions/tests/test_permissions.py | 6 ++++-- 3 files changed, 14 insertions(+), 4 deletions(-) create mode 100644 drf_simplepermissions/exceptions.py diff --git a/drf_simplepermissions/exceptions.py b/drf_simplepermissions/exceptions.py new file mode 100644 index 0000000..a09b2aa --- /dev/null +++ b/drf_simplepermissions/exceptions.py @@ -0,0 +1,6 @@ +class SimpleUserException(Exception): + pass + + +class SimpleModeException(Exception): + pass diff --git a/drf_simplepermissions/permissions.py b/drf_simplepermissions/permissions.py index 93ee0a4..476964e 100644 --- a/drf_simplepermissions/permissions.py +++ b/drf_simplepermissions/permissions.py @@ -1,5 +1,7 @@ from django.contrib.auth.models import User from rest_framework import permissions +from drf_simplepermissions.exceptions import SimpleModeException +from drf_simplepermissions.exceptions import SimpleUserException class SimplePermissions(permissions.BasePermission): @@ -36,11 +38,11 @@ def is_demo(user, demo_group='demo', demo_mode=None): basestring = str if not isinstance(user, User): - raise Exception('user is not a valid User object') + raise SimpleUserException('user is not a valid User object') if demo_mode is not None: if not isinstance(demo_mode, bool): - raise Exception('demo_mode {0} is unsupported'.format( + raise SimpleModeException('demo_mode {0} is unsupported'.format( demo_mode, )) diff --git a/drf_simplepermissions/tests/test_permissions.py b/drf_simplepermissions/tests/test_permissions.py index e4c23a1..8242a02 100644 --- a/drf_simplepermissions/tests/test_permissions.py +++ b/drf_simplepermissions/tests/test_permissions.py @@ -5,6 +5,8 @@ from django.contrib.contenttypes.models import ContentType from drf_simplepermissions import SimplePermissions from drf_simplepermissions import is_demo +from drf_simplepermissions.exceptions import SimpleModeException +from drf_simplepermissions.exceptions import SimpleUserException class View: @@ -109,7 +111,7 @@ def test_demo_group_unsupported_object(self): self.assertEqual(is_demo(user=self.user, demo_group=unsupported_group), False) # noqa def test_demo_group_unsupported_demo_mode(self): - self.assertRaises(Exception, is_demo, demo_group=True) # noqa + self.assertRaises(SimpleModeException, is_demo, user=self.user, demo_mode='foo') # noqa def test_demo_unsupported_user_object(self): - self.assertRaises(Exception, is_demo, user=True) + self.assertRaises(SimpleUserException, is_demo, user=True) From eb08ac25f904459060e577533ee2cfa0359db061 Mon Sep 17 00:00:00 2001 From: ju5t Date: Thu, 23 Aug 2018 20:53:10 +0200 Subject: [PATCH 05/22] Update README.md --- README.md | 23 +++++++++++++++++++---- 1 file changed, 19 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 4b60473..e4814fd 100644 --- a/README.md +++ b/README.md @@ -1,10 +1,12 @@ # drf_simplepermissions -This is a simple class to handle permissions in a DRF view. It allows you to -list permissions as a tuple, list or string without writing custom classes -for each exception. +This is a simple class to handle permissions in a Django application. It allows +you to list permissions as a tuple, list or string without writing custom +classes for each exception. -``` +# Usage + +```python from drf_simplepermissions import SimplePermissions from rest_framework import generics @@ -18,6 +20,19 @@ class SimpleView(generics.GenericAPIView): ... ``` +It also includes a simple `is_demo()`-method which can be used to check if +views or other methods should be running in demo mode. + +```python +from drf_simplepermissions import is_demo + +if is_demo(User, demo_group='demo'): + # We should run in demo mode when the user is in 'demo' + +if is_demo(User, demo_mode=True): + # We should run in demo mode as it's set globally +``` + # Installation Not documented yet. From a5bcb564308cf5860fa279643f6424e6aa828fe8 Mon Sep 17 00:00:00 2001 From: ju5t Date: Thu, 23 Aug 2018 20:54:20 +0200 Subject: [PATCH 06/22] Bump version to 1.0.0 --- setup.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/setup.py b/setup.py index 5db84ab..05dbce3 100644 --- a/setup.py +++ b/setup.py @@ -1,7 +1,7 @@ from setuptools import setup setup(name='drf-simplepermissions', - version='0.0.1', + version='1.0.0', description='SimplePermissions checks against a list of permissions', url='https://git.sensson.net/bellmann/python-drf-simplepermissions', author='Bellmann BV', From af273a433e009504c2c5ba7b9b363b35937f4cef Mon Sep 17 00:00:00 2001 From: ju5t Date: Thu, 23 Aug 2018 21:56:12 +0200 Subject: [PATCH 07/22] Set demo_mode to False by default This changes the behaviour from demo_mode to always override demo mode to only override it if it's True. It assumes that you don't want to override demo mode on an demo application but you may want to set specific users as demo users in production (for whatever reason). --- drf_simplepermissions/permissions.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drf_simplepermissions/permissions.py b/drf_simplepermissions/permissions.py index 476964e..ccdde14 100644 --- a/drf_simplepermissions/permissions.py +++ b/drf_simplepermissions/permissions.py @@ -23,7 +23,7 @@ def has_permission(self, request, view): return False -def is_demo(user, demo_group='demo', demo_mode=None): +def is_demo(user, demo_group='demo', demo_mode=False): '''is_demo checks if a user is added to a demo group or groups. If a list of groups is supplied, it will try to match against any group and if a match is found, it will return true. @@ -40,7 +40,7 @@ def is_demo(user, demo_group='demo', demo_mode=None): if not isinstance(user, User): raise SimpleUserException('user is not a valid User object') - if demo_mode is not None: + if demo_mode is not False: if not isinstance(demo_mode, bool): raise SimpleModeException('demo_mode {0} is unsupported'.format( demo_mode, From 59594ada5aea30fac2fedfa868ecf91f664bf3e8 Mon Sep 17 00:00:00 2001 From: ju5t Date: Thu, 23 Aug 2018 22:00:12 +0200 Subject: [PATCH 08/22] Bump version to 1.1.0 --- setup.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/setup.py b/setup.py index 05dbce3..52b17b9 100644 --- a/setup.py +++ b/setup.py @@ -1,7 +1,7 @@ from setuptools import setup setup(name='drf-simplepermissions', - version='1.0.0', + version='1.1.0', description='SimplePermissions checks against a list of permissions', url='https://git.sensson.net/bellmann/python-drf-simplepermissions', author='Bellmann BV', From 3cffff1cc8f661cc31d46dc6e2e66f8efd1790bb Mon Sep 17 00:00:00 2001 From: ju5t Date: Thu, 23 Aug 2018 22:26:21 +0200 Subject: [PATCH 09/22] (#3) No exception on invalid user object This may be used at times where a user object simply isn't available and you still want to run is_demo(). If it throws an exception you need to catch that, which makes the method unfriendly to use. It doesn't throw an exception anymore. Instead it will only check the user object if its actually a User. Makes sense. --- drf_simplepermissions/exceptions.py | 4 ---- drf_simplepermissions/permissions.py | 13 +++++-------- drf_simplepermissions/tests/test_permissions.py | 15 +++++++-------- 3 files changed, 12 insertions(+), 20 deletions(-) diff --git a/drf_simplepermissions/exceptions.py b/drf_simplepermissions/exceptions.py index a09b2aa..8c270fb 100644 --- a/drf_simplepermissions/exceptions.py +++ b/drf_simplepermissions/exceptions.py @@ -1,6 +1,2 @@ -class SimpleUserException(Exception): - pass - - class SimpleModeException(Exception): pass diff --git a/drf_simplepermissions/permissions.py b/drf_simplepermissions/permissions.py index ccdde14..c083ca5 100644 --- a/drf_simplepermissions/permissions.py +++ b/drf_simplepermissions/permissions.py @@ -1,7 +1,6 @@ from django.contrib.auth.models import User from rest_framework import permissions from drf_simplepermissions.exceptions import SimpleModeException -from drf_simplepermissions.exceptions import SimpleUserException class SimplePermissions(permissions.BasePermission): @@ -37,9 +36,6 @@ def is_demo(user, demo_group='demo', demo_mode=False): except NameError: basestring = str - if not isinstance(user, User): - raise SimpleUserException('user is not a valid User object') - if demo_mode is not False: if not isinstance(demo_mode, bool): raise SimpleModeException('demo_mode {0} is unsupported'.format( @@ -48,10 +44,11 @@ def is_demo(user, demo_group='demo', demo_mode=False): return demo_mode - if isinstance(demo_group, basestring): - return user.groups.filter(name=demo_group).exists() + if isinstance(user, User): + if isinstance(demo_group, basestring): + return user.groups.filter(name=demo_group).exists() - if isinstance(demo_group, (list)): - return user.groups.filter(name__in=demo_group).exists() + if isinstance(demo_group, (list)): + return user.groups.filter(name__in=demo_group).exists() return False diff --git a/drf_simplepermissions/tests/test_permissions.py b/drf_simplepermissions/tests/test_permissions.py index 8242a02..681ab24 100644 --- a/drf_simplepermissions/tests/test_permissions.py +++ b/drf_simplepermissions/tests/test_permissions.py @@ -6,7 +6,6 @@ from drf_simplepermissions import SimplePermissions from drf_simplepermissions import is_demo from drf_simplepermissions.exceptions import SimpleModeException -from drf_simplepermissions.exceptions import SimpleUserException class View: @@ -75,13 +74,13 @@ def setUp(self): self.user = User.objects.create_user('foo', password='bar') def test_demo_default(self): - self.assertEqual(is_demo(user=self.user), False) # noqa + self.assertEqual(is_demo(user=self.user), False) def test_demo_mode_true(self): - self.assertEqual(is_demo(user=self.user, demo_mode=True), True) # noqa + self.assertEqual(is_demo(user=self.user, demo_mode=True), True) def test_demo_mode_false(self): - self.assertEqual(is_demo(user=self.user, demo_mode=False), False) # noqa + self.assertEqual(is_demo(user=self.user, demo_mode=False), False) def test_demo_group_default_name(self): group = Group.objects.create(name='demo') @@ -91,12 +90,12 @@ def test_demo_group_default_name(self): def test_demo_group_custom_name(self): group = Group.objects.create(name='foobar') group.user_set.add(self.user) - self.assertEqual(is_demo(user=self.user, demo_group='foobar'), True) # noqa + self.assertEqual(is_demo(user=self.user, demo_group='foobar'), True) def test_demo_group_custom_name_with_default_group(self): group = Group.objects.create(name='demo') group.user_set.add(self.user) - self.assertEqual(is_demo(user=self.user, demo_group='foobar'), False) # noqa + self.assertEqual(is_demo(user=self.user, demo_group='foobar'), False) def test_demo_multiple_groups_true(self): groups = ['group1', 'group2'] @@ -104,7 +103,7 @@ def test_demo_multiple_groups_true(self): group = Group.objects.create(name=group_name) group.user_set.add(self.user) - self.assertEqual(is_demo(user=self.user, demo_group=groups), True) # noqa + self.assertEqual(is_demo(user=self.user, demo_group=groups), True) def test_demo_group_unsupported_object(self): unsupported_group = type('demo_group', (), {})() @@ -114,4 +113,4 @@ def test_demo_group_unsupported_demo_mode(self): self.assertRaises(SimpleModeException, is_demo, user=self.user, demo_mode='foo') # noqa def test_demo_unsupported_user_object(self): - self.assertRaises(SimpleUserException, is_demo, user=True) + self.assertEqual(is_demo(user=False), False) From 1f5bee71e06090a2bff9314e16b97014dfd6d306 Mon Sep 17 00:00:00 2001 From: ju5t Date: Thu, 23 Aug 2018 22:28:27 +0200 Subject: [PATCH 10/22] Bump version to 1.2.0 --- setup.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/setup.py b/setup.py index 52b17b9..68dc58c 100644 --- a/setup.py +++ b/setup.py @@ -1,7 +1,7 @@ from setuptools import setup setup(name='drf-simplepermissions', - version='1.1.0', + version='1.2.0', description='SimplePermissions checks against a list of permissions', url='https://git.sensson.net/bellmann/python-drf-simplepermissions', author='Bellmann BV', From 570a90438a1f5cc8ad49c5129fffb1f21074cde0 Mon Sep 17 00:00:00 2001 From: ju5t Date: Fri, 24 Aug 2018 08:35:47 +0200 Subject: [PATCH 11/22] Drop demo_mode as an attribute of is_demo() This would lead to a lot of duplicate code. Instead we now check if settings.DEMO is True and if so, we'll enable demo mode. If it's False, you can override it by adding the user to a predefined group. --- README.md | 6 +++--- drf_simplepermissions/permissions.py | 20 ++++++++++++------- .../tests/test_permissions.py | 16 ++++++++++++--- 3 files changed, 29 insertions(+), 13 deletions(-) diff --git a/README.md b/README.md index e4814fd..559c130 100644 --- a/README.md +++ b/README.md @@ -28,11 +28,11 @@ from drf_simplepermissions import is_demo if is_demo(User, demo_group='demo'): # We should run in demo mode when the user is in 'demo' - -if is_demo(User, demo_mode=True): - # We should run in demo mode as it's set globally ``` +You can override enable demo mode globally by adding `DEMO = True` to your +application's `settings.py`. + # Installation Not documented yet. diff --git a/drf_simplepermissions/permissions.py b/drf_simplepermissions/permissions.py index c083ca5..7f43733 100644 --- a/drf_simplepermissions/permissions.py +++ b/drf_simplepermissions/permissions.py @@ -1,3 +1,4 @@ +from django.conf import settings from django.contrib.auth.models import User from rest_framework import permissions from drf_simplepermissions.exceptions import SimpleModeException @@ -22,27 +23,32 @@ def has_permission(self, request, view): return False -def is_demo(user, demo_group='demo', demo_mode=False): +def is_demo(user, demo_group='demo'): '''is_demo checks if a user is added to a demo group or groups. If a list of groups is supplied, it will try to match against any group and if a match is found, it will return true. + Global demo mode can be enabled by changing `settings.DEMO` to True. If + it's set to False you can override it by adding users to a group. You + can't override `settings.DEMO` when it's set to True. + This allows you to setup demo accounts that are restricted in what they can do or what they can see. Keep in mind that it is not intended to - be used as a permission_classes' class.''' + be used as a permission_classes' class as that has a different purpose.''' try: basestring except NameError: basestring = str - if demo_mode is not False: - if not isinstance(demo_mode, bool): - raise SimpleModeException('demo_mode {0} is unsupported'.format( - demo_mode, + if hasattr(settings, 'DEMO'): + if not isinstance(settings.DEMO, bool): + raise SimpleModeException('DEMO {0} is unsupported'.format( + settings.DEMO, )) - return demo_mode + if settings.DEMO: + return settings.DEMO if isinstance(user, User): if isinstance(demo_group, basestring): diff --git a/drf_simplepermissions/tests/test_permissions.py b/drf_simplepermissions/tests/test_permissions.py index 681ab24..82085dd 100644 --- a/drf_simplepermissions/tests/test_permissions.py +++ b/drf_simplepermissions/tests/test_permissions.py @@ -1,4 +1,5 @@ from django.test import TestCase +from django.test import override_settings from django.contrib.auth.models import User from django.contrib.auth.models import Group from django.contrib.auth.models import Permission @@ -76,11 +77,13 @@ def setUp(self): def test_demo_default(self): self.assertEqual(is_demo(user=self.user), False) + @override_settings(DEMO=True) def test_demo_mode_true(self): - self.assertEqual(is_demo(user=self.user, demo_mode=True), True) + self.assertEqual(is_demo(user=self.user), True) + @override_settings(DEMO=False) def test_demo_mode_false(self): - self.assertEqual(is_demo(user=self.user, demo_mode=False), False) + self.assertEqual(is_demo(user=self.user), False) def test_demo_group_default_name(self): group = Group.objects.create(name='demo') @@ -105,12 +108,19 @@ def test_demo_multiple_groups_true(self): self.assertEqual(is_demo(user=self.user, demo_group=groups), True) + @override_settings(DEMO=False) + def test_demo_mode_for_global_false_but_user_in_demo_group(self): + group = Group.objects.create(name='demo') + group.user_set.add(self.user) + self.assertEqual(is_demo(user=self.user), True) + def test_demo_group_unsupported_object(self): unsupported_group = type('demo_group', (), {})() self.assertEqual(is_demo(user=self.user, demo_group=unsupported_group), False) # noqa + @override_settings(DEMO='foo') def test_demo_group_unsupported_demo_mode(self): - self.assertRaises(SimpleModeException, is_demo, user=self.user, demo_mode='foo') # noqa + self.assertRaises(SimpleModeException, is_demo, user=self.user) def test_demo_unsupported_user_object(self): self.assertEqual(is_demo(user=False), False) From 5b7dcd0eb02cffbe3ff4585a8f18a81d19ff808b Mon Sep 17 00:00:00 2001 From: ju5t Date: Fri, 24 Aug 2018 21:39:18 +0200 Subject: [PATCH 12/22] Drop demo_group as an attribute of is_demo() This would lead to a lot of duplicate code. Instead we now check settings.DEMO_GROUPS for a list of valid demo groups. --- README.md | 23 ++++++++++++++++--- drf_simplepermissions/permissions.py | 21 ++++++++++------- .../tests/test_permissions.py | 13 +++++++---- 3 files changed, 41 insertions(+), 16 deletions(-) diff --git a/README.md b/README.md index 559c130..05deeb8 100644 --- a/README.md +++ b/README.md @@ -26,12 +26,29 @@ views or other methods should be running in demo mode. ```python from drf_simplepermissions import is_demo -if is_demo(User, demo_group='demo'): +if is_demo(User): # We should run in demo mode when the user is in 'demo' ``` -You can override enable demo mode globally by adding `DEMO = True` to your -application's `settings.py`. +# Settings + +Settings can be managed in `settings.py`. + +## DEMO + +Global demo mode can be enabled by changing `settings.DEMO` to True. If +it's set to False you can override it by adding users to a group. You +can't override `settings.DEMO` when it's set to True. When global demo +mode is set to true, all users no matter their group membership will be +considered demo users. + +## DEMO_GROUPS + +`settings.DEMO_GROUPS` contains a string or a list of groups that should be +considered demo users. It will try to match against any group and if a match +is found, it will return true. It is set to 'demo' by default. Groups are +not managed by this module and should be added manually or with a custom +migration. # Installation diff --git a/drf_simplepermissions/permissions.py b/drf_simplepermissions/permissions.py index 7f43733..403a3fa 100644 --- a/drf_simplepermissions/permissions.py +++ b/drf_simplepermissions/permissions.py @@ -23,10 +23,10 @@ def has_permission(self, request, view): return False -def is_demo(user, demo_group='demo'): - '''is_demo checks if a user is added to a demo group or groups. If a - list of groups is supplied, it will try to match against any group and - if a match is found, it will return true. +def is_demo(user): + '''is_demo checks if a user is added to a demo group or groups. It will try + to match against any group and if a match is found, it will return true. It + uses `settings.DEMO_GROUPS` as its source to check against. Global demo mode can be enabled by changing `settings.DEMO` to True. If it's set to False you can override it by adding users to a group. You @@ -41,6 +41,8 @@ def is_demo(user, demo_group='demo'): except NameError: basestring = str + demo_groups = 'demo' + if hasattr(settings, 'DEMO'): if not isinstance(settings.DEMO, bool): raise SimpleModeException('DEMO {0} is unsupported'.format( @@ -50,11 +52,14 @@ def is_demo(user, demo_group='demo'): if settings.DEMO: return settings.DEMO + if hasattr(settings, 'DEMO_GROUPS'): + demo_groups = settings.DEMO_GROUPS + if isinstance(user, User): - if isinstance(demo_group, basestring): - return user.groups.filter(name=demo_group).exists() + if isinstance(demo_groups, basestring): + return user.groups.filter(name=demo_groups).exists() - if isinstance(demo_group, (list)): - return user.groups.filter(name__in=demo_group).exists() + if isinstance(demo_groups, (list)): + return user.groups.filter(name__in=demo_groups).exists() return False diff --git a/drf_simplepermissions/tests/test_permissions.py b/drf_simplepermissions/tests/test_permissions.py index 82085dd..6ef4120 100644 --- a/drf_simplepermissions/tests/test_permissions.py +++ b/drf_simplepermissions/tests/test_permissions.py @@ -90,23 +90,26 @@ def test_demo_group_default_name(self): group.user_set.add(self.user) self.assertEqual(is_demo(user=self.user), True) + @override_settings(DEMO_GROUPS='foobar') def test_demo_group_custom_name(self): group = Group.objects.create(name='foobar') group.user_set.add(self.user) - self.assertEqual(is_demo(user=self.user, demo_group='foobar'), True) + self.assertEqual(is_demo(user=self.user), True) + @override_settings(DEMO_GROUPS='foobar') def test_demo_group_custom_name_with_default_group(self): group = Group.objects.create(name='demo') group.user_set.add(self.user) - self.assertEqual(is_demo(user=self.user, demo_group='foobar'), False) + self.assertEqual(is_demo(user=self.user), False) + @override_settings(DEMO_GROUPS=['group1', 'group2']) def test_demo_multiple_groups_true(self): groups = ['group1', 'group2'] for group_name in groups: group = Group.objects.create(name=group_name) group.user_set.add(self.user) - self.assertEqual(is_demo(user=self.user, demo_group=groups), True) + self.assertEqual(is_demo(user=self.user), True) @override_settings(DEMO=False) def test_demo_mode_for_global_false_but_user_in_demo_group(self): @@ -114,9 +117,9 @@ def test_demo_mode_for_global_false_but_user_in_demo_group(self): group.user_set.add(self.user) self.assertEqual(is_demo(user=self.user), True) + @override_settings(DEMO_GROUPS=type('demo_group', (), {})()) def test_demo_group_unsupported_object(self): - unsupported_group = type('demo_group', (), {})() - self.assertEqual(is_demo(user=self.user, demo_group=unsupported_group), False) # noqa + self.assertEqual(is_demo(user=self.user), False) # noqa @override_settings(DEMO='foo') def test_demo_group_unsupported_demo_mode(self): From 1b7653fb6971f7efc619ddeb8a5788825f5b5bf2 Mon Sep 17 00:00:00 2001 From: ju5t Date: Sat, 25 Aug 2018 09:16:00 +0200 Subject: [PATCH 13/22] Drop version to 0.0.4 Releasing a 1.0.0 made no sense. --- setup.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/setup.py b/setup.py index 68dc58c..e5c7746 100644 --- a/setup.py +++ b/setup.py @@ -1,7 +1,7 @@ from setuptools import setup setup(name='drf-simplepermissions', - version='1.2.0', + version='0.0.4', description='SimplePermissions checks against a list of permissions', url='https://git.sensson.net/bellmann/python-drf-simplepermissions', author='Bellmann BV', From 94ad5cdea860b4ff67f9a590e978ec0a526d7c65 Mon Sep 17 00:00:00 2001 From: ju5t Date: Sat, 25 Aug 2018 09:38:15 +0200 Subject: [PATCH 14/22] Remove htmlcov artifact --- .gitlab-ci.yml | 4 ---- 1 file changed, 4 deletions(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 983c1e8..0e8ced4 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -5,10 +5,6 @@ - python -V - pip install tox coverage: '/TOTAL.+ ([0-9]{1,3}%)/' - artifacts: - paths: - - htmlcov - expire_in: 2 days test:python27: <<: *test-commands From 7da4f968ac280ca471268f7608a844c105bca5eb Mon Sep 17 00:00:00 2001 From: ju5t Date: Wed, 9 Dec 2020 17:06:13 +0100 Subject: [PATCH 15/22] chore: setup new repository details --- setup.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/setup.py b/setup.py index e5c7746..5fbc7da 100644 --- a/setup.py +++ b/setup.py @@ -3,9 +3,9 @@ setup(name='drf-simplepermissions', version='0.0.4', description='SimplePermissions checks against a list of permissions', - url='https://git.sensson.net/bellmann/python-drf-simplepermissions', + url='https://github.com/bellmann/python-drf-simplepermissions', author='Bellmann BV', - author_email='ton@bellmann.nl', + author_email='opensource@bellmann.nl', packages=['drf_simplepermissions'], install_requires=[ 'django', From 85ccee469cf3a3f10aafa0e5a4e886aa76ffbcc2 Mon Sep 17 00:00:00 2001 From: ju5t Date: Wed, 9 Dec 2020 17:10:35 +0100 Subject: [PATCH 16/22] test: switch to gh-actions --- .github/workflows/test.yml | 34 ++++++++++++++++++++++++++++++++++ 1 file changed, 34 insertions(+) create mode 100644 .github/workflows/test.yml diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml new file mode 100644 index 0000000..760ef97 --- /dev/null +++ b/.github/workflows/test.yml @@ -0,0 +1,34 @@ +# This workflow will install Python dependencies, run tests and lint with a variety of Python versions +# For more information see: https://help.github.com/actions/language-and-framework-guides/using-python-with-github-actions + +name: Test drf-simplepermissions + +on: + push: + branches-ignore: + - master + pull_request: + branches: [ develop ] + +jobs: + build: + + runs-on: ubuntu-latest + strategy: + matrix: + python-version: ['2.7', '3.6', '3.7', '3.8'] + + steps: + - uses: actions/checkout@v2 + - name: Set up Python ${{ matrix.python-version }} + uses: actions/setup-python@v2 + with: + python-version: ${{ matrix.python-version }} + - name: Install dependencies + run: | + python -m pip install --upgrade pip + pip install tox + if [ -f requirements.txt ]; then pip install -r requirements.txt; fi + - name: Test with tox + run: | + tox -e setup,flake8 From af3afacf0f9cb6fa434bc56c718589c18c7f23b4 Mon Sep 17 00:00:00 2001 From: ju5t Date: Wed, 9 Dec 2020 17:22:03 +0100 Subject: [PATCH 17/22] fix: do not use star for import --- drf_simplepermissions/__init__.py | 5 +++-- tox.ini | 2 +- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/drf_simplepermissions/__init__.py b/drf_simplepermissions/__init__.py index a82c9e8..728538f 100644 --- a/drf_simplepermissions/__init__.py +++ b/drf_simplepermissions/__init__.py @@ -1,5 +1,6 @@ -from .permissions import * # noqa +from .permissions import is_demo +from .permissions import SimplePermissions -__version__ = '0.0.1' +__version__ = '0.0.4' __all__ = ['SimplePermissions', 'is_demo'] diff --git a/tox.ini b/tox.ini index 3e632b4..13e07bc 100644 --- a/tox.ini +++ b/tox.ini @@ -21,4 +21,4 @@ commands = [testenv:flake8] deps = flake8 -commands = flake8 gongchang +commands = flake8 drf_simplepermissions From 3c97b098d524036865405acbc831d96ac004a1f7 Mon Sep 17 00:00:00 2001 From: ju5t Date: Wed, 9 Dec 2020 21:07:05 +0100 Subject: [PATCH 18/22] test: rename yaml and drop 2.7 from tests --- .github/workflows/{test.yml => ci.yml} | 23 ++++++++++++++++------- 1 file changed, 16 insertions(+), 7 deletions(-) rename .github/workflows/{test.yml => ci.yml} (60%) diff --git a/.github/workflows/test.yml b/.github/workflows/ci.yml similarity index 60% rename from .github/workflows/test.yml rename to .github/workflows/ci.yml index 760ef97..3ab67d5 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/ci.yml @@ -1,7 +1,4 @@ -# This workflow will install Python dependencies, run tests and lint with a variety of Python versions -# For more information see: https://help.github.com/actions/language-and-framework-guides/using-python-with-github-actions - -name: Test drf-simplepermissions +name: drf-simplepermissions on: push: @@ -11,12 +8,11 @@ on: branches: [ develop ] jobs: - build: - + test: runs-on: ubuntu-latest strategy: matrix: - python-version: ['2.7', '3.6', '3.7', '3.8'] + python-version: ['3.6', '3.7', '3.8'] steps: - uses: actions/checkout@v2 @@ -32,3 +28,16 @@ jobs: - name: Test with tox run: | tox -e setup,flake8 + + publish: + runs-on: ubuntu-latest + needs: test + steps: + - uses: actions/checkout@master + - name: Publish Python Package + uses: mariamrf/py-package-publish-action@v1.0.0 + with: + python_version: '3.6.0' + env: + TWINE_USERNAME: __token__ + TWINE_PASSWORD: ${{ secrets.PYPI }} From 8e7753ab83462aff88774e28d7d8acb6ca7d4a55 Mon Sep 17 00:00:00 2001 From: ju5t Date: Wed, 9 Dec 2020 21:07:25 +0100 Subject: [PATCH 19/22] chore: add minimum python requirement --- setup.py | 1 + 1 file changed, 1 insertion(+) diff --git a/setup.py b/setup.py index 5fbc7da..595cedf 100644 --- a/setup.py +++ b/setup.py @@ -11,4 +11,5 @@ 'django', 'djangorestframework', ], + python_requires='>=3.4' zip_safe=False) From d58ccb122de8dcbbe28b92306e99619c2a71203f Mon Sep 17 00:00:00 2001 From: ju5t Date: Wed, 9 Dec 2020 21:15:47 +0100 Subject: [PATCH 20/22] fix: missing comma --- .github/workflows/{ci.yml => test.yml} | 13 ------------- setup.py | 2 +- 2 files changed, 1 insertion(+), 14 deletions(-) rename .github/workflows/{ci.yml => test.yml} (68%) diff --git a/.github/workflows/ci.yml b/.github/workflows/test.yml similarity index 68% rename from .github/workflows/ci.yml rename to .github/workflows/test.yml index 3ab67d5..48ce3b4 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/test.yml @@ -28,16 +28,3 @@ jobs: - name: Test with tox run: | tox -e setup,flake8 - - publish: - runs-on: ubuntu-latest - needs: test - steps: - - uses: actions/checkout@master - - name: Publish Python Package - uses: mariamrf/py-package-publish-action@v1.0.0 - with: - python_version: '3.6.0' - env: - TWINE_USERNAME: __token__ - TWINE_PASSWORD: ${{ secrets.PYPI }} diff --git a/setup.py b/setup.py index 595cedf..b2585d0 100644 --- a/setup.py +++ b/setup.py @@ -11,5 +11,5 @@ 'django', 'djangorestframework', ], - python_requires='>=3.4' + python_requires='>=3.4', zip_safe=False) From c4e9d57a8ecf4406bc5279d78a390f7e016202c7 Mon Sep 17 00:00:00 2001 From: ju5t Date: Thu, 10 Dec 2020 12:22:24 +0100 Subject: [PATCH 21/22] feat: use releases in github for publishing --- .github/workflows/publish.yml | 27 +++++++++++++++++++++++++++ .github/workflows/test.yml | 2 +- drf_simplepermissions/__init__.py | 2 +- setup.py | 2 +- 4 files changed, 30 insertions(+), 3 deletions(-) create mode 100644 .github/workflows/publish.yml diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml new file mode 100644 index 0000000..7bfe660 --- /dev/null +++ b/.github/workflows/publish.yml @@ -0,0 +1,27 @@ +name: publish + +on: + release: + types: [released] + +jobs: + release: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + - name: Set up Python 3.8 + uses: actions/setup-python@v2 + with: + python-version: 3.8 + - name: Install Tools + run: | + python -m pip install --upgrade pip + pip install setuptools wheel twine + - name: Package and Upload + env: + PACKAGE_VERSION: ${{ github.event.release.tag_name }} + TWINE_USERNAME: __token__ + TWINE_PASSWORD: ${{ secrets.PYPI }} + run: | + python setup.py sdist bdist_wheel + twine upload dist/* diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 48ce3b4..3de109f 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -1,4 +1,4 @@ -name: drf-simplepermissions +name: test on: push: diff --git a/drf_simplepermissions/__init__.py b/drf_simplepermissions/__init__.py index 728538f..822d337 100644 --- a/drf_simplepermissions/__init__.py +++ b/drf_simplepermissions/__init__.py @@ -2,5 +2,5 @@ from .permissions import SimplePermissions -__version__ = '0.0.4' +__version__ = os.environ.get('PACKAGE_VERSION', '0.0.0'), __all__ = ['SimplePermissions', 'is_demo'] diff --git a/setup.py b/setup.py index b2585d0..05b91b0 100644 --- a/setup.py +++ b/setup.py @@ -1,7 +1,7 @@ from setuptools import setup setup(name='drf-simplepermissions', - version='0.0.4', + version=os.environ.get('PACKAGE_VERSION', '0.0.0'), description='SimplePermissions checks against a list of permissions', url='https://github.com/bellmann/python-drf-simplepermissions', author='Bellmann BV', From ac3b3ff86ce85e1a884c35efa4a04d40312c2ee2 Mon Sep 17 00:00:00 2001 From: ju5t Date: Thu, 10 Dec 2020 12:26:59 +0100 Subject: [PATCH 22/22] fix: import os --- drf_simplepermissions/__init__.py | 1 + setup.py | 1 + 2 files changed, 2 insertions(+) diff --git a/drf_simplepermissions/__init__.py b/drf_simplepermissions/__init__.py index 822d337..a129c64 100644 --- a/drf_simplepermissions/__init__.py +++ b/drf_simplepermissions/__init__.py @@ -1,3 +1,4 @@ +import os from .permissions import is_demo from .permissions import SimplePermissions diff --git a/setup.py b/setup.py index 05b91b0..9e2dba5 100644 --- a/setup.py +++ b/setup.py @@ -1,3 +1,4 @@ +import os from setuptools import setup setup(name='drf-simplepermissions',