Changeset 8aa85d0 in Klonkt


Ignore:
Timestamp:
06/16/2026 06:58:03 AM (3 months ago)
Author:
roboburr <roboburr@…>
Branches:
main
Children:
2c246d4
Parents:
eef691e
Message:

Prutter = premium Hub feature: Hub-only + behind premium gate

Prutter (DMs) is now hard-scoped to Hub mode (route 404s outside hub) and
locked behind the premium gate via the new premiumUnlocked() (= premium off
→ freely available, demos keep working; premium on → Patreon required).
UI entry points (topnav/bottom-tab/Send DM) follow the same condition.
Added to the premium description in Admin → Settings.

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

Location:
src
Files:
7 edited

Legend:

Unmodified
Added
Removed
  • src/middleware/render.js

    reef691e r8aa85d0  
    1818import { isViewer } from './auth.js';
    1919import { getSetting } from '../services/SettingsService.js';
    20 import { isPremium as isPremiumInstance, premiumEnabled } from '../services/PatreonService.js';
     20import { isPremium as isPremiumInstance, premiumEnabled, premiumUnlocked } from '../services/PatreonService.js';
    2121import { PLATFORMS as PLATFORMS_CATALOG } from '../services/PlatformIcons.js';
    2222
     
    8080    isPremium: isPremiumInstance(),
    8181    premiumEnabled: premiumEnabled(),
     82    premiumUnlocked: premiumUnlocked(),
    8283    siteOwnerAvatar,
    8384    site: _site,
  • src/routes/prutter.js

    reef691e r8aa85d0  
    1919import { renderPage } from '../middleware/render.js';
    2020import { requireAuth, isViewer } from '../middleware/auth.js';
     21import { getTenancy } from '../services/SettingsService.js';
     22import { premiumUnlocked } from '../services/PatreonService.js';
    2123import PermissionsService from '../services/PermissionsService.js';
    2224
     
    3133}
    3234
    33 // Middleware: require both auth + Prutter enabled
     35// Middleware: Prutter = Hub-feature achter de premium-laag, plus login.
     36//  - alleen in Hub-modus (DM tussen artiesten/leden van het collectief)
     37//  - vergrendeld als de premium-laag aan staat maar Patreon niet gekoppeld is
     38//    (premium uit = niet gegate → huidige gedrag, demo's blijven werken)
     39//  - geen anonieme DMs
    3440function requirePrutter(req, res, next) {
    3541  if (!siteAllowsDM(req, res)) return res.status(404).send('Prutter not enabled on this site');
     42  if (getTenancy() !== 'hub') return res.status(404).send('Prutter is alleen beschikbaar in Hub-modus');
     43  if (!premiumUnlocked()) {
     44    return res.status(403).send('Prutter is een premium-functie — koppel Patreon in Beheer → Instellingen.');
     45  }
    3646  return requireAuth(req, res, next);
    3747}
  • src/services/PatreonService.js

    reef691e r8aa85d0  
    8282}
    8383
     84// Is een premium-feature beschikbaar? True als de premium-laag UIT staat (dan is
     85// niets gegate — huidige gedrag), of AAN én deze instance is entitled. False alleen
     86// als premium aan staat maar er geen geldige Patreon-koppeling is (= betaalmuur).
     87export function premiumUnlocked() {
     88  return !premiumEnabled() || isPremium();
     89}
     90
    8491export function entitlementStatus() {
    8592  return {
  • src/views/pages/admin-settings.ejs

    reef691e r8aa85d0  
    4444  <section class="set-card" style="margin-top:1rem">
    4545    <h2>Premium (Patreon)</h2>
    46     <p class="set-help">Ontgrendel de premium-modules (Hub-modus, Statistieken, Fan-login)
    47       met je <strong>$10-lifetime</strong> Patreon-steun. De app en alle updates blijven gratis.</p>
     46    <p class="set-help">Ontgrendel de premium-modules (Hub-modus, Statistieken, Fan-login,
     47      Prutter-DMs) met je <strong>$10-lifetime</strong> Patreon-steun. De app en alle updates
     48      blijven gratis.</p>
    4849    <% if (premium.premium) { %>
    4950      <p class="set-help"><strong>✓ Premium actief.</strong>
  • src/views/pages/user.ejs

    reef691e r8aa85d0  
    2727        <% } %>
    2828      </p>
    29       <% if (user && user.id !== author.id && site && site.enable_prutter) { %>
     29      <% if (user && user.id !== author.id && site && site.enable_prutter && (typeof tenancy !== 'undefined' && tenancy === 'hub') && (typeof premiumUnlocked === 'undefined' || premiumUnlocked)) { %>
    3030        <p class="user-actions">
    3131          <a href="<%= siteUrlBase %>/prutter/new?to=<%= encodeURIComponent(author.username) %>" class="btn btn-primary">💬 Send DM</a>
  • src/views/partials/bottom-tab.ejs

    reef691e r8aa85d0  
    1313const _canPost     = !!(user && (typeof canMutate === 'undefined' || canMutate)
    1414                        && permissions && permissions.canCreatePost && permissions.canCreatePost(user, site));
    15 const _hasPrutter  = !!(user && site && site.enable_prutter && (typeof tenancy !== 'undefined' && tenancy === 'hub'));
     15const _hasPrutter  = !!(user && site && site.enable_prutter && (typeof tenancy !== 'undefined' && tenancy === 'hub') && (typeof premiumUnlocked === 'undefined' || premiumUnlocked));
    1616const _ownProfile  = user ? ('/users/' + user.username) : null;
    1717
  • src/views/partials/topnav.ejs

    reef691e r8aa85d0  
    1515const _isAdmin     = typeof bodyClass !== 'undefined' && bodyClass.indexOf('on-admin') >= 0;
    1616const _hasSearch   = !site || site.show_search === undefined || site.show_search;
    17 const _hasPrutter  = user && site && site.enable_prutter && (typeof tenancy !== 'undefined' && tenancy === 'hub');
     17const _hasPrutter  = user && site && site.enable_prutter && (typeof tenancy !== 'undefined' && tenancy === 'hub') && (typeof premiumUnlocked === 'undefined' || premiumUnlocked);
    1818const _canPost     = user && (typeof canMutate === 'undefined' || canMutate)
    1919                     && permissions && permissions.canCreatePost && permissions.canCreatePost(user, site);
Note: See TracChangeset for help on using the changeset viewer.