-
-
Notifications
You must be signed in to change notification settings - Fork 6.9k
Modify permission operands to use custom messages #9649
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
rest_framework/permissions.py
Outdated
self.message1 = getattr(op1, 'message', None) | ||
self.message2 = getattr(op2, 'message', None) | ||
self.message = self.message1 or self.message2 | ||
if self.message1 and self.message2: | ||
self.message = '"{0}" {1} "{2}"'.format( | ||
self.message1, _('OR'), self.message2, | ||
) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I started working on getting this into proper shape, and I'm having trouble with this part.
And I need some help
Imagine a case:
class IsWhitelistedPath(BasePermission):
message = "Path not whitelisted"
...
...
permission_classess = [IsAuthenticated | IsWhitelistedPath]
Here, in case of error, message will be "Path not whitelisted", completely ignoring the first one. This is wrong. And we do not have message
available at the init time, because "AND" (and some of my permission classes) are setting self.message dynamically in has_permission
call.
I come up with something like this:
class OR(OperatorBase):
def has_permission(self, request, view):
collector = ResultCollector()
for perm in self._permissions:
if perm.has_permission(request, view):
return True
else:
collector.add_message_and_code(perm)
collector.finalize(self)
return False
...
class ResultCollector:
def __init__(self):
self.messages = ()
self.codes = ()
def add_message_and_code(self, perm):
message = getattr(perm, 'message', None)
code = getattr(perm, 'code', None)
self.messages += (message,)
self.codes += (code,)
def finalize(self, perm):
perm.message = self.messages
perm.code = self.codes
Each failed permission adds it's message to a list, and we can handle this later, to produce a list of errors.
In this example, that will be:
[
ErrorDetail('You do not have permission to perform this action.', 'permission_denied'),
ErrorDetail('Path not whitelisted.'),
]
Maybe we should wrap it into additional container, something like {"detail": "Any of the listed perms required", "errors": [{"message": ..., "code": ...}]`... to make it clearer...
What do you think? @auvipy @tomchristie @samitnuk
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I would suggest make the CI green first
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done.
And, now it includes my proposed changes.
253f0e5
to
431f8fe
Compare
I would suggest undocumenting operands for permissions, and informally deprecating them with comments in the codebase. Ie. No enforced behavioral change, but improved doc guidance. |
You mean, removing a section from docs mentioning bitwise operators? https://www.django-rest-framework.org/api-guide/permissions/#permissions
@tomchristie Maybe I misunderstood something, but this does not look like "improved doc guidance". Operands are working fine, and the only minor problem that resulting errors are missing |
Is there a reason why this was closed? I'd really like to have a solution for this use case as it is not that uncommon. |
|
Refs #6427
This is continuation of #6499 #6502
This PR fixes error where permissions were missing
.message
property after applying&
or|
.I'll mark this as a draft, and add the same handling for
.code
property. And maybe see if we can somehow refactor/optimize/make_better.And I will add documentation. Probably, the only point worth mentioning is the new
message_inverted
property, because other change is just a bugfix, and everyone already expects that .message and .code will not be lost when using combined permission.