Skip to content

Commit

Permalink
[WIP] Trying to setup Matomo
Browse files Browse the repository at this point in the history
  • Loading branch information
abelsiqueira committed Oct 19, 2023
1 parent 48a503b commit cb06ccf
Show file tree
Hide file tree
Showing 8 changed files with 220 additions and 18 deletions.
45 changes: 36 additions & 9 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 2 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
"@quasar/extras": "^1.0.0",
"ajv": "^8.6.2",
"ajv-formats": "^2.1.1",
"cookie": "^0.5.0",
"core-js": "^3.6.5",
"deep-filter": "^1.0.2",
"js-yaml": "^3.14.1",
Expand All @@ -38,6 +39,7 @@
"@quasar/app": "^3.0.0",
"@quasar/quasar-app-extension-testing": "^2.0.0-beta.2",
"@quasar/quasar-app-extension-testing-unit-jest": "^3.0.0-alpha.3",
"@types/cookie": "^0.5.2",
"@types/cypress": "^1.1.3",
"@types/js-yaml": "^4.0.2",
"@types/node": "^10.17.15",
Expand Down
8 changes: 7 additions & 1 deletion src/App.vue
Original file line number Diff line number Diff line change
@@ -1,10 +1,16 @@
<template>
<PrivacyNotice />
<router-view />
</template>

<script lang="ts">
import PrivacyNotice from 'src/components/PrivacyNotice.vue'
export default ({
name: 'App'
name: 'App',
components: {
PrivacyNotice
}
})
</script>
38 changes: 38 additions & 0 deletions src/components/PrivacyNotice.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
<script lang="ts">
import { defineComponent } from 'vue'
import { useQuasar } from 'quasar'
export default defineComponent({
name: 'PrivacyNotice',
setup () {
const $q = useQuasar()
const tempWindow = window as any

Check failure on line 9 in src/components/PrivacyNotice.vue

View workflow job for this annotation

GitHub Actions / lint

Unsafe assignment of an `any` value

Check warning on line 9 in src/components/PrivacyNotice.vue

View workflow job for this annotation

GitHub Actions / lint

Unexpected any. Specify a different type
const _paq = tempWindow._paq = tempWindow._paq || []

Check failure on line 11 in src/components/PrivacyNotice.vue

View workflow job for this annotation

GitHub Actions / lint

Unsafe assignment of an `any` value

Check failure on line 11 in src/components/PrivacyNotice.vue

View workflow job for this annotation

GitHub Actions / lint

Unsafe assignment of an `any` value

Check failure on line 11 in src/components/PrivacyNotice.vue

View workflow job for this annotation

GitHub Actions / lint

Unsafe member access ._paq on an `any` value

Check failure on line 11 in src/components/PrivacyNotice.vue

View workflow job for this annotation

GitHub Actions / lint

Unsafe member access ._paq on an `any` value
const accept = () => {
_paq.push(['rememberConsentGiven'])

Check failure on line 14 in src/components/PrivacyNotice.vue

View workflow job for this annotation

GitHub Actions / lint

Unsafe member access .push on an `any` value

Check failure on line 14 in src/components/PrivacyNotice.vue

View workflow job for this annotation

GitHub Actions / lint

Unsafe call of an `any` typed value
_paq.push(['setConsentGiven'])

Check failure on line 15 in src/components/PrivacyNotice.vue

View workflow job for this annotation

GitHub Actions / lint

Unsafe member access .push on an `any` value

Check failure on line 15 in src/components/PrivacyNotice.vue

View workflow job for this annotation

GitHub Actions / lint

Unsafe call of an `any` typed value
}
const refuse = () => {
_paq.push(['forgetConsentGiven'])

Check failure on line 19 in src/components/PrivacyNotice.vue

View workflow job for this annotation

GitHub Actions / lint

Unsafe member access .push on an `any` value
}
$q.notify({
message: 'We use <a href="/cookies" class="link-over-primary" target="_blank">cookies</a> with <a href="https://matomo.org" class="link-over-primary" target="_black">matomo.org</a> to anonymously track usage and improve our app. Do you accept?',
color: 'primary',
progress: true,
timeout: 0,
actions: [
{ label: 'Accept', color: 'white', handler: accept },
{ label: 'Refuse', color: 'white', handler: refuse }
],
html: true
})
return {
}
}
})
</script>
16 changes: 14 additions & 2 deletions src/css/app.css
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ a:not(.q-btn) {
text-decoration: none
}

