canvas-lms/lib/google_analytics_dimensions.rb

89 lines
3.2 KiB
Ruby

# frozen_string_literal: true
#
# 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 GoogleAnalyticsDimensions
# Prepare some contextual data to supplement a pageview hit when submitting to
# GA to provide the analyst with more context surrounding the request:
#
# {
# "enrollments": BoolMask.<student, teacher, observer>,
# "admin": BoolMask.<admin, site_admin>,
# "masquerading": Bool
# }
#
# Bool is a "0" or "1" value (encoded as strings) while "BoolMask" is a stream
# of bools encoded also as a string. For example:
#
# {
# "enrollments": "010", # a teacher
# "admin": "11", # an admin and a site admin
# "masquerading": "0" # nope
# }
#
# Encoding flags in such a way gives us the flexibility to represent future
# values while also giving the analyst more freedom in reporting (GA supports
# regex filtering.)
def self.calculate(domain_root_account:, user:, real_user:)
user_roles = user ? user.roles(domain_root_account) : []
{
admin: _encode_admin_status(roles: user_roles),
enrollments: _encode_enrollments(roles: user_roles),
masquerading: _encode_masquerading_status(user: user, real_user: real_user),
org_type: _encode_org_type(account: domain_root_account),
user_id: _compute_non_compromising_user_id(user: user),
}
end
# we only need some identifier that GA can utilize to track users across
# different devices but we don't want it to know who the users are (e.g. their
# canvas id)
#
# see https://support.google.com/analytics/answer/2992042?hl=en
# see https://developers.google.com/analytics/devguides/collection/analyticsjs/cookies-user-id
def self._compute_non_compromising_user_id(user:)
user ? Canvas::Security.hmac_sha512(user.id.to_s)[0, 32] : nil
end
def self._encode_admin_status(roles:)
# again, look at User#user_roles for the definition
%w[admin root_admin].map do |enrollment_type|
roles.include?(enrollment_type) ? '1' : '0'
end.join('')
end
def self._encode_enrollments(roles:)
# keep in mind that some of these roles may be rolled up from different
# enrollment types, see User#user_roles for the meat
%w[student teacher observer].map do |enrollment_type|
roles.include?(enrollment_type) ? '1' : '0'
end.join('')
end
def self._encode_org_type(account:)
account&.external_integration_keys&.find_by(
key_type: 'salesforce_org_type'
)&.key_value
end
def self._encode_masquerading_status(user:, real_user:)
real_user && real_user != user ? '1' : '0'
end
end