From 272ba5b004f33c444b2c63a419810c479b5cb5fc Mon Sep 17 00:00:00 2001 From: Luke Barnard Date: Tue, 15 May 2018 13:15:40 +0100 Subject: [PATCH 1/4] Implement opt-in analytics with cookie bar --- src/components/structures/LoggedInView.js | 5 +- src/components/structures/MatrixChat.js | 32 +++++++++- src/components/views/globals/CookieBar.js | 73 +++++++++++++++++++++++ src/i18n/strings/en_EN.json | 5 +- src/settings/Settings.js | 9 ++- 5 files changed, 118 insertions(+), 6 deletions(-) create mode 100644 src/components/views/globals/CookieBar.js diff --git a/src/components/structures/LoggedInView.js b/src/components/structures/LoggedInView.js index d9ac9de693..abb2eb92aa 100644 --- a/src/components/structures/LoggedInView.js +++ b/src/components/structures/LoggedInView.js @@ -266,6 +266,7 @@ const LoggedInView = React.createClass({ const GroupView = sdk.getComponent('structures.GroupView'); const MyGroups = sdk.getComponent('structures.MyGroups'); const MatrixToolbar = sdk.getComponent('globals.MatrixToolbar'); + const CookieBar = sdk.getComponent('globals.CookieBar'); const NewVersionBar = sdk.getComponent('globals.NewVersionBar'); const UpdateCheckBar = sdk.getComponent('globals.UpdateCheckBar'); const PasswordNagBar = sdk.getComponent('globals.PasswordNagBar'); @@ -353,7 +354,9 @@ const LoggedInView = React.createClass({ let topBar; const isGuest = this.props.matrixClient.isGuest(); - if (this.props.hasNewVersion) { + if (this.props.showCookieBar) { + topBar = ; + } else if (this.props.hasNewVersion) { topBar = ; diff --git a/src/components/structures/MatrixChat.js b/src/components/structures/MatrixChat.js index 3005bc86ad..051b9ed10b 100644 --- a/src/components/structures/MatrixChat.js +++ b/src/components/structures/MatrixChat.js @@ -165,6 +165,8 @@ export default React.createClass({ newVersionReleaseNotes: null, checkingForUpdate: null, + showCookieBar: false, + // Parameters used in the registration dance with the IS register_client_secret: null, register_session_id: null, @@ -227,8 +229,6 @@ export default React.createClass({ componentWillMount: function() { SdkConfig.put(this.props.config); - if (!SettingsStore.getValue("analyticsOptOut")) Analytics.enable(); - // Used by _viewRoom before getting state from sync this.firstSyncComplete = false; this.firstSyncPromise = Promise.defer(); @@ -361,6 +361,16 @@ export default React.createClass({ // loadSession as there's logic there to ask the user if they want // to try logging out. }); + + if (SettingsStore.getValue("showCookieBar")) { + this.setState({ + showCookieBar: true, + }); + } + + if (SettingsStore.getValue("analyticsOptIn")) { + Analytics.enable(); + } }, componentWillUnmount: function() { @@ -673,6 +683,23 @@ export default React.createClass({ hideToSRUsers: false, }); break; + case 'accept_cookies': + SettingsStore.setValue("analyticsOptIn", null, SettingLevel.DEVICE, true); + SettingsStore.setValue("showCookieBar", null, SettingLevel.DEVICE, false); + + this.setState({ + showCookieBar: false, + }); + Analytics.enable(); + break; + case 'reject_cookies': + SettingsStore.setValue("analyticsOptIn", null, SettingLevel.DEVICE, false); + SettingsStore.setValue("showCookieBar", null, SettingLevel.DEVICE, false); + + this.setState({ + showCookieBar: false, + }); + break; } }, @@ -1621,6 +1648,7 @@ export default React.createClass({ onRegistered={this.onRegistered} currentRoomId={this.state.currentRoomId} teamToken={this._teamToken} + showCookieBar={this.state.showCookieBar} {...this.props} {...this.state} /> diff --git a/src/components/views/globals/CookieBar.js b/src/components/views/globals/CookieBar.js new file mode 100644 index 0000000000..f1fbbcc83a --- /dev/null +++ b/src/components/views/globals/CookieBar.js @@ -0,0 +1,73 @@ +/* +Copyright 2018 New Vector Ltd. + +Licensed 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 dis from '../../../dispatcher'; +import { _t } from '../../../languageHandler'; +import sdk from '../../../index'; + +const PrivacyLink = (sub) => + + { sub } + ; + +export default React.createClass({ + onAccept: function() { + dis.dispatch({ + action: 'accept_cookies', + }); + }, + + onReject: function() { + dis.dispatch({ + action: 'reject_cookies', + }); + }, + + render: function() { + const AccessibleButton = sdk.getComponent('elements.AccessibleButton'); + const toolbarClasses = "mx_MatrixToolbar"; + return ( +
+ Warning +
+ { _t( + "Help us improve Riot by sending usage data. " + + "This will use a cookie " + + "(see our cookie and " + + "privacy policies)", + {}, + { + // XXX: We need to link to the page that explains our cookies + 'CookieLink': PrivacyLink, + 'PrivacyLink': PrivacyLink, + }, + ) } +
+ + { _t("Send usage data") } + + + + +
+ ); + }, +}); diff --git a/src/i18n/strings/en_EN.json b/src/i18n/strings/en_EN.json index 9b932ef2b6..0126661a07 100644 --- a/src/i18n/strings/en_EN.json +++ b/src/i18n/strings/en_EN.json @@ -210,7 +210,8 @@ "Mirror local video feed": "Mirror local video feed", "Disable Community Filter Panel": "Disable Community Filter Panel", "Disable Peer-to-Peer for 1:1 calls": "Disable Peer-to-Peer for 1:1 calls", - "Opt out of analytics": "Opt out of analytics", + "Send analytics data": "Send analytics data", + "Show cookie bar": "Show cookie bar", "Never send encrypted messages to unverified devices from this device": "Never send encrypted messages to unverified devices from this device", "Never send encrypted messages to unverified devices in this room from this device": "Never send encrypted messages to unverified devices in this room from this device", "Enable inline URL previews by default": "Enable inline URL previews by default", @@ -637,6 +638,8 @@ "Something went wrong when trying to get your communities.": "Something went wrong when trying to get your communities.", "Display your community flair in rooms configured to show it.": "Display your community flair in rooms configured to show it.", "You're not currently a member of any communities.": "You're not currently a member of any communities.", + "Help us improve Riot by sending usage data. This will use a cookie (see our cookie and privacy policies)": "Help us improve Riot by sending usage data. This will use a cookie (see our cookie and privacy policies)", + "Send usage data": "Send usage data", "You are not receiving desktop notifications": "You are not receiving desktop notifications", "Enable them now": "Enable them now", "What's New": "What's New", diff --git a/src/settings/Settings.js b/src/settings/Settings.js index 663318f990..8f50885c14 100644 --- a/src/settings/Settings.js +++ b/src/settings/Settings.js @@ -213,11 +213,16 @@ export const SETTINGS = { supportedLevels: LEVELS_DEVICE_ONLY_SETTINGS_WITH_CONFIG, default: "en", }, - "analyticsOptOut": { + "analyticsOptIn": { supportedLevels: LEVELS_DEVICE_ONLY_SETTINGS_WITH_CONFIG, - displayName: _td('Opt out of analytics'), + displayName: _td('Send analytics data'), default: false, }, + "showCookieBar": { + supportedLevels: LEVELS_DEVICE_ONLY_SETTINGS_WITH_CONFIG, + displayName: _td('Show cookie bar'), + default: true, + }, "autocompleteDelay": { supportedLevels: LEVELS_DEVICE_ONLY_SETTINGS_WITH_CONFIG, default: 200, From 0c22343bb895f118df613896d63e4cfd61f08ef0 Mon Sep 17 00:00:00 2001 From: Luke Barnard Date: Tue, 15 May 2018 15:38:47 +0100 Subject: [PATCH 2/4] Remove cookie bar setting from UserSettings --- src/i18n/strings/en_EN.json | 1 - src/settings/Settings.js | 1 - 2 files changed, 2 deletions(-) diff --git a/src/i18n/strings/en_EN.json b/src/i18n/strings/en_EN.json index 0126661a07..448f5e3a1c 100644 --- a/src/i18n/strings/en_EN.json +++ b/src/i18n/strings/en_EN.json @@ -211,7 +211,6 @@ "Disable Community Filter Panel": "Disable Community Filter Panel", "Disable Peer-to-Peer for 1:1 calls": "Disable Peer-to-Peer for 1:1 calls", "Send analytics data": "Send analytics data", - "Show cookie bar": "Show cookie bar", "Never send encrypted messages to unverified devices from this device": "Never send encrypted messages to unverified devices from this device", "Never send encrypted messages to unverified devices in this room from this device": "Never send encrypted messages to unverified devices in this room from this device", "Enable inline URL previews by default": "Enable inline URL previews by default", diff --git a/src/settings/Settings.js b/src/settings/Settings.js index 8f50885c14..b1bc4161fd 100644 --- a/src/settings/Settings.js +++ b/src/settings/Settings.js @@ -220,7 +220,6 @@ export const SETTINGS = { }, "showCookieBar": { supportedLevels: LEVELS_DEVICE_ONLY_SETTINGS_WITH_CONFIG, - displayName: _td('Show cookie bar'), default: true, }, "autocompleteDelay": { From c191464e972f1298e81ebd46e253381e1eb2d6bd Mon Sep 17 00:00:00 2001 From: Luke Barnard Date: Tue, 15 May 2018 15:39:12 +0100 Subject: [PATCH 3/4] Fix UserSettings for new analyticsOptIn --- src/components/structures/UserSettings.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/components/structures/UserSettings.js b/src/components/structures/UserSettings.js index 35a55284fd..c8ce79905d 100644 --- a/src/components/structures/UserSettings.js +++ b/src/components/structures/UserSettings.js @@ -86,9 +86,9 @@ const SIMPLE_SETTINGS = [ // These settings must be defined in SettingsStore const ANALYTICS_SETTINGS = [ { - id: 'analyticsOptOut', + id: 'analyticsOptIn', fn: function(checked) { - Analytics[checked ? 'disable' : 'enable'](); + checked ? Analytics.enable() : Analytics.disable(); }, }, ]; From e98b31958be34769f17c7309692b186ff82cbbe9 Mon Sep 17 00:00:00 2001 From: Luke Barnard Date: Wed, 16 May 2018 10:41:18 +0100 Subject: [PATCH 4/4] Allow arbitrary hrefs for cookie/privacy links --- src/components/views/globals/CookieBar.js | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/components/views/globals/CookieBar.js b/src/components/views/globals/CookieBar.js index f1fbbcc83a..7625518252 100644 --- a/src/components/views/globals/CookieBar.js +++ b/src/components/views/globals/CookieBar.js @@ -19,11 +19,11 @@ import dis from '../../../dispatcher'; import { _t } from '../../../languageHandler'; import sdk from '../../../index'; -const PrivacyLink = (sub) => +const makeLink = (href) => (sub) => { sub } ; @@ -56,8 +56,8 @@ export default React.createClass({ {}, { // XXX: We need to link to the page that explains our cookies - 'CookieLink': PrivacyLink, - 'PrivacyLink': PrivacyLink, + 'CookieLink': makeLink("https://riot.im/privacy"), + 'PrivacyLink': makeLink("https://riot.im/privacy"), }, ) }