Add script fetch api stats from plausible
parent
0f69388e1a
commit
6a4606155a
|
@ -0,0 +1,52 @@
|
|||
import 'dotenv/config.js'
|
||||
import 'isomorphic-fetch'
|
||||
|
||||
const fetchApiStats = async (page, start, end, interval) => {
|
||||
const url =
|
||||
'https://plausible.io/api/v1/stats/timeseries?' +
|
||||
Object.entries({
|
||||
site_id: 'mon-entreprise.urssaf.fr/api',
|
||||
period: 'custom',
|
||||
date: start + ',' + end,
|
||||
interval,
|
||||
metrics: 'pageviews,visitors',
|
||||
filters: 'event:page==' + page,
|
||||
})
|
||||
.map(([k, v]) => encodeURIComponent(k) + '=' + encodeURIComponent(v))
|
||||
.join('&')
|
||||
|
||||
const result = await fetch(url, {
|
||||
headers: new Headers({
|
||||
Authorization: `Bearer ${process.env.PLAUSIBLE_API_KEY}`,
|
||||
}),
|
||||
})
|
||||
|
||||
return result.json()
|
||||
}
|
||||
|
||||
export const apiStats = async (start, end, interval) => {
|
||||
const names = ['evaluate', 'rules', 'rule']
|
||||
const data = Object.values(
|
||||
(
|
||||
await Promise.all([
|
||||
fetchApiStats('/api/v1/evaluate', start, end, interval),
|
||||
fetchApiStats('/api/v1/rules', start, end, interval),
|
||||
fetchApiStats('/api/v1/rules/*', start, end, interval),
|
||||
])
|
||||
)
|
||||
.flatMap(({ results }, i) =>
|
||||
results.map(({ date, pageviews }) => ({ date, [names[i]]: pageviews }))
|
||||
)
|
||||
.reduce(
|
||||
(acc, el) => (
|
||||
acc[el.date]
|
||||
? (acc[el.date] = { ...acc[el.date], ...el })
|
||||
: (acc[el.date] = el),
|
||||
acc
|
||||
),
|
||||
{}
|
||||
)
|
||||
)
|
||||
|
||||
return data
|
||||
}
|
|
@ -3,6 +3,7 @@ import 'isomorphic-fetch'
|
|||
import fs from 'fs'
|
||||
import path from 'path'
|
||||
import { fileURLToPath } from 'url'
|
||||
import { apiStats } from './fetch-api-stats.js'
|
||||
import { createDataDir, writeInDataDir } from './utils.js'
|
||||
|
||||
const matomoSiteVisitsHistory = JSON.parse(
|
||||
|
@ -180,7 +181,9 @@ async function fetchDailyVisits() {
|
|||
(await fetchApi(buildSiteQuery(last60days, 'D')))[0].Rows
|
||||
)
|
||||
|
||||
return { pages, site }
|
||||
const { start, end } = last60days
|
||||
|
||||
return { pages, site, api: await apiStats(start, end, 'date') }
|
||||
}
|
||||
|
||||
async function fetchMonthlyVisits() {
|
||||
|
@ -198,7 +201,9 @@ async function fetchMonthlyVisits() {
|
|||
),
|
||||
]
|
||||
|
||||
return { pages, site }
|
||||
const { start, end } = last36Months
|
||||
|
||||
return { pages, site, api: await apiStats(start, end, 'month') }
|
||||
}
|
||||
|
||||
async function fetchUserAnswersStats() {
|
||||
|
@ -292,20 +297,29 @@ async function main() {
|
|||
)
|
||||
return
|
||||
}
|
||||
const visitesJours = await fetchDailyVisits()
|
||||
const visitesMois = await fetchMonthlyVisits()
|
||||
const satisfaction = uniformiseData(
|
||||
flattenPage(await fetchApi(buildSatisfactionQuery()))
|
||||
).map((page) => {
|
||||
// eslint-disable-next-line no-unused-vars
|
||||
const { date, ...satisfactionPage } = {
|
||||
month: new Date(new Date(page.date).setDate(1)),
|
||||
...page,
|
||||
const [
|
||||
visitesJours,
|
||||
visitesMois,
|
||||
rawSatisfaction,
|
||||
retoursUtilisateurs,
|
||||
nbAnswersLast30days,
|
||||
] = await Promise.all([
|
||||
fetchDailyVisits(),
|
||||
fetchMonthlyVisits(),
|
||||
fetchApi(buildSatisfactionQuery()),
|
||||
fetchUserFeedbackIssues(),
|
||||
fetchUserAnswersStats(),
|
||||
])
|
||||
const satisfaction = uniformiseData(flattenPage(await rawSatisfaction)).map(
|
||||
(page) => {
|
||||
// eslint-disable-next-line no-unused-vars
|
||||
const { date, ...satisfactionPage } = {
|
||||
month: new Date(new Date(page.date).setDate(1)),
|
||||
...page,
|
||||
}
|
||||
return satisfactionPage
|
||||
}
|
||||
return satisfactionPage
|
||||
})
|
||||
const retoursUtilisateurs = await fetchUserFeedbackIssues()
|
||||
const nbAnswersLast30days = await fetchUserAnswersStats()
|
||||
)
|
||||
writeInDataDir('stats.json', {
|
||||
visitesJours,
|
||||
visitesMois,
|
||||
|
@ -314,7 +328,7 @@ async function main() {
|
|||
nbAnswersLast30days,
|
||||
})
|
||||
} catch (e) {
|
||||
console.log(e)
|
||||
console.error(e)
|
||||
}
|
||||
}
|
||||
main()
|
||||
|
|
|
@ -26,7 +26,7 @@ import { Page, PageChapter2, PageSatisfaction, StatsStruct } from './types'
|
|||
import { formatDay, formatMonth } from './utils'
|
||||
|
||||
type Period = 'mois' | 'jours'
|
||||
type Chapter2 = PageChapter2 | 'PAM'
|
||||
type Chapter2 = PageChapter2 | 'PAM' | 'api-rest'
|
||||
|
||||
type Pageish = Page | PageSatisfaction
|
||||
|
||||
|
@ -105,11 +105,6 @@ const computeTotals = (
|
|||
: data.map((d) => d.nombre).reduce((a, b) => a + b, 0)
|
||||
}
|
||||
|
||||
interface BrushStartEndIndex {
|
||||
startIndex?: number
|
||||
endIndex?: number
|
||||
}
|
||||
|
||||
interface StatsDetailProps {
|
||||
stats: StatsStruct
|
||||
}
|
||||
|
@ -140,6 +135,9 @@ const StatsDetail = ({ stats }: StatsDetailProps) => {
|
|||
if (!chapter2) {
|
||||
return rawData.site
|
||||
}
|
||||
if (chapter2 === 'api-rest') {
|
||||
return rawData.api.map(({ date, ...nombre }) => ({ date, nombre }))
|
||||
}
|
||||
|
||||
return filterByChapter2(rawData.pages as Pageish[], chapter2)
|
||||
}, [period, chapter2])
|
||||
|
@ -233,17 +231,21 @@ const StatsDetail = ({ stats }: StatsDetailProps) => {
|
|||
endIndex={endDateIndex}
|
||||
/>
|
||||
|
||||
<H3>
|
||||
Cumuls pour la période{' '}
|
||||
{period === 'jours'
|
||||
? `du ${formatDay(slicedVisits[0].date)} au ${formatDay(
|
||||
slicedVisits[slicedVisits.length - 1].date
|
||||
)}`
|
||||
: `de ${formatMonth(slicedVisits[0].date)}` +
|
||||
(slicedVisits.length > 1
|
||||
? ` à ${formatMonth(slicedVisits[slicedVisits.length - 1].date)}`
|
||||
: '')}
|
||||
</H3>
|
||||
{slicedVisits.length > 0 && (
|
||||
<H3>
|
||||
Cumuls pour la période{' '}
|
||||
{period === 'jours'
|
||||
? `du ${formatDay(slicedVisits[0].date)} au ${formatDay(
|
||||
slicedVisits[slicedVisits.length - 1].date
|
||||
)}`
|
||||
: `de ${formatMonth(slicedVisits[0].date)}` +
|
||||
(slicedVisits.length > 1
|
||||
? ` à ${formatMonth(
|
||||
slicedVisits[slicedVisits.length - 1].date
|
||||
)}`
|
||||
: '')}
|
||||
</H3>
|
||||
)}
|
||||
|
||||
<Grid container spacing={2}>
|
||||
<BigIndicator
|
||||
|
@ -387,8 +389,10 @@ function SimulateursChoice(props: {
|
|||
<Select
|
||||
onSelectionChange={(val) => {
|
||||
props.onChange(
|
||||
typeof val === 'string' && val.length
|
||||
typeof val === 'string' && val.length && !isNaN(parseInt(val))
|
||||
? getChapter2(simulateurs[parseInt(val)])
|
||||
: val === 'api-rest'
|
||||
? val
|
||||
: ''
|
||||
)
|
||||
}}
|
||||
|
@ -398,7 +402,11 @@ function SimulateursChoice(props: {
|
|||
{[
|
||||
<Item key={''} textValue="Tout le site">
|
||||
<Emoji emoji="🌍" />
|
||||
Tout le site
|
||||
Tout le site
|
||||
</Item>,
|
||||
<Item key={'api-rest'} textValue="API REST">
|
||||
<Emoji emoji="👩💻" />
|
||||
API REST
|
||||
</Item>,
|
||||
...simulateurs.map((s, i) => (
|
||||
<Item key={i} textValue={s.shortName}>
|
||||
|
|
|
@ -39,16 +39,24 @@ export enum SatisfactionLevel {
|
|||
TrèsBien = 'très bien',
|
||||
}
|
||||
|
||||
export interface Visites {
|
||||
interface Visites {
|
||||
pages: Page[]
|
||||
site: Site[]
|
||||
api: API[]
|
||||
}
|
||||
|
||||
export interface Site {
|
||||
interface Site {
|
||||
date: string
|
||||
nombre: number
|
||||
}
|
||||
|
||||
interface API {
|
||||
date: string
|
||||
evaluate: number
|
||||
rules: number
|
||||
rule: number
|
||||
}
|
||||
|
||||
export enum PageChapter2 {
|
||||
AideDeclarationIndependant = 'aide_declaration_independant',
|
||||
ArtisteAuteur = 'artiste_auteur',
|
||||
|
|
Loading…
Reference in New Issue