source: Klonkt/src/middleware/site.js@ 7bc636b

main
Last change on this file since 7bc636b was 7bc636b, checked in by Robin <robin@…>, 4 months ago

Initial commit — PrutFolio v1 source (pulled from Hetzner /srv/prutfolio)

  • Property mode set to 100644
File size: 3.0 KB
Line 
1/**
2 * Site middleware — resolve which site this request is for.
3 *
4 * Resolution order:
5 * 1. Path /sites/:slug → that site
6 * 2. (Future) Subdomain bedrijf1.example.com → matching site
7 * 3. Default site (first one in DB)
8 *
9 * Sets res.locals.site for all downstream handlers.
10 */
11
12import db from '../config/database.js';
13
14export function resolveSite(req, res, next) {
15 // Try /sites/:slug pattern
16 const m = req.path.match(/^\/sites\/([a-zA-Z0-9_-]+)(\/.*)?$/);
17 if (m) {
18 const slug = m[1];
19 const site = db.prepare('SELECT * FROM sites WHERE slug = ?').get(slug);
20 if (site) {
21 res.locals.site = site;
22 // Strip /sites/:slug from req.url so downstream routes see the rest
23 req.url = (m[2] || '/');
24 // Also rewrite originalUrl for redirect targets to keep the prefix
25 res.locals.siteUrlBase = `/sites/${slug}`;
26 return next();
27 }
28 }
29
30 // Future: subdomain mapping
31 const host = req.get('host')?.toLowerCase().replace(/:\d+$/, '');
32 if (host) {
33 const site = db.prepare('SELECT * FROM sites WHERE slug = ?').get(host);
34 if (site) {
35 res.locals.site = site;
36 res.locals.siteUrlBase = '';
37 return next();
38 }
39 }
40
41 // Default: pick first site
42 const defaultSite = db.prepare('SELECT * FROM sites ORDER BY created_at ASC LIMIT 1').get();
43 if (defaultSite) {
44 res.locals.site = defaultSite;
45 res.locals.siteUrlBase = '';
46 }
47
48 next();
49}
50
51/**
52 * Audio tracks loader — pulls site-level tracks for the persistent player widget.
53 * Per Robin: player is separate from the footer, gated by site.enable_audio_player.
54 * Returns empty array if no site or audio is disabled — shell.ejs uses the
55 * length to decide whether to mount audio-player.js.
56 */
57export function loadAudioTracks(req, res, next) {
58 const site = res.locals.site;
59 if (!site || site.enable_audio_player === 0) {
60 res.locals.audioTracks = [];
61 return next();
62 }
63
64 try {
65 res.locals.audioTracks = db.prepare(`
66 SELECT t.id, t.title, t.artist, t.duration, t.position,
67 m.url AS media_url
68 FROM audio_tracks t
69 LEFT JOIN media m ON m.id = t.media_id
70 WHERE t.site_id = ?
71 ORDER BY t.position ASC, t.created_at ASC
72 `).all(site.id);
73 } catch (e) {
74 // media table might not be queryable in some test setups — fall back gracefully
75 res.locals.audioTracks = [];
76 }
77
78 next();
79}
80
81/**
82 * Theme loader — applies user/site theme preferences.
83 */
84export function loadTheme(req, res, next) {
85 const PALETTES = ['sage','paper','ocean','forest','stone','midnight','sunset','cream'];
86
87 const user = req.session?.user;
88 const site = res.locals.site;
89
90 // Priority: user setting > site setting > default
91 const palette = (user && PALETTES.includes(user.palette) ? user.palette : null)
92 || (site && PALETTES.includes(site.palette) ? site.palette : null)
93 || 'sage';
94
95 res.locals.palette = palette;
96 res.locals.theme = (user && ['dark','light'].includes(user.theme)) ? user.theme : 'dark';
97
98 next();
99}
Note: See TracBrowser for help on using the repository browser.