source: Klonkt/src/routes/hub.js@ b56afa7

main
Last change on this file since b56afa7 was 7881080, checked in by roboburr <roboburr@…>, 3 months ago

Hub #3: explicit is_primary flag + shared getPrimarySite() (DRY)

The "oldest site = primary site" assumption was duplicated independently in
resolveSite, hub.js, account.js and admin.js (fragile: if the oldest happened
to be an artist site, the hub home would be wrong). Now:

  • sites.is_primary column + backfill (marks the oldest if none is primary yet; ensurePrimarySite sets it on fresh installs) → existing behaviour exactly preserved.
  • one getPrimarySite() helper (is_primary, fallback oldest) replaces the 4 copies.
  • god can CHOOSE the primary/main site: ★ button + "primary" badge on /admin/sites (exactly one primary via a transaction).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@…>

  • Property mode set to 100644
File size: 3.5 KB
Line 
1/**
2 * Hub-hoofdpagina — alleen in hub-modus. In plaats van de primaire Klonkt-site te
3 * tonen, rendert '/' hier een bedrijfs-overview: de laatste posts van ALLE
4 * gebruikers samengevat + een lijst van de Klonkt-site's.
5 *
6 * In solo-modus doet dit niets (next()) en rendert posts.js de enige site.
7 */
8
9import express from 'express';
10import db from '../config/database.js';
11import { renderPage } from '../middleware/render.js';
12import { getTenancy, getSetting } from '../services/SettingsService.js';
13
14const router = express.Router();
15
16router.get('/', (req, res, next) => {
17 if (getTenancy() !== 'hub') return next();
18 // Als resolveSite een specifieke site adresseerde (/user/:slug of /sites/:slug),
19 // is req.url naar '/' herschreven — dan NIET de overview tonen maar de site zelf
20 // laten renderen door posts.js. siteUrlBase is dan gezet.
21 if (res.locals.siteUrlBase) return next();
22
23 // Laatste gepubliceerde posts over álle sites heen.
24 const posts = db.prepare(`
25 SELECT p.title, p.slug, p.excerpt, p.published_at, p.created_at,
26 p.cover_image_url, p.type,
27 s.slug AS site_slug, s.title AS site_title, s.profile_photo AS site_photo,
28 u.username AS author_username
29 FROM posts p
30 JOIN sites s ON s.id = p.site_id
31 LEFT JOIN users u ON u.id = p.author_id
32 WHERE p.status = 'published'
33 ORDER BY COALESCE(p.published_at, p.created_at) DESC
34 LIMIT 24
35 `).all();
36
37 // De hoofd-/labelsite (de expliciet primaire = de bedrijfs-/hoofdaccount) is
38 // GEEN artiest; die tonen we apart bovenaan, niet in de Artiesten-roster.
39 const mainSite = db.prepare(`
40 SELECT s.id, s.slug, s.title, s.tagline, s.profile_photo, s.accent,
41 u.avatar_url AS owner_avatar,
42 (SELECT COUNT(*) FROM posts WHERE site_id = s.id AND status = 'published') AS post_count
43 FROM sites s
44 LEFT JOIN users u ON u.id = s.owner_id
45 WHERE s.is_primary = 1
46 LIMIT 1
47 `).get() || null;
48 const mainId = mainSite ? mainSite.id : '';
49
50 // Uitgelichte Klonkt-site's voor de home-roster: meest-actief eerst (aantal
51 // gepubliceerde posts), dan nieuwste. Excl. de hoofdsite. Beperkt tot
52 // HOME_ROSTER_LIMIT zodat de home schaalt — volledige lijst staat op /leden.
53 const HOME_ROSTER_LIMIT = 24;
54 const artists = db.prepare(`
55 SELECT s.slug, s.title, s.tagline, s.profile_photo, s.accent,
56 u.avatar_url AS owner_avatar,
57 (SELECT COUNT(*) FROM posts WHERE site_id = s.id AND status = 'published') AS post_count
58 FROM sites s
59 LEFT JOIN users u ON u.id = s.owner_id
60 WHERE s.id != @mainId
61 ORDER BY post_count DESC, s.created_at DESC
62 LIMIT @limit
63 `).all({ mainId, limit: HOME_ROSTER_LIMIT });
64 const totalArtists = db.prepare('SELECT COUNT(*) AS c FROM sites WHERE id != ?').get(mainId).c;
65
66 // De hub-pagina is GENERIEK (van geen enkele user) — branding komt uit globale
67 // instellingen die de admin in Beheer beheert, niet uit een site.
68 const hub = {
69 title: getSetting('hub_title') || 'Overzicht',
70 tagline: getSetting('hub_tagline') || '',
71 intro: getSetting('hub_intro') || '',
72 heroImage: getSetting('hub_hero_image') || '',
73 heroOverlay: (() => { const v = parseInt(getSetting('hub_hero_overlay'), 10); return Number.isFinite(v) ? Math.max(0, Math.min(100, v)) : 45; })(),
74 };
75
76 renderPage(req, res, 'pages/hub-home', {
77 pageTitle: hub.title,
78 socialDescr: hub.intro || hub.tagline || '',
79 bodyClass: 'on-home on-hub',
80 hub,
81 mainSite,
82 artists,
83 totalArtists,
84 rosterLimit: HOME_ROSTER_LIMIT,
85 posts,
86 });
87});
88
89export default router;
Note: See TracBrowser for help on using the repository browser.