source: Klonkt/src/routes/admin-paid.js

main
Last change on this file was 0475b13, checked in by roboburr <roboburr@…>, 5 weeks ago

Acht schone pagina's uit inline script naar modules (shaer-bqr, stap 3b)

Alle acht zonder EJS-interpolatie, dus ongewijzigd te verplaatsen: admin-help,
admin-epk, admin-paid, admin-settings, auth-register, admin-push, admin-site-edit
(2 blokken) en authorize-interaction (3 blokken).

Elke route zegt nu welke module hij wil via pageJs; de bootstrap in de shell
haalt hem op. Meerdere blokken uit een pagina belanden in EEN module, gescheiden
door een streep -- ze deelden toch al een pagina en een levensduur.

Templates compileren, modules syntactisch ok, suite 565/565. Het echte bewijs
per pagina is er via een LINK naartoe gaan; na een herlading werkt alles toch al.

Commit met expliciete paden, niet met -A: eerder vandaag veegde ik daarmee
andermans werk uit dezelfde werkmap mee.

  • Property mode set to 100644
File size: 3.3 KB
Line 
1/**
2 * Admin: Paid posts (premium module, god-only). Slice 1 of klonkt-demo-aki.
3 *
4 * GET /admin/paid -> the owner's Patreon config form + status
5 * POST /admin/paid -> save config (secret/token stored encrypted)
6 * POST /admin/paid/disconnect -> forget the config
7 *
8 * Premium-gated via premiumUnlocked(), like stats/downloads. This is the site
9 * owner's OWN Patreon campaign, separate from Klonkt Premium's license flow.
10 */
11import express from 'express';
12import { renderPage } from '../middleware/render.js';
13import { requireGod } from '../middleware/auth.js';
14import { premiumUnlocked } from '../services/PatreonService.js';
15import { cryptoBoxReady } from '../services/CryptoBox.js';
16import PaidPatreon from '../services/PaidPatreonService.js';
17
18const router = express.Router();
19
20// The redirect URI the owner MUST whitelist in their Patreon client. Must match
21// exactly what paid.js sends, or Patreon shows its own error page (which we
22// cannot skin) instead of returning the visitor to us.
23const redirectUri = (req) =>
24 (process.env.PUBLIC_BASE_URL || `${req.protocol}://${req.get('host')}`).replace(/\/+$/, '') + '/paid/callback';
25
26function gate(req, res) {
27 if (!premiumUnlocked()) {
28 res.status(403).send('Betaalde posts is een premium-functie: koppel Patreon in Beheer, Instellingen.');
29 return false;
30 }
31 if (!res.locals.site) { res.status(400).send('Geen site.'); return false; }
32 return true;
33}
34
35router.get('/', requireGod, (req, res) => {
36 if (!gate(req, res)) return;
37 renderPage(req, res, 'pages/admin-paid', {
38 pageJs: 'admin-paid',
39 pageTitleKey: 'apaid.t',
40 bodyClass: 'on-admin',
41 status: PaidPatreon.ownerStatus(res.locals.site.id),
42 secretReady: cryptoBoxReady(),
43 redirectUri: redirectUri(req),
44 saved: req.query.saved === '1',
45 error: req.query.error || null,
46 });
47});
48
49router.post('/', requireGod, (req, res) => {
50 if (!gate(req, res)) return;
51 if (!cryptoBoxReady()) return res.redirect('/admin/paid?error=' + encodeURIComponent('De encryptiesleutel kon niet worden aangemaakt of gelezen (schrijfrechten op de opslagmap?); secrets kunnen niet veilig worden opgeslagen.'));
52 const b = req.body || {};
53 const eur = String(b.default_min_eur || '').replace(',', '.').trim();
54 const cents = eur ? Math.round(parseFloat(eur) * 100) : undefined;
55 try {
56 PaidPatreon.saveOwnerConfig(res.locals.site.id, {
57 clientId: (b.client_id || '').trim() || undefined,
58 // Empty secret/token fields keep the stored value (no re-paste needed).
59 clientSecret: (b.client_secret || '').trim() || undefined,
60 campaignId: (b.campaign_id || '').trim() || undefined,
61 accessToken: (b.access_token || '').trim() || undefined,
62 refreshToken: (b.refresh_token || '').trim() || undefined,
63 // Empty clears it (null), a value sets it. Unlike secrets, this is not
64 // sensitive and there's a clear "remove the link" intent.
65 patreonUrl: (b.patreon_url || '').trim() || null,
66 defaultMinCents: Number.isFinite(cents) ? cents : undefined,
67 });
68 return res.redirect('/admin/paid?saved=1');
69 } catch (e) {
70 return res.redirect('/admin/paid?error=' + encodeURIComponent(e.message || 'Opslaan mislukt'));
71 }
72});
73
74router.post('/disconnect', requireGod, (req, res) => {
75 if (!gate(req, res)) return;
76 PaidPatreon.disconnect(res.locals.site.id);
77 res.redirect('/admin/paid?saved=1');
78});
79
80export default router;
Note: See TracBrowser for help on using the repository browser.