mirror of
https://github.com/valitydev/redash.git
synced 2024-11-06 09:05:17 +00:00
Change roles to permissions
This commit is contained in:
parent
cff710ee52
commit
3d95d6b8c9
@ -7,7 +7,7 @@ if __name__ == '__main__':
|
||||
db.connect_db()
|
||||
migrator = Migrator(db.database)
|
||||
with db.database.transaction():
|
||||
migrator.add_column(models.User, models.User.roles, 'roles')
|
||||
models.User.update(roles=['admin', 'viewer', 'editor']).where(models.User.is_admin == True).execute()
|
||||
migrator.add_column(models.User, models.User.permissions, 'permissions')
|
||||
models.User.update(permissions=['admin'] + models.User.DEFAULT_PERMISSIONS).where(models.User.is_admin == True).execute()
|
||||
|
||||
db.close_db(None)
|
@ -1,16 +1,18 @@
|
||||
import functools
|
||||
import hashlib
|
||||
import hmac
|
||||
from flask import current_app, request, make_response, g, redirect, url_for
|
||||
from flask.ext.googleauth import GoogleAuth, login
|
||||
from flask.ext.login import LoginManager, login_user, current_user, AnonymousUserMixin
|
||||
import time
|
||||
import logging
|
||||
from flask.ext.restful import abort
|
||||
|
||||
from flask import request, make_response, redirect, url_for
|
||||
from flask.ext.googleauth import GoogleAuth, login
|
||||
from flask.ext.login import LoginManager, login_user, current_user
|
||||
from werkzeug.contrib.fixers import ProxyFix
|
||||
|
||||
from models import AnonymousUser
|
||||
from redash import models, settings
|
||||
|
||||
|
||||
login_manager = LoginManager()
|
||||
logger = logging.getLogger('authentication')
|
||||
|
||||
@ -88,29 +90,6 @@ def load_user(user_id):
|
||||
return models.User.select().where(models.User.id == user_id).first()
|
||||
|
||||
|
||||
def requires_role(role):
|
||||
return requires_roles((role,))
|
||||
|
||||
|
||||
class requires_roles(object):
|
||||
def __init__(self, roles):
|
||||
self.roles = roles
|
||||
|
||||
def __call__(self, fn):
|
||||
@functools.wraps(fn)
|
||||
def decorated(*args, **kwargs):
|
||||
has_roles = reduce(lambda a, b: a and b,
|
||||
map(lambda role: role in current_user.roles, self.roles),
|
||||
True)
|
||||
|
||||
if has_roles:
|
||||
return fn(*args, **kwargs)
|
||||
else:
|
||||
abort(403)
|
||||
|
||||
return decorated
|
||||
|
||||
|
||||
def setup_authentication(app):
|
||||
if settings.GOOGLE_OPENID_ENABLED:
|
||||
openid_auth = GoogleAuth(app, url_prefix="/google_auth")
|
||||
|
@ -17,7 +17,7 @@ from flask.ext.restful import Resource, abort
|
||||
from flask_login import current_user, login_user, logout_user
|
||||
|
||||
import sqlparse
|
||||
from authentication import requires_role
|
||||
from permissions import require_permission
|
||||
from redash import settings, utils
|
||||
from redash import data
|
||||
|
||||
@ -84,7 +84,7 @@ def logout():
|
||||
|
||||
@app.route('/status.json')
|
||||
@auth.required
|
||||
@requires_role('admin')
|
||||
@require_permission('admin')
|
||||
def status_api():
|
||||
status = {}
|
||||
info = redis_connection.info()
|
||||
@ -133,6 +133,7 @@ class DashboardListAPI(BaseResource):
|
||||
|
||||
return dashboards
|
||||
|
||||
@require_permission('create_dashboard')
|
||||
def post(self):
|
||||
dashboard_properties = request.get_json(force=True)
|
||||
dashboard = models.Dashboard(name=dashboard_properties['name'],
|
||||
@ -151,6 +152,7 @@ class DashboardAPI(BaseResource):
|
||||
|
||||
return dashboard.to_dict(with_widgets=True)
|
||||
|
||||
@require_permission('edit_dashboard')
|
||||
def post(self, dashboard_slug):
|
||||
dashboard_properties = request.get_json(force=True)
|
||||
# TODO: either convert all requests to use slugs or ids
|
||||
@ -161,6 +163,7 @@ class DashboardAPI(BaseResource):
|
||||
|
||||
return dashboard.to_dict(with_widgets=True)
|
||||
|
||||
@require_permission('edit_dashboard')
|
||||
def delete(self, dashboard_slug):
|
||||
dashboard = models.Dashboard.get_by_slug(dashboard_slug)
|
||||
dashboard.is_archived = True
|
||||
@ -171,6 +174,7 @@ api.add_resource(DashboardAPI, '/api/dashboards/<dashboard_slug>', endpoint='das
|
||||
|
||||
|
||||
class WidgetListAPI(BaseResource):
|
||||
@require_permission('edit_dashboard')
|
||||
def post(self):
|
||||
widget_properties = request.get_json(force=True)
|
||||
widget_properties['options'] = json.dumps(widget_properties['options'])
|
||||
@ -202,6 +206,7 @@ class WidgetListAPI(BaseResource):
|
||||
|
||||
|
||||
class WidgetAPI(BaseResource):
|
||||
@require_permission('edit_dashboard')
|
||||
def delete(self, widget_id):
|
||||
widget = models.Widget.get(models.Widget.id == widget_id)
|
||||
# TODO: reposition existing ones
|
||||
@ -218,6 +223,7 @@ api.add_resource(WidgetAPI, '/api/widgets/<int:widget_id>', endpoint='widget')
|
||||
|
||||
|
||||
class QueryListAPI(BaseResource):
|
||||
@require_permission('create_query')
|
||||
def post(self):
|
||||
query_def = request.get_json(force=True)
|
||||
# id, created_at, api_key
|
||||
@ -237,6 +243,7 @@ class QueryListAPI(BaseResource):
|
||||
|
||||
|
||||
class QueryAPI(BaseResource):
|
||||
@require_permission('edit_query')
|
||||
def post(self, query_id):
|
||||
query_def = request.get_json(force=True)
|
||||
for field in ['id', 'created_at', 'api_key', 'visualizations', 'latest_query_data', 'user']:
|
||||
@ -263,6 +270,7 @@ api.add_resource(QueryAPI, '/api/queries/<query_id>', endpoint='query')
|
||||
|
||||
|
||||
class VisualizationListAPI(BaseResource):
|
||||
@require_permission('edit_query')
|
||||
def post(self):
|
||||
kwargs = request.get_json(force=True)
|
||||
kwargs['options'] = json.dumps(kwargs['options'])
|
||||
@ -275,6 +283,7 @@ class VisualizationListAPI(BaseResource):
|
||||
|
||||
|
||||
class VisualizationAPI(BaseResource):
|
||||
@require_permission('edit_query')
|
||||
def post(self, visualization_id):
|
||||
kwargs = request.get_json(force=True)
|
||||
if 'options' in kwargs:
|
||||
@ -288,6 +297,7 @@ class VisualizationAPI(BaseResource):
|
||||
|
||||
return vis.to_dict(with_query=False)
|
||||
|
||||
@require_permission('edit_query')
|
||||
def delete(self, visualization_id):
|
||||
vis = models.Visualization.get(models.Visualization.id == visualization_id)
|
||||
vis.delete_instance()
|
||||
@ -297,6 +307,7 @@ api.add_resource(VisualizationAPI, '/api/visualizations/<visualization_id>', end
|
||||
|
||||
|
||||
class QueryResultListAPI(BaseResource):
|
||||
@require_permission('execute_query')
|
||||
def post(self):
|
||||
params = request.json
|
||||
|
||||
|
@ -18,17 +18,20 @@ class BaseModel(db.Model):
|
||||
|
||||
class AnonymousUser(AnonymousUserMixin):
|
||||
@property
|
||||
def roles(self):
|
||||
def permissions(self):
|
||||
return []
|
||||
|
||||
|
||||
class User(BaseModel, UserMixin):
|
||||
DEFAULT_PERMISSIONS = ['create_dashboard', 'create_query', 'edit_dashboard', 'edit_query',
|
||||
'execute_query']
|
||||
|
||||
id = peewee.PrimaryKeyField()
|
||||
name = peewee.CharField(max_length=320)
|
||||
email = peewee.CharField(max_length=320, index=True, unique=True)
|
||||
password_hash = peewee.CharField(max_length=128, null=True)
|
||||
is_admin = peewee.BooleanField(default=False)
|
||||
roles = ArrayField(peewee.CharField, default=['editor', 'viewer'])
|
||||
permissions = ArrayField(peewee.CharField, default=DEFAULT_PERMISSIONS)
|
||||
|
||||
class Meta:
|
||||
db_table = 'users'
|
||||
|
27
redash/permissions.py
Normal file
27
redash/permissions.py
Normal file
@ -0,0 +1,27 @@
|
||||
import functools
|
||||
from flask.ext.login import current_user
|
||||
from flask.ext.restful import abort
|
||||
|
||||
|
||||
class require_permissions(object):
|
||||
def __init__(self, permissions):
|
||||
self.permissions = permissions
|
||||
|
||||
def __call__(self, fn):
|
||||
@functools.wraps(fn)
|
||||
def decorated(*args, **kwargs):
|
||||
has_permissions = reduce(lambda a, b: a and b,
|
||||
map(lambda permission: permission in current_user.permissions,
|
||||
self.permissions),
|
||||
True)
|
||||
|
||||
if has_permissions:
|
||||
return fn(*args, **kwargs)
|
||||
else:
|
||||
abort(403)
|
||||
|
||||
return decorated
|
||||
|
||||
|
||||
def require_permission(permission):
|
||||
return require_permissions((permission,))
|
Loading…
Reference in New Issue
Block a user