From 46c6987e57a69f64b090c6b9b7e872d3d80aa05d Mon Sep 17 00:00:00 2001 From: Arik Fraimovich Date: Fri, 30 Aug 2019 19:42:40 +0300 Subject: [PATCH 01/12] Initial commit of BeaconConsent component --- client/app/components/BeaconConsent.jsx | 36 +++++++++++++++++ client/app/pages/home/home.html | 52 +++++++++++++++++++------ 2 files changed, 76 insertions(+), 12 deletions(-) create mode 100644 client/app/components/BeaconConsent.jsx diff --git a/client/app/components/BeaconConsent.jsx b/client/app/components/BeaconConsent.jsx new file mode 100644 index 0000000000..8754011d4a --- /dev/null +++ b/client/app/components/BeaconConsent.jsx @@ -0,0 +1,36 @@ +import React from 'react'; +import { react2angular } from 'react2angular'; +import Card from 'antd/lib/card'; +import Button from 'antd/lib/button'; +import Text from 'antd/lib/typography'; + +export function BeaconConsent() { + // if (!clientConfig.showBeaconConsentMessage) { + // return; + // } + + return ( +
+ + + Shared data includes: number of users, queries, dashboards, alerts, widgets and visulizations. Also types of + data sources, alert destination and visualizations. + + All the data is aggregated and does not include anything sensitive or private. +
+ + +
+
+
+ ); +} + +export default function init(ngModule) { + console.log('hello world'); + ngModule.component('beaconConsent', react2angular(BeaconConsent)); +} + +init.init = true; diff --git a/client/app/pages/home/home.html b/client/app/pages/home/home.html index 0e362af2b5..29d8eace91 100644 --- a/client/app/pages/home/home.html +++ b/client/app/pages/home/home.html @@ -1,9 +1,24 @@
-
- You have enabled ALLOW_PARAMETERS_IN_EMBEDS. This setting is now deprecated and should be turned off. Parameters in embeds are supported by default. Read more. +
+ You have enabled ALLOW_PARAMETERS_IN_EMBEDS. This setting is + now deprecated and should be turned off. Parameters in embeds are supported + by default. + Read more.
-
- We have sent an email with a confirmation link to your email address. Please follow the link to verify your email address. Resend email. +
+ We have sent an email with a confirmation link to your email address. Please + follow the link to verify your email address. + Resend email.
@@ -51,17 +72,24 @@ Favorite Queries will appear here

