Repository: tl-its-umich-edu/my-learning-analytics
Pull request #1644: #1630 Upgrade cookie consent react module 1.2.1
Author: login: jaydonkrooss
Created: 2025-03-05T21:24:32Z | Merged: 2025-03-07T15:21:46Z



Diff:
diff --git a/assets/src/containers/App.js b/assets/src/containers/App.js
index 6b526ef7..f9480dd7 100755
--- a/assets/src/containers/App.js
+++ b/assets/src/containers/App.js
@@ -5,11 +5,27 @@ import Course from './Course'
 import WarningBanner from '../components/WarningBanner'
 import AlertBanner from '../components/AlertBanner'
 import { Helmet } from 'react-helmet'
-import useGoogleAnalytics from '@tl-its-umich-edu/react-ga-onetrust-consent'
+import {useGoogleAnalytics, useUmConsent} from '@tl-its-umich-edu/react-ga-onetrust-consent'
 
 function App (props) {
-  const { user, gaId, cspNonce, oneTrustScriptDomain } = props
-  useGoogleAnalytics({ googleAnalyticsId: gaId, nonce: cspNonce, oneTrustScriptDomain })
+  const { user, gaId, cspNonce } = props
+  const { gaInitialized, gaHandlers } = useGoogleAnalytics({ googleAnalyticsId: gaId, nonce: cspNonce })
+  const { umConsentInitialize, umConsentInitialized } = useUmConsent()
+
+  if (
+    !umConsentInitialized &&
+    gaInitialized &&
+    gaHandlers.onConsentApprove &&
+    gaHandlers.onConsentReject
+  ) {
+    const consentParams = {
+      developmentMode: false,
+      alwaysShow: false,
+      onConsentApprove: gaHandlers.onConsentApprove,
+      onConsentReject: gaHandlers.onConsentReject,
+    };
+    umConsentInitialize(consentParams)
+  }
 
   if (!user.isLoggedIn) {
     if (user.loginURL === '') {
diff --git a/assets/src/globals.js b/assets/src/globals.js
index 93e574fa..87d73dce 100644
--- a/assets/src/globals.js
+++ b/assets/src/globals.js
@@ -54,6 +54,5 @@ const siteTheme = createTheme({
   props: componentSettings
 })
 const gaId = mylaGlobals.google_analytics_id
-const oneTrustScriptDomain = mylaGlobals.one_trust_script_domain
 
-export { user, siteTheme, gaId, cspNonce, viewHelpURLs, surveyLink, oneTrustScriptDomain }
+export { user, siteTheme, gaId, cspNonce, viewHelpURLs, surveyLink }
diff --git a/assets/src/index.js b/assets/src/index.js
index e0bcd366..a3fb8d67 100755
--- a/assets/src/index.js
+++ b/assets/src/index.js
@@ -6,7 +6,7 @@ import './index.css'
 import App from './containers/App'
 import client from './service/client'
 import { ApolloProvider } from '@apollo/client'
-import { user, siteTheme, gaId, cspNonce, oneTrustScriptDomain } from './globals'
+import { user, siteTheme, gaId, cspNonce } from './globals'
 // import * as serviceWorker from './serviceWorker'
 
 const container = document.getElementById('root')
@@ -15,7 +15,7 @@ root.render(
   <Router basename='/'>
     <ApolloProvider client={client}>
       <ThemeProvider theme={siteTheme}>
-        <App user={user} gaId={gaId} cspNonce={cspNonce} oneTrustScriptDomain={oneTrustScriptDomain} />
+        <App user={user} gaId={gaId} cspNonce={cspNonce} />
       </ThemeProvider>
     </ApolloProvider>
   </Router>
diff --git a/config/env_sample.hjson b/config/env_sample.hjson
index 2ac31cf5..11fa1f15 100644
--- a/config/env_sample.hjson
+++ b/config/env_sample.hjson
@@ -18,8 +18,6 @@
     # URL_VIEW_GRADE_DISTRIBUTION
     # ID for your Google Analytics, defaults to nothing/disabled
     "GA_ID": "",
-    # ID of OneTrust script domain, used for google analytics integration
-    "OT_SCRIPT_DOMAIN": ""
     # The hex value to be used in the front end for the primary color of the palette and theme
     "PRIMARY_UI_COLOR": "#00274C",
     # Configuration of CSP see https://django-csp.readthedocs.io/en/latest/configuration.html
@@ -29,15 +27,15 @@
         "REPORT_ONLY": true,
         # You should set your domain as the DEFAULT_SRC
         "DEFAULT_SRC": ["'self'","example.edu"],
-        "SCRIPT_SRC": ["'self'", "'unsafe-inline'", "*.googletagmanager.com"],
+        "SCRIPT_SRC": ["'self'", "'unsafe-inline'", "*.googletagmanager.com", "*.umich.edu", "umich.edu"],
         "IMG_SRC": ["'self'", "data:", "*.google-analytics.com", "*.googletagmanager.com"],
         "OBJECT_SRC": [],
         "MEDIA_SRC": [],
         # If you're embedding in Canvas you may need to include instructure.com as FRAME_SRC
         "FRAME_SRC": [],
         "FONT_SRC": ["'self'", "fonts.gstatic.com"],
-        "CONNECT_SRC": ["'self'", "*.google-analytics.com", "*.analytics.google.com", "*.googletagmanager.com"],
-        "STYLE_SRC": ["'self'", "'unsafe-inline'"],
+        "CONNECT_SRC": ["'self'", "*.google-analytics.com", "*.analytics.google.com", "*.googletagmanager.com", "*.umich.edu", "umich.edu"],
+        "STYLE_SRC": ["'self'", "'unsafe-inline'", "*.umich.edu", "umich.edu"],
         "BASE_URI": [],
         "FRAME_ANCESTORS": [],
         "FORM_ACTION": [],
diff --git a/dashboard/common/utils.py b/dashboard/common/utils.py
index b9bcf3e9..6b9444fc 100644
--- a/dashboard/common/utils.py
+++ b/dashboard/common/utils.py
@@ -102,7 +102,6 @@ def get_myla_globals(request):
         logout_url = settings.LOGOUT_URL
 
     google_analytics_id = settings.GA_ID if settings.GA_ID else ""
-    one_trust_script_domain = settings.OT_SCRIPT_DOMAIN if settings.OT_SCRIPT_DOMAIN else ""
     primary_ui_color = settings.PRIMARY_UI_COLOR
 
     myla_globals = {
@@ -115,7 +114,6 @@ def get_myla_globals(request):
         "logout": logout_url,
         "primary_ui_color": primary_ui_color,
         "google_analytics_id": google_analytics_id,
-        "one_trust_script_domain": one_trust_script_domain,
         "view_help_urls": {
             'ra': settings.URL_VIEW_RESOURCES_ACCESSED,
             'ap': settings.URL_VIEW_ASSIGNMENT_PLANNING,
diff --git a/dashboard/settings.py b/dashboard/settings.py
index 4e3e5b0c..5f146c56 100644
--- a/dashboard/settings.py
+++ b/dashboard/settings.py
@@ -78,7 +78,6 @@ def apply_env_overrides(env: Dict[str, Any], environ: os._Environ) -> Dict[str,
 
 # Google Analytics ID
 GA_ID = ENV.get('GA_ID', '')
-OT_SCRIPT_DOMAIN = ENV.get('OT_SCRIPT_DOMAIN', '')
 
 # Resource values from env
 RESOURCE_VALUES = ENV.get("RESOURCE_VALUES", {"files": {"types": ["canvas"], "icon": "fas fa-file fa-lg"}})
diff --git a/package-lock.json b/package-lock.json
index a5b16a8b..4b6b83f8 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -12,7 +12,7 @@
         "@emotion/styled": "11.11.0",
         "@mui/icons-material": "5.15.3",
         "@mui/material": "5.15.3",
-        "@tl-its-umich-edu/react-ga-onetrust-consent": "github:tl-its-umich-edu/react-ga-onetrust-consent#v1.0.0",
+        "@tl-its-umich-edu/react-ga-onetrust-consent": "github:tl-its-umich-edu/react-ga-onetrust-consent#v1.2.1",
         "clsx": "2.1.0",
         "d3": "7.8.5",
         "d3-v6-tip": "1.0.9",
@@ -3410,16 +3410,18 @@
       }
     },
     "node_modules/@tl-its-umich-edu/react-ga-onetrust-consent": {
-      "version": "1.0.0",
-      "resolved": "git+ssh://git@github.com/tl-its-umich-edu/react-ga-onetrust-consent.git#b7d25b3468f8a87665dd394ed7915b62c2d53b22",
+      "version": "1.2.1",
+      "resolved": "git+ssh://git@github.com/tl-its-umich-edu/react-ga-onetrust-consent.git#cf10d4d8966539a18cc023a027ee8101099e3e98",
       "license": "Apache-2.0",
       "dependencies": {
         "jest-environment-jsdom": "29.7.0",
         "js-cookie": "3.0.5",
-        "react": "18.3.1",
-        "react-dom": "18.3.1",
-        "react-ga4": "2.1.0",
-        "react-router-dom": "6.25.1"
+        "react-ga4": "2.1.0"
+      },
+      "peerDependencies": {
+        "react": "18.x",
+        "react-dom": "18.x",
+        "react-router-dom": "6.x"
       }
     },
     "node_modules/@tl-its-umich-edu/react-ga-onetrust-consent/node_modules/@jest/environment": {
diff --git a/package.json b/package.json
index 9a862de0..2f8d66b5 100644
--- a/package.json
+++ b/package.json
@@ -10,7 +10,7 @@
     "@emotion/styled": "11.11.0",
     "@mui/icons-material": "5.15.3",
     "@mui/material": "5.15.3",
-    "@tl-its-umich-edu/react-ga-onetrust-consent": "github:tl-its-umich-edu/react-ga-onetrust-consent#v1.0.0",
+    "@tl-its-umich-edu/react-ga-onetrust-consent": "github:tl-its-umich-edu/react-ga-onetrust-consent#v1.2.1",
     "clsx": "2.1.0",
     "d3": "7.8.5",
     "d3-v6-tip": "1.0.9",
@@ -26,8 +26,21 @@
   },
   "babel": {
     "presets": [
-      ["@babel/preset-env",{"targets": {"esmodules": true}}],
-      ["@babel/preset-react",{"runtime": "automatic"}]]
+      [
+        "@babel/preset-env",
+        {
+          "targets": {
+            "esmodules": true
+          }
+        }
+      ],
+      [
+        "@babel/preset-react",
+        {
+          "runtime": "automatic"
+        }
+      ]
+    ]
   },
   "scripts": {
     "prod": "BABEL_ENV=production webpack --config webpack.config.js --mode production",


Reviews:
user: login: pushyamig
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-06T14:25:54Z
user: login: pushyamig
body: We still have the issue with cookie not being set for local run, I am ok merging it if this is solved on non-prod server. I have one comment about CSP props update with banner for documentation purpose. 

This is working as expected 
state: APPROVED
author_association: CONTRIBUTOR
submitted_at: 2025-03-06T14:36:10Z
user: login: jonespm
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-03-06T15:21:45Z
user: login: pushyamig
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-06T15:34:50Z
user: login: pushyamig
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-06T15:35:51Z
user: login: pushyamig
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-06T15:38:28Z

Review comments:
diff_hunk: @@ -5,11 +5,27 @@ import Course from './Course'
 import WarningBanner from '../components/WarningBanner'
 import AlertBanner from '../components/AlertBanner'
 import { Helmet } from 'react-helmet'
-import useGoogleAnalytics from '@tl-its-umich-edu/react-ga-onetrust-consent'
+import {useGoogleAnalytics, useUmConsent} from '@tl-its-umich-edu/react-ga-onetrust-consent'
 
 function App (props) {
-  const { user, gaId, cspNonce, oneTrustScriptDomain } = props
-  useGoogleAnalytics({ googleAnalyticsId: gaId, nonce: cspNonce, oneTrustScriptDomain })
+  const { user, gaId, cspNonce } = props
+  const { gaInitialized, gaHandlers } = useGoogleAnalytics({ googleAnalyticsId: gaId, nonce: cspNonce })
+  const { umConsentInitialize, umConsentInitialized } = useUmConsent()
+
+  if (
+    !umConsentInitialized &&
+    gaInitialized &&
+    gaHandlers.onConsentApprove &&
+    gaHandlers.onConsentReject
+  ) {
+    const consentParams = {
+      developmentMode: false,
+      alwaysShow: false,
+      onConsentApprove: gaHandlers.onConsentApprove,
+      onConsentReject: gaHandlers.onConsentReject,
+    };
+    umConsentInitialize(consentParams)
+  }
path: assets/src/containers/App.js
user: login: pushyamig
body: I see the with Loophole or ngrok the cookie doesn't set, looks like further diagnosis on this could be local thing and not non-prod/prod issue. 
created_at: 2025-03-06T14:25:54Z
author_association: CONTRIBUTOR
diff_hunk: @@ -5,11 +5,27 @@ import Course from './Course'
 import WarningBanner from '../components/WarningBanner'
 import AlertBanner from '../components/AlertBanner'
 import { Helmet } from 'react-helmet'
-import useGoogleAnalytics from '@tl-its-umich-edu/react-ga-onetrust-consent'
+import {useGoogleAnalytics, useUmConsent} from '@tl-its-umich-edu/react-ga-onetrust-consent'
 
 function App (props) {
-  const { user, gaId, cspNonce, oneTrustScriptDomain } = props
-  useGoogleAnalytics({ googleAnalyticsId: gaId, nonce: cspNonce, oneTrustScriptDomain })
+  const { user, gaId, cspNonce } = props
+  const { gaInitialized, gaHandlers } = useGoogleAnalytics({ googleAnalyticsId: gaId, nonce: cspNonce })
+  const { umConsentInitialize, umConsentInitialized } = useUmConsent()
+
+  if (
+    !umConsentInitialized &&
+    gaInitialized &&
+    gaHandlers.onConsentApprove &&
+    gaHandlers.onConsentReject
+  ) {
+    const consentParams = {
+      developmentMode: false,
+      alwaysShow: false,
+      onConsentApprove: gaHandlers.onConsentApprove,
+      onConsentReject: gaHandlers.onConsentReject,
+    };
+    umConsentInitialize(consentParams)
+  }
path: assets/src/containers/App.js
user: login: jonespm
body: I haven't tested the apps that launch from Canvas but ROHQ works fine on localhost and sounds like you tested CCM? I think it's fine to merge this and test it too if that's the case. Would be nice if we could figure out why it wasn't working. But I'm also hoping we can get this library updated to support the localStorage option.
created_at: 2025-03-06T15:21:45Z
author_association: MEMBER
diff_hunk: @@ -5,11 +5,27 @@ import Course from './Course'
 import WarningBanner from '../components/WarningBanner'
 import AlertBanner from '../components/AlertBanner'
 import { Helmet } from 'react-helmet'
-import useGoogleAnalytics from '@tl-its-umich-edu/react-ga-onetrust-consent'
+import {useGoogleAnalytics, useUmConsent} from '@tl-its-umich-edu/react-ga-onetrust-consent'
 
 function App (props) {
-  const { user, gaId, cspNonce, oneTrustScriptDomain } = props
-  useGoogleAnalytics({ googleAnalyticsId: gaId, nonce: cspNonce, oneTrustScriptDomain })
+  const { user, gaId, cspNonce } = props
+  const { gaInitialized, gaHandlers } = useGoogleAnalytics({ googleAnalyticsId: gaId, nonce: cspNonce })
+  const { umConsentInitialize, umConsentInitialized } = useUmConsent()
+
+  if (
+    !umConsentInitialized &&
+    gaInitialized &&
+    gaHandlers.onConsentApprove &&
+    gaHandlers.onConsentReject
+  ) {
+    const consentParams = {
+      developmentMode: false,
+      alwaysShow: false,
+      onConsentApprove: gaHandlers.onConsentApprove,
+      onConsentReject: gaHandlers.onConsentReject,
+    };
+    umConsentInitialize(consentParams)
+  }
path: assets/src/containers/App.js
user: login: pushyamig
body: Yes I tested in CCM same behavior it won't set the cookie either ngrok/loop hole.
created_at: 2025-03-06T15:34:50Z
author_association: CONTRIBUTOR
diff_hunk: @@ -5,11 +5,27 @@ import Course from './Course'
 import WarningBanner from '../components/WarningBanner'
 import AlertBanner from '../components/AlertBanner'
 import { Helmet } from 'react-helmet'
-import useGoogleAnalytics from '@tl-its-umich-edu/react-ga-onetrust-consent'
+import {useGoogleAnalytics, useUmConsent} from '@tl-its-umich-edu/react-ga-onetrust-consent'
 
 function App (props) {
-  const { user, gaId, cspNonce, oneTrustScriptDomain } = props
-  useGoogleAnalytics({ googleAnalyticsId: gaId, nonce: cspNonce, oneTrustScriptDomain })
+  const { user, gaId, cspNonce } = props
+  const { gaInitialized, gaHandlers } = useGoogleAnalytics({ googleAnalyticsId: gaId, nonce: cspNonce })
+  const { umConsentInitialize, umConsentInitialized } = useUmConsent()
+
+  if (
+    !umConsentInitialized &&
+    gaInitialized &&
+    gaHandlers.onConsentApprove &&
+    gaHandlers.onConsentReject
+  ) {
+    const consentParams = {
+      developmentMode: false,
+      alwaysShow: false,
+      onConsentApprove: gaHandlers.onConsentApprove,
+      onConsentReject: gaHandlers.onConsentReject,
+    };
+    umConsentInitialize(consentParams)
+  }
path: assets/src/containers/App.js
user: login: pushyamig
body: I am fine merging it now
created_at: 2025-03-06T15:35:51Z
author_association: CONTRIBUTOR
diff_hunk: @@ -5,11 +5,27 @@ import Course from './Course'
 import WarningBanner from '../components/WarningBanner'
 import AlertBanner from '../components/AlertBanner'
 import { Helmet } from 'react-helmet'
-import useGoogleAnalytics from '@tl-its-umich-edu/react-ga-onetrust-consent'
+import {useGoogleAnalytics, useUmConsent} from '@tl-its-umich-edu/react-ga-onetrust-consent'
 
 function App (props) {
-  const { user, gaId, cspNonce, oneTrustScriptDomain } = props
-  useGoogleAnalytics({ googleAnalyticsId: gaId, nonce: cspNonce, oneTrustScriptDomain })
+  const { user, gaId, cspNonce } = props
+  const { gaInitialized, gaHandlers } = useGoogleAnalytics({ googleAnalyticsId: gaId, nonce: cspNonce })
+  const { umConsentInitialize, umConsentInitialized } = useUmConsent()
+
+  if (
+    !umConsentInitialized &&
+    gaInitialized &&
+    gaHandlers.onConsentApprove &&
+    gaHandlers.onConsentReject
+  ) {
+    const consentParams = {
+      developmentMode: false,
+      alwaysShow: false,
+      onConsentApprove: gaHandlers.onConsentApprove,
+      onConsentReject: gaHandlers.onConsentReject,
+    };
+    umConsentInitialize(consentParams)
+  }
path: assets/src/containers/App.js
user: login: pushyamig
body: If I remember correctly with oneTrust approach last time we never tested the PR from Localhost, the PR changes were set on Openshift Non-prod and we were just testing from there. So I don't know exactly why we did that last time, so to me we can merge and test it from Openshift
created_at: 2025-03-06T15:38:28Z
author_association: CONTRIBUTOR

PR comments:
user: login: pushyamig
created_at: 2025-03-06T14:08:30Z
body: I am reviewing this now
author_association: CONTRIBUTOR
user: login: pushyamig
created_at: 2025-03-06T14:24:52Z
body: CSP variable need to be updated with `"*.umich.edu", "umich.edu"` for `SCRIPT_SRC` and `STYLE_SRC` variables. I think the sample .env.sample.hjson should reflect this. 
author_association: CONTRIBUTOR
user: login: pushyamig
created_at: 2025-03-06T14:26:30Z
body: This integration seems to be working for banner appearing and GA capture
author_association: CONTRIBUTOR
user: login: pushyamig
created_at: 2025-03-06T14:27:15Z
body: @jonespm I think i will defer to your approval if we want to merge this and as we put this on Non-prod the cookie issue can be resolved or not. 
author_association: CONTRIBUTOR