Changeset 1794fac in Klonkt
- Timestamp:
- 06/19/2026 04:07:24 AM (3 months ago)
- Branches:
- main
- Children:
- 6be57b4
- Parents:
- 37edecd
- Location:
- src
- Files:
-
- 4 edited
-
config/database.js (modified) (1 diff)
-
routes/admin-stats.js (modified) (1 diff)
-
services/StatsService.js (modified) (4 diffs)
-
views/pages/admin-stats.ejs (modified) (3 diffs)
Legend:
- Unmodified
- Added
- Removed
-
src/config/database.js
r37edecd r1794fac 146 146 ); 147 147 CREATE INDEX IF NOT EXISTS idx_stat_visitor_day ON stat_visitor_day(site_id, day); 148 CREATE TABLE IF NOT EXISTS stat_referrer ( 149 site_id TEXT NOT NULL, 150 host TEXT NOT NULL, 151 count INTEGER NOT NULL DEFAULT 0, 152 PRIMARY KEY (site_id, host) 153 ); 148 154 `); 149 155 -
src/routes/admin-stats.js
r37edecd r1794fac 31 31 } catch { linkClicks = []; } 32 32 } 33 const days = [7, 14, 30, 90].includes(parseInt(req.query.days, 10)) ? parseInt(req.query.days, 10) : 14; 33 34 renderPage(req, res, 'pages/admin-stats', { 34 35 pageTitle: 'Statistieken', 35 36 bodyClass: 'on-admin', 36 stats: getStats( 14),37 stats: getStats(days), 37 38 linkClicks, 38 39 }); -
src/services/StatsService.js
r37edecd r1794fac 58 58 bumpPost: db.prepare('UPDATE posts SET view_count = COALESCE(view_count, 0) + 1 WHERE id = ?'), 59 59 bumpTrack: db.prepare('UPDATE audio_tracks SET play_count = COALESCE(play_count, 0) + 1 WHERE id = ?'), 60 bumpReferrer: db.prepare(` 61 INSERT INTO stat_referrer (site_id, host, count) VALUES (?, ?, 1) 62 ON CONFLICT(site_id, host) DO UPDATE SET count = count + 1 63 `), 60 64 }; 61 65 return _s; 66 } 67 68 // Externe referrer-host uit de Referer-header (pro-stats #5). Lege/eigen-site/ 69 // ongeldige referrers worden overgeslagen → alleen echte externe bronnen tellen. 70 function recordReferrer(siteId, req) { 71 try { 72 const ref = req && req.headers && (req.headers.referer || req.headers.referrer); 73 if (!ref) return; 74 const host = new URL(ref).host.replace(/^www\./, '').toLowerCase(); 75 if (!host) return; 76 const own = ((req.headers && req.headers.host) || '').replace(/^www\./, '').toLowerCase(); 77 if (host === own) return; // interne navigatie telt niet als bron 78 stmts().bumpReferrer.run(siteId, host.slice(0, 120)); 79 } catch { /* geen geldige referrer-URL → overslaan */ } 62 80 } 63 81 … … 68 86 stmts().bumpDaily.run(siteId, d); 69 87 stmts().addVisitor.run(siteId, d, visitorHash(req)); 88 recordReferrer(siteId, req); 70 89 } catch { /* statistieken mogen nooit een request breken */ } 71 90 } … … 86 105 // Instance-brede statistieken (solo = de site, hub = alle sites samen). 87 106 export function getStats(days = 14) { 107 days = [7, 14, 30, 90].includes(Number(days)) ? Number(days) : 14; 88 108 const pvMap = Object.fromEntries( 89 109 db.prepare('SELECT day, SUM(pageviews) AS pv FROM stat_daily GROUP BY day').all().map((r) => [r.day, r.pv]), … … 113 133 ORDER BY play_count DESC LIMIT 5 114 134 `).all(); 115 return { totals, series, topPosts, topTracks, days }; 135 // Top externe bronnen (pro #5) — instance-breed geaggregeerd per host. 136 let referrers = []; 137 try { 138 referrers = db.prepare( 139 'SELECT host, SUM(count) AS n FROM stat_referrer GROUP BY host ORDER BY n DESC LIMIT 10' 140 ).all(); 141 } catch { referrers = []; } 142 // All-time totalen (cookieloze unieke bezoekers = som van dag-uniques). 143 const allTime = { 144 pageviews: db.prepare('SELECT COALESCE(SUM(pageviews),0) AS n FROM stat_daily').get().n, 145 visitorDays: db.prepare('SELECT COUNT(*) AS n FROM stat_visitor_day').get().n, 146 }; 147 return { totals, series, topPosts, topTracks, referrers, allTime, days }; 116 148 } -
src/views/pages/admin-stats.ejs
r37edecd r1794fac 9 9 10 10 <div class="stats-cards"> 11 <div class="stat-card"><div class="stat-num"><%= s.totals.visitors %></div><div class="stat-label">Bezoekers ( 14d)</div></div>12 <div class="stat-card"><div class="stat-num"><%= s.totals.pageviews %></div><div class="stat-label">Weergaven ( 14d)</div></div>11 <div class="stat-card"><div class="stat-num"><%= s.totals.visitors %></div><div class="stat-label">Bezoekers (<%= s.days %>d)</div></div> 12 <div class="stat-card"><div class="stat-num"><%= s.totals.pageviews %></div><div class="stat-label">Weergaven (<%= s.days %>d)</div></div> 13 13 <div class="stat-card"><div class="stat-num"><%= s.totals.plays %></div><div class="stat-label">Plays (totaal)</div></div> 14 14 <div class="stat-card"><div class="stat-num"><%= s.totals.postViews %></div><div class="stat-label">Post-weergaven (totaal)</div></div> 15 15 </div> 16 16 17 <% if (typeof s.allTime !== 'undefined') { %> 18 <p class="stats-note">All-time: <strong><%= s.allTime.pageviews %></strong> weergaven · <strong><%= s.allTime.visitorDays %></strong> bezoeker-dagen.</p> 19 <% } %> 20 21 <div class="stats-period"> 22 Periode: 23 <% [7,14,30,90].forEach(function(n){ %> 24 <a href="/admin/stats?days=<%= n %>" class="<%= s.days === n ? 'is-on' : '' %>"><%= n %>d</a> 25 <% }); %> 26 </div> 27 17 28 <section class="stats-chart-wrap"> 18 29 <div class="stats-chart-head"> 19 <h2>Laatste 14dagen</h2>30 <h2>Laatste <%= s.days %> dagen</h2> 20 31 <div class="stats-legend"> 21 32 <span class="lg lg-vis">Bezoekers</span> … … 66 77 </div> 67 78 79 <% if (typeof s.referrers !== 'undefined' && s.referrers.length) { %> 80 <section class="stats-top" style="margin-top:1.2rem"> 81 <h2>🌐 Bronnen (waar bezoekers vandaan komen)</h2> 82 <ol> 83 <% s.referrers.forEach(function(r){ %> 84 <li><span><%= r.host %></span><span class="stats-count"><%= r.n %></span></li> 85 <% }); %> 86 </ol> 87 </section> 88 <% } %> 89 68 90 <% if (typeof linkClicks !== 'undefined' && linkClicks.length) { %> 69 91 <section class="stats-top" style="margin-top:1.2rem"> … … 112 134 .stats-count { color: var(--accent); font-weight: 700; font-variant-numeric: tabular-nums; } 113 135 .stats-empty { color: var(--ink-muted); font-size: .88rem; margin: 0; } 136 .stats-period { margin: .2rem 0 1.2rem; font-size: .9rem; color: var(--ink-muted); } 137 .stats-period a { display: inline-block; margin-left: .4rem; padding: .2rem .6rem; border: 1px solid var(--rule); border-radius: 999px; text-decoration: none; color: var(--ink); } 138 .stats-period a.is-on { background: var(--accent); color: #fff; border-color: var(--accent); } 114 139 </style>
Note:
See TracChangeset
for help on using the changeset viewer.
![(please configure the [header_logo] section in trac.ini)](/chrome/site/your_project_logo.png)