Changeset 37edecd in Klonkt for src


Ignore:
Timestamp:
06/19/2026 03:46:42 AM (3 months ago)
Author:
roboburr <roboburr@…>
Branches:
main
Children:
1794fac
Parents:
91094a4
Message:

Link-in-bio + click stats (premium feature #6)

Linktree-style page from the existing sites.profile_links (JSON [{platform,url}])
+ PLATFORMS icons. Clicks counted per url.

  • DB: link_clicks (site_id, url, clicks), PK (site_id,url).
  • routes/linkbio.js (premium-gated): GET /links (page with profile_links as buttons), GET /links/go/:i (counts click per url + 302 redirect). Open-redirect safe: only redirects to a url in the site's own profile_links; http(s)/mailto only.
  • view pages/linkbio.ejs (photo/name/bio + brand-coloured buttons with SVG icons).
  • admin-stats: link-clicks section (top 50, per url) for the current site.
  • admin dashboard: 🔗 Link-in-bio link (premium, non-hub).

node --check passed.

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

Location:
src
Files:
2 added
5 edited

Legend:

Unmodified
Added
Removed
  • src/config/database.js

    r91094a4 r37edecd  
    219219    );
    220220  `);
     221
     222  // Link-in-bio klikstatistiek (premium #6). Per (site, url) een teller; de
     223  // link-in-bio-pagina linkt via /links/go/:i dat de klik telt en doorstuurt.
     224  db.exec(`
     225    CREATE TABLE IF NOT EXISTS link_clicks (
     226      site_id TEXT NOT NULL,
     227      url TEXT NOT NULL,
     228      clicks INTEGER DEFAULT 0,
     229      updated_at DATETIME DEFAULT CURRENT_TIMESTAMP,
     230      PRIMARY KEY (site_id, url)
     231    );
     232  `);
    221233}
    222234
  • src/routes/admin-stats.js

    r91094a4 r37edecd  
    1010
    1111import express from 'express';
     12import db from '../config/database.js';
    1213import { renderPage } from '../middleware/render.js';
    1314import { requireGod } from '../middleware/auth.js';
     
    2122    return res.status(403).send('Statistieken is een premium-functie — koppel Patreon in Beheer → Instellingen.');
    2223  }
     24  // Link-in-bio klikken (premium #6) voor de huidige site.
     25  let linkClicks = [];
     26  if (res.locals.site) {
     27    try {
     28      linkClicks = db.prepare(
     29        'SELECT url, clicks FROM link_clicks WHERE site_id = ? AND clicks > 0 ORDER BY clicks DESC LIMIT 50'
     30      ).all(res.locals.site.id);
     31    } catch { linkClicks = []; }
     32  }
    2333  renderPage(req, res, 'pages/admin-stats', {
    2434    pageTitle: 'Statistieken',
    2535    bodyClass: 'on-admin',
    2636    stats: getStats(14),
     37    linkClicks,
    2738  });
    2839});
  • src/server.js

    r91094a4 r37edecd  
    5656import adminNewsletterRoutes from './routes/admin-newsletter.js';
    5757import downloadRoutes from './routes/download.js';
     58import linkbioRoutes from './routes/linkbio.js';
    5859
    5960if (!process.env.SESSION_SECRET) {
     
    273274app.use('/', newsletterRoutes); // /nieuwsbrief in/uitschrijven (premium; niet-premium: next())
    274275app.use('/', downloadRoutes); // /downloads + /download/:id download-voor-email (premium)
     276app.use('/', linkbioRoutes); // /links link-in-bio + klikstats (premium)
    275277app.use('/', postsRoutes);
    276278
  • src/views/pages/admin-stats.ejs

    r91094a4 r37edecd  
    6565    </section>
    6666  </div>
     67
     68  <% if (typeof linkClicks !== 'undefined' && linkClicks.length) { %>
     69    <section class="stats-top" style="margin-top:1.2rem">
     70      <h2>🔗 Link-in-bio klikken</h2>
     71      <ol>
     72        <% linkClicks.forEach(function(l){ %>
     73          <li><a href="<%= l.url %>" target="_blank" rel="noopener"><%= l.url.replace(/^https?:\/\//,'').slice(0,48) %></a><span class="stats-count"><%= l.clicks %></span></li>
     74        <% }); %>
     75      </ol>
     76    </section>
     77  <% } %>
    6778</div>
    6879
  • src/views/pages/admin.ejs

    r91094a4 r37edecd  
    3636      <% if (tenancy !== 'hub' && primarySite) { %><a href="/pers" class="btn" target="_blank">📰 Perskit</a><% } %>
    3737      <% if (tenancy !== 'hub' && primarySite) { %><a href="/downloads" class="btn" target="_blank">⬇ Downloads</a><% } %>
     38      <% if (tenancy !== 'hub' && primarySite) { %><a href="/links" class="btn" target="_blank">🔗 Link-in-bio</a><% } %>
    3839    <% } %>
    3940    <a href="/admin/updates" class="btn">🔄 Updates</a>
Note: See TracChangeset for help on using the changeset viewer.