superset-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From b...@apache.org
Subject [incubator-superset] branch lyft-develop updated: Validate start/end when scheduling queries (#7528)
Date Thu, 16 May 2019 19:47:25 GMT
This is an automated email from the ASF dual-hosted git repository.

beto pushed a commit to branch lyft-develop
in repository https://gitbox.apache.org/repos/asf/incubator-superset.git


The following commit(s) were added to refs/heads/lyft-develop by this push:
     new 5c86a40  Validate start/end when scheduling queries (#7528)
5c86a40 is described below

commit 5c86a40dc053b2c370e49bca3bf5d4d0ea82c755
Author: Beto Dealmeida <roberto@dealmeida.net>
AuthorDate: Thu May 16 12:47:14 2019 -0700

    Validate start/end when scheduling queries (#7528)
    
    * Validate start/end when scheduling queries
    
    * Use chrono instead of Sugar
---
 docs/installation.rst                              | 20 ++++++++-
 superset/assets/package-lock.json                  | 15 +++++++
 superset/assets/package.json                       |  1 +
 .../src/SqlLab/components/ScheduleQueryButton.jsx  | 50 +++++++++++++++++++++-
 4 files changed, 82 insertions(+), 4 deletions(-)

diff --git a/docs/installation.rst b/docs/installation.rst
index c7c24fc..82459c7 100644
--- a/docs/installation.rst
+++ b/docs/installation.rst
@@ -858,13 +858,19 @@ To allow scheduled queries, add the following to your `config.py`:
                     },
                     'start_date': {
                         'type': 'string',
-                        'format': 'date-time',
                         'title': 'Start date',
+                        # date-time is parsed using the chrono library, see
+                        # https://www.npmjs.com/package/chrono-node#usage
+                        'format': 'date-time',
+                        'default': 'tomorrow at 9am',
                     },
                     'end_date': {
                         'type': 'string',
-                        'format': 'date-time',
                         'title': 'End date',
+                        # date-time is parsed using the chrono library, see
+                        # https://www.npmjs.com/package/chrono-node#usage
+                        'format': 'date-time',
+                        'default': '9am in 30 days',
                     },
                     'schedule_interval': {
                         'type': 'string',
@@ -890,6 +896,16 @@ To allow scheduled queries, add the following to your `config.py`:
                     ),
                 },
             },
+            'VALIDATION': [
+                # ensure that start_date <= end_date
+                {
+                    'name': 'less_equal',
+                    'arguments': ['start_date', 'end_date'],
+                    'message': 'End date cannot be before start date',
+                    # this is where the error message is shown
+                    'container': 'end_date',
+                },
+            ],
         },
     }
 
diff --git a/superset/assets/package-lock.json b/superset/assets/package-lock.json
index e5075d9..da886a0 100644
--- a/superset/assets/package-lock.json
+++ b/superset/assets/package-lock.json
@@ -5662,6 +5662,21 @@
         "tslib": "^1.9.0"
       }
     },
+    "chrono-node": {
+      "version": "1.3.11",
+      "resolved": "https://registry.npmjs.org/chrono-node/-/chrono-node-1.3.11.tgz",
+      "integrity": "sha512-jDWRnY6nYvzfV3HPYBqo+tot7tcsUs9i3arGbMdI0TouPSXP2C2y/Ctp27rxKTQDi6yuTxAB2cw+Q6igGhOhdQ==",
+      "requires": {
+        "moment": "2.21.0"
+      },
+      "dependencies": {
+        "moment": {
+          "version": "2.21.0",
+          "resolved": "https://registry.npmjs.org/moment/-/moment-2.21.0.tgz",
+          "integrity": "sha512-TCZ36BjURTeFTM/CwRcViQlfkMvL1/vFISuNLO5GkcVm1+QHfbSiNqZuWeMFjj1/3+uAjXswgRk30j1kkLYJBQ=="
+        }
+      }
+    },
     "ci-info": {
       "version": "2.0.0",
       "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-2.0.0.tgz",
diff --git a/superset/assets/package.json b/superset/assets/package.json
index 6edb971..52e82b1 100644
--- a/superset/assets/package.json
+++ b/superset/assets/package.json
@@ -84,6 +84,7 @@
     "bootstrap": "^3.3.6",
     "bootstrap-slider": "^10.0.0",
     "brace": "^0.11.1",
+    "chrono-node": "^1.3.11",
     "classnames": "^2.2.5",
     "d3-array": "^1.2.4",
     "d3-color": "^1.2.0",
diff --git a/superset/assets/src/SqlLab/components/ScheduleQueryButton.jsx b/superset/assets/src/SqlLab/components/ScheduleQueryButton.jsx
index 2e7e16e..99ecaa5 100644
--- a/superset/assets/src/SqlLab/components/ScheduleQueryButton.jsx
+++ b/superset/assets/src/SqlLab/components/ScheduleQueryButton.jsx
@@ -19,11 +19,56 @@
 import React from 'react';
 import PropTypes from 'prop-types';
 import Form from 'react-jsonschema-form';
+import chrono from 'chrono-node';
 import { t } from '@superset-ui/translation';
 
 import Button from '../../components/Button';
 import ModalTrigger from '../../components/ModalTrigger';
 
+const validators = {
+  greater: (a, b) => a > b,
+  greater_equal: (a, b) => a >= b,
+  less: (a, b) => a < b,
+  less_equal: (a, b) => a <= b,
+};
+
+function getJSONSchema() {
+  const jsonSchema = window.featureFlags.SCHEDULED_QUERIES.JSONSCHEMA;
+  // parse date-time into usable value (eg, 'today' => `new Date()`)
+  Object.entries(jsonSchema.properties).forEach(([key, properties]) => {
+    if (properties.default && properties.format === 'date-time') {
+      jsonSchema.properties[key] = {
+        ...properties,
+        default: chrono.parseDate(properties.default).toISOString(),
+      };
+    }
+  });
+  return jsonSchema;
+}
+
+function getUISchema() {
+  return window.featureFlags.SCHEDULED_QUERIES.UISCHEMA;
+}
+
+function getValidationRules() {
+  return window.featureFlags.SCHEDULED_QUERIES.VALIDATION || [];
+}
+
+function getValidator() {
+  const rules = getValidationRules();
+  return (formData, errors) => {
+    rules.forEach((rule) => {
+      const test = validators[rule.name];
+      const args = rule.arguments.map(name => formData[name]);
+      const container = rule.container || rule.arguments.slice(-1)[0];
+      if (!test(...args)) {
+        errors[container].addError(rule.message);
+      }
+    });
+    return errors;
+  };
+}
+
 const propTypes = {
   defaultLabel: PropTypes.string,
   sql: PropTypes.string.isRequired,
@@ -79,9 +124,10 @@ class ScheduleQueryButton extends React.PureComponent {
   renderModalBody() {
     return (
       <Form
-        schema={window.featureFlags.SCHEDULED_QUERIES.JSONSCHEMA}
-        uiSchema={window.featureFlags.SCHEDULED_QUERIES.UISCHEMA}
+        schema={getJSONSchema()}
+        uiSchema={getUISchema()}
         onSubmit={this.onSchedule}
+        validate={getValidator()}
       />
     );
   }


Mime
View raw message