Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

add frontend piwik tracking code #14

Open
wants to merge 4 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions src/ui-client/src/containers/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ import DataImportContainer from '../containers/DataImport/DataImport';
import UserQuestionModal from './UserQuestionModal/UserQuestionModal';
import { SavedQueryMap } from '../models/Query';
import { sleep } from '../utils/Sleep';
import { addMatomoTracking } from '../utils/piwik';
import NotificationModal from '../components/Modals/NotificationModal/NotificationModal';
import MaintainenceModal from '../components/Modals/MaintainenceModal/MaintainenceModal';
import './App.css';
Expand Down Expand Up @@ -74,6 +75,7 @@ class App extends React.Component<Props> {
this.handleSessionTokenRefresh();
dispatch(getIdToken());
dispatch(refreshServerStateLoop());
addMatomoTracking();
}

public componentDidUpdate() {
Expand Down
78 changes: 78 additions & 0 deletions src/ui-client/src/utils/envConfig.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
import Axios from "axios";
import { getAuthConfig, getUserTokenAndContext } from "../services/authApi";
interface EnvVar {
key: string;
value: string | object;
}

export async function fetchEnvData(): Promise<any> {
return new Promise((resolve) => {
// fetch data from appsettings.json and env.json
Promise.allSettled([
getAuthConfig().then((config) => config), // general config settings
getAuthConfig().then((config) => getUserTokenAndContext(config)), // user auth specific settings
Axios.get("/env.json"), // env.json, generated via script to be populated with environment variables
])
.then((results) => {
let returnResults = {};
if (results[0].value) {
returnResults = results[0].value;
}
if (results[1].value) {
returnResults = {
...returnResults,
// user auth/context info will be under the `user` key
user: results[1].value
}
}
if (results[2].value && results[2].value.data) {
returnResults = {
...returnResults,
...results[2].value.data
}
}
resolve(returnResults);
})
.catch((e) => resolve(null));
});
}
// data coming from appsettings && env.json
export async function getEnvData() {
const results = await fetchEnvData();
if (window && results) {
window["appConfig"] = results;
console.table("Environment variables:",getEnvs());
}
return results;
}
export function getEnv(key: string) {
//window application global variables
if (window && window["appConfig"] && window["appConfig"][key])
return window["appConfig"][key];
const envDefined = typeof process !== "undefined" && process.env;
//enviroment variables as defined by Node
if (envDefined && process.env[key]) return process.env[key];
return "";
}

export function getEnvs(): EnvVar[] {
let arrEnvs: EnvVar[] = [];
const BLACK_LIST = ["SECRET", "KEY", "TOKEN", "CREDENTIALS"];
if (window && window["appConfig"]) {
const keys = Object.keys(window["appConfig"]);
keys.forEach((key) => {
if (BLACK_LIST.indexOf(key.toUpperCase()) !== -1) return true;
arrEnvs.push({ key: key, value: window["appConfig"][key] });
});
}
const envDefined = typeof process !== "undefined" && process.env;
if (envDefined) {
const envKeys = Object.keys(process.env);
envKeys.forEach((key) => {
if (BLACK_LIST.indexOf(key.toUpperCase()) !== -1) return true;
arrEnvs.push({ key: key, value: process.env[key] });
});
}
console.log("Environment variables ", arrEnvs);
return arrEnvs;
}
55 changes: 55 additions & 0 deletions src/ui-client/src/utils/piwik.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
import {getEnvData} from "./envConfig";

// get user Id from config, i.e. see getAuthConfig, getUserTokenAndContext from authAPI
export function getUserIdFromEnv(config) : number | string | null {
if (!config) return null;
if (config.user && config.user.name) return config.user.name;
if (config.profile) return config.profile;
if (config.fhirUser) return config.fhirUser;
if (config["preferred_username"]) return config["preferred_username"];
return null;
}
// get PIWIK siteId from environment variable
export function getMatomoSiteIdFromEnv(config) : number | null{
if (!config) return null;
const envs = config.client ? config.client: config;
// appsettings.json {client: .....}
// env.json
if (envs["REACT_APP_MATOMO_SITE_ID"]) return envs["REACT_APP_MATOMO_SITE_ID"];
if (envs["MATOMO_SITE_ID"]) return envs["MATOMO_SITE_ID"];
if (envs["REACT_APP_PIWIK_SITE_ID"]) return envs["REACT_APP_PIWIK_SITE_ID"];
if (envs["PIWIK_SITE_ID"]) return envs["PIWIK_SITE_ID"];
return envs["SITE_ID"];
}
export async function addMatomoTracking() {
// already generated script, return
if (!window || document.querySelector("#matomoScript")) return;
const envData = await getEnvData();
const userId = getUserIdFromEnv(envData);
console.log("PIWIK userId ", userId);
// no user Id return
if (!userId) return;
const siteId = getMatomoSiteIdFromEnv(envData);
console.log("PIWIK siteId ", siteId)
// no site Id return
if (!siteId) return;
// init global piwik tracking object
// note this will only be executed if BOTH userId and siteId are present
window._paq = [];
window._paq.push(["trackPageView"]);
window._paq.push(["enableLinkTracking"]);
window._paq.push(["setSiteId", siteId]);
window._paq.push(["setUserId", userId]);

let u = "https://piwik.cirg.washington.edu/";
window._paq.push(["setTrackerUrl", u + "matomo.php"]);
let d = document,
g = d.createElement("script"),
headElement = document.querySelector("head");
g.type = "text/javascript";
g.async = true;
g.defer = true;
g.setAttribute("src", u + "matomo.js");
g.setAttribute("id", "matomoScript");
headElement.appendChild(g);
}
Loading