You are viewing a plain text version of this content. The canonical link for it is here.
Posted to notifications@superset.apache.org by GitBox <gi...@apache.org> on 2018/08/08 00:39:17 UTC
[GitHub] mistercrunch closed pull request #5550: Template dashboard
mistercrunch closed pull request #5550: Template dashboard
URL: https://github.com/apache/incubator-superset/pull/5550
This is a PR merged from a forked repository.
As GitHub hides the original diff on merge, it is displayed below for
the sake of provenance:
As this is a foreign pull request (from a fork), the diff is supplied
below (as it won't show otherwise due to GitHub magic):
diff --git a/superset/config.py b/superset/config.py
index ca9fcbdb6a..a5e4f2988c 100644
--- a/superset/config.py
+++ b/superset/config.py
@@ -412,6 +412,9 @@ class CeleryConfig(object):
# an XSS security vulnerability
ENABLE_JAVASCRIPT_CONTROLS = False
+# The id of a template dashboard that should be copied to every new user
+DASHBOARD_TEMPLATE_ID = None
+
# A callable that allows altering the database conneciton URL and params
# on the fly, at runtime. This allows for things like impersonation or
# arbitrary logic. For instance you can wire different users to
diff --git a/superset/migrations/versions/0c5070e96b57_add_user_attributes_table.py b/superset/migrations/versions/0c5070e96b57_add_user_attributes_table.py
new file mode 100644
index 0000000000..69eba1b62f
--- /dev/null
+++ b/superset/migrations/versions/0c5070e96b57_add_user_attributes_table.py
@@ -0,0 +1,35 @@
+"""add user attributes table
+
+Revision ID: 0c5070e96b57
+Revises: 7fcdcde0761c
+Create Date: 2018-08-06 14:38:18.965248
+
+"""
+
+# revision identifiers, used by Alembic.
+revision = '0c5070e96b57'
+down_revision = '7fcdcde0761c'
+
+from alembic import op
+import sqlalchemy as sa
+
+
+def upgrade():
+ op.create_table('user_attribute',
+ sa.Column('created_on', sa.DateTime(), nullable=True),
+ sa.Column('changed_on', sa.DateTime(), nullable=True),
+ sa.Column('id', sa.Integer(), nullable=False),
+ sa.Column('user_id', sa.Integer(), nullable=True),
+ sa.Column('welcome_dashboard_id', sa.Integer(), nullable=True),
+ sa.Column('created_by_fk', sa.Integer(), nullable=True),
+ sa.Column('changed_by_fk', sa.Integer(), nullable=True),
+ sa.ForeignKeyConstraint(['changed_by_fk'], ['ab_user.id'], ),
+ sa.ForeignKeyConstraint(['created_by_fk'], ['ab_user.id'], ),
+ sa.ForeignKeyConstraint(['user_id'], ['ab_user.id'], ),
+ sa.ForeignKeyConstraint(['welcome_dashboard_id'], ['dashboards.id'], ),
+ sa.PrimaryKeyConstraint('id')
+ )
+
+
+def downgrade():
+ op.drop_table('user_attribute')
diff --git a/superset/models/__init__.py b/superset/models/__init__.py
index 18df0e6088..2084aee0c9 100644
--- a/superset/models/__init__.py
+++ b/superset/models/__init__.py
@@ -1,3 +1,4 @@
# -*- coding: utf-8 -*-
from . import core # noqa
from . import sql_lab # noqa
+from . import user_attributes # noqa
diff --git a/superset/models/core.py b/superset/models/core.py
index a02be607b9..d4f5fa158f 100644
--- a/superset/models/core.py
+++ b/superset/models/core.py
@@ -17,6 +17,7 @@
from flask import escape, g, Markup, request
from flask_appbuilder import Model
from flask_appbuilder.models.decorators import renders
+from flask_appbuilder.security.sqla.models import User
from future.standard_library import install_aliases
import numpy
import pandas as pd
@@ -28,7 +29,7 @@
)
from sqlalchemy.engine import url
from sqlalchemy.engine.url import make_url
-from sqlalchemy.orm import relationship, subqueryload
+from sqlalchemy.orm import relationship, sessionmaker, subqueryload
from sqlalchemy.orm.session import make_transient
from sqlalchemy.pool import NullPool
from sqlalchemy.schema import UniqueConstraint
@@ -39,6 +40,7 @@
from superset.connectors.connector_registry import ConnectorRegistry
from superset.legacy import update_time_range
from superset.models.helpers import AuditMixinNullable, ImportMixin, set_perm
+from superset.models.user_attributes import UserAttribute
from superset.viz import viz_types
install_aliases()
from urllib import parse # noqa
@@ -59,6 +61,41 @@ def set_related_perm(mapper, connection, target): # noqa
target.perm = ds.perm
+def copy_dashboard(mapper, connection, target):
+ dashboard_id = config.get('DASHBOARD_TEMPLATE_ID')
+ if dashboard_id is None:
+ return
+
+ Session = sessionmaker(autoflush=False)
+ session = Session(bind=connection)
+ new_user = session.query(User).filter_by(id=target.id).first()
+
+ # copy template dashboard to user
+ template = session.query(Dashboard).filter_by(id=int(dashboard_id)).first()
+ dashboard = Dashboard(
+ dashboard_title=template.dashboard_title,
+ position_json=template.position_json,
+ description=template.description,
+ css=template.css,
+ json_metadata=template.json_metadata,
+ slices=template.slices,
+ owners=[new_user],
+ )
+ session.add(dashboard)
+ session.commit()
+
+ # set dashboard as the welcome dashboard
+ extra_attributes = UserAttribute(
+ user_id=target.id,
+ welcome_dashboard_id=dashboard.id,
+ )
+ session.add(extra_attributes)
+ session.commit()
+
+
+sqla.event.listen(User, 'after_insert', copy_dashboard)
+
+
class Url(Model, AuditMixinNullable):
"""Used for the short url feature"""
diff --git a/superset/models/user_attributes.py b/superset/models/user_attributes.py
new file mode 100644
index 0000000000..faf41274dc
--- /dev/null
+++ b/superset/models/user_attributes.py
@@ -0,0 +1,36 @@
+# -*- coding: utf-8 -*-
+from __future__ import absolute_import
+from __future__ import division
+from __future__ import print_function
+from __future__ import unicode_literals
+
+from flask_appbuilder import Model
+from sqlalchemy import Column, ForeignKey, Integer
+from sqlalchemy.orm import relationship
+
+from superset import security_manager
+from superset.models.helpers import AuditMixinNullable
+
+
+class UserAttribute(Model, AuditMixinNullable):
+
+ """
+ Custom attributes attached to the user.
+
+ Extending the user attribute is tricky due to its dependency on the
+ authentication typew an circular dependencies in Superset. Instead, we use
+ a custom model for adding attributes.
+
+ """
+
+ __tablename__ = 'user_attribute'
+ id = Column(Integer, primary_key=True) # pylint: disable=invalid-name
+ user_id = Column(Integer, ForeignKey('ab_user.id'))
+ user = relationship(
+ security_manager.user_model,
+ backref='extra_attributes',
+ foreign_keys=[user_id],
+ )
+
+ welcome_dashboard_id = Column(Integer, ForeignKey('dashboards.id'))
+ welcome_dashboard = relationship('Dashboard')
diff --git a/superset/views/core.py b/superset/views/core.py
index 14c5469195..e4a4dfa639 100755
--- a/superset/views/core.py
+++ b/superset/views/core.py
@@ -45,6 +45,7 @@
from superset.legacy import cast_form_data, update_time_range
import superset.models.core as models
from superset.models.sql_lab import Query
+from superset.models.user_attributes import UserAttribute
from superset.sql_parse import SupersetQuery
from superset.utils import (
merge_extra_filters, merge_request_params, QueryStatus,
@@ -2694,6 +2695,15 @@ def welcome(self):
if not g.user or not g.user.get_id():
return redirect(appbuilder.get_url_for_login)
+ welcome_dashboard_id = (
+ db.session
+ .query(UserAttribute.welcome_dashboard_id)
+ .filter_by(user_id=g.user.get_id())
+ .scalar()
+ )
+ if welcome_dashboard_id:
+ return self.dashboard(str(welcome_dashboard_id))
+
payload = {
'user': bootstrap_user_data(),
'common': self.common_bootsrap_payload(),
----------------------------------------------------------------
This is an automated message from the Apache Git Service.
To respond to the message, please log on GitHub and use the
URL above to go to the specific comment.
For queries about this service, please contact Infrastructure at:
users@infra.apache.org
With regards,
Apache Git Services
---------------------------------------------------------------------
To unsubscribe, e-mail: notifications-unsubscribe@superset.apache.org
For additional commands, e-mail: notifications-help@superset.apache.org