Skip to content

Commit

Permalink
feat: Integration of Matomo (#43) (#180)
Browse files Browse the repository at this point in the history
  • Loading branch information
gromdimon authored Nov 3, 2023
1 parent 247d9b1 commit 0bf5869
Show file tree
Hide file tree
Showing 11 changed files with 134 additions and 4 deletions.
12 changes: 12 additions & 0 deletions backend/app/api/internal/api.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import subprocess

from fastapi import APIRouter, Response
from fastapi.responses import JSONResponse

from app.api.internal.endpoints import proxy, remote
from app.core.config import settings
Expand All @@ -20,3 +21,14 @@ async def version():
else:
version = subprocess.check_output(["git", "describe", "--tags", "--dirty"]).strip()
return Response(content=version)


@api_router.get("/frontend-settings")
@api_router.post("/frontend-settings")
async def matomo():
"""Return Frontend settings"""
frontend_settings = {
"matomo_host": settings.MATOMO_HOST,
"matomo_site_id": settings.MATOMO_SITE_ID,
}
return JSONResponse(content=frontend_settings)
5 changes: 5 additions & 0 deletions backend/app/core/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,11 @@ def assemble_reev_version(cls, v: str | None, info: ValidationInfo) -> str | Non
else:
return None

#: Matomo host
MATOMO_HOST: str | None = None
#: Matomo site ID
MATOMO_SITE_ID: int | None = None

# == API-related settings ==

#: URL prefix for internal API
Expand Down
20 changes: 20 additions & 0 deletions backend/tests/test_main.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,3 +33,23 @@ async def test_favicon(client: TestClient):
response = client.get("/favicon.ico")
assert response.status_code == 200
assert response.headers["content-type"] == "image/vnd.microsoft.icon"


@pytest.mark.asyncio
async def test_frontend_settings(monkeypatch: MonkeyPatch, client: TestClient):
"""Test frontend settings endpoint."""
monkeypatch.setattr(settings, "MATOMO_HOST", "matomo.example.com")
monkeypatch.setattr(settings, "MATOMO_SITE_ID", 42)
response = client.get("/internal/frontend-settings")
assert response.status_code == 200
assert response.json() == {"matomo_host": "matomo.example.com", "matomo_site_id": 42}


@pytest.mark.asyncio
async def test_frontend_settings_no_matomo(monkeypatch: MonkeyPatch, client: TestClient):
"""Test frontend settings endpoint with no matomo."""
monkeypatch.setattr(settings, "MATOMO_HOST", None)
monkeypatch.setattr(settings, "MATOMO_SITE_ID", None)
response = client.get("/internal/frontend-settings")
assert response.status_code == 200
assert response.json() == {"matomo_host": None, "matomo_site_id": None}
10 changes: 10 additions & 0 deletions frontend/package-lock.json

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

1 change: 1 addition & 0 deletions frontend/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
"vega": "^5.25.0",
"vega-embed": "^6.22.2",
"vue": "^3.3.4",
"vue-matomo": "^4.2.0",
"vue-router": "^4.2.5",
"vue3-easy-data-table": "^1.5.47",
"vuetify": "^3.3.19"
Expand Down
23 changes: 23 additions & 0 deletions frontend/src/api/__tests__/settings.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import { beforeEach, describe, expect, it, vi } from 'vitest'
import createFetchMock from 'vitest-fetch-mock'

import { SettingsClient } from '@/api/settings'

const fetchMocker = createFetchMock(vi)

describe.concurrent('Settings Client', () => {
beforeEach(() => {
fetchMocker.enableMocks()
fetchMocker.resetMocks()
})

it('fetches version info correctly', async () => {
fetchMocker.mockResponseOnce(
JSON.stringify({ matomo_host: 'https://matomo.example.com/', matomo_site_id: '1' })
)

const client = new SettingsClient()
const result = await client.fetchFrontendSettings()
expect(result).toEqual({ matomo_host: 'https://matomo.example.com/', matomo_site_id: '1' })
})
})
20 changes: 20 additions & 0 deletions frontend/src/api/settings.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import { API_INTERNAL_BASE_PREFIX } from '@/api/common'

const API_BASE_URL = API_INTERNAL_BASE_PREFIX

export class SettingsClient {
private apiBaseUrl: string
private csrfToken: string | null

constructor(apiBaseUrl?: string, csrfToken?: string) {
this.apiBaseUrl = apiBaseUrl ?? API_BASE_URL
this.csrfToken = csrfToken ?? null
}

async fetchFrontendSettings(): Promise<any> {
const response = await fetch(`${this.apiBaseUrl}frontend-settings`, {
method: 'GET'
})
return await response.json()
}
}
10 changes: 7 additions & 3 deletions frontend/src/main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,12 @@ import { registerPlugins } from '@/plugins'

import App from './App.vue'

const app = createApp(App)
async function bootstrap() {
const app = createApp(App)

registerPlugins(app)
await registerPlugins(app)

app.mount('#app')
app.mount('#app')
}

bootstrap()
6 changes: 5 additions & 1 deletion frontend/src/plugins/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,12 @@ import type { App } from 'vue'

import router from '../router'
import pinia from '../stores'
import setupMatomo from './matomo'
import vuetify from './vuetify'

export function registerPlugins(app: App) {
export async function registerPlugins(app: App) {
app.use(vuetify).use(router).use(pinia)

// Initialize Matomo
await setupMatomo(app, router)
}
28 changes: 28 additions & 0 deletions frontend/src/plugins/matomo.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
/**
* plugins/matomo.ts
*
* Matomo documentation: https://developer.matomo.org/guides/spa-tracking
*/
import { type App } from 'vue'
import VueMatomo from 'vue-matomo'

import { SettingsClient } from '@/api/settings'

async function setupMatomo(app: App, router: any) {
try {
const client = new SettingsClient()
const response = await client.fetchFrontendSettings()

app.use(VueMatomo, {
host: response['matomo_host'],
siteId: response['matomo_site_id'],
router: router,
requireConsent: true,
disableCookies: true
})
} catch (error) {
console.error('Failed to initialize Matomo:', error)
}
}

export default setupMatomo
3 changes: 3 additions & 0 deletions frontend/vite.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -42,5 +42,8 @@ export default defineConfig({
secure: false
}
}
},
build: {
chunkSizeWarningLimit: 3000
}
})

0 comments on commit 0bf5869

Please sign in to comment.