This is an automated email from the ASF dual-hosted git repository.
beto pushed a commit to branch lyft-release-sp8
in repository https://gitbox.apache.org/repos/asf/incubator-superset.git
The following commit(s) were added to refs/heads/lyft-release-sp8 by this push:
new c7f8f27 Validate start/end when scheduling queries (#7508)
c7f8f27 is described below
commit c7f8f274df1a37cead0b3fa9cd145c491e48dc4c
Author: Beto Dealmeida <[email protected]>
AuthorDate: Thu May 16 10:39:08 2019 -0700
Validate start/end when scheduling queries (#7508)
* 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()}
/>
);
}