a:not(.q-btn):hover{
a:not(.q-btn):hover {
text-decoration: underline
}

Expand All @@ -69,16 +69,23 @@ h1 {
font-size: 32pt;
font-weight: bold;
}

h2 {
font-size: 26pt;
}

h3 {
font-size: 22pt;
}

h4 {
font-size: 20pt;
}
h1, h2, h3, h4 {

h1,
h2,
h3,
h4 {
line-height: normal;
margin: 1rem 0rem;
}
Expand Down Expand Up @@ -133,3 +140,8 @@ body {
transform: translateX(-50%);
opacity: 1;
}

.link-over-primary {
color: white !important;
text-decoration: underline !important;
}
37 changes: 31 additions & 6 deletions src/index.template.html
Original file line number Diff line number Diff line change
@@ -1,17 +1,42 @@
<!DOCTYPE html>
<html>
<head>
<title><%= productName %></title>

<head>
<title>
<%= productName %>
</title>

<meta charset="utf-8">
<meta name="description" content="<%= productDescription %>">
<meta name="format-detection" content="telephone=no">
<meta name="msapplication-tap-highlight" content="no">
<meta name="viewport" content="initial-scale=1, maximum-scale=5, minimum-scale=1, width=device-width<% if (ctx.mode.cordova || ctx.mode.capacitor) { %>, viewport-fit=cover<% } %>">
<meta name="viewport"
content="initial-scale=1, maximum-scale=5, minimum-scale=1, width=device-width<% if (ctx.mode.cordova || ctx.mode.capacitor) { %>, viewport-fit=cover<% } %>">
<link rel="icon" type="image/png" href="favicon.png">
</head>
<body>

<!-- Matomo -->
<script>
var _paq = window._paq = window._paq || [];
/* tracker methods like "setCustomDimension" should be called before "trackPageView" */
console.log('sup')
_paq.push(['requireConsent']);
_paq.push(['trackPageView']);
_paq.push(['enableLinkTracking']);
(function () {
var u = "//matomo.research.software/";
_paq.push(['setTrackerUrl', u + 'matomo.php']);
_paq.push(['setSiteId', '4']);
var d = document, g = d.createElement('script'), s = d.getElementsByTagName('script')[0];
g.async = true; g.src = u + 'matomo.js'; s.parentNode.insertBefore(g, s);
})();
</script>
<!-- End Matomo Code -->

</head>

<body>
<!-- DO NOT touch the following DIV -->
<div id="q-app"></div>
</body>
</body>

</html>
59 changes: 59 additions & 0 deletions src/store/nodeCookies.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
// Copied from https://github.com/research-software-directory/RSD-as-a-service/blob/main/frontend/components/cookies/nodeCookies.ts

import { IncomingMessage } from 'http'
import cookie from 'cookie'

export type Matomo = {
id: string | null
consent: boolean | null
}

/**
* Extract Matomo cookies
* Available only on the server side, using plain Node request
* @param req
* @returns Session
*/
export function getMatomoCookies (req: IncomingMessage) {
// check for cookies
if (req?.headers?.cookie) {
// parse cookies from node request
const cookies = cookie.parse(req.headers.cookie)
// validate and decode
return {
mtm_consent: cookies?.mtm_consent,
mtm_consent_removed: cookies?.mtm_consent_removed
}
} else {
return {
mtm_consent: undefined,
mtm_consent_removed: undefined
}
}
}

/**
* Extract matomo consent based on cookies
* Available only on the server side, using plain Node request
* @param req
* @returns Session
*/
export function getMatomoConsent (req:IncomingMessage) {
// check for cookies
// console.log('getMatomoConsent...', req)
if (req?.headers?.cookie) {
const matomo = getMatomoCookies(req)
if (matomo?.mtm_consent) {
return {
matomoConsent: true
}
} else if (matomo?.mtm_consent_removed) {
return {
matomoConsent: false
}
}
}
return {
matomoConsent: null
}
}
33 changes: 33 additions & 0 deletions test/jest/__tests__/store/matomo.jest.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
// Copied from https://github.com/research-software-directory/RSD-as-a-service/blob/main/frontend/components/cookies/nodeCookies.test.ts

import { describe, expect, it, jest } from '@jest/globals'

Check warning on line 3 in test/jest/__tests__/store/matomo.jest.spec.ts

View workflow job for this annotation

GitHub Actions / lint

'describe' is defined but never used

Check warning on line 3 in test/jest/__tests__/store/matomo.jest.spec.ts

View workflow job for this annotation

GitHub Actions / lint

'jest' is defined but never used
import { getMatomoConsent } from 'src/store/nodeCookies'

const mockRequest:any = {

Check warning on line 6 in test/jest/__tests__/store/matomo.jest.spec.ts

View workflow job for this annotation

GitHub Actions / lint

Unexpected any. Specify a different type
headers: {
cookie: '_pk_id.1.a7f1=7b08ec6de0eadf14.1664460134.; mtm_consent=1664460134155; _pk_ref.1.a7f1=%5B%22%22%2C%22%22%2C1670956090%2C%22https%3A%2F%2Fconnect.surfconext.nl%2F%22%5D; _pk_ses.1.a7f1=1'
}
}

it('extracts mtm_consent cookie from request', () => {
// extract matomo cookie
const { matomoConsent } = getMatomoConsent(mockRequest)
// assert consent is true
expect(matomoConsent).toBe(true)
})

it('extracts mtm_consent_removed cookie from request', () => {
mockRequest.headers.cookie = 'mtm_consent_removed=1664460134155;'
// extract matomo cookie
const { matomoConsent } = getMatomoConsent(mockRequest)
// expect consent is false
expect(matomoConsent).toBe(false)
})

it('extracts mtm_consent is not present', () => {
mockRequest.headers.cookie = '_pk_ses.1.a7f1=1;'
// extract matomo cookie
const { matomoConsent } = getMatomoConsent(mockRequest)
// expect consent is false
expect(matomoConsent).toBe(null)
})

0 comments on commit cb06ccf

Please sign in to comment.