source: Klonkt/src/routes/epk.js@ 2900f1d

main
Last change on this file since 2900f1d was 255e3d3, checked in by roboburr <roboburr@…>, 3 months ago

EPK / press kit (premium feature #4): shareable /pers press page per Klonkt site

New premium-gated /pers (solo) or /user/:slug/pers (hub): a clean, public press
kit with hero (photo/title/tagline), short bio, top tracks, recent posts, and a
contact/booking button. Intended to be shared with bookers/press.

  • src/routes/epk.js: GET /pers, premiumUnlocked() gate (non-premium -> next() -> 404), page itself is public (no login). No email leak: contact via explicit setting epk_contact[_<siteId>], bio via epk_bio_<siteId> (fallback site.tagline).
  • src/views/pages/epk.ejs: standalone press-kit view (inline scoped styles, site-accent).
  • server.js: epkRoutes mounted before the postsRoutes catch-all.

First of the 8 premium features. node --check passed; local test suite only fails
on missing better-sqlite3 in this Windows clone (runs on the VPS).

Co-Authored-By: Claude <noreply@…>

  • Property mode set to 100644
File size: 2.1 KB
Line 
1/**
2 * EPK / perskit (premium) — een deelbare perspagina per Klonkt-site.
3 *
4 * GET /pers (solo) of /user/:slug/pers (hub, via resolveSite + siteUrlBase)
5 * -> nette, openbare perskit: hero (foto/titel/tagline), korte bio, topnummers,
6 * recente posts en een contact-knop. Bedoeld om naar boekers/pers te sturen.
7 *
8 * Premium-gated: niet-premium instances hebben GEEN /pers (next() -> 404 via de
9 * catch-all). De PAGINA zelf is openbaar (geen login) zodat pers 'm kan bekijken;
10 * alleen het BESTAAN ervan is premium. Geen login-e-mail lekken: contact loopt via
11 * een expliciet ingesteld pers-adres (epk_contact, per site) of anders de site zelf.
12 */
13
14import express from 'express';
15import db from '../config/database.js';
16import { renderPage } from '../middleware/render.js';
17import { premiumUnlocked } from '../services/PatreonService.js';
18import { getSetting } from '../services/SettingsService.js';
19
20const router = express.Router();
21
22router.get('/pers', (req, res, next) => {
23 if (!premiumUnlocked()) return next(); // geen premium -> geen perskit
24 const site = res.locals.site;
25 if (!site) return next();
26
27 const tracks = db.prepare(
28 `SELECT title, artist, duration, cover_url
29 FROM audio_tracks
30 WHERE site_id = ?
31 ORDER BY position ASC, created_at ASC
32 LIMIT 6`
33 ).all(site.id);
34
35 const posts = db.prepare(
36 `SELECT slug, title, created_at
37 FROM posts
38 WHERE site_id = ? AND status = 'published'
39 ORDER BY created_at DESC
40 LIMIT 5`
41 ).all(site.id);
42
43 // Pers-contact: per-site instelling (epk_contact_<siteId>) als die er is, anders
44 // de globale epk_contact. NOOIT automatisch de login-mail tonen.
45 const contact = (getSetting('epk_contact_' + site.id, '') || getSetting('epk_contact', '') || '').trim();
46 // Korte pers-bio: per-site instelling, anders de tagline van de site.
47 const bio = (getSetting('epk_bio_' + site.id, '') || site.tagline || '').trim();
48
49 renderPage(req, res, 'pages/epk', {
50 pageTitle: (site.title || 'Perskit') + ' — Perskit',
51 bodyClass: 'on-epk',
52 epkTracks: tracks,
53 epkPosts: posts,
54 epkContact: contact,
55 epkBio: bio,
56 });
57});
58
59export default router;
Note: See TracBrowser for help on using the repository browser.