From 18a5e614d9759dc7aa08faeee5a0d227b80257d7 Mon Sep 17 00:00:00 2001 From: Malcolm Bouzi Date: Wed, 27 Nov 2019 11:57:59 -0500 Subject: [PATCH] satellite/web: add segmentio plugin (#3405) --- satellite/console/consoleweb/server.go | 12 ++-- scripts/testdata/satellite-config.yaml.lock | 3 + web/satellite/index.html | 1 + web/satellite/package-lock.json | 17 ++---- web/satellite/package.json | 13 +++-- web/satellite/src/App.vue | 5 ++ web/satellite/src/main.ts | 3 + web/satellite/src/types/plugins.ts | 3 +- .../utils/constants/analyticsEventNames.ts | 8 +++ web/satellite/src/utils/plugins/segment.ts | 58 +++++++++++++++++++ web/satellite/tsconfig.json | 3 +- 11 files changed, 103 insertions(+), 23 deletions(-) create mode 100644 web/satellite/src/utils/constants/analyticsEventNames.ts create mode 100644 web/satellite/src/utils/plugins/segment.ts diff --git a/satellite/console/consoleweb/server.go b/satellite/console/consoleweb/server.go index 2902ec5c0..645ff67d6 100644 --- a/satellite/console/consoleweb/server.go +++ b/satellite/console/consoleweb/server.go @@ -70,6 +70,7 @@ type Config struct { SatelliteName string `help:"used to display at web satellite console" default:"Storj"` SatelliteOperator string `help:"name of organization which set up satellite" default:"Storj Labs" ` TermsAndConditionsURL string `help:"url link to terms and conditions page" default:"https://storj.io/storage-sla/"` + SegmentIOPublicKey string `help:"used to initialize segment.io at web satellite console" default:""` } // Server represents console web server @@ -215,10 +216,11 @@ func (server *Server) appHandler(w http.ResponseWriter, r *http.Request) { cspValues := []string{ "default-src 'self'", + "connect-src 'self' api.segment.io", "frame-ancestors " + server.config.FrameAncestors, "frame-src 'self' *.stripe.com", - "img-src 'self' data:", - "script-src 'self' *.stripe.com cdn.segment.com", + "img-src 'self' data: *.customer.io", + "script-src 'self' *.stripe.com cdn.segment.com *.customer.io", } header.Set(contentType, "text/html; charset=UTF-8") @@ -227,11 +229,13 @@ func (server *Server) appHandler(w http.ResponseWriter, r *http.Request) { header.Set("Referrer-Policy", "same-origin") // Only expose the referring url when navigating around the satellite itself. var data struct { - SatelliteName string - StripePublicKey string + SatelliteName string + SegmentIOPublicKey string + StripePublicKey string } data.SatelliteName = server.config.SatelliteName + data.SegmentIOPublicKey = server.config.SegmentIOPublicKey data.StripePublicKey = server.stripePublicKey if server.templates.index == nil || server.templates.index.Execute(w, data) != nil { diff --git a/scripts/testdata/satellite-config.yaml.lock b/scripts/testdata/satellite-config.yaml.lock index 063f1662c..8eb459f94 100644 --- a/scripts/testdata/satellite-config.yaml.lock +++ b/scripts/testdata/satellite-config.yaml.lock @@ -61,6 +61,9 @@ # name of organization which set up satellite # console.satellite-operator: Storj Labs +# used to initialize segment.io at web satellite console +# console.segment-io-public-key: "" + # used to communicate with web crawlers and other web robots # console.seo: "User-agent: *\nDisallow: \nDisallow: /cgi-bin/" diff --git a/web/satellite/index.html b/web/satellite/index.html index ee381ba6f..8ba365dc4 100644 --- a/web/satellite/index.html +++ b/web/satellite/index.html @@ -4,6 +4,7 @@ + {{ .SatelliteName }} diff --git a/web/satellite/package-lock.json b/web/satellite/package-lock.json index f9ade372d..51f031e58 100644 --- a/web/satellite/package-lock.json +++ b/web/satellite/package-lock.json @@ -1070,6 +1070,11 @@ "integrity": "sha512-ce5d3q03Ex0sy4R14722Rmt6MT07Ua+k4FwDfdcToYJcMKNtRVQvJ6JCAPdAmAnbRb6CsX6aYb9m96NGod9uTw==", "dev": true }, + "@types/segment-analytics": { + "version": "0.0.32", + "resolved": "https://registry.npmjs.org/@types/segment-analytics/-/segment-analytics-0.0.32.tgz", + "integrity": "sha512-p0SHnfHfZwemTeaISvu8WUXtw81A4AOU4GEr7B9S9jLx2iu/z/4aLT0flRJtHVusVAlMeJSdobn0uD/oR1sFEw==" + }, "@types/sinon": { "version": "7.0.13", "resolved": "https://registry.npmjs.org/@types/sinon/-/sinon-7.0.13.tgz", @@ -9627,8 +9632,7 @@ "load-script": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/load-script/-/load-script-1.0.0.tgz", - "integrity": "sha1-BJGTngvuVkPuSUp+PaPSuscMbKQ=", - "dev": true + "integrity": "sha1-BJGTngvuVkPuSUp+PaPSuscMbKQ=" }, "loader-runner": { "version": "2.4.0", @@ -15805,15 +15809,6 @@ "resolved": "https://registry.npmjs.org/vue-router/-/vue-router-3.1.2.tgz", "integrity": "sha512-WssQEHSEvIS1/CI4CO2T8LJdoK4Q9Ngox28K7FDNMTfzNTk2WS5D0dDlqYCaPG+AG4Z8wJkn1KrBc7AhspZJUQ==" }, - "vue-segment-analytics": { - "version": "0.3.2", - "resolved": "https://registry.npmjs.org/vue-segment-analytics/-/vue-segment-analytics-0.3.2.tgz", - "integrity": "sha512-jajq+K991iEv18QDBG4INWvHXH+Ur/IYJdfbQOOUYdDSP6j/UYSGwFfv6JTgRuEx1PO5jZEfSKHRbWSU7MId7A==", - "dev": true, - "requires": { - "load-script": "~1.0.0" - } - }, "vue-style-loader": { "version": "4.1.2", "resolved": "https://registry.npmjs.org/vue-style-loader/-/vue-style-loader-4.1.2.tgz", diff --git a/web/satellite/package.json b/web/satellite/package.json index ba6105c3a..999657a00 100644 --- a/web/satellite/package.json +++ b/web/satellite/package.json @@ -10,6 +10,7 @@ "dev": "vue-cli-service build --mode development" }, "dependencies": { + "@types/segment-analytics": "0.0.32", "apollo-cache-inmemory": "1.6.3", "apollo-client": "2.6.4", "apollo-link": "1.2.12", @@ -17,6 +18,7 @@ "apollo-link-http": "1.5.15", "graphql": "14.5.4", "graphql-tag": "2.10.1", + "load-script": "^1.0.0", "moment": "2.24.0", "stripe": "7.8.0", "vue": "2.6.10", @@ -38,24 +40,23 @@ "@vue/test-utils": "1.0.0-beta.29", "babel-core": "7.0.0-bridge.0", "compression-webpack-plugin": "3.0.0", - "stylelint": "11.1.1", - "stylelint-webpack-plugin": "1.0.2", - "stylelint-config-standard": "19.0.0", - "stylelint-scss": "3.12.0", "jest-fetch-mock": "2.1.2", "node-sass": "4.12.0", "sass-loader": "7.1.0", "sinon": "7.4.1", + "stylelint": "11.1.1", + "stylelint-config-standard": "19.0.0", + "stylelint-scss": "3.12.0", + "stylelint-webpack-plugin": "1.0.2", "ts-jest": "24.0.2", "tslint": "5.19.0", "tslint-consistent-codestyle": "1.15.1", "tslint-loader": "3.5.4", "typescript": "3.5.3", - "vue-segment-analytics": "0.3.2", "vue-svg-loader": "0.12.0", + "vue-template-compiler": "2.6.10", "vue-tslint": "0.3.2", "vue-tslint-loader": "3.5.6", - "vue-template-compiler": "2.6.10", "webpack": "4.39.3" }, "postcss": { diff --git a/web/satellite/src/App.vue b/web/satellite/src/App.vue index 0491dd2db..04974a462 100644 --- a/web/satellite/src/App.vue +++ b/web/satellite/src/App.vue @@ -38,10 +38,15 @@ export default class App extends Vue { public mounted(): void { const satelliteName = MetaUtils.getMetaContent('satellite-name'); + const segmentioId = MetaUtils.getMetaContent('segment-io'); if (satelliteName) { this.$store.dispatch(APP_STATE_ACTIONS.SET_SATELLITE_NAME, satelliteName); } + + if (segmentioId) { + this.$segment.init(segmentioId); + } } public onClick(e: Event): void { diff --git a/web/satellite/src/main.ts b/web/satellite/src/main.ts index 66d9cbe81..f9c532bb9 100644 --- a/web/satellite/src/main.ts +++ b/web/satellite/src/main.ts @@ -5,6 +5,7 @@ import Vue, { VNode } from 'vue'; import { DirectiveBinding } from 'vue/types/options'; import { NotificatorPlugin } from '@/utils/plugins/notificator'; +import { SegmentioPlugin } from '@/utils/plugins/segment'; import App from './App.vue'; import { router } from './router'; @@ -15,8 +16,10 @@ Vue.config.performance = true; Vue.config.productionTip = false; const notificator = new NotificatorPlugin(); +const segment = new SegmentioPlugin(); Vue.use(notificator); +Vue.use(segment); let clickOutsideEvent: EventListener; diff --git a/web/satellite/src/types/plugins.ts b/web/satellite/src/types/plugins.ts index 84f2ab15a..36baca6c1 100644 --- a/web/satellite/src/types/plugins.ts +++ b/web/satellite/src/types/plugins.ts @@ -4,10 +4,11 @@ import Vue from 'vue'; import { Notificator } from '@/utils/plugins/notificator'; +import { Segmentio } from '@/utils/plugins/segment'; declare module 'vue/types/vue' { interface Vue { - $segment: any; // define real typings here if you want + $segment: Segmentio; // define real typings here if you want $notify: Notificator; } } diff --git a/web/satellite/src/utils/constants/analyticsEventNames.ts b/web/satellite/src/utils/constants/analyticsEventNames.ts new file mode 100644 index 000000000..83963519b --- /dev/null +++ b/web/satellite/src/utils/constants/analyticsEventNames.ts @@ -0,0 +1,8 @@ +// Copyright (C) 2019 Storj Labs, Inc. +// See LICENSE for copying information. + +export enum SegmentEvent { + CLICKED_LOGO = 'clicked-on-logo', + CLICKED_LOGIN = 'clicked-on-login', + CLICKED_BACK_TO_LOGIN = 'clicked-on-back-to-login', +} diff --git a/web/satellite/src/utils/plugins/segment.ts b/web/satellite/src/utils/plugins/segment.ts new file mode 100644 index 000000000..8ef9ba38e --- /dev/null +++ b/web/satellite/src/utils/plugins/segment.ts @@ -0,0 +1,58 @@ +// Copyright (C) 2019 Storj Labs, Inc. +// See LICENSE for copying information. + +import loadScript from 'load-script'; + +import { SegmentEvent } from '@/utils/constants/analyticsEventNames'; + +/** + * Segmentio is a wrapper around segment.io analytics package + */ +export class Segmentio { + analytics: SegmentAnalytics.AnalyticsJS; + public init(key: string) { + if (this.analytics || key.length === 0 || key.includes('SegmentIOPublicKey')) { + return; + } + const source = `https://cdn.segment.com/analytics.js/v1/${key}/analytics.min.js`; + loadScript(source, (error) => { + if (error) { + return; + } + + this.analytics = window['analytics']; + }); + + this.page(); + } + + public page() { + if (!this.analytics) { + return; + } + + this.analytics.page(); + } + + public identify() { + if (!this.analytics) { + return; + } + + this.analytics.identify(); + } + + public track(event: SegmentEvent, properties?: Object, options?: SegmentAnalytics.SegmentOpts, callback?: () => void) { + if (!this.analytics) { + return; + } + + this.analytics.track(event, properties, options, callback); + } +} + +export class SegmentioPlugin { + public install(Vue) { + Vue.prototype.$segment = new Segmentio(); + } +} diff --git a/web/satellite/tsconfig.json b/web/satellite/tsconfig.json index 44fce888d..a5c8504bf 100644 --- a/web/satellite/tsconfig.json +++ b/web/satellite/tsconfig.json @@ -15,7 +15,8 @@ "strictPropertyInitialization": false, "types": [ "webpack-env", - "jest" + "jest", + "segment-analytics" ], "paths": { "@/*": [