blob: d4ae9f45e83ad9e1a3684837c45d1e5dfcf32b17 [file] [log] [blame]
"""a collection of model-related helper classes and functions"""
from __future__ import absolute_import
from __future__ import division
from __future__ import print_function
from __future__ import unicode_literals
from datetime import datetime
import json
import re
from flask import escape, Markup
from flask_appbuilder.models.decorators import renders
from flask_appbuilder.models.mixins import AuditMixin
import humanize
import sqlalchemy as sa
from sqlalchemy.ext.declarative import declared_attr
from superset import sm
from superset.utils import QueryStatus
class ImportMixin(object):
def override(self, obj):
"""Overrides the plain fields of the dashboard."""
for field in obj.__class__.export_fields:
setattr(self, field, getattr(obj, field))
def copy(self):
"""Creates a copy of the dashboard without relationships."""
new_obj = self.__class__()
new_obj.override(self)
return new_obj
def alter_params(self, **kwargs):
d = self.params_dict
d.update(kwargs)
self.params = json.dumps(d)
@property
def params_dict(self):
if self.params:
params = re.sub(',[ \t\r\n]+}', '}', self.params)
params = re.sub(',[ \t\r\n]+\]', ']', params)
return json.loads(params)
else:
return {}
class AuditMixinNullable(AuditMixin):
"""Altering the AuditMixin to use nullable fields
Allows creating objects programmatically outside of CRUD
"""
created_on = sa.Column(sa.DateTime, default=datetime.now, nullable=True)
changed_on = sa.Column(
sa.DateTime, default=datetime.now,
onupdate=datetime.now, nullable=True)
@declared_attr
def created_by_fk(self): # noqa
return sa.Column(
sa.Integer, sa.ForeignKey('ab_user.id'),
default=self.get_user_id, nullable=True)
@declared_attr
def changed_by_fk(self): # noqa
return sa.Column(
sa.Integer, sa.ForeignKey('ab_user.id'),
default=self.get_user_id, onupdate=self.get_user_id, nullable=True)
def _user_link(self, user):
if not user:
return ''
url = '/superset/profile/{}/'.format(user.username)
return Markup('<a href="{}">{}</a>'.format(url, escape(user) or ''))
@renders('created_by')
def creator(self): # noqa
return self._user_link(self.created_by)
@property
def changed_by_(self):
return self._user_link(self.changed_by)
@renders('changed_on')
def changed_on_(self):
return Markup(
'<span class="no-wrap">{}</span>'.format(self.changed_on))
@renders('changed_on')
def modified(self):
s = humanize.naturaltime(datetime.now() - self.changed_on)
return Markup('<span class="no-wrap">{}</span>'.format(s))
@property
def icons(self):
return """
<a
href="{self.datasource_edit_url}"
data-toggle="tooltip"
title="{self.datasource}">
<i class="fa fa-database"></i>
</a>
""".format(**locals())
class QueryResult(object):
"""Object returned by the query interface"""
def __init__( # noqa
self,
df,
query,
duration,
status=QueryStatus.SUCCESS,
error_message=None):
self.df = df
self.query = query
self.duration = duration
self.status = status
self.error_message = error_message
def merge_perm(sm, permission_name, view_menu_name, connection):
permission = sm.find_permission(permission_name)
view_menu = sm.find_view_menu(view_menu_name)
pv = None
if not permission:
permission_table = sm.permission_model.__table__
connection.execute(
permission_table.insert()
.values(name=permission_name),
)
if not view_menu:
view_menu_table = sm.viewmenu_model.__table__
connection.execute(
view_menu_table.insert()
.values(name=view_menu_name),
)
permission = sm.find_permission(permission_name)
view_menu = sm.find_view_menu(view_menu_name)
if permission and view_menu:
pv = sm.get_session.query(sm.permissionview_model).filter_by(
permission=permission, view_menu=view_menu).first()
if not pv and permission and view_menu:
permission_view_table = sm.permissionview_model.__table__
connection.execute(
permission_view_table.insert()
.values(
permission_id=permission.id,
view_menu_id=view_menu.id,
),
)
def set_perm(mapper, connection, target): # noqa
if target.perm != target.get_perm():
link_table = target.__table__
connection.execute(
link_table.update()
.where(link_table.c.id == target.id)
.values(perm=target.get_perm()),
)
# add to view menu if not already exists
merge_perm(sm, 'datasource_access', target.get_perm(), connection)