Enable FullStory, with throttling
closes UX-31 flag=enable_fullstory test plan: 1. LOG OUT BETWEEN TESTS 2. to determine if fullstory was enabled, you can: a. use devtools to look for the fullstory script in the HEAD. It will be after the <!-- fullstory snippet --> comment, making it easy to find b. lok for a network request for edge.fullstory.com/s/fs.js 3. to your dynamic_settings.yml, add config: canvas: fullstory: sampling_rate: 1.0 app_key: 'anything' - do not enable the flag - log in > expect fullstory not to be enabled - enable the flag - log in > expect fullstory to be enabled - change sampling_rate to 0.0 - log in > expect fullstory not to be enabled Change-Id: I27885ebafea3066a8996a45f990118584f2bf56c Reviewed-on: https://gerrit.instructure.com/c/canvas-lms/+/230591 Tested-by: Service Cloud Jenkins <svc.cloudjenkins@instructure.com> Reviewed-by: Simon Williams <simon@instructure.com> Reviewed-by: Gary Mei <gmei@instructure.com> QA-Review: Anju Reddy <areddy@instructure.com> Product-Review: Ed Schiebel <eschiebel@instructure.com>
This commit is contained in:
parent
c0325eb466
commit
efc6a1247a
|
@ -16,6 +16,8 @@
|
|||
# with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
module Login::Shared
|
||||
include FullStoryHelper
|
||||
|
||||
def reset_session_for_login
|
||||
reset_session_saving_keys(:return_to,
|
||||
:oauth,
|
||||
|
@ -68,6 +70,8 @@ module Login::Shared
|
|||
session[:require_terms] = true if @domain_root_account.require_acceptance_of_terms?(user)
|
||||
@current_user = user
|
||||
|
||||
fullstory_init(@domain_root_account, session)
|
||||
|
||||
respond_to do |format|
|
||||
if (oauth = session[:oauth2])
|
||||
provider = Canvas::Oauth::Provider.new(oauth[:client_id], oauth[:redirect_uri], oauth[:scopes], oauth[:purpose])
|
||||
|
|
|
@ -0,0 +1,42 @@
|
|||
#
|
||||
# Copyright (C) 2020 - present Instructure, Inc.
|
||||
#
|
||||
# This file is part of Canvas.
|
||||
#
|
||||
# Canvas is free software: you can redistribute it and/or modify it under
|
||||
# the terms of the GNU Affero General Public License as published by the Free
|
||||
# Software Foundation, version 3 of the License.
|
||||
#
|
||||
# Canvas is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
|
||||
# A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
|
||||
# details.
|
||||
#
|
||||
# You should have received a copy of the GNU Affero General Public License along
|
||||
# with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
|
||||
module FullStoryHelper
|
||||
# the feature determines if fullstory is turned on
|
||||
# then we enabled it only for every nth login
|
||||
def fullstory_init(account, session)
|
||||
fullstory_enabled = account.feature_enabled?(:enable_fullstory) rescue false
|
||||
return unless fullstory_enabled
|
||||
|
||||
# this session is already hooked up
|
||||
return if session.key?(:fullstory_enabled)
|
||||
|
||||
fsconfig = Canvas::DynamicSettings.find('fullstory', tree: 'config', service: 'canvas')
|
||||
rate = fsconfig[:sampling_rate].to_f
|
||||
sample = rand()
|
||||
session[:fullstory_enabled] = rate >= 0.0 && rate <= 1.0 && sample < rate
|
||||
end
|
||||
|
||||
def fullstory_app_key
|
||||
Canvas::DynamicSettings.find('fullstory', tree: 'config', service: 'canvas')[:app_key] rescue nil
|
||||
end
|
||||
|
||||
def fullstory_enabled_for_session?(session)
|
||||
!!session[:fullstory_enabled]
|
||||
end
|
||||
end
|
|
@ -98,4 +98,9 @@
|
|||
<% end %>
|
||||
<title><%= @page_title || (yield :page_title).presence || t('default_page_title', "Canvas LMS") %></title>
|
||||
<%= render partial: 'layouts/google_analytics_snippet' %>
|
||||
|
||||
<!-- fullstory snippet -->
|
||||
<% if fullstory_enabled_for_session?(session) %>
|
||||
<%= render :partial => "shared/fullstory_snippet" %>
|
||||
<% end %>
|
||||
</head>
|
||||
|
|
|
@ -0,0 +1,44 @@
|
|||
<%
|
||||
# Copyright (C) 2020 - present Instructure, Inc.
|
||||
#
|
||||
# This file is part of Canvas.
|
||||
#
|
||||
# Canvas is free software: you can redistribute it and/or modify it under
|
||||
# the terms of the GNU Affero General Public License as published by the Free
|
||||
# Software Foundation, version 3 of the License.
|
||||
#
|
||||
# Canvas is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
|
||||
# A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
|
||||
# details.
|
||||
#
|
||||
# You should have received a copy of the GNU Affero General Public License along
|
||||
# with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
%>
|
||||
|
||||
<%
|
||||
fullstory_key = fullstory_app_key
|
||||
if (fullstory_key) %>
|
||||
<script>
|
||||
window['_fs_debug'] = false;
|
||||
window['_fs_host'] = 'fullstory.com';
|
||||
window['_fs_script'] = 'edge.fullstory.com/s/fs.js';
|
||||
window['_fs_org'] = '<%=raw(fullstory_key)%>';
|
||||
window['_fs_namespace'] = 'FS';
|
||||
(function(m,n,e,t,l,o,g,y){
|
||||
if (e in m) {if(m.console && m.console.log) { m.console.log('FullStory namespace conflict. Please set window["_fs_namespace"].');} return;}
|
||||
g=m[e]=function(a,b,s){g.q?g.q.push([a,b,s]):g._api(a,b,s);};g.q=[];
|
||||
o=n.createElement(t);o.async=1;o.crossOrigin='anonymous';o.src='https://'+_fs_script;
|
||||
y=n.getElementsByTagName(t)[0];y.parentNode.insertBefore(o,y);
|
||||
g.identify=function(i,v,s){g(l,{uid:i},s);if(v)g(l,v,s)};g.setUserVars=function(v,s){g(l,v,s)};g.event=function(i,v,s){g('event',{n:i,p:v},s)};
|
||||
g.shutdown=function(){g("rec",!1)};g.restart=function(){g("rec",!0)};
|
||||
g.log = function(a,b){g("log",[a,b])};
|
||||
g.consent=function(a){g("consent",!arguments.length||a)};
|
||||
g.identifyAccount=function(i,v){o='account';v=v||{};v.acctId=i;g(o,v)};
|
||||
g.clearUserCookie=function(){};
|
||||
g._w={};y='XMLHttpRequest';g._w[y]=m[y];y='fetch';g._w[y]=m[y];
|
||||
if(m[y])m[y]=function(){return g._w[y].apply(this,arguments)};
|
||||
g._v="1.1.1";
|
||||
})(window,document,window['_fs_namespace'],'script','user');
|
||||
</script>
|
||||
<% end %>
|
|
@ -37,6 +37,9 @@ development:
|
|||
ios-pandata-secret: teamrocketblastoffatthespeedoflight
|
||||
android-pandata-key: ANDROID_pandata_key
|
||||
android-pandata-secret: surrendernoworpreparetofight
|
||||
fullstory:
|
||||
sampling_rate: '0.0' # randomly inject this fraction of the time
|
||||
app_key: 'xyzzy'
|
||||
|
||||
private:
|
||||
canvas:
|
||||
|
|
|
@ -57,3 +57,9 @@ uxs_4_omg_a_scary_blueprint_checkbox:
|
|||
Show a checkbox that optionally lets an account admin publish courses
|
||||
automatically after associating and syncing with a blueprint course
|
||||
applies_to: RootAccount
|
||||
enable_fullstory:
|
||||
state: hidden
|
||||
display_name: Enable fullstory
|
||||
description: |-
|
||||
Include FullStory recording of the user's session
|
||||
applies_to: RootAccount
|
||||
|
|
|
@ -0,0 +1,80 @@
|
|||
#
|
||||
# Copyright (C) 2020 - present Instructure, Inc.
|
||||
#
|
||||
# This file is part of Canvas.
|
||||
#
|
||||
# Canvas is free software: you can redistribute it and/or modify it under
|
||||
# the terms of the GNU Affero General Public License as published by the Free
|
||||
# Software Foundation, version 3 of the License.
|
||||
#
|
||||
# Canvas is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
|
||||
# A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
|
||||
# details.
|
||||
#
|
||||
# You should have received a copy of the GNU Affero General Public License along
|
||||
# with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
|
||||
require 'spec_helper'
|
||||
|
||||
describe "fullstory" do
|
||||
include FullStoryHelper
|
||||
|
||||
before :each do
|
||||
@domain_root_account = Account.default
|
||||
@session = {}
|
||||
end
|
||||
|
||||
context "with feature enabled" do
|
||||
before :each do
|
||||
@domain_root_account.enable_feature!(:enable_fullstory)
|
||||
end
|
||||
|
||||
it 'is enabled if login is sampled' do
|
||||
allow(FullStoryHelper).to receive(:rand).and_return(0.5)
|
||||
override_dynamic_settings(config: {canvas: { fullstory: {sampling_rate: 1, app_key: '12345'} } }) do
|
||||
fullstory_init(@domain_root_account, @session)
|
||||
expect(fullstory_app_key).to eql('12345')
|
||||
expect(@session[:fullstory_enabled]).to be_truthy
|
||||
expect(fullstory_enabled_for_session?(@session)).to be_truthy
|
||||
end
|
||||
end
|
||||
|
||||
it 'is disabled if login is not sampled' do
|
||||
allow(FullStoryHelper).to receive(:rand).and_return(0.5)
|
||||
override_dynamic_settings(config: {canvas: { fullstory: {sampling_rate: 0, app_key: '12345'} } }) do
|
||||
fullstory_init(@domain_root_account, @session)
|
||||
expect(fullstory_app_key).to eql('12345')
|
||||
expect(@session[:fullstory_enabled]).to be_falsey
|
||||
expect(fullstory_enabled_for_session?(@session)).to be_falsey
|
||||
end
|
||||
end
|
||||
|
||||
it "doesn't explode if the dynamic settings are missing" do
|
||||
allow(FullStoryHelper).to receive(:rand).and_return(0.5)
|
||||
override_dynamic_settings(config: {canvas: { fullstory: nil } }) do
|
||||
fullstory_init(@domain_root_account, @session)
|
||||
expect(fullstory_app_key).to be_nil
|
||||
expect(@session[:fullstory_enabled]).to be_falsey
|
||||
expect(fullstory_enabled_for_session?(@session)).to be_falsey
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context "with feature disabled" do
|
||||
before :each do
|
||||
@domain_root_account.disable_feature!(:enable_fullstory)
|
||||
end
|
||||
|
||||
it 'is disabled' do
|
||||
allow(FullStoryHelper).to receive(:rand).and_return(0.5)
|
||||
override_dynamic_settings(config: {canvas: { fullstory: {sampling_rate: 1, app_key: '12345'} } }) do
|
||||
fullstory_init(@domain_root_account, @session)
|
||||
expect(fullstory_app_key).to eql('12345')
|
||||
expect(@session[:fullstory_enabled]).to be_falsey
|
||||
expect(fullstory_enabled_for_session?(@session)).to be_falsey
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
Loading…
Reference in New Issue