feat: add ap pageviews analytics

This commit is contained in:
Barış Soner Uşaklı
2025-07-11 15:09:55 -04:00
parent 59c1ce853f
commit 559a2d233d
7 changed files with 39 additions and 4 deletions

View File

@@ -75,6 +75,7 @@
"graphs.page-views-registered": "Page Views Registered", "graphs.page-views-registered": "Page Views Registered",
"graphs.page-views-guest": "Page Views Guest", "graphs.page-views-guest": "Page Views Guest",
"graphs.page-views-bot": "Page Views Bot", "graphs.page-views-bot": "Page Views Bot",
"graphs.page-views-ap": "ActivityPub Page Views",
"graphs.unique-visitors": "Unique Visitors", "graphs.unique-visitors": "Unique Visitors",
"graphs.registered-users": "Registered Users", "graphs.registered-users": "Registered Users",
"graphs.guest-users": "Guest Users", "graphs.guest-users": "Guest Users",

View File

@@ -165,6 +165,7 @@ function setupGraphs(callback) {
t.translateKey('admin/dashboard:graphs.page-views-registered', []), t.translateKey('admin/dashboard:graphs.page-views-registered', []),
t.translateKey('admin/dashboard:graphs.page-views-guest', []), t.translateKey('admin/dashboard:graphs.page-views-guest', []),
t.translateKey('admin/dashboard:graphs.page-views-bot', []), t.translateKey('admin/dashboard:graphs.page-views-bot', []),
t.translateKey('admin/dashboard:graphs.page-views-ap', []),
t.translateKey('admin/dashboard:graphs.unique-visitors', []), t.translateKey('admin/dashboard:graphs.unique-visitors', []),
t.translateKey('admin/dashboard:graphs.registered-users', []), t.translateKey('admin/dashboard:graphs.registered-users', []),
t.translateKey('admin/dashboard:graphs.guest-users', []), t.translateKey('admin/dashboard:graphs.guest-users', []),
@@ -231,6 +232,18 @@ function setupGraphs(callback) {
fill: 'origin', fill: 'origin',
tension: tension, tension: tension,
backgroundColor: 'rgba(151,187,205,0.2)', backgroundColor: 'rgba(151,187,205,0.2)',
borderColor: 'rgba(110, 187, 132, 1)',
pointBackgroundColor: 'rgba(110, 187, 132, 1)',
pointHoverBackgroundColor: 'rgba(110, 187, 132, 1)',
pointBorderColor: '#fff',
pointHoverBorderColor: 'rgba(110, 187, 132, 1)',
data: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
},
{
label: translations[5],
fill: 'origin',
tension: tension,
backgroundColor: 'rgba(151,187,205,0.2)',
borderColor: 'rgba(151,187,205,1)', borderColor: 'rgba(151,187,205,1)',
pointBackgroundColor: 'rgba(151,187,205,1)', pointBackgroundColor: 'rgba(151,187,205,1)',
pointHoverBackgroundColor: 'rgba(151,187,205,1)', pointHoverBackgroundColor: 'rgba(151,187,205,1)',
@@ -247,7 +260,8 @@ function setupGraphs(callback) {
data.datasets[1].yAxisID = 'left-y-axis'; data.datasets[1].yAxisID = 'left-y-axis';
data.datasets[2].yAxisID = 'left-y-axis'; data.datasets[2].yAxisID = 'left-y-axis';
data.datasets[3].yAxisID = 'left-y-axis'; data.datasets[3].yAxisID = 'left-y-axis';
data.datasets[4].yAxisID = 'right-y-axis'; data.datasets[4].yAxisID = 'left-y-axis';
data.datasets[5].yAxisID = 'right-y-axis';
graphs.traffic = new Chart(trafficCtx, { graphs.traffic = new Chart(trafficCtx, {
type: 'line', type: 'line',
@@ -269,7 +283,7 @@ function setupGraphs(callback) {
type: 'linear', type: 'linear',
title: { title: {
display: true, display: true,
text: translations[4], text: translations[5],
}, },
beginAtZero: true, beginAtZero: true,
}, },
@@ -446,7 +460,8 @@ function updateTrafficGraph(units, until, amount) {
graphs.traffic.data.datasets[1].data = data.pageviewsRegistered; graphs.traffic.data.datasets[1].data = data.pageviewsRegistered;
graphs.traffic.data.datasets[2].data = data.pageviewsGuest; graphs.traffic.data.datasets[2].data = data.pageviewsGuest;
graphs.traffic.data.datasets[3].data = data.pageviewsBot; graphs.traffic.data.datasets[3].data = data.pageviewsBot;
graphs.traffic.data.datasets[4].data = data.uniqueVisitors; graphs.traffic.data.datasets[4].data = data.appageviews;
graphs.traffic.data.datasets[5].data = data.uniqueVisitors;
graphs.traffic.data.labels = graphs.traffic.data.xLabels; graphs.traffic.data.labels = graphs.traffic.data.xLabels;
graphs.traffic.update(); graphs.traffic.update();

View File

@@ -21,6 +21,7 @@ let local = {
pageViewsRegistered: 0, pageViewsRegistered: 0,
pageViewsGuest: 0, pageViewsGuest: 0,
pageViewsBot: 0, pageViewsBot: 0,
apPageViews: 0,
uniquevisitors: 0, uniquevisitors: 0,
}; };
const empty = _.cloneDeep(local); const empty = _.cloneDeep(local);
@@ -117,6 +118,10 @@ Analytics.pageView = async function (payload) {
} }
}; };
Analytics.apPageView = function () {
local.apPageViews += 1;
};
Analytics.writeData = async function () { Analytics.writeData = async function () {
const today = new Date(); const today = new Date();
const month = new Date(); const month = new Date();
@@ -162,6 +167,12 @@ Analytics.writeData = async function () {
total.pageViewsBot = 0; total.pageViewsBot = 0;
} }
if (total.apPageViews > 0) {
incrByBulk.push(['analytics:pageviews:ap', total.apPageViews, today.getTime()]);
incrByBulk.push(['analytics:pageviews:ap:month', total.apPageViews, month.getTime()]);
total.apPageViews = 0;
}
if (total.uniquevisitors > 0) { if (total.uniquevisitors > 0) {
incrByBulk.push(['analytics:uniquevisitors', total.uniquevisitors, today.getTime()]); incrByBulk.push(['analytics:uniquevisitors', total.uniquevisitors, today.getTime()]);
total.uniquevisitors = 0; total.uniquevisitors = 0;

View File

@@ -91,7 +91,7 @@ async function getLatestVersion() {
dashboardController.getAnalytics = async (req, res, next) => { dashboardController.getAnalytics = async (req, res, next) => {
// Basic validation // Basic validation
const validUnits = ['days', 'hours']; const validUnits = ['days', 'hours'];
const validSets = ['uniquevisitors', 'pageviews', 'pageviews:registered', 'pageviews:bot', 'pageviews:guest']; const validSets = ['uniquevisitors', 'pageviews', 'pageviews:registered', 'pageviews:bot', 'pageviews:guest', 'pageviews:ap'];
const until = req.query.until ? new Date(parseInt(req.query.until, 10)) : Date.now(); const until = req.query.until ? new Date(parseInt(req.query.until, 10)) : Date.now();
const count = req.query.count || (req.query.units === 'hours' ? 24 : 30); const count = req.query.count || (req.query.units === 'hours' ? 24 : 30);
if (isNaN(until) || !validUnits.includes(req.query.units)) { if (isNaN(until) || !validUnits.includes(req.query.units)) {

View File

@@ -3,11 +3,17 @@
const db = require('../database'); const db = require('../database');
const meta = require('../meta'); const meta = require('../meta');
const activitypub = require('../activitypub'); const activitypub = require('../activitypub');
const analytics = require('../analytics');
const middleware = module.exports; const middleware = module.exports;
middleware.enabled = async (req, res, next) => next(!meta.config.activitypubEnabled ? 'route' : undefined); middleware.enabled = async (req, res, next) => next(!meta.config.activitypubEnabled ? 'route' : undefined);
middleware.pageview = async (req, res, next) => {
analytics.apPageView();
next();
};
middleware.assertS2S = async function (req, res, next) { middleware.assertS2S = async function (req, res, next) {
// For whatever reason, express accepts does not recognize "profile" as a valid differentiator // For whatever reason, express accepts does not recognize "profile" as a valid differentiator
// Therefore, manual header parsing is used here. // Therefore, manual header parsing is used here.

View File

@@ -14,6 +14,7 @@ module.exports = function (app, middleware, controllers) {
const middlewares = [ const middlewares = [
middleware.activitypub.enabled, middleware.activitypub.enabled,
middleware.activitypub.pageview,
middleware.activitypub.assertS2S, middleware.activitypub.assertS2S,
middleware.activitypub.verify, middleware.activitypub.verify,
middleware.activitypub.configureResponse, middleware.activitypub.configureResponse,

View File

@@ -30,6 +30,7 @@ Analytics.get = async function (socket, data) {
pageviewsRegistered: getStats('analytics:pageviews:registered', until, data.amount), pageviewsRegistered: getStats('analytics:pageviews:registered', until, data.amount),
pageviewsGuest: getStats('analytics:pageviews:guest', until, data.amount), pageviewsGuest: getStats('analytics:pageviews:guest', until, data.amount),
pageviewsBot: getStats('analytics:pageviews:bot', until, data.amount), pageviewsBot: getStats('analytics:pageviews:bot', until, data.amount),
appageviews: getStats('analytics:pageviews:ap', until, data.amount),
summary: analytics.getSummary(), summary: analytics.getSummary(),
}); });
result.pastDay = result.pageviews.reduce((a, b) => parseInt(a, 10) + parseInt(b, 10)); result.pastDay = result.pageviews.reduce((a, b) => parseInt(a, 10) + parseInt(b, 10));