diff --git a/api/package.json b/api/package.json index 2d570d15c..50b632c32 100644 --- a/api/package.json +++ b/api/package.json @@ -42,6 +42,7 @@ "koa-static": "^5.0.0", "modele-social": "workspace:^", "nodemon": "^3.0.1", + "piano-analytics-js": "^6.13.0", "publicodes": "^1.0.0-beta.76", "rate-limiter-flexible": "^2.4.2", "swagger-ui-dist": "^5.7.2" diff --git a/api/source/analytics.ts b/api/source/analytics.ts new file mode 100644 index 000000000..54eba548f --- /dev/null +++ b/api/source/analytics.ts @@ -0,0 +1,42 @@ +import { BaseContext } from 'koa' +// @ts-ignore +import { pianoAnalytics } from 'piano-analytics-js' + +pianoAnalytics.setConfigurations({ + site: 617190, + collectDomain: 'https://tm.urssaf.fr', +}) + +function pathToPageData(path: string) { + const [pageChapter1, pageChapter2, page] = path.split('/').filter(Boolean) + + return { + page, + page_chapter1: pageChapter1, + page_chapter2: pageChapter2, + } +} + +export const analyticsMiddleware = async ( + ctx: BaseContext, + next: () => Promise +) => { + if (process.env.NODE_ENV !== 'production') { + return next() + } + const pageData = pathToPageData(ctx.path) + pianoAnalytics.sendEvent( + 'page.display', // Event name + pageData // Event properties + ) + const result = await next() + pianoAnalytics.sendEvent( + 'click.exit', // Event used for tracking status code + { + click: ctx.status, + ...pageData, // Event properties + } + ) + + return result +} diff --git a/api/source/index.ts b/api/source/index.ts index a3163a356..5e3d17318 100644 --- a/api/source/index.ts +++ b/api/source/index.ts @@ -5,9 +5,9 @@ import Koa from 'koa' import rules from 'modele-social' import Engine from 'publicodes' +import { analyticsMiddleware } from './analytics.js' import { catchErrors } from './errors.js' import openapi from './openapi.json' assert { type: 'json' } -import { plausibleMiddleware } from './plausible.js' import { rateLimiterMiddleware } from './rate-limiter.js' import { redisCacheMiddleware } from './redis-cache.js' import { docRoutes } from './route/doc.js' @@ -49,7 +49,7 @@ router.use( '/api/v1', rateLimiterMiddleware, redisCacheMiddleware(), - plausibleMiddleware, + analyticsMiddleware, apiRoutes ) diff --git a/api/source/plausible.ts b/api/source/plausible.ts deleted file mode 100644 index 1870cf444..000000000 --- a/api/source/plausible.ts +++ /dev/null @@ -1,65 +0,0 @@ -import got, { RequestError } from 'got' -import { BaseContext } from 'koa' - -interface PlausibleEvent { - eventName: string - props?: Record -} - -export const plausibleEvent = ( - ctx: BaseContext, - { eventName, props }: PlausibleEvent -) => { - const userAgent = ctx.headers['user-agent'] ?? '' - const xForwardedFor = - (Array.isArray(ctx.headers['x-forwarded-for']) - ? ctx.headers['x-forwarded-for'][0] - : ctx.headers['x-forwarded-for']) ?? '' - const referer = ctx.headers.referer ?? '' - const url = ctx.href - - return got('https://plausible.io/api/event', { - method: 'POST', - headers: { - 'user-agent': userAgent, - 'x-forwarded-for': xForwardedFor, - }, - json: { - domain: 'mon-entreprise.urssaf.fr/api', - name: eventName, - referer, - url, - props, - }, - }) -} - -export const plausibleMiddleware = async ( - ctx: BaseContext, - next: () => Promise -) => { - if (process.env.NODE_ENV !== 'production') { - return await next() - } - - void plausibleEvent(ctx, { eventName: 'pageview' }).catch((err) => { - const error = err as RequestError - // eslint-disable-next-line no-console - console.error(error.code, error.message) - }) - - const result = await next() - - void plausibleEvent(ctx, { - eventName: 'status', - props: { - status: ctx.status, - }, - }).catch((err) => { - const error = err as RequestError - // eslint-disable-next-line no-console - console.error(error.code, error.message) - }) - - return result -} diff --git a/api/source/route/doc.ts b/api/source/route/doc.ts index 33fde5731..fd2c44614 100644 --- a/api/source/route/doc.ts +++ b/api/source/route/doc.ts @@ -2,14 +2,14 @@ import Router from '@koa/router' import koaStatic from 'koa-static' import { absolutePath } from 'swagger-ui-dist' -import { plausibleMiddleware } from '../plausible.js' +import { analyticsMiddleware } from '../analytics.js' export const docRoutes = () => { const router = new Router() router.all( '/doc/(.*)', - plausibleMiddleware, + analyticsMiddleware, async (ctx, next) => { const rewriteURL = (typeof ctx.url === 'string' && ctx.url.replace(/.*\/doc\//, '/')) || diff --git a/api/source/route/openapi.ts b/api/source/route/openapi.ts index 80fdc0f69..5b00a130b 100644 --- a/api/source/route/openapi.ts +++ b/api/source/route/openapi.ts @@ -2,7 +2,7 @@ import Router from '@koa/router' import { openapi as publicodesOpenapi } from '@publicodes/api' import { Context } from 'koa' -import { plausibleMiddleware } from '../plausible.js' +import { analyticsMiddleware } from '../analytics.js' import { mergeDeep } from '../utils.js' /** @@ -15,7 +15,7 @@ export const openapiRoutes = (customOpenapi: Record) => { const mergedOpenapi = mergeDeep(publicodesOpenapi, customOpenapi) - router.get('/openapi.json', plausibleMiddleware, (ctx: Context) => { + router.get('/openapi.json', analyticsMiddleware, (ctx: Context) => { ctx.type = 'application/json' ctx.body = mergedOpenapi }) diff --git a/site/package.json b/site/package.json index 221b929c3..c539809ee 100644 --- a/site/package.json +++ b/site/package.json @@ -69,6 +69,7 @@ "isbot": "^3.7.0", "markdown-to-jsx": "^7.3.2", "modele-social": "workspace:^", + "piano-analytics-js": "^6.13.0", "publicodes": "^1.0.0-beta.76", "publicodes-react": "^1.0.0-beta.76", "react": "^18.2.0", diff --git a/yarn.lock b/yarn.lock index a2bf3b95e..83abb73b1 100644 --- a/yarn.lock +++ b/yarn.lock @@ -13459,6 +13459,7 @@ __metadata: koa-static: ^5.0.0 modele-social: "workspace:^" nodemon: ^3.0.1 + piano-analytics-js: ^6.13.0 publicodes: ^1.0.0-beta.76 rate-limiter-flexible: ^2.4.2 swagger-ui-dist: ^5.7.2 @@ -25542,6 +25543,13 @@ __metadata: languageName: node linkType: hard +"piano-analytics-js@npm:^6.13.0": + version: 6.13.0 + resolution: "piano-analytics-js@npm:6.13.0" + checksum: e80272cd8bd72eb85cbd674a57bf6baf6328ba28bdc3511aab626e730a40a9a4a8656e4d43824ec30e66f776c2598c0e79fe4f6918ba7593a7a8941c462935c0 + languageName: node + linkType: hard + "picocolors@npm:^1.0.0": version: 1.0.0 resolution: "picocolors@npm:1.0.0" @@ -28378,6 +28386,7 @@ __metadata: markdown-to-jsx: ^7.3.2 modele-social: "workspace:^" netlify-cli: ^16.4.0 + piano-analytics-js: ^6.13.0 publicodes: ^1.0.0-beta.76 publicodes-react: ^1.0.0-beta.76 react: ^18.2.0