Merge pull request #164 from EverythingMe/feature_view_query_permission

Feature: "view_query" permission
This commit is contained in:
Arik Fraimovich 2014-04-06 20:31:20 +03:00
commit 2d3348b1a9
7 changed files with 39 additions and 7 deletions

View File

@ -80,18 +80,22 @@ def drop_tables():
@users_manager.option('name', help="User's full name")
@users_manager.option('--admin', dest='is_admin', action="store_true", default=False, help="set user as admin")
@users_manager.option('--google', dest='google_auth', action="store_true", default=False, help="user uses Google Auth to login")
def create(email, name, is_admin=False, google_auth=False):
@users_manager.option('--password', dest='password', default=None, help="Password for users who don't use Google Auth (leave blank for prompt).")
@users_manager.option('--permissions', dest='permissions', default=models.User.DEFAULT_PERMISSIONS, help="Comma seperated list of permissions (leave blank for default).")
def create(email, name, permissions, is_admin=False, google_auth=False, password=None):
print "Creating user (%s, %s)..." % (email, name)
print "Admin: %r" % is_admin
print "Login with Google Auth: %r\n" % google_auth
if isinstance(permissions, basestring):
permissions = permissions.split(',')
permissions.remove('') # in case it was empty string
permissions = models.User.DEFAULT_PERMISSIONS
if is_admin:
permissions += ['admin']
user = models.User(email=email, name=name, permissions=permissions)
if not google_auth:
password = prompt_pass("Password")
password = password or prompt_pass("Password")
user.hash_password(password)
try:

View File

@ -0,0 +1,13 @@
import peewee
from redash import db
from redash import models
if __name__ == '__main__':
db.connect_db()
previous_default_permissions = models.User.DEFAULT_PERMISSIONS[:]
previous_default_permissions.remove('view_query')
models.User.update(permissions=peewee.fn.array_append(models.User.permissions, 'view_query')).where(peewee.SQL("'view_source' = any(permissions)")).execute()
db.close_db(None)

View File

@ -55,7 +55,7 @@
<li><a data-toggle="modal" href="#new_dashboard_dialog" ng-show="currentUser.hasPermission('create_dashboard')">New Dashboard</a></li>
</ul>
</li>
<li class="dropdown">
<li class="dropdown" ng-show="currentUser.hasPermission('view_query')">
<a href="#" class="dropdown-toggle" data-toggle="dropdown">Queries <b class="caret"></b></a>
<ul class="dropdown-menu">
<li ng-show="currentUser.hasPermission('create_query')"><a href="/queries/new">New Query</a></li>

View File

@ -25,7 +25,8 @@
<div class="panel-heading">
<h3 class="panel-title">
<p>
<query-link query="query" visualization="widget.visualization"></query-link>
<span ng-hide="currentUser.hasPermission('view_query')">{{query.name}}</span>
<query-link query="query" visualization="widget.visualization" ng-show="currentUser.hasPermission('view_query')"></query-link>
</p>
<div class="text-muted" ng-bind="query.description"></div>
</h3>
@ -39,7 +40,7 @@
tooltip-placement="bottom">Updated: <span am-time-ago="queryResult.getUpdatedAt()"></span></span>
<span class="pull-right">
<a class="btn btn-default btn-xs" ng-href="/queries/{{query.id}}#{{widget.visualization.id}}"><span class="glyphicon glyphicon-link"></span></a>
<a class="btn btn-default btn-xs" ng-href="/queries/{{query.id}}#{{widget.visualization.id}}" ng-show="currentUser.hasPermission('view_query')"><span class="glyphicon glyphicon-link"></span></a>
<button type="button" class="btn btn-default btn-xs" ng-show="dashboard.canEdit()" ng-click="deleteWidget()" title="Remove Widget"><span class="glyphicon glyphicon-trash"></span></button>
</span>

View File

@ -40,6 +40,7 @@ class HMACAuthentication(object):
calculated_signature = sign(query.api_key, request.path, expires)
if query.api_key and signature == calculated_signature:
login_user(models.ApiUser(query.api_key), remember=False)
return True
return False

View File

@ -249,6 +249,7 @@ class QueryListAPI(BaseResource):
return query.to_dict(with_result=False)
@require_permission('view_query')
def get(self):
return [q.to_dict(with_result=False, with_stats=True) for q in models.Query.all_queries()]
@ -272,6 +273,7 @@ class QueryAPI(BaseResource):
return query.to_dict(with_result=False, with_visualizations=True)
@require_permission('view_query')
def get(self, query_id):
q = models.Query.get(models.Query.id == query_id)
if q:
@ -345,6 +347,7 @@ class QueryResultListAPI(BaseResource):
class QueryResultAPI(BaseResource):
@require_permission('view_query')
def get(self, query_result_id):
query_result = models.QueryResult.get_by_id(query_result_id)
if query_result:
@ -354,6 +357,7 @@ class QueryResultAPI(BaseResource):
class CsvQueryResultsAPI(BaseResource):
@require_permission('view_query')
def get(self, query_id, query_result_id=None):
if not query_result_id:
query = models.Query.get(models.Query.id == query_id)

View File

@ -22,9 +22,18 @@ class AnonymousUser(AnonymousUserMixin):
return []
class ApiUser(UserMixin):
def __init__(self, api_key):
self.id = api_key
@property
def permissions(self):
return ['view_query']
class User(BaseModel, UserMixin):
DEFAULT_PERMISSIONS = ['create_dashboard', 'create_query', 'edit_dashboard', 'edit_query',
'view_source', 'execute_query']
'view_query', 'view_source', 'execute_query']
id = peewee.PrimaryKeyField()
name = peewee.CharField(max_length=320)