Skip to content

Conversation

@ManishShah120
Copy link
Contributor

Closes #249

@ManishShah120 ManishShah120 changed the title [feature] Implemented view permissions by extending DjangoModelPermissions class #249 [feature] Implemented view permissions by extending DjangoModelPermissions class #249 May 22, 2021
@ManishShah120 ManishShah120 self-assigned this May 22, 2021
Comment on lines 93 to 97
if request.method == 'GET':
if request.user.has_perms(perms) or request.user.has_perms(change_perm):
return True
else:
return False
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Did not handled the case of super user becasue superuser by default has all the permissions.

Copy link
Member

@atb00ker atb00ker May 22, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think you can add a check at the top of the function stating:

if user.is_superuser:
    return True

They are allowed to do anything regardless of any permission (this check is there in other has_permission functions too)!

P.S: Not sure if this would be required, please test! 😄

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@atb00ker I am trying to implement this in more generic way, cause am thinking of opening a similar PR in DRF repo once this gets merged here.

By default superuser has all permissions i.e., it can do anything it wants. suppose manually someone removes all the permissions for any specific model for superuser. Then in that case this would not work, since we will return True if it;s a super user, so that case will fail.

What do you think?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

To the best of my knowledge, removing permissions from superuser is an anti-pattern, but I understand your point.

  1. We should look at existing DRF functions and implement it in a similar way.
  2. I'll also wait for @nemesisdesign check this! 😄

Copy link
Member

@atb00ker atb00ker left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This looks good to me, small comments:

Comment on lines 93 to 97
if request.method == 'GET':
if request.user.has_perms(perms) or request.user.has_perms(change_perm):
return True
else:
return False
Copy link
Member

@atb00ker atb00ker May 22, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think you can add a check at the top of the function stating:

if user.is_superuser:
    return True

They are allowed to do anything regardless of any permission (this check is there in other has_permission functions too)!

P.S: Not sure if this would be required, please test! 😄

@ManishShah120
Copy link
Contributor Author

Quoting from the issue #249

Tests:

  • ensure an user of the operator group (not flagged as supersuser) cannot view both endpoints
  • Added
  • ensure an user of the administrator group (not flagged as supersuser) can view both endpoints
  • Added
  • add the view permission to the operator group, ensure the user now can view both endpoints but cannot change anything (put or delete)
  • Added

@ManishShah120 ManishShah120 requested a review from okraits May 25, 2021 11:32
Copy link
Member

@nemesifier nemesifier left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks on the right track! I'll need to test it.

But definitely please go ahead with the PR to Django REST Framework, hopefully we can get something similar or better merged there.

Copy link
Member

@okraits okraits left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks fine. No objections from me.

Copy link
Member

@okraits okraits left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks fine.

Copy link
Member

@atb00ker atb00ker left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this is looking good, small improvement in the tests.

Comment on lines 131 to 135
user = User.objects.create_user(
username='operator', password='tester', email='[email protected]'
)
operator_group = Group.objects.filter(name='Operator')
user.groups.set(operator_group)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just FYI, I think there are functions for common actions. Like _create_operator.
These should be inherited and used! 😄

Copy link
Contributor Author

@ManishShah120 ManishShah120 May 31, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hey, @atb00ker Yes, I tried to use it but with this function, the user gets all the permissions without being in the operator group, and here we only needed testapp.view_template permission.

operator_group = Group.objects.filter(name='Operator')
user.groups.set(operator_group)
org1 = self._get_org()
OrganizationUser.objects.create(user=user, organization=org1, is_admin=True)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

atb00ker
atb00ker previously approved these changes May 31, 2021
Copy link
Member

@atb00ker atb00ker left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Functional Test:

  • superuser has access
  • non-su without view permission & org manager doesn't have access
  • non-su with view permission & not org manager has access but sees nothing
  • non-su with view permission & org manager can see temp for their obj. (not shared obj)

Copy link
Member

@nemesifier nemesifier left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Great work @ManishShah120 @atb00ker! 👍

Missing:

  • Documentation (please add it near to the other sections related to DRF)
  • Code simplification (see below)

if user.has_perms(perms) or user.has_perms(change_perm):
return True
else:
return False
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

what about:

# user must have either view permission or change permission
return user.has_perms(perms) or user.has_perms(change_perm)

self.client.force_login(user)
token = self._obtain_auth_token()
auth = dict(HTTP_AUTHORIZATION=f'Bearer {token}')
t1 = self._create_template(organization=org1)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

the first lines of each tests look really similar, please try to make a private helper method which prepares the data needed for the test, so we can make the actual test code shorter and easier to read.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done, Please have a look. 👍

return org and (user.is_superuser or user.is_owner(org))


class ViewDjangoModelPermissions(DjangoModelPermissions):
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we could call this simply DjangoModelPermissions

@@ -1,5 +1,5 @@
from django.utils.translation import gettext_lazy as _
from rest_framework.permissions import BasePermission
from rest_framework.permissions import BasePermission, DjangoModelPermissions
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

here you'd import it as BaseDjangoModelPermissions

Copy link
Member

@atb00ker atb00ker left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM! 👍

Comment on lines +139 to +141
user = self._get_user()
operator_group = Group.objects.filter(name='Operator')
user.groups.set(operator_group)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Doesn't _get_operator() help here?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No @atb00ker.

Copy link
Member

@nemesifier nemesifier left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[feature] Add class to implement view permissions in DRF

5 participants