- + From a06b019a85888e776bcbe5236167387e3c8570ad Mon Sep 17 00:00:00 2001 From: Arik Fraimovich Date: Fri, 30 Aug 2019 19:50:49 +0300 Subject: [PATCH 02/12] Add comment about being able to change setting --- client/app/components/BeaconConsent.jsx | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/client/app/components/BeaconConsent.jsx b/client/app/components/BeaconConsent.jsx index 8754011d4a..a8acec0a9f 100644 --- a/client/app/components/BeaconConsent.jsx +++ b/client/app/components/BeaconConsent.jsx @@ -23,13 +23,17 @@ export function BeaconConsent() { +
+ + You can always change your descision from the Organization Settings screen. + +
); } export default function init(ngModule) { - console.log('hello world'); ngModule.component('beaconConsent', react2angular(BeaconConsent)); } From 8506d2094cc8179fab66737072710b4d13c838c1 Mon Sep 17 00:00:00 2001 From: Arik Fraimovich Date: Fri, 30 Aug 2019 20:00:09 +0300 Subject: [PATCH 03/12] Use correctly --- client/app/components/BeaconConsent.jsx | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/client/app/components/BeaconConsent.jsx b/client/app/components/BeaconConsent.jsx index a8acec0a9f..01b34bf70a 100644 --- a/client/app/components/BeaconConsent.jsx +++ b/client/app/components/BeaconConsent.jsx @@ -2,7 +2,9 @@ import React from 'react'; import { react2angular } from 'react2angular'; import Card from 'antd/lib/card'; import Button from 'antd/lib/button'; -import Text from 'antd/lib/typography'; +import Typography from 'antd/lib/typography'; + +const Text = Typography.Text; export function BeaconConsent() { // if (!clientConfig.showBeaconConsentMessage) { @@ -12,7 +14,7 @@ export function BeaconConsent() { return (
- + Shared data includes: number of users, queries, dashboards, alerts, widgets and visulizations. Also types of data sources, alert destination and visualizations. @@ -25,7 +27,8 @@ export function BeaconConsent() {
- You can always change your descision from the Organization Settings screen. + You can always change your descision from the Organization Settings{' '} + screen.
From 40b7845bdb5e761b6b18b3dd3d8c36a2c8b4bc1f Mon Sep 17 00:00:00 2001 From: Arik Fraimovich Date: Mon, 9 Sep 2019 17:56:42 +0300 Subject: [PATCH 04/12] Final version of consent screen --- client/app/components/BeaconConsent.jsx | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/client/app/components/BeaconConsent.jsx b/client/app/components/BeaconConsent.jsx index 01b34bf70a..fb4784085e 100644 --- a/client/app/components/BeaconConsent.jsx +++ b/client/app/components/BeaconConsent.jsx @@ -13,12 +13,15 @@ export function BeaconConsent() { return (
- - - Shared data includes: number of users, queries, dashboards, alerts, widgets and visulizations. Also types of - data sources, alert destination and visualizations. - - All the data is aggregated and does not include anything sensitive or private. + + Help Redash improve by automatically sending anonymous usage data: +
+
    +
  • Number of users, queries, dashboards, alerts, widgets and visualizations.
  • +
  • Types of data sources, alert destinations and visualizations.
  • +
+
+ All data is aggregated and will never include any sensitive or private data.
- You can always change your descision from the Organization Settings{' '} - screen. + You can change this setting anytime from the Organization Settings page.
From 6cbc28b31047fa0dc3dded869c3c5bbd96b2065c Mon Sep 17 00:00:00 2001 From: Arik Fraimovich Date: Tue, 10 Sep 2019 12:54:12 +0300 Subject: [PATCH 05/12] Show beacon consent message on homepage only if it wasn't enabled already. --- client/app/components/BeaconConsent.jsx | 17 +++++++++++++---- redash/handlers/authentication.py | 3 +++ redash/settings/organization.py | 1 + 3 files changed, 17 insertions(+), 4 deletions(-) diff --git a/client/app/components/BeaconConsent.jsx b/client/app/components/BeaconConsent.jsx index fb4784085e..b17a9fb885 100644 --- a/client/app/components/BeaconConsent.jsx +++ b/client/app/components/BeaconConsent.jsx @@ -3,13 +3,22 @@ import { react2angular } from 'react2angular'; import Card from 'antd/lib/card'; import Button from 'antd/lib/button'; import Typography from 'antd/lib/typography'; +import { clientConfig } from '@/services/auth'; const Text = Typography.Text; export function BeaconConsent() { - // if (!clientConfig.showBeaconConsentMessage) { - // return; - // } + if (!clientConfig.showBeaconConsentMessage) { + return; + } + + // import OrgSettings from '@/services/organizationSettings'; + // OrgSettings.save(this.state.formValues) + // .then((response) => { + // const settings = get(response, 'settings'); + // this.setState({ settings, formValues: { ...settings } }); + // }) + // .finally(() => this.setState({ submitting: false })); return (
@@ -22,7 +31,7 @@ export function BeaconConsent() {
All data is aggregated and will never include any sensitive or private data. -
+
diff --git a/redash/handlers/authentication.py b/redash/handlers/authentication.py index a698dfb496..4b2e151228 100644 --- a/redash/handlers/authentication.py +++ b/redash/handlers/authentication.py @@ -225,6 +225,9 @@ def client_config(): } else: client_config = {} + + if current_user.has_permission('admin') and current_org.get_setting('beacon_consent') is None: + client_config['showBeaconConsentMessage'] = True defaults = { 'allowScriptsInUserInput': settings.ALLOW_SCRIPTS_IN_USER_INPUT, diff --git a/redash/settings/organization.py b/redash/settings/organization.py index 37c5b73260..853a6cd4ec 100644 --- a/redash/settings/organization.py +++ b/redash/settings/organization.py @@ -35,6 +35,7 @@ os.environ.get('REDASH_SEND_EMAIL_ON_FAILED_SCHEDULED_QUERIES', 'false')) settings = { + "beacon_consent": None, "auth_password_login_enabled": PASSWORD_LOGIN_ENABLED, "auth_saml_enabled": SAML_LOGIN_ENABLED, "auth_saml_entity_id": SAML_ENTITY_ID, From 4f1ad90bfee03bc1cab1f03852ff5002047b8394 Mon Sep 17 00:00:00 2001 From: Arik Fraimovich Date: Tue, 10 Sep 2019 12:55:20 +0300 Subject: [PATCH 06/12] Add consent setting to organization settings screen. --- .../pages/settings/OrganizationSettings.jsx | 31 ++++++++++++------- 1 file changed, 20 insertions(+), 11 deletions(-) diff --git a/client/app/pages/settings/OrganizationSettings.jsx b/client/app/pages/settings/OrganizationSettings.jsx index 75bdfbbf0e..632649cbd6 100644 --- a/client/app/pages/settings/OrganizationSettings.jsx +++ b/client/app/pages/settings/OrganizationSettings.jsx @@ -155,16 +155,16 @@ class OrganizationSettings extends React.Component { ))} - + this.handleChange('multi_byte_search_enabled', e.target.checked)} + name="feature_show_permissions_control" + checked={formValues.feature_show_permissions_control} + onChange={e => this.handleChange('feature_show_permissions_control', e.target.checked)} > - Enable multi-byte (Chinese, Japanese, and Korean) search for query names and descriptions (slower) + Enable experimental multiple owners support - + Email query owners when scheduled queries fail - + this.handleChange('feature_show_permissions_control', e.target.checked)} + name="multi_byte_search_enabled" + checked={formValues.multi_byte_search_enabled} + onChange={e => this.handleChange('multi_byte_search_enabled', e.target.checked)} > - Enable experimental multiple owners support + Enable multi-byte (Chinese, Japanese, and Korean) search for query names and descriptions (slower) + + + + this.handleChange('beacon_consent', e.target.checked)} + > + Help Redash improve by automatically sending anonymous usage data From b98cf41b9ad8041dad07999c9f40fdca5dabb896 Mon Sep 17 00:00:00 2001 From: Arik Fraimovich Date: Tue, 10 Sep 2019 13:21:40 +0300 Subject: [PATCH 07/12] Add support for custom message in OrgSetting.save. --- client/app/services/organizationSettings.js | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/client/app/services/organizationSettings.js b/client/app/services/organizationSettings.js index 1226bd35a6..dde3c01ea6 100644 --- a/client/app/services/organizationSettings.js +++ b/client/app/services/organizationSettings.js @@ -3,10 +3,13 @@ import notification from '@/services/notification'; export default { get: () => $http.get('api/settings/organization').then(response => response.data), - save: data => $http.post('api/settings/organization', data).then((response) => { - notification.success('Settings changes saved.'); - return response.data; - }).catch(() => { - notification.error('Failed saving changes.'); - }), + save: (data, message = 'Settings changes saved.') => $http + .post('api/settings/organization', data) + .then((response) => { + notification.success(message); + return response.data; + }) + .catch(() => { + notification.error('Failed saving changes.'); + }), }; From e6b4b4f8311a7ef2ecabf4bcff91af2db3e3fc35 Mon Sep 17 00:00:00 2001 From: Arik Fraimovich Date: Tue, 10 Sep 2019 13:22:03 +0300 Subject: [PATCH 08/12] Implmenet consent saving. --- client/app/components/BeaconConsent.jsx | 41 +++++++++++++++++-------- 1 file changed, 29 insertions(+), 12 deletions(-) diff --git a/client/app/components/BeaconConsent.jsx b/client/app/components/BeaconConsent.jsx index b17a9fb885..fc1fe584a4 100644 --- a/client/app/components/BeaconConsent.jsx +++ b/client/app/components/BeaconConsent.jsx @@ -1,24 +1,39 @@ -import React from 'react'; +import React, { useState } from 'react'; import { react2angular } from 'react2angular'; import Card from 'antd/lib/card'; import Button from 'antd/lib/button'; import Typography from 'antd/lib/typography'; import { clientConfig } from '@/services/auth'; +import OrgSettings from '@/services/organizationSettings'; const Text = Typography.Text; export function BeaconConsent() { - if (!clientConfig.showBeaconConsentMessage) { - return; + const [hide, setHide] = useState(false); + + if (!clientConfig.showBeaconConsentMessage || hide) { + return null; } - // import OrgSettings from '@/services/organizationSettings'; - // OrgSettings.save(this.state.formValues) - // .then((response) => { - // const settings = get(response, 'settings'); - // this.setState({ settings, formValues: { ...settings } }); - // }) - // .finally(() => this.setState({ submitting: false })); + const hideConsentCard = () => { + clientConfig.showBeaconConsentMessage = false; + setHide(true); + }; + + const confirmConsent = (confirm) => { + let message = '🙏 Thank you.'; + + if (!confirm) { + message = 'Settings Saved.'; + } + + OrgSettings.save({ beacon_consent: confirm }, message) + // .then(() => { + // // const settings = get(response, 'settings'); + // // this.setState({ settings, formValues: { ...settings } }); + // }) + .finally(hideConsentCard); + }; return (
@@ -32,10 +47,12 @@ export function BeaconConsent() {
All data is aggregated and will never include any sensitive or private data.
- - +
From 0684a547bc02b6938f4f6ba5369e0fbcaeabd6ea Mon Sep 17 00:00:00 2001 From: Arik Fraimovich Date: Tue, 10 Sep 2019 13:45:39 +0300 Subject: [PATCH 09/12] If consent given, send extra data --- redash/version_check.py | 59 ++++++++++++++++++++++++++++++++++++++--- 1 file changed, 55 insertions(+), 4 deletions(-) diff --git a/redash/version_check.py b/redash/version_check.py index 8d6e5b0bfd..bdf9b96644 100644 --- a/redash/version_check.py +++ b/redash/version_check.py @@ -4,23 +4,74 @@ from redash import __version__ as current_version from redash import redis_connection +from redash.models import db, Organization from redash.utils import json_dumps REDIS_KEY = "new_version_available" +def usage_data(): + counts_query = """ + SELECT 'users_count' as name, count(0) as value + FROM users + WHERE disabled_at is null + + UNION ALL + + SELECT 'queries_count' as name, count(0) as value + FROM queries + WHERE is_archived is false + + UNION ALL + + SELECT 'alerts_count' as name, count(0) as value + FROM alerts + + UNION ALL + + SELECT 'dashboards_count' as name, count(0) as value + FROM dashboards + WHERE is_archived is false + + UNION ALL + + SELECT 'widgets_count' as name, count(0) as value + FROM widgets + WHERE visualization_id is not null + + UNION ALL + + SELECT 'textbox_count' as name, count(0) as value + FROM widgets + WHERE visualization_id is null + """ + + data_sources_query = "SELECT type, count(0) FROM data_sources GROUP by 1" + visualizations_query = "SELECT type, count(0) FROM visualizations GROUP by 1" + destinations_query = "SELECT type, count(0) FROM notification_destinations GROUP by 1" + + data = {name: value for (name, value) in db.session.execute(counts_query)} + data['data_sources'] = {name: value for (name, value) in db.session.execute(data_sources_query)} + data['visualization_types'] = {name: value for (name, value) in db.session.execute(visualizations_query)} + data['destination_types'] = {name: value for (name, value) in db.session.execute(destinations_query)} + + return data + + def run_version_check(): logging.info("Performing version check.") logging.info("Current version: %s", current_version) - data = json_dumps({ + data = { 'current_version': current_version - }) - headers = {'content-type': 'application/json'} + } + + if Organization.query.first().get_setting('beacon_consent'): + data['usage'] = usage_data() try: response = requests.post('https://version.redash.io/api/report?channel=stable', - data=data, headers=headers, timeout=3.0) + json=data, timeout=3.0) latest_version = response.json()['release']['version'] _compare_and_update(latest_version) From db89adbfc037dca858c8849fba90c283a427d57a Mon Sep 17 00:00:00 2001 From: Arik Fraimovich Date: Wed, 11 Sep 2019 11:04:47 +0300 Subject: [PATCH 10/12] Add HelpTrigger --- client/app/components/BeaconConsent.jsx | 11 ++++++++++- client/app/components/HelpTrigger.jsx | 4 ++++ client/app/pages/settings/OrganizationSettings.jsx | 2 +- 3 files changed, 15 insertions(+), 2 deletions(-) diff --git a/client/app/components/BeaconConsent.jsx b/client/app/components/BeaconConsent.jsx index fc1fe584a4..0cad3113d1 100644 --- a/client/app/components/BeaconConsent.jsx +++ b/client/app/components/BeaconConsent.jsx @@ -4,6 +4,7 @@ import Card from 'antd/lib/card'; import Button from 'antd/lib/button'; import Typography from 'antd/lib/typography'; import { clientConfig } from '@/services/auth'; +import { HelpTrigger } from '@/components/HelpTrigger'; import OrgSettings from '@/services/organizationSettings'; const Text = Typography.Text; @@ -37,7 +38,15 @@ export function BeaconConsent() { return (
- + + Would you be ok with sharing anonymous usage data with the Redash team?{' '} + + + )} + bordered={false} + > Help Redash improve by automatically sending anonymous usage data:
    diff --git a/client/app/components/HelpTrigger.jsx b/client/app/components/HelpTrigger.jsx index ce2bbd20ad..e3ece0cc9d 100644 --- a/client/app/components/HelpTrigger.jsx +++ b/client/app/components/HelpTrigger.jsx @@ -32,6 +32,10 @@ export const TYPES = { '/user-guide/users/authentication-options', 'Guide: Authentication Options', ], + USAGE_DATA_SHARING: [ + '/open-source/admin-guide/usage-data', + 'Help: Anonymous Usage Data Sharing', + ], DS_ATHENA: [ '/data-sources/amazon-athena-setup', 'Guide: Help Setting up Amazon Athena', diff --git a/client/app/pages/settings/OrganizationSettings.jsx b/client/app/pages/settings/OrganizationSettings.jsx index 632649cbd6..ba3cb69456 100644 --- a/client/app/pages/settings/OrganizationSettings.jsx +++ b/client/app/pages/settings/OrganizationSettings.jsx @@ -181,7 +181,7 @@ class OrganizationSettings extends React.Component { Enable multi-byte (Chinese, Japanese, and Korean) search for query names and descriptions (slower) - + Anonymous Usage Data Sharing }> Date: Wed, 11 Sep 2019 11:06:38 +0300 Subject: [PATCH 11/12] Make CodeClimate happy --- redash/handlers/authentication.py | 2 +- redash/version_check.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/redash/handlers/authentication.py b/redash/handlers/authentication.py index 4b2e151228..2a5082d601 100644 --- a/redash/handlers/authentication.py +++ b/redash/handlers/authentication.py @@ -225,7 +225,7 @@ def client_config(): } else: client_config = {} - + if current_user.has_permission('admin') and current_org.get_setting('beacon_consent') is None: client_config['showBeaconConsentMessage'] = True diff --git a/redash/version_check.py b/redash/version_check.py index bdf9b96644..0870460b8b 100644 --- a/redash/version_check.py +++ b/redash/version_check.py @@ -41,7 +41,7 @@ def usage_data(): UNION ALL - SELECT 'textbox_count' as name, count(0) as value + SELECT 'textbox_count' as name, count(0) as value FROM widgets WHERE visualization_id is null """ From 0c824ded0bb264408863cd11bb98c29b7fa19bfc Mon Sep 17 00:00:00 2001 From: Arik Fraimovich Date: Wed, 11 Sep 2019 11:12:16 +0300 Subject: [PATCH 12/12] Wrap everything with DynamicComponent --- client/app/components/BeaconConsent.jsx | 69 ++++++++++--------- .../pages/settings/OrganizationSettings.jsx | 23 ++++--- 2 files changed, 49 insertions(+), 43 deletions(-) diff --git a/client/app/components/BeaconConsent.jsx b/client/app/components/BeaconConsent.jsx index 0cad3113d1..e551eb6a0f 100644 --- a/client/app/components/BeaconConsent.jsx +++ b/client/app/components/BeaconConsent.jsx @@ -5,6 +5,7 @@ import Button from 'antd/lib/button'; import Typography from 'antd/lib/typography'; import { clientConfig } from '@/services/auth'; import { HelpTrigger } from '@/components/HelpTrigger'; +import DynamicComponent from '@/components/DynamicComponent'; import OrgSettings from '@/services/organizationSettings'; const Text = Typography.Text; @@ -37,39 +38,41 @@ export function BeaconConsent() { }; return ( -
    - - Would you be ok with sharing anonymous usage data with the Redash team?{' '} - - - )} - bordered={false} - > - Help Redash improve by automatically sending anonymous usage data: -
    -
      -
    • Number of users, queries, dashboards, alerts, widgets and visualizations.
    • -
    • Types of data sources, alert destinations and visualizations.
    • -
    -
    - All data is aggregated and will never include any sensitive or private data. -
    - - -
    -
    - - You can change this setting anytime from the Organization Settings page. - -
    -
    -
    + +
    + + Would you be ok with sharing anonymous usage data with the Redash team?{' '} + + + )} + bordered={false} + > + Help Redash improve by automatically sending anonymous usage data: +
    +
      +
    • Number of users, queries, dashboards, alerts, widgets and visualizations.
    • +
    • Types of data sources, alert destinations and visualizations.
    • +
    +
    + All data is aggregated and will never include any sensitive or private data. +
    + + +
    +
    + + You can change this setting anytime from the Organization Settings page. + +
    +
    +
    +
    ); } diff --git a/client/app/pages/settings/OrganizationSettings.jsx b/client/app/pages/settings/OrganizationSettings.jsx index ba3cb69456..32e4d6c83b 100644 --- a/client/app/pages/settings/OrganizationSettings.jsx +++ b/client/app/pages/settings/OrganizationSettings.jsx @@ -10,13 +10,14 @@ import Select from 'antd/lib/select'; import Checkbox from 'antd/lib/checkbox'; import Tooltip from 'antd/lib/tooltip'; import LoadingState from '@/components/items-list/components/LoadingState'; -import { HelpTrigger } from '@/components/HelpTrigger'; import { routesToAngularRoutes } from '@/lib/utils'; import { clientConfig } from '@/services/auth'; import settingsMenu from '@/services/settingsMenu'; import recordEvent from '@/services/recordEvent'; import OrgSettings from '@/services/organizationSettings'; +import { HelpTrigger } from '@/components/HelpTrigger'; +import DynamicComponent from '@/components/DynamicComponent'; const Option = Select.Option; @@ -181,15 +182,17 @@ class OrganizationSettings extends React.Component { Enable multi-byte (Chinese, Japanese, and Korean) search for query names and descriptions (slower)
    - Anonymous Usage Data Sharing }> - this.handleChange('beacon_consent', e.target.checked)} - > - Help Redash improve by automatically sending anonymous usage data - - + + Anonymous Usage Data Sharing }> + this.handleChange('beacon_consent', e.target.checked)} + > + Help Redash improve by automatically sending anonymous usage data + + + ); }