mirror of https://github.com/requarks/wiki
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
155 lines
4.6 KiB
155 lines
4.6 KiB
import { audit } from '../helpers/audit.ts'
|
|
import type { FastifyInstance } from 'fastify'
|
|
import type { AnalyticsProviderInput } from '../models/analytics.ts'
|
|
|
|
/**
|
|
* Analytics API Routes
|
|
*/
|
|
async function routes(app: FastifyInstance) {
|
|
/**
|
|
* GET SITE ANALYTICS CONFIGURATION
|
|
*/
|
|
app.get<{ Params: { siteId: string } }>(
|
|
'/sites/:siteId/analytics',
|
|
{
|
|
config: {
|
|
permissions: ['manage:sites']
|
|
},
|
|
schema: {
|
|
summary: 'Get the analytics configuration of a site',
|
|
description:
|
|
'One entry per analytics module installed in `modules/analytics`, whether or not it has ever been enabled, each with the values this site has configured for it. Nothing is masked: every value here ends up in the HTML the site serves, so none of it can be a secret.',
|
|
tags: ['Analytics'],
|
|
params: {
|
|
type: 'object',
|
|
properties: {
|
|
siteId: {
|
|
type: 'string',
|
|
format: 'uuid'
|
|
}
|
|
},
|
|
required: ['siteId']
|
|
},
|
|
response: {
|
|
200: {
|
|
description: 'Analytics configuration of the site',
|
|
type: 'object',
|
|
properties: {
|
|
providers: {
|
|
type: 'array',
|
|
items: { $ref: 'AnalyticsProvider#' }
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
},
|
|
async (req, reply) => {
|
|
const site = await WIKI.models.sites.getSiteById({ id: req.params.siteId })
|
|
if (!site) {
|
|
return reply.notFound('Site does not exist.')
|
|
}
|
|
return { providers: WIKI.models.analytics.getSiteProviders(req.params.siteId) }
|
|
}
|
|
)
|
|
|
|
/**
|
|
* UPDATE SITE ANALYTICS CONFIGURATION
|
|
*/
|
|
app.put<{
|
|
Params: { siteId: string }
|
|
Body: { providers?: AnalyticsProviderInput[] }
|
|
}>(
|
|
'/sites/:siteId/analytics',
|
|
{
|
|
config: {
|
|
permissions: ['manage:sites']
|
|
},
|
|
schema: {
|
|
summary: 'Update the analytics configuration of a site',
|
|
description:
|
|
'Only the providers listed are affected, and within each of them only the props the module declares. Everything is validated before any of it is written, so a rejected request changes nothing. A saved change applies to the next document the site serves, on every instance.',
|
|
tags: ['Analytics'],
|
|
params: {
|
|
type: 'object',
|
|
properties: {
|
|
siteId: {
|
|
type: 'string',
|
|
format: 'uuid'
|
|
}
|
|
},
|
|
required: ['siteId']
|
|
},
|
|
body: {
|
|
type: 'object',
|
|
properties: {
|
|
providers: {
|
|
type: 'array',
|
|
items: { $ref: 'AnalyticsProviderInput#' }
|
|
}
|
|
}
|
|
},
|
|
response: {
|
|
200: {
|
|
description: 'Analytics configuration updated successfully',
|
|
type: 'object',
|
|
properties: {
|
|
ok: {
|
|
type: 'boolean'
|
|
},
|
|
message: {
|
|
type: 'string'
|
|
},
|
|
updated: {
|
|
type: 'integer',
|
|
description:
|
|
'How many providers were written. One already in the requested state still counts.'
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
},
|
|
async (req, reply) => {
|
|
const site = await WIKI.models.sites.getSiteById({ id: req.params.siteId })
|
|
if (!site) {
|
|
return reply.notFound('Site does not exist.')
|
|
}
|
|
|
|
// -> Validated as a whole first: the admin area saves every provider at once, and a partially
|
|
// applied configuration is worse than a refused one
|
|
const patches = req.body.providers ?? []
|
|
for (const patch of patches) {
|
|
const invalid = WIKI.models.analytics.validateProvider(patch)
|
|
if (invalid) {
|
|
return reply.badRequest(invalid)
|
|
}
|
|
}
|
|
|
|
const updated = await WIKI.models.analytics.updateSiteProviders(req.params.siteId, patches)
|
|
|
|
/*
|
|
Which providers were written and whether each was turned on — not the values, which are
|
|
identifiers of accounts at a third party rather than anything about this wiki. `meta` carries
|
|
identity and never payload.
|
|
*/
|
|
await audit(req, 'admin', 'updateAnalytics', {
|
|
siteId: req.params.siteId,
|
|
providers: patches.map((patch) => ({
|
|
key: patch.key,
|
|
isEnabled: patch.isEnabled,
|
|
changedFields: Object.keys(patch.config ?? {})
|
|
}))
|
|
})
|
|
|
|
return {
|
|
ok: true,
|
|
message: 'Analytics configuration updated successfully.',
|
|
updated
|
|
}
|
|
}
|
|
)
|
|
}
|
|
|
|
export default routes
|