You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@superset.apache.org by mi...@apache.org on 2019/06/01 01:28:14 UTC

[incubator-superset] branch release--0.33 updated (7591a70 -> fbf4080)

This is an automated email from the ASF dual-hosted git repository.

michellet pushed a change to branch release--0.33
in repository https://gitbox.apache.org/repos/asf/incubator-superset.git.


    from 7591a70  0.33.0rc1
     new b126d3d  Bump FAB to 2.0.0 (#7323)
     new 703d13f  [SQL Lab] Increase timeout threshold for offline check (#7411)
     new dbaa37f  [security] Adding Flask-Talisman (#7443)
     new e4bed9d  [sql lab] Fix new query stuck at pending state (#7523)
     new 5d1df08  fix: cache issue for api/v1/query (#7507)
     new ad37673  [testconn] Explicit closing engine connection (#7570)
     new c4dc38a  Adding controls for verifying options (#7468)
     new 1e7f30f  [sql lab]revert #4833 (#7498)
     new 99de5a4  Remove aggregates from metric options if datasource has no columns (#7586)
     new 7e77a64  [SQL Lab] fix unnecessary offline action (#7594)
     new 23842e4  Talisman config (#7529)
     new fb0bf03  Disabling flask-talisman by default (#7535)
     new fbf4080  0.33.0rc1.dev2

The 13 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails.  The revisions
listed as "add" were already present in the repository and have only
been added to this reference.


Summary of changes:
 docs/faq.rst                                       |   4 +-
 docs/installation.rst                              |  17 ++--
 requirements.txt                                   |  21 +++-
 setup.py                                           |   3 +-
 superset/__init__.py                               |  19 ++--
 superset/assets/package-lock.json                  |   2 +-
 superset/assets/package.json                       |   2 +-
 .../explore/components/MetricsControl_spec.jsx     |   8 ++
 .../explore/components/withVerification_spec.jsx   | 106 +++++++++++++++++++++
 ...outhPane_spec.jsx => QueryAutoRefresh_spec.jsx} |  58 ++++++-----
 .../assets/spec/javascripts/sqllab/fixtures.js     |   2 +
 .../src/SqlLab/components/QueryAutoRefresh.jsx     |  28 ++++--
 .../explore/components/controls/MetricsControl.jsx |  10 +-
 .../src/explore/components/controls/index.js       |   4 +
 .../components/controls/withVerification.jsx       |  88 +++++++++++++++++
 superset/cli.py                                    |   3 +-
 superset/common/query_context.py                   |   6 +-
 superset/config.py                                 |  19 ++--
 superset/utils/core.py                             |   5 -
 superset/views/core.py                             |  55 +++--------
 tests/security_tests.py                            |   2 +
 21 files changed, 341 insertions(+), 121 deletions(-)
 create mode 100644 superset/assets/spec/javascripts/explore/components/withVerification_spec.jsx
 copy superset/assets/spec/javascripts/sqllab/{SouthPane_spec.jsx => QueryAutoRefresh_spec.jsx} (56%)
 create mode 100644 superset/assets/src/explore/components/controls/withVerification.jsx


[incubator-superset] 10/13: [SQL Lab] fix unnecessary offline action (#7594)

Posted by mi...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

michellet pushed a commit to branch release--0.33
in repository https://gitbox.apache.org/repos/asf/incubator-superset.git

commit 7e77a64966ff69402394caaeb1bc9c1ae5f5554f
Author: Grace Guo <gr...@airbnb.com>
AuthorDate: Thu May 30 10:38:49 2019 -0700

    [SQL Lab] fix unnecessary offline action (#7594)
    
    
    (cherry picked from commit dbdb6b093aeb0b482494e7a4ee65b5836b5070ea)
---
 .../javascripts/sqllab/QueryAutoRefresh_spec.jsx   | 72 ++++++++++++++++++++++
 .../assets/spec/javascripts/sqllab/fixtures.js     |  2 +
 .../src/SqlLab/components/QueryAutoRefresh.jsx     | 23 +++++--
 3 files changed, 92 insertions(+), 5 deletions(-)

diff --git a/superset/assets/spec/javascripts/sqllab/QueryAutoRefresh_spec.jsx b/superset/assets/spec/javascripts/sqllab/QueryAutoRefresh_spec.jsx
new file mode 100644
index 0000000..527ecd6
--- /dev/null
+++ b/superset/assets/spec/javascripts/sqllab/QueryAutoRefresh_spec.jsx
@@ -0,0 +1,72 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+import React from 'react';
+import { shallow } from 'enzyme';
+import sinon from 'sinon';
+import thunk from 'redux-thunk';
+import configureStore from 'redux-mock-store';
+
+import QueryAutoRefresh from '../../../src/SqlLab/components/QueryAutoRefresh';
+import { initialState, runningQuery } from './fixtures';
+
+describe('QueryAutoRefresh', () => {
+  const middlewares = [thunk];
+  const mockStore = configureStore(middlewares);
+  const sqlLab = {
+    ...initialState.sqlLab,
+    queries: {
+      ryhMUZCGb: runningQuery,
+    },
+  };
+  const state = {
+    ...initialState,
+    sqlLab,
+
+  };
+  const store = mockStore(state);
+
+  const getWrapper = () => (
+    shallow(<QueryAutoRefresh />, {
+      context: { store },
+    }).dive());
+
+  let wrapper;
+
+  it('shouldCheckForQueries', () => {
+    wrapper = getWrapper();
+    expect(wrapper.instance().shouldCheckForQueries()).toBe(true);
+  });
+
+  it('setUserOffline', () => {
+    wrapper = getWrapper();
+    const spy = sinon.spy(wrapper.instance().props.actions, 'setUserOffline');
+
+    // state not changed
+    wrapper.setState({
+      offline: false,
+    });
+    expect(spy.called).toBe(false);
+
+    // state is changed
+    wrapper.setState({
+      offline: true,
+    });
+    expect(spy.callCount).toBe(1);
+  });
+});
diff --git a/superset/assets/spec/javascripts/sqllab/fixtures.js b/superset/assets/spec/javascripts/sqllab/fixtures.js
index 6471be1..8b44857 100644
--- a/superset/assets/spec/javascripts/sqllab/fixtures.js
+++ b/superset/assets/spec/javascripts/sqllab/fixtures.js
@@ -366,11 +366,13 @@ export const runningQuery = {
   id: 'ryhMUZCGb',
   progress: 90,
   state: 'running',
+  startDttm: Date.now() - 500,
 };
 export const cachedQuery = Object.assign({}, queries[0], { cached: true });
 
 export const initialState = {
   sqlLab: {
+    offline: false,
     alerts: [],
     queries: {},
     databases: {},
diff --git a/superset/assets/src/SqlLab/components/QueryAutoRefresh.jsx b/superset/assets/src/SqlLab/components/QueryAutoRefresh.jsx
index 16aff30..a8fd8a7 100644
--- a/superset/assets/src/SqlLab/components/QueryAutoRefresh.jsx
+++ b/superset/assets/src/SqlLab/components/QueryAutoRefresh.jsx
@@ -30,9 +30,20 @@ const MAX_QUERY_AGE_TO_POLL = 21600000;
 const QUERY_TIMEOUT_LIMIT = 10000;
 
 class QueryAutoRefresh extends React.PureComponent {
+  constructor(props) {
+    super(props);
+    this.state = {
+      offline: props.offline,
+    };
+  }
   componentWillMount() {
     this.startTimer();
   }
+  componentDidUpdate(prevProps) {
+    if (prevProps.offline !== this.state.offline) {
+      this.props.actions.setUserOffline(this.state.offline);
+    }
+  }
   componentWillUnmount() {
     this.stopTimer();
   }
@@ -67,12 +78,12 @@ class QueryAutoRefresh extends React.PureComponent {
         if (Object.keys(json).length > 0) {
           this.props.actions.refreshQueries(json);
         }
-        this.props.actions.setUserOffline(false);
-        }).catch(() => {
-          this.props.actions.setUserOffline(true);
-        });
+        this.setState({ offline: false });
+      }).catch(() => {
+        this.setState({ offline: true });
+      });
     } else {
-      this.props.actions.setUserOffline(false);
+      this.setState({ offline: false });
     }
   }
   render() {
@@ -80,6 +91,7 @@ class QueryAutoRefresh extends React.PureComponent {
   }
 }
 QueryAutoRefresh.propTypes = {
+  offline: PropTypes.bool.isRequired,
   queries: PropTypes.object.isRequired,
   actions: PropTypes.object.isRequired,
   queriesLastUpdate: PropTypes.number.isRequired,
@@ -87,6 +99,7 @@ QueryAutoRefresh.propTypes = {
 
 function mapStateToProps({ sqlLab }) {
   return {
+    offline: sqlLab.offline,
     queries: sqlLab.queries,
     queriesLastUpdate: sqlLab.queriesLastUpdate,
   };


[incubator-superset] 09/13: Remove aggregates from metric options if datasource has no columns (#7586)

Posted by mi...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

michellet pushed a commit to branch release--0.33
in repository https://gitbox.apache.org/repos/asf/incubator-superset.git

commit 99de5a44fceffb402ef7223436a1af89516035ff
Author: michellethomas <mi...@gmail.com>
AuthorDate: Fri May 24 11:10:35 2019 -0700

    Remove aggregates from metric options if datasource has no columns (#7586)
    
    
    (cherry picked from commit 47ba2ad3947a83bb5299c9f80a9aedd4a756a004)
---
 .../javascripts/explore/components/MetricsControl_spec.jsx     |  8 ++++++++
 .../assets/src/explore/components/controls/MetricsControl.jsx  | 10 +++++++---
 2 files changed, 15 insertions(+), 3 deletions(-)

diff --git a/superset/assets/spec/javascripts/explore/components/MetricsControl_spec.jsx b/superset/assets/spec/javascripts/explore/components/MetricsControl_spec.jsx
index 6f2c657..31bddf8 100644
--- a/superset/assets/spec/javascripts/explore/components/MetricsControl_spec.jsx
+++ b/superset/assets/spec/javascripts/explore/components/MetricsControl_spec.jsx
@@ -85,6 +85,14 @@ describe('MetricsControl', () => {
       ]);
     });
 
+    it('does not show aggregates in options if no columns', () => {
+      const { wrapper } = setup({ columns: [] });
+      expect(wrapper.state('options')).toEqual([
+        { optionName: 'sum__value', metric_name: 'sum__value', expression: 'SUM(energy_usage.value)' },
+        { optionName: 'avg__value', metric_name: 'avg__value', expression: 'AVG(energy_usage.value)' },
+      ]);
+    });
+
     it('coerces Adhoc Metrics from form data into instances of the AdhocMetric class and leaves saved metrics', () => {
       const { wrapper } = setup({
         value: [
diff --git a/superset/assets/src/explore/components/controls/MetricsControl.jsx b/superset/assets/src/explore/components/controls/MetricsControl.jsx
index b42cc81..1e49355 100644
--- a/superset/assets/src/explore/components/controls/MetricsControl.jsx
+++ b/superset/assets/src/explore/components/controls/MetricsControl.jsx
@@ -238,10 +238,14 @@ export default class MetricsControl extends React.PureComponent {
   }
 
   optionsForSelect(props) {
+    const { columns, savedMetrics } = props;
+    const aggregates = columns && columns.length ?
+      Object.keys(AGGREGATES).map(aggregate => ({ aggregate_name: aggregate })) :
+      [];
     const options = [
-      ...props.columns,
-      ...Object.keys(AGGREGATES).map(aggregate => ({ aggregate_name: aggregate })),
-      ...props.savedMetrics,
+      ...columns,
+      ...aggregates,
+      ...savedMetrics,
     ];
 
     return options.reduce((results, option) => {


[incubator-superset] 03/13: [security] Adding Flask-Talisman (#7443)

Posted by mi...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

michellet pushed a commit to branch release--0.33
in repository https://gitbox.apache.org/repos/asf/incubator-superset.git

commit dbaa37f406926e532094e72d69f682e1713a6c2d
Author: John Bodley <45...@users.noreply.github.com>
AuthorDate: Mon May 13 17:08:24 2019 -0700

    [security] Adding Flask-Talisman (#7443)
    
    
    (cherry picked from commit a4392c8fcdb52fa4bc23c0bdeb6903b6e173e530)
---
 requirements.txt       |  4 +++-
 setup.py               |  1 +
 superset/__init__.py   |  3 +++
 superset/config.py     | 10 +++-------
 superset/views/core.py |  2 +-
 5 files changed, 11 insertions(+), 9 deletions(-)

diff --git a/requirements.txt b/requirements.txt
index 1863a22..3076586 100644
--- a/requirements.txt
+++ b/requirements.txt
@@ -4,6 +4,7 @@
 #
 #    pip-compile --output-file requirements.txt setup.py
 #
+
 alembic==1.0.0            # via flask-migrate
 amqp==2.3.2               # via kombu
 apispec[yaml]==1.2.0      # via flask-appbuilder
@@ -32,6 +33,7 @@ flask-login==0.4.1        # via flask-appbuilder
 flask-migrate==2.1.1
 flask-openid==1.2.5       # via flask-appbuilder
 flask-sqlalchemy==2.3.2   # via flask-appbuilder, flask-migrate
+flask-talisman==0.6.0
 flask-wtf==0.14.2
 flask==1.0.2
 geopy==1.11.0
@@ -70,7 +72,7 @@ requests==2.20.0
 retry==0.9.2
 selenium==3.141.0
 simplejson==3.15.0
-six==1.11.0               # via bleach, cryptography, flask-jwt-extended, isodate, jsonschema, pathlib2, polyline, prison, pydruid, pyrsistent, python-dateutil, sqlalchemy-utils, wtforms-json
+six==1.11.0               # via bleach, cryptography, flask-jwt-extended, flask-talisman, isodate, jsonschema, pathlib2, polyline, prison, pydruid, pyrsistent, python-dateutil, sqlalchemy-utils, wtforms-json
 sqlalchemy-utils==0.32.21
 sqlalchemy==1.3.1
 sqlparse==0.2.4
diff --git a/setup.py b/setup.py
index b97b49a..b7ec596 100644
--- a/setup.py
+++ b/setup.py
@@ -80,6 +80,7 @@ setup(
         'flask-appbuilder>=2.0.0, <2.3.0',
         'flask-caching',
         'flask-compress',
+        'flask-talisman',
         'flask-migrate',
         'flask-wtf',
         'geopy',
diff --git a/superset/__init__.py b/superset/__init__.py
index c405c01..217d0a5 100644
--- a/superset/__init__.py
+++ b/superset/__init__.py
@@ -27,6 +27,7 @@ from flask_appbuilder import AppBuilder, IndexView, SQLA
 from flask_appbuilder.baseviews import expose
 from flask_compress import Compress
 from flask_migrate import Migrate
+from flask_talisman import Talisman
 from flask_wtf.csrf import CSRFProtect
 from werkzeug.contrib.fixers import ProxyFix
 import wtforms_json
@@ -228,6 +229,8 @@ def is_feature_enabled(feature):
 if conf.get('ENABLE_FLASK_COMPRESS'):
     Compress(app)
 
+Talisman(app, content_security_policy=None)
+
 # Hook that provides administrators a handle on the Flask APP
 # after initialization
 flask_app_mutator = app.config.get('FLASK_APP_MUTATOR')
diff --git a/superset/config.py b/superset/config.py
index 96ccb09..b1052fe 100644
--- a/superset/config.py
+++ b/superset/config.py
@@ -403,13 +403,9 @@ CELERY_CONFIG = CeleryConfig
 CELERY_CONFIG = None
 """
 
-# static http headers to be served by your Superset server.
-# This header prevents iFrames from other domains and
-# "clickjacking" as a result
-HTTP_HEADERS = {'X-Frame-Options': 'SAMEORIGIN'}
-# If you need to allow iframes from other domains (and are
-# aware of the risks), you can disable this header:
-# HTTP_HEADERS = {}
+# Additional static HTTP headers to be served by your Superset server. Note
+# Flask-Talisman aplies the relevant security HTTP headers.
+HTTP_HEADERS = {}
 
 # The db id here results in selecting this one as a default in SQL Lab
 DEFAULT_DB_ID = None
diff --git a/superset/views/core.py b/superset/views/core.py
index d910923..019d400 100755
--- a/superset/views/core.py
+++ b/superset/views/core.py
@@ -3006,7 +3006,7 @@ appbuilder.add_separator('Sources')
 
 
 @app.after_request
-def apply_caching(response):
+def apply_http_headers(response):
     """Applies the configuration's http headers to all responses"""
     for k, v in config.get('HTTP_HEADERS').items():
         response.headers[k] = v


[incubator-superset] 13/13: 0.33.0rc1.dev2

Posted by mi...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

michellet pushed a commit to branch release--0.33
in repository https://gitbox.apache.org/repos/asf/incubator-superset.git

commit fbf4080ce6f88bb03ad3309813cdc39bf3fe5523
Author: Michelle Thomas <mi...@gmail.com>
AuthorDate: Fri May 31 18:27:05 2019 -0700

    0.33.0rc1.dev2
---
 superset/assets/package-lock.json | 2 +-
 superset/assets/package.json      | 2 +-
 2 files changed, 2 insertions(+), 2 deletions(-)

diff --git a/superset/assets/package-lock.json b/superset/assets/package-lock.json
index dfe31a7..8d3a12d 100644
--- a/superset/assets/package-lock.json
+++ b/superset/assets/package-lock.json
@@ -1,6 +1,6 @@
 {
   "name": "superset",
-  "version": "0.33.0rc1.dev1",
+  "version": "0.33.0rc1.dev2",
   "lockfileVersion": 1,
   "requires": true,
   "dependencies": {
diff --git a/superset/assets/package.json b/superset/assets/package.json
index fe173db..b39740a 100644
--- a/superset/assets/package.json
+++ b/superset/assets/package.json
@@ -1,6 +1,6 @@
 {
   "name": "superset",
-  "version": "0.33.0rc1",
+  "version": "0.33.0rc1.dev2",
   "description": "Superset is a data exploration platform designed to be visual, intuitive, and interactive.",
   "license": "Apache-2.0",
   "directories": {


[incubator-superset] 01/13: Bump FAB to 2.0.0 (#7323)

Posted by mi...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

michellet pushed a commit to branch release--0.33
in repository https://gitbox.apache.org/repos/asf/incubator-superset.git

commit b126d3dadb5d8a5866bc3608f9f25b93a8e28126
Author: Daniel Vaz Gaspar <da...@gmail.com>
AuthorDate: Tue Apr 30 17:01:18 2019 +0100

    Bump FAB to 2.0.0 (#7323)
    
    * Bump FAB to 2.0.0
    
    * [tests] whitelist SecurityApi login and refresh endpoints
    
    * [style] Fix, C812 missing trailing commas
    
    * [security] Remove SUPERSET_UPDATE_PERMS flag
    
    Registering sources needs to be performed after the views are
    initialized on UPDATE_PERMS=False configuration
    
    * [docs] New, FAB_UPDATE_PERMS and flask fab cli
    
    * [docs] Fix, db upgrade needs to come first, create-admin needs a db
    
    * [cli] New, superset init bootstraps all permissions for FAB and Superset
    
    * [style] Fix, flakes
    
    (cherry picked from commit 06c4610e8eb3127ad15526ebc0c83c2424c2e658)
---
 docs/faq.rst            |  4 ++--
 docs/installation.rst   | 17 ++++++-----------
 requirements.txt        | 19 ++++++++++++++-----
 setup.py                |  2 +-
 superset/__init__.py    | 14 ++++++--------
 superset/cli.py         |  3 ++-
 superset/utils/core.py  |  5 -----
 tests/security_tests.py |  2 ++
 8 files changed, 33 insertions(+), 33 deletions(-)

diff --git a/docs/faq.rst b/docs/faq.rst
index d1f781f..426e0ab 100644
--- a/docs/faq.rst
+++ b/docs/faq.rst
@@ -186,8 +186,8 @@ by setting the ``stagger_refresh`` to ``false`` and modify the stagger period by
 Here, the entire dashboard will refresh at once if periodic refresh is on. The stagger time of
 2.5 seconds is ignored.
 
-Why does fabmanager or superset freezed/hung/not responding when started (my home directory is NFS mounted)?
-------------------------------------------------------------------------------------------------------------
+Why does 'flask fab' or superset freezed/hung/not responding when started (my home directory is NFS mounted)?
+-------------------------------------------------------------------------------------------------------------
 By default, superset creates and uses an sqlite database at ``~/.superset/superset.db``. Sqlite is known to `don't work well if used on NFS`__ due to broken file locking implementation on NFS.
 
 __ https://www.sqlite.org/lockingv3.html
diff --git a/docs/installation.rst b/docs/installation.rst
index 7bc9f61..9db408c 100644
--- a/docs/installation.rst
+++ b/docs/installation.rst
@@ -170,12 +170,13 @@ Follow these few simple steps to install Superset.::
     # Install superset
     pip install superset
 
-    # Create an admin user (you will be prompted to set a username, first and last name before setting a password)
-    fabmanager create-admin --app superset
-
     # Initialize the database
     superset db upgrade
 
+    # Create an admin user (you will be prompted to set a username, first and last name before setting a password)
+    $ export FLASK_APP=superset
+    flask fab create-admin
+
     # Load some data to play with
     superset load_examples
 
@@ -183,7 +184,7 @@ Follow these few simple steps to install Superset.::
     superset init
 
     # To start a development web server on port 8088, use -p to bind to another port
-    superset runserver -d
+    flask run -p 8080 --with-threads --reload --debugger
 
 
 After installation, you should be able to point your browser to the right
@@ -236,17 +237,11 @@ workers this creates a lot of contention and race conditions when defining
 permissions and views.
 
 To alleviate this issue, the automatic updating of permissions can be disabled
-by setting the environment variable
-`SUPERSET_UPDATE_PERMS` environment variable to `0`.
-The value `1` enables it, `0` disables it. Note if undefined the functionality
-is enabled to maintain backwards compatibility.
+by setting `FAB_UPDATE_PERMS = False` (defaults to True).
 
 In a production environment initialization could take on the following form:
 
-  export SUPERSET_UPDATE_PERMS=1
   superset init
-
-  export SUPERSET_UPDATE_PERMS=0
   gunicorn -w 10 ... superset:app
 
 Configuration behind a load balancer
diff --git a/requirements.txt b/requirements.txt
index 4b6b4f5..1863a22 100644
--- a/requirements.txt
+++ b/requirements.txt
@@ -6,7 +6,9 @@
 #
 alembic==1.0.0            # via flask-migrate
 amqp==2.3.2               # via kombu
+apispec[yaml]==1.2.0      # via flask-appbuilder
 asn1crypto==0.24.0        # via cryptography
+attrs==19.1.0             # via jsonschema
 babel==2.6.0              # via flask-babel
 billiard==3.5.0.4         # via celery
 bleach==3.0.2
@@ -21,10 +23,11 @@ croniter==0.3.29
 cryptography==2.4.2
 decorator==4.3.0          # via retry
 defusedxml==0.5.0         # via python3-openid
-flask-appbuilder==1.12.5
+flask-appbuilder==2.0.0
 flask-babel==0.11.1       # via flask-appbuilder
 flask-caching==1.4.0
 flask-compress==1.4.0
+flask-jwt-extended==3.18.1  # via flask-appbuilder
 flask-login==0.4.1        # via flask-appbuilder
 flask-migrate==2.1.1
 flask-openid==1.2.5       # via flask-appbuilder
@@ -38,19 +41,25 @@ idna==2.6
 isodate==0.6.0
 itsdangerous==0.24        # via flask
 jinja2==2.10              # via flask, flask-babel
+jsonschema==3.0.1         # via flask-appbuilder
 kombu==4.2.1              # via celery
 mako==1.0.7               # via alembic
 markdown==3.0
 markupsafe==1.0           # via jinja2, mako
+marshmallow-enum==1.4.1   # via flask-appbuilder
+marshmallow-sqlalchemy==0.16.2  # via flask-appbuilder
+marshmallow==2.19.2       # via flask-appbuilder, marshmallow-enum, marshmallow-sqlalchemy
 numpy==1.15.2             # via pandas
 pandas==0.23.4
 parsedatetime==2.0.0
 pathlib2==2.3.0
 polyline==1.3.2
+prison==0.1.0             # via flask-appbuilder
 py==1.7.0                 # via retry
 pycparser==2.19           # via cffi
-pydruid==0.5.0
-pyjwt==1.7.1              # via flask-appbuilder
+pydruid==0.5.2
+pyjwt==1.7.1              # via flask-appbuilder, flask-jwt-extended
+pyrsistent==0.14.11       # via jsonschema
 python-dateutil==2.6.1
 python-editor==1.0.3      # via alembic
 python-geohash==0.8.5
@@ -61,7 +70,7 @@ requests==2.20.0
 retry==0.9.2
 selenium==3.141.0
 simplejson==3.15.0
-six==1.11.0               # via bleach, cryptography, isodate, pathlib2, polyline, pydruid, python-dateutil, sqlalchemy-utils, wtforms-json
+six==1.11.0               # via bleach, cryptography, flask-jwt-extended, isodate, jsonschema, pathlib2, polyline, prison, pydruid, pyrsistent, python-dateutil, sqlalchemy-utils, wtforms-json
 sqlalchemy-utils==0.32.21
 sqlalchemy==1.3.1
 sqlparse==0.2.4
@@ -69,6 +78,6 @@ unicodecsv==0.14.1
 urllib3==1.22             # via requests, selenium
 vine==1.1.4               # via amqp
 webencodings==0.5.1       # via bleach
-werkzeug==0.14.1          # via flask
+werkzeug==0.14.1          # via flask, flask-jwt-extended
 wtforms-json==0.3.3
 wtforms==2.2.1            # via flask-wtf, wtforms-json
diff --git a/setup.py b/setup.py
index 9c6278e..b97b49a 100644
--- a/setup.py
+++ b/setup.py
@@ -77,7 +77,7 @@ setup(
         'croniter>=0.3.28',
         'cryptography>=2.4.2',
         'flask>=1.0.0, <2.0.0',
-        'flask-appbuilder>=1.12.5, <2.0.0',
+        'flask-appbuilder>=2.0.0, <2.3.0',
         'flask-caching',
         'flask-compress',
         'flask-migrate',
diff --git a/superset/__init__.py b/superset/__init__.py
index 7d0df26..c405c01 100644
--- a/superset/__init__.py
+++ b/superset/__init__.py
@@ -34,8 +34,7 @@ import wtforms_json
 from superset import config
 from superset.connectors.connector_registry import ConnectorRegistry
 from superset.security import SupersetSecurityManager
-from superset.utils.core import (
-    get_update_perms_flag, pessimistic_connection_handling, setup_cache)
+from superset.utils.core import pessimistic_connection_handling, setup_cache
 
 wtforms_json.init()
 
@@ -202,7 +201,6 @@ appbuilder = AppBuilder(
     base_template='superset/base.html',
     indexview=MyIndexView,
     security_manager_class=custom_sm,
-    update_perms=get_update_perms_flag(),
 )
 
 security_manager = appbuilder.sm
@@ -226,11 +224,6 @@ def is_feature_enabled(feature):
     return get_feature_flags().get(feature)
 
 
-# Registering sources
-module_datasource_map = app.config.get('DEFAULT_MODULE_DS_MAP')
-module_datasource_map.update(app.config.get('ADDITIONAL_MODULE_DS_MAP'))
-ConnectorRegistry.register_sources(module_datasource_map)
-
 # Flask-Compress
 if conf.get('ENABLE_FLASK_COMPRESS'):
     Compress(app)
@@ -242,3 +235,8 @@ if flask_app_mutator:
     flask_app_mutator(app)
 
 from superset import views  # noqa
+
+# Registering sources
+module_datasource_map = app.config.get('DEFAULT_MODULE_DS_MAP')
+module_datasource_map.update(app.config.get('ADDITIONAL_MODULE_DS_MAP'))
+ConnectorRegistry.register_sources(module_datasource_map)
diff --git a/superset/cli.py b/superset/cli.py
index 7f5fe17..1aff4bd 100755
--- a/superset/cli.py
+++ b/superset/cli.py
@@ -28,7 +28,7 @@ import werkzeug.serving
 import yaml
 
 from superset import (
-    app, data, db, security_manager,
+    app, appbuilder, data, db, security_manager,
 )
 from superset.utils import (
     core as utils, dashboard_import_export, dict_import_export)
@@ -50,6 +50,7 @@ def make_shell_context():
 def init():
     """Inits the Superset application"""
     utils.get_or_create_main_db()
+    appbuilder.add_permissions(update_perms=True)
     security_manager.sync_role_definitions()
 
 
diff --git a/superset/utils/core.py b/superset/utils/core.py
index be8bc08..6230b6f 100644
--- a/superset/utils/core.py
+++ b/superset/utils/core.py
@@ -846,11 +846,6 @@ def merge_request_params(form_data, params):
     form_data['url_params'] = url_params
 
 
-def get_update_perms_flag():
-    val = os.environ.get('SUPERSET_UPDATE_PERMS')
-    return val.lower() not in ('0', 'false', 'no') if val else True
-
-
 def user_label(user):
     """Given a user ORM FAB object, returns a label"""
     if user:
diff --git a/tests/security_tests.py b/tests/security_tests.py
index 063f1e8..4667611 100644
--- a/tests/security_tests.py
+++ b/tests/security_tests.py
@@ -247,6 +247,8 @@ class RolePermissionTests(SupersetTestCase):
             ['Superset', 'log'],
             ['Superset', 'theme'],
             ['Superset', 'welcome'],
+            ['SecurityApi', 'login'],
+            ['SecurityApi', 'refresh'],
         ]
         unsecured_views = []
         for view_class in appbuilder.baseviews:


[incubator-superset] 08/13: [sql lab]revert #4833 (#7498)

Posted by mi...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

michellet pushed a commit to branch release--0.33
in repository https://gitbox.apache.org/repos/asf/incubator-superset.git

commit 1e7f30fb45f24f8dc1ef8460eb41e8c30e48f402
Author: Grace Guo <gr...@airbnb.com>
AuthorDate: Thu May 23 17:39:40 2019 -0700

    [sql lab]revert #4833 (#7498)
    
    (cherry picked from commit 20143293eb9cac93a1692dcd552be5cb48b5d3e9)
---
 superset/views/core.py | 48 ++++++++----------------------------------------
 1 file changed, 8 insertions(+), 40 deletions(-)

diff --git a/superset/views/core.py b/superset/views/core.py
index 32cabad..8b621bc 100755
--- a/superset/views/core.py
+++ b/superset/views/core.py
@@ -21,7 +21,6 @@ import inspect
 import logging
 import os
 import re
-import time
 import traceback
 from typing import List  # noqa: F401
 from urllib import parse
@@ -37,10 +36,8 @@ from flask_babel import gettext as __
 from flask_babel import lazy_gettext as _
 import pandas as pd
 import simplejson as json
-import sqlalchemy as sqla
 from sqlalchemy import (
-    and_, Column, create_engine, ForeignKey, Integer, MetaData, or_, select, Table,
-    update)
+    and_, Column, create_engine, ForeignKey, Integer, MetaData, or_, select, Table)
 from sqlalchemy.engine.url import make_url
 from sqlalchemy.exc import IntegrityError
 from werkzeug.routing import BaseConverter
@@ -1840,7 +1837,7 @@ class Superset(BaseSupersetView):
                 M.Slice.id == M.Log.slice_id,
             )
             .filter(
-                sqla.and_(
+                and_(
                     ~M.Log.action.in_(('queries', 'shortner', 'sql_json')),
                     M.Log.user_id == user_id,
                 ),
@@ -1910,7 +1907,7 @@ class Superset(BaseSupersetView):
             )
             .join(
                 models.FavStar,
-                sqla.and_(
+                and_(
                     models.FavStar.user_id == int(user_id),
                     models.FavStar.class_name == 'Dashboard',
                     models.Dashboard.id == models.FavStar.obj_id,
@@ -1948,7 +1945,7 @@ class Superset(BaseSupersetView):
                 Dash,
             )
             .filter(
-                sqla.or_(
+                or_(
                     Dash.created_by_fk == user_id,
                     Dash.changed_by_fk == user_id,
                 ),
@@ -1981,13 +1978,13 @@ class Superset(BaseSupersetView):
             db.session.query(Slice,
                              FavStar.dttm).join(
                 models.FavStar,
-                sqla.and_(
+                and_(
                     models.FavStar.user_id == int(user_id),
                     models.FavStar.class_name == 'slice',
                     models.Slice.id == models.FavStar.obj_id,
                 ),
                 isouter=True).filter(
-                sqla.or_(
+                or_(
                     Slice.created_by_fk == user_id,
                     Slice.changed_by_fk == user_id,
                     FavStar.user_id == user_id,
@@ -2018,7 +2015,7 @@ class Superset(BaseSupersetView):
         qry = (
             db.session.query(Slice)
             .filter(
-                sqla.or_(
+                or_(
                     Slice.created_by_fk == user_id,
                     Slice.changed_by_fk == user_id,
                 ),
@@ -2050,7 +2047,7 @@ class Superset(BaseSupersetView):
             )
             .join(
                 models.FavStar,
-                sqla.and_(
+                and_(
                     models.FavStar.user_id == int(user_id),
                     models.FavStar.class_name == 'slice',
                     models.Slice.id == models.FavStar.obj_id,
@@ -2728,35 +2725,6 @@ class Superset(BaseSupersetView):
             .all()
         )
         dict_queries = {q.client_id: q.to_dict() for q in sql_queries}
-
-        now = int(round(time.time() * 1000))
-
-        unfinished_states = [
-            QueryStatus.PENDING,
-            QueryStatus.RUNNING,
-        ]
-
-        queries_to_timeout = [
-            client_id for client_id, query_dict in dict_queries.items()
-            if (
-                query_dict['state'] in unfinished_states and (
-                    now - query_dict['startDttm'] >
-                    config.get('SQLLAB_ASYNC_TIME_LIMIT_SEC') * 1000
-                )
-            )
-        ]
-
-        if queries_to_timeout:
-            update(Query).where(
-                and_(
-                    Query.user_id == g.user.get_id(),
-                    Query.client_id in queries_to_timeout,
-                ),
-            ).values(state=QueryStatus.TIMED_OUT)
-
-            for client_id in queries_to_timeout:
-                dict_queries[client_id]['status'] = QueryStatus.TIMED_OUT
-
         return json_success(
             json.dumps(dict_queries, default=utils.json_int_dttm_ser))
 


[incubator-superset] 05/13: fix: cache issue for api/v1/query (#7507)

Posted by mi...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

michellet pushed a commit to branch release--0.33
in repository https://gitbox.apache.org/repos/asf/incubator-superset.git

commit 5d1df0835cb0a0aa22e6a163fed9c60ffb7a3e18
Author: Conglei <sh...@gmail.com>
AuthorDate: Tue May 14 14:21:05 2019 -0700

    fix: cache issue for api/v1/query (#7507)
    
    
    (cherry picked from commit fda10026548169b507a2ccad3049bd3305c7978b)
---
 superset/common/query_context.py | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/superset/common/query_context.py b/superset/common/query_context.py
index bb91666..fd6298d 100644
--- a/superset/common/query_context.py
+++ b/superset/common/query_context.py
@@ -206,16 +206,16 @@ class QueryContext:
                         df=df if df is not None else None,
                         query=query,
                     )
-                    cache_value = pkl.dumps(
+                    cache_binary = pkl.dumps(
                         cache_value, protocol=pkl.HIGHEST_PROTOCOL)
 
                     logging.info('Caching {} chars at key {}'.format(
-                        len(cache_value), cache_key))
+                        len(cache_binary), cache_key))
 
                     stats_logger.incr('set_cache_key')
                     cache.set(
                         cache_key,
-                        cache_value,
+                        cache_value=cache_binary,
                         timeout=self.cache_timeout)
                 except Exception as e:
                     # cache.set call can fail if the backend is down or if


[incubator-superset] 12/13: Disabling flask-talisman by default (#7535)

Posted by mi...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

michellet pushed a commit to branch release--0.33
in repository https://gitbox.apache.org/repos/asf/incubator-superset.git

commit fb0bf03c029af153ded455afefdf45e05d204b6c
Author: Maxime Beauchemin <ma...@gmail.com>
AuthorDate: Mon May 20 16:58:36 2019 -0700

    Disabling flask-talisman by default (#7535)
    
    flask-talisman was enabled recently and while it may be virtuous in some
    cases, it seems to break things out of the box.
    
    Locally and in dev mode, upon my first redirect it sends to HTTPS and
    things it crashes.
    
    I think it should be opt-in, maybe we can recommend turning this on in
    production in the docs?
    
    (cherry picked from commit 1fdc96a3817e802209b0ffe580ff6f12c7335551)
---
 superset/config.py | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/superset/config.py b/superset/config.py
index 8d11f0b..10c9bcb 100644
--- a/superset/config.py
+++ b/superset/config.py
@@ -601,7 +601,7 @@ IS_EPOCH_S_TRULY_UTC = False
 
 
 # Do you want Talisman enabled?
-TALISMAN_ENABLED = True
+TALISMAN_ENABLED = False
 # If you want Talisman, how do you want it configured??
 TALISMAN_CONFIG = {
     'content_security_policy': None,


[incubator-superset] 11/13: Talisman config (#7529)

Posted by mi...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

michellet pushed a commit to branch release--0.33
in repository https://gitbox.apache.org/repos/asf/incubator-superset.git

commit 23842e43a448f78be89b0bdfc51713c4a45e633e
Author: Craig Rueda <cr...@craigrueda.com>
AuthorDate: Thu May 16 20:55:59 2019 -0700

    Talisman config (#7529)
    
    * Making Talisman configurable
    
    * Fixing double quotes
    
    * Fixing flake8
    
    * Removing default
    
    (cherry picked from commit 21a467094ba3e194b9799026f0706c5453a5fb1e)
---
 superset/__init__.py | 4 +++-
 superset/config.py   | 9 +++++++++
 2 files changed, 12 insertions(+), 1 deletion(-)

diff --git a/superset/__init__.py b/superset/__init__.py
index 217d0a5..c995c2f 100644
--- a/superset/__init__.py
+++ b/superset/__init__.py
@@ -229,7 +229,9 @@ def is_feature_enabled(feature):
 if conf.get('ENABLE_FLASK_COMPRESS'):
     Compress(app)
 
-Talisman(app, content_security_policy=None)
+if app.config['TALISMAN_ENABLED']:
+    talisman_config = app.config.get('TALISMAN_CONFIG')
+    Talisman(app, **talisman_config)
 
 # Hook that provides administrators a handle on the Flask APP
 # after initialization
diff --git a/superset/config.py b/superset/config.py
index b1052fe..8d11f0b 100644
--- a/superset/config.py
+++ b/superset/config.py
@@ -600,6 +600,15 @@ DEFAULT_RELATIVE_END_TIME = 'today'
 IS_EPOCH_S_TRULY_UTC = False
 
 
+# Do you want Talisman enabled?
+TALISMAN_ENABLED = True
+# If you want Talisman, how do you want it configured??
+TALISMAN_CONFIG = {
+    'content_security_policy': None,
+    'force_https': True,
+    'force_https_permanent': False,
+}
+
 try:
     if CONFIG_PATH_ENV_VAR in os.environ:
         # Explicitly import config module that is not in pythonpath; useful


[incubator-superset] 07/13: Adding controls for verifying options (#7468)

Posted by mi...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

michellet pushed a commit to branch release--0.33
in repository https://gitbox.apache.org/repos/asf/incubator-superset.git

commit c4dc38a34d6bddfc667fe2db5e44889c67380920
Author: michellethomas <mi...@gmail.com>
AuthorDate: Wed May 22 16:39:01 2019 -0700

    Adding controls for verifying options (#7468)
    
    * Creating withVerification HOC
    
    * Updating to use componentDidMount and componentDidUpdate and adding propTypes
    
    * Adding tests to withVerification
    
    * Adding documentation to withVerification
    
    (cherry picked from commit 421183d3f46c48215e88e9d7d285f2dc6c7ccfe6)
---
 .../explore/components/withVerification_spec.jsx   | 106 +++++++++++++++++++++
 .../src/explore/components/controls/index.js       |   4 +
 .../components/controls/withVerification.jsx       |  88 +++++++++++++++++
 3 files changed, 198 insertions(+)

diff --git a/superset/assets/spec/javascripts/explore/components/withVerification_spec.jsx b/superset/assets/spec/javascripts/explore/components/withVerification_spec.jsx
new file mode 100644
index 0000000..44377ea
--- /dev/null
+++ b/superset/assets/spec/javascripts/explore/components/withVerification_spec.jsx
@@ -0,0 +1,106 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+import React from 'react';
+import sinon from 'sinon';
+import { shallow } from 'enzyme';
+import fetchMock from 'fetch-mock';
+
+import MetricsControl from '../../../../src/explore/components/controls/MetricsControl';
+import withVerification from '../../../../src/explore/components/controls/withVerification';
+
+const defaultProps = {
+  name: 'metrics',
+  label: 'Metrics',
+  value: undefined,
+  multi: true,
+  columns: [
+    { type: 'VARCHAR(255)', column_name: 'source' },
+    { type: 'VARCHAR(255)', column_name: 'target' },
+    { type: 'DOUBLE', column_name: 'value' },
+  ],
+  savedMetrics: [
+    { metric_name: 'sum__value', expression: 'SUM(energy_usage.value)' },
+    { metric_name: 'avg__value', expression: 'AVG(energy_usage.value)' },
+  ],
+  datasourceType: 'sqla',
+  getEndpoint: controlValues => `valid_metrics?data=${controlValues}`,
+};
+
+const VALID_METRIC = { metric_name: 'sum__value', expression: 'SUM(energy_usage.value)' };
+
+function setup(overrides) {
+  const onChange = sinon.spy();
+  const props = {
+    onChange,
+    ...defaultProps,
+    ...overrides,
+  };
+  const VerifiedControl = withVerification(MetricsControl, 'metric_name', 'savedMetrics');
+  const wrapper = shallow(<VerifiedControl {...props} />);
+  fetchMock.mock('glob:*/valid_metrics*', `["${VALID_METRIC.metric_name}"]`);
+  return { props, wrapper, onChange };
+}
+
+afterEach(fetchMock.restore);
+
+describe('VerifiedMetricsControl', () => {
+
+  it('Gets valid options', () => {
+    const { wrapper } = setup();
+    setTimeout(() => {
+      expect(fetchMock.calls(defaultProps.getEndpoint())).toHaveLength(1);
+      expect(wrapper.state('validOptions')).toEqual([VALID_METRIC]);
+      fetchMock.reset();
+    }, 0);
+  });
+
+  it('Returns verified options', () => {
+    const { wrapper } = setup();
+    setTimeout(() => {
+      expect(fetchMock.calls(defaultProps.getEndpoint())).toHaveLength(1);
+      const child = wrapper.find(MetricsControl);
+      expect(child.props().savedMetrics).toEqual([VALID_METRIC]);
+      fetchMock.reset();
+    }, 0);
+  });
+
+  it('Makes no calls if endpoint is not set', () => {
+    const { wrapper } = setup({
+      getEndpoint: () => null,
+    });
+    setTimeout(() => {
+      expect(fetchMock.calls(defaultProps.getEndpoint())).toHaveLength(0);
+      expect(wrapper.state('validOptions')).toEqual(new Set());
+      fetchMock.reset();
+    }, 0);
+  });
+
+  it('Calls endpoint if control values change', () => {
+    const { props, wrapper } = setup({ controlValues: { metrics: 'sum__value' } });
+    setTimeout(() => {
+      expect(fetchMock.calls(defaultProps.getEndpoint())).toHaveLength(1);
+      fetchMock.reset();
+    }, 0);
+    wrapper.setProps({ ...props, controlValues: { metrics: 'avg__value' } });
+    setTimeout(() => {
+      expect(fetchMock.calls(defaultProps.getEndpoint())).toHaveLength(1);
+      fetchMock.reset();
+    }, 0);
+  });
+});
diff --git a/superset/assets/src/explore/components/controls/index.js b/superset/assets/src/explore/components/controls/index.js
index d1a2f2c..f96d728 100644
--- a/superset/assets/src/explore/components/controls/index.js
+++ b/superset/assets/src/explore/components/controls/index.js
@@ -39,6 +39,7 @@ import MetricsControl from './MetricsControl';
 import AdhocFilterControl from './AdhocFilterControl';
 import FilterPanel from './FilterPanel';
 import FilterBoxItemControl from './FilterBoxItemControl';
+import withVerification from './withVerification';
 
 const controlMap = {
   AnnotationLayerControl,
@@ -64,5 +65,8 @@ const controlMap = {
   AdhocFilterControl,
   FilterPanel,
   FilterBoxItemControl,
+  MetricsControlVerifiedOptions: withVerification(MetricsControl, 'metric_name', 'savedMetrics'),
+  SelectControlVerifiedOptions: withVerification(SelectControl, 'column_name', 'options'),
+  AdhocFilterControlVerifiedOptions: withVerification(AdhocFilterControl, 'column_name', 'columns'),
 };
 export default controlMap;
diff --git a/superset/assets/src/explore/components/controls/withVerification.jsx b/superset/assets/src/explore/components/controls/withVerification.jsx
new file mode 100644
index 0000000..8f1e549
--- /dev/null
+++ b/superset/assets/src/explore/components/controls/withVerification.jsx
@@ -0,0 +1,88 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+import React from 'react';
+import { SupersetClient } from '@superset-ui/connection';
+
+import { isEqual } from 'lodash';
+
+export default function withVerification(WrappedComponent, optionLabel, optionsName) {
+  /*
+   * This function will verify control options before passing them to the control by calling an
+   * endpoint on mount and when the controlValues change. controlValues should be set in
+   * mapStateToProps that can be added as a control override along with getEndpoint.
+   */
+  class withVerificationComponent extends React.Component {
+    constructor(props) {
+      super(props);
+      this.state = {
+        validOptions: new Set(),
+        hasRunVerification: false,
+      };
+
+      this.getValidOptions = this.getValidOptions.bind(this);
+    }
+
+    componentDidMount() {
+      this.getValidOptions();
+    }
+
+    componentDidUpdate(prevProps) {
+      const { hasRunVerification } = this.state;
+      if (!isEqual(this.props.controlValues, prevProps.controlValues) || !hasRunVerification) {
+        this.getValidOptions();
+      }
+    }
+
+    getValidOptions() {
+      const endpoint = this.props.getEndpoint(this.props.controlValues);
+      if (endpoint) {
+        SupersetClient.get({
+          endpoint,
+        }).then(({ json }) => {
+          if (Array.isArray(json)) {
+            this.setState({ validOptions: new Set(json) || new Set() });
+          }
+        }).catch(error => console.log(error));
+
+        if (!this.state.hasRunVerification) {
+          this.setState({ hasRunVerification: true });
+        }
+      }
+    }
+
+    render() {
+      const { validOptions } = this.state;
+      const options = this.props[optionsName];
+      const verifiedOptions = validOptions.size ?
+        options.filter(o => (validOptions.has(o[optionLabel]))) :
+        options;
+
+      const newProps = { ...this.props, [optionsName]: verifiedOptions };
+
+      return (
+        <WrappedComponent
+          {...newProps}
+        />
+      );
+    }
+  }
+  withVerificationComponent.propTypes = WrappedComponent.propTypes;
+  return withVerificationComponent;
+}
+


[incubator-superset] 04/13: [sql lab] Fix new query stuck at pending state (#7523)

Posted by mi...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

michellet pushed a commit to branch release--0.33
in repository https://gitbox.apache.org/repos/asf/incubator-superset.git

commit e4bed9d5aab160842a3294b284c0bf446dc9547b
Author: Grace Guo <gr...@airbnb.com>
AuthorDate: Thu May 16 15:22:23 2019 -0700

    [sql lab] Fix new query stuck at pending state (#7523)
    
    
    (cherry picked from commit 7f858e4566bd4944a904c0530709e0ba0a89eb5e)
---
 superset/assets/src/SqlLab/components/QueryAutoRefresh.jsx | 3 +--
 1 file changed, 1 insertion(+), 2 deletions(-)

diff --git a/superset/assets/src/SqlLab/components/QueryAutoRefresh.jsx b/superset/assets/src/SqlLab/components/QueryAutoRefresh.jsx
index 6db56d7..16aff30 100644
--- a/superset/assets/src/SqlLab/components/QueryAutoRefresh.jsx
+++ b/superset/assets/src/SqlLab/components/QueryAutoRefresh.jsx
@@ -38,11 +38,10 @@ class QueryAutoRefresh extends React.PureComponent {
   }
   shouldCheckForQueries() {
     // if there are started or running queries, this method should return true
-    const { queries, queriesLastUpdate } = this.props;
+    const { queries } = this.props;
     const now = new Date().getTime();
 
     return (
-      queriesLastUpdate > 0 &&
       Object.values(queries).some(
         q => ['running', 'started', 'pending', 'fetching'].indexOf(q.state) >= 0 &&
         now - q.startDttm < MAX_QUERY_AGE_TO_POLL,


[incubator-superset] 02/13: [SQL Lab] Increase timeout threshold for offline check (#7411)

Posted by mi...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

michellet pushed a commit to branch release--0.33
in repository https://gitbox.apache.org/repos/asf/incubator-superset.git

commit 703d13fa0bd610f9e2cb10eece414e5a5a2f9fa0
Author: Grace Guo <gr...@airbnb.com>
AuthorDate: Tue Apr 30 00:56:44 2019 -0700

    [SQL Lab] Increase timeout threshold for offline check (#7411)
    
    
    (cherry picked from commit 11408d01894c6408f95597b1ef032d03df6a7397)
---
 superset/assets/src/SqlLab/components/QueryAutoRefresh.jsx | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/superset/assets/src/SqlLab/components/QueryAutoRefresh.jsx b/superset/assets/src/SqlLab/components/QueryAutoRefresh.jsx
index 541ce2d..6db56d7 100644
--- a/superset/assets/src/SqlLab/components/QueryAutoRefresh.jsx
+++ b/superset/assets/src/SqlLab/components/QueryAutoRefresh.jsx
@@ -27,7 +27,7 @@ import * as Actions from '../actions/sqlLab';
 const QUERY_UPDATE_FREQ = 2000;
 const QUERY_UPDATE_BUFFER_MS = 5000;
 const MAX_QUERY_AGE_TO_POLL = 21600000;
-const QUERY_TIMEOUT_LIMIT = 7000;
+const QUERY_TIMEOUT_LIMIT = 10000;
 
 class QueryAutoRefresh extends React.PureComponent {
   componentWillMount() {


[incubator-superset] 06/13: [testconn] Explicit closing engine connection (#7570)

Posted by mi...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

michellet pushed a commit to branch release--0.33
in repository https://gitbox.apache.org/repos/asf/incubator-superset.git

commit ad37673609bf216af58f64cafe9bf3dda566b2f7
Author: John Bodley <45...@users.noreply.github.com>
AuthorDate: Wed May 22 09:42:03 2019 -0700

    [testconn] Explicit closing engine connection (#7570)
    
    (cherry picked from commit e5739fbbd2eb9150a5ec889cd38f588501945a43)
---
 superset/views/core.py | 9 ++++++---
 1 file changed, 6 insertions(+), 3 deletions(-)

diff --git a/superset/views/core.py b/superset/views/core.py
index 019d400..32cabad 100755
--- a/superset/views/core.py
+++ b/superset/views/core.py
@@ -15,6 +15,7 @@
 # specific language governing permissions and limitations
 # under the License.
 # pylint: disable=C,R,W
+from contextlib import closing
 from datetime import datetime, timedelta
 import inspect
 import logging
@@ -38,7 +39,8 @@ import pandas as pd
 import simplejson as json
 import sqlalchemy as sqla
 from sqlalchemy import (
-    and_, Column, create_engine, ForeignKey, Integer, MetaData, or_, Table, update)
+    and_, Column, create_engine, ForeignKey, Integer, MetaData, or_, select, Table,
+    update)
 from sqlalchemy.engine.url import make_url
 from sqlalchemy.exc import IntegrityError
 from werkzeug.routing import BaseConverter
@@ -1806,8 +1808,9 @@ class Superset(BaseSupersetView):
                 connect_args['configuration'] = configuration
 
             engine = create_engine(uri, **engine_params)
-            engine.connect()
-            return json_success(json.dumps(engine.table_names(), indent=4))
+
+            with closing(engine.connect()) as conn:
+                return json_success(json.dumps(conn.scalar(select([1]))))
         except Exception as e:
             logging.exception(e)
             return json_error_response((