From d9b76386c0cb8b921bc711c96a829357e07979c5 Mon Sep 17 00:00:00 2001 From: enahum Date: Tue, 8 Aug 2017 12:43:41 -0400 Subject: [PATCH] RN-288 Add analytics with segment.io (#828) * Add analytics with segment.io * Feedback review --- NOTICE.txt | 31 +++++++++++++++++++++++++ app/actions/views/root.js | 13 ++++++++--- app/mattermost.js | 49 ++++++++++++++++++++++++++++++--------- assets/base/config.json | 3 ++- fastlane/Fastfile | 32 +++++++++++++++++++++++++ package.json | 1 + yarn.lock | 11 +++++++++ 7 files changed, 125 insertions(+), 15 deletions(-) diff --git a/NOTICE.txt b/NOTICE.txt index 18573549a..68e08b42d 100644 --- a/NOTICE.txt +++ b/NOTICE.txt @@ -1123,3 +1123,34 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. --- + +## analytics-react-native + +This product contains 'analytics-react-native', A React Native client for Segment. The hassle-free way to integrate analytics into any application. + +* HOMEPAGE: + * https://github.com/neiker/analytics-react-native + +* LICENSE: + +MIT License + +Copyright (c) 2016 Javier Alvarez + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/app/actions/views/root.js b/app/actions/views/root.js index 5da2dcb69..d22235afe 100644 --- a/app/actions/views/root.js +++ b/app/actions/views/root.js @@ -16,9 +16,16 @@ import {markChannelAsRead, viewChannel} from 'mattermost-redux/actions/channels' export function loadConfigAndLicense(serverVersion) { return async (dispatch, getState) => { - getClientConfig()(dispatch, getState); - getLicenseConfig()(dispatch, getState); - setServerVersion(serverVersion)(dispatch, getState); + const [config, license] = await Promise.all([ + getClientConfig()(dispatch, getState), + getLicenseConfig()(dispatch, getState) + ]); + + if (config && license) { + setServerVersion(serverVersion)(dispatch, getState); + } + + return {config, license}; }; } diff --git a/app/mattermost.js b/app/mattermost.js index e840323fc..53479a711 100644 --- a/app/mattermost.js +++ b/app/mattermost.js @@ -2,6 +2,7 @@ // See License.txt for license information. import 'babel-polyfill'; +import Analytics from 'analytics-react-native'; import Orientation from 'react-native-orientation'; import {Provider} from 'react-redux'; import {Navigation} from 'react-native-navigation'; @@ -106,12 +107,45 @@ export default class Mattermost { return intl; }; + configureAnalytics = (config) => { + if (config && config.DiagnosticsEnabled === 'true' && config.DiagnosticId && Config.SegmentApiKey) { + if (!global.analytics) { + global.analytics = new Analytics(Config.SegmentApiKey); + global.analytics.identify({ + userId: config.DiagnosticId, + context: { + ip: '0.0.0.0' + }, + page: { + path: '', + referrer: '', + search: '', + title: '', + url: '' + }, + anonymousId: '00000000000000000000000000' + }); + } + } else { + global.analytics = null; + } + }; + + configurePushNotifications = () => { + PushNotifications.configure({ + onRegister: this.onRegisterDevice, + onNotification: this.onPushNotification, + popInitialNotification: true, + requestPermissions: true + }); + }; + handleAppStateChange = (appState) => { const {dispatch, getState} = store; setAppState(appState === 'active')(dispatch, getState); }; - handleConfigChanged = (serverVersion) => { + handleConfigChanged = async (serverVersion) => { const {dispatch, getState} = store; const version = serverVersion.match(/^[0-9]*.[0-9]*.[0-9]*(-[a-zA-Z0-9.-]*)?/g)[0]; const intl = this.getIntl(); @@ -129,7 +163,8 @@ export default class Mattermost { ); } else { setServerVersion('')(dispatch, getState); - loadConfigAndLicense(serverVersion)(dispatch, getState); + const data = await loadConfigAndLicense(serverVersion)(dispatch, getState); + this.configureAnalytics(data.config); } } }; @@ -139,6 +174,7 @@ export default class Mattermost { Client4.serverVersion = ''; Client.serverVersion = ''; Client.token = null; + Client4.userId = ''; PushNotifications.cancelAllLocalNotifications(); setServerVersion('')(dispatch, getState); this.startApp('fade'); @@ -174,15 +210,6 @@ export default class Mattermost { } }; - configurePushNotifications = () => { - PushNotifications.configure({ - onRegister: this.onRegisterDevice, - onNotification: this.onPushNotification, - popInitialNotification: true, - requestPermissions: true - }); - }; - onRegisterDevice = (data) => { const {dispatch, getState} = store; let prefix; diff --git a/assets/base/config.json b/assets/base/config.json index b897f9757..66b69fe3a 100644 --- a/assets/base/config.json +++ b/assets/base/config.json @@ -5,5 +5,6 @@ "ShowErrorsList": false, "MinServerVersion": "3.10.0", "PlatformNoticeURL": "https://about.mattermost.com/platform-notice-txt/", - "MobileNoticeURL": "https://about.mattermost.com/mobile-notice-txt/" + "MobileNoticeURL": "https://about.mattermost.com/mobile-notice-txt/", + "SegmentApiKey": "3MT7rAoC0OP7yy3ThzqFSAtKzmzqtUPX" } diff --git a/fastlane/Fastfile b/fastlane/Fastfile index 8ca9ac881..779725af9 100644 --- a/fastlane/Fastfile +++ b/fastlane/Fastfile @@ -46,6 +46,14 @@ platform :ios do lane :beta do match(type: 'appstore', app_identifier: 'com.mattermost.rnbeta') + if ENV['SEGMENT_API_KEY'] + find_replace_string( + path_to_file: './dist/assets/config.json', + old_string: '"SegmentApiKey": "3MT7rAoC0OP7yy3ThzqFSAtKzmzqtUPX"', + new_string: "\"SegmentApiKey\": \"#{ENV['SEGMENT_API_KEY']}\"" + ) + end + build_ios({ release: true, increment_build: true, @@ -90,6 +98,14 @@ platform :ios do lane :release do match(type: 'appstore', app_identifier: 'com.mattermost.rn') + if ENV['SEGMENT_API_KEY'] + find_replace_string( + path_to_file: './dist/assets/config.json', + old_string: '"SegmentApiKey": "3MT7rAoC0OP7yy3ThzqFSAtKzmzqtUPX"', + new_string: "\"SegmentApiKey\": \"#{ENV['SEGMENT_API_KEY']}\"" + ) + end + # snapshot update_app_identifier( @@ -243,6 +259,14 @@ platform :android do desc 'Submit a new Beta Build to Google Play' lane :alpha do + if ENV['SEGMENT_API_KEY'] + find_replace_string( + path_to_file: './dist/assets/config.json', + old_string: '"SegmentApiKey": "3MT7rAoC0OP7yy3ThzqFSAtKzmzqtUPX"', + new_string: "\"SegmentApiKey\": \"#{ENV['SEGMENT_API_KEY']}\"" + ) + end + build_android({ release: true, increment_build: true, @@ -343,6 +367,14 @@ platform :android do new_string: 'Mattermost;' ) + if ENV['SEGMENT_API_KEY'] + find_replace_string( + path_to_file: './dist/assets/config.json', + old_string: '"SegmentApiKey": "3MT7rAoC0OP7yy3ThzqFSAtKzmzqtUPX"', + new_string: "\"SegmentApiKey\": \"#{ENV['SEGMENT_API_KEY']}\"" + ) + end + build_android({ release: true, increment_build: false, diff --git a/package.json b/package.json index 34d6235b6..6f691fb37 100644 --- a/package.json +++ b/package.json @@ -7,6 +7,7 @@ "license": "Apache 2.0", "private": true, "dependencies": { + "analytics-react-native": "1.1.0", "babel-polyfill": "6.23.0", "commonmark": "hmhealey/commonmark.js#3139568442da83c5520685dc033eaf417dada2c0", "commonmark-react-renderer": "hmhealey/commonmark-react-renderer#c5d00343664c89da40d5a2ffa8b083e7cc1615d7", diff --git a/yarn.lock b/yarn.lock index dfd17c2f9..ba69db63c 100644 --- a/yarn.lock +++ b/yarn.lock @@ -75,6 +75,13 @@ amdefine@>=0.0.4: version "1.0.1" resolved "https://registry.yarnpkg.com/amdefine/-/amdefine-1.0.1.tgz#4a5282ac164729e93619bcfd3ad151f817ce91f5" +analytics-react-native@1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/analytics-react-native/-/analytics-react-native-1.1.0.tgz#9e8a2552146568de94190ad911616416259e219b" + dependencies: + base-64 "0.1.0" + type-of "2.0.1" + ansi-escapes@^1.1.0: version "1.4.0" resolved "https://registry.yarnpkg.com/ansi-escapes/-/ansi-escapes-1.4.0.tgz#d3a8a83b319aa67793662b13e761c7911422306e" @@ -5742,6 +5749,10 @@ type-is@~1.6.14, type-is@~1.6.6: media-typer "0.3.0" mime-types "~2.1.15" +type-of@2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/type-of/-/type-of-2.0.1.tgz#e72a1741896568e9f628378d816d6912f7f23972" + typedarray@^0.0.6: version "0.0.6" resolved "https://registry.yarnpkg.com/typedarray/-/typedarray-0.0.6.tgz#867ac74e3864187b1d3d47d996a78ec5c8830777"