forked from getredash/redash
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request getredash#1113 from whummer/feat/share-access-perm…
…issions Add: share modify/access permissions for queries and dashboard
- Loading branch information
Showing
7 changed files
with
420 additions
and
36 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,96 @@ | ||
from collections import defaultdict | ||
|
||
from redash.handlers.base import BaseResource, get_object_or_404 | ||
from redash.models import AccessPermission, Query, Dashboard, User | ||
from redash.permissions import require_admin_or_owner, ACCESS_TYPES | ||
from flask import request | ||
from flask_restful import abort | ||
|
||
|
||
model_to_types = { | ||
'queries': Query, | ||
'dashboards': Dashboard | ||
} | ||
|
||
|
||
def get_model_from_type(type): | ||
model = model_to_types.get(type) | ||
if model is None: | ||
abort(404) | ||
return model | ||
|
||
|
||
class ObjectPermissionsListResource(BaseResource): | ||
def get(self, object_type, object_id): | ||
model = get_model_from_type(object_type) | ||
obj = get_object_or_404(model.get_by_id_and_org, object_id, self.current_org) | ||
|
||
# TODO: include grantees in search to avoid N+1 queries | ||
permissions = AccessPermission.find(obj) | ||
|
||
result = defaultdict(list) | ||
|
||
for perm in permissions: | ||
result[perm.access_type].append(perm.grantee.to_dict()) | ||
|
||
return result | ||
|
||
def post(self, object_type, object_id): | ||
model = get_model_from_type(object_type) | ||
obj = get_object_or_404(model.get_by_id_and_org, object_id, self.current_org) | ||
|
||
require_admin_or_owner(obj.user_id) | ||
|
||
req = request.get_json(True) | ||
|
||
access_type = req['access_type'] | ||
|
||
if access_type not in ACCESS_TYPES: | ||
abort(400, message='Unknown access type.') | ||
|
||
try: | ||
grantee = User.get_by_id_and_org(req['user_id'], self.current_org) | ||
except User.DoesNotExist: | ||
abort(400, message='User not found.') | ||
|
||
permission = AccessPermission.grant(obj, access_type, grantee, self.current_user) | ||
|
||
self.record_event({ | ||
'action': 'grant_permission', | ||
'object_id': object_id, | ||
'object_type': object_type, | ||
'access_type': access_type, | ||
'grantee': grantee.id | ||
}) | ||
|
||
return permission.to_dict() | ||
|
||
def delete(self, object_type, object_id): | ||
model = get_model_from_type(object_type) | ||
obj = get_object_or_404(model.get_by_id_and_org, object_id, self.current_org) | ||
|
||
require_admin_or_owner(obj.user_id) | ||
|
||
req = request.get_json(True) | ||
grantee = req['user_id'] | ||
access_type = req['access_type'] | ||
|
||
AccessPermission.revoke(obj, grantee, access_type) | ||
|
||
self.record_event({ | ||
'action': 'revoke_permission', | ||
'object_id': object_id, | ||
'object_type': object_type, | ||
'access_type': access_type, | ||
'grantee': grantee | ||
}) | ||
|
||
|
||
class CheckPermissionResource(BaseResource): | ||
def get(self, object_type, object_id, access_type): | ||
model = get_model_from_type(object_type) | ||
obj = get_object_or_404(model.get_by_id_and_org, object_id, self.current_org) | ||
|
||
has_access = AccessPermission.exists(obj, access_type, self.current_user) | ||
|
||
return {'response': has_access} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.