← back to Rentv 2026
Move LA Commercial + market-pulse sections to admin-only (APIs, page shells, nav links, search)
d4c5df3fd4bbde0ae15f728e7a8f1a07f4bcf1a9 · 2026-07-28 16:36:40 -0700 · Steve Abrams
Files touched
Diff
commit d4c5df3fd4bbde0ae15f728e7a8f1a07f4bcf1a9
Author: Steve Abrams <steve@designerwallcoverings.com>
Date: Tue Jul 28 16:36:40 2026 -0700
Move LA Commercial + market-pulse sections to admin-only (APIs, page shells, nav links, search)
---
server.js | 29 +++++++++++++++++++----------
1 file changed, 19 insertions(+), 10 deletions(-)
diff --git a/server.js b/server.js
index b1faac93..f331cdb4 100644
--- a/server.js
+++ b/server.js
@@ -90,6 +90,13 @@ function sendPage(res, absFile) {
if (!INTERNAL_PAGE.test(absFile) && html.indexOf('rentv-footer') === -1) {
html = closeBody() ? html.replace('</body>', FOOTER_TAG + '</body>') : html + FOOTER_TAG;
}
+ // Admin-only sections (LA Commercial + market-pulse analytics) are gated server-side; also
+ // hide their nav links from user-tier so the front page shows no dead links (zero-flash,
+ // server-rendered off req.role — no dependency on JS or per-page nav edits).
+ if (res.req && res.req.role !== 'admin' && html.indexOf('rentv-hide-admin-nav') === -1) {
+ const hideCss = '<style id="rentv-hide-admin-nav">a[href^="/la-commercial"],a[href^="/pulse"],a[href^="/sector"],a[href^="/hub"],a[href^="/brief"]{display:none!important}</style>';
+ html = html.indexOf('</head>') !== -1 ? html.replace('</head>', hideCss + '</head>') : hideCss + html;
+ }
res.type('html').send(html);
}
// Expose the caller's role to the front end so shells can hide/show internal nav.
@@ -131,7 +138,7 @@ app.get('/api/markets', (_q, r) => {
// ── LA Commercial: parcels/assessed-value/broker digest from the usrealestate backend
// (refreshed by `node pull-la-commercial.mjs`). Property-level LA CRE intelligence. ──
-app.get('/api/la-commercial', (_q, r) => {
+app.get('/api/la-commercial', adminOnly, (_q, r) => {
r.set('Cache-Control', 'public, max-age=300');
r.json(readJSON('la-commercial.json', { marquee: [], recent: [], firms: [] }));
});
@@ -510,13 +517,15 @@ app.get('/api/search', (req, res) => {
const blob = [p.title, p.dek, p.author, p.cat].join(' ');
if (hit(blob)) push('The REview', { title: p.title, sub: [p.cat, p.author].filter(Boolean).join(' · '), href: '/post.html?id=' + encodeURIComponent(p.id), image: p.image || '', s: score(blob) });
});
- // LA Commercial firms
- const la = readJSON('la-commercial.json', {}) || {};
- asArr(la.firms).forEach((f) => {
- const name = f.name || f.firm || f;
- const blob = [name, f.focus, f.city].join(' ');
- if (hit(blob)) push('LA Commercial', { title: name, sub: [f.focus, f.city].filter(Boolean).join(' · ') || 'Firm', href: '/la-commercial', image: '', s: score(blob) });
- });
+ // LA Commercial firms — admin-only section, so only admin-tier searches surface it.
+ if (req.role === 'admin') {
+ const la = readJSON('la-commercial.json', {}) || {};
+ asArr(la.firms).forEach((f) => {
+ const name = f.name || f.firm || f;
+ const blob = [name, f.focus, f.city].join(' ');
+ if (hit(blob)) push('LA Commercial', { title: name, sub: [f.focus, f.city].filter(Boolean).join(' · ') || 'Firm', href: '/la-commercial', image: '', s: score(blob) });
+ });
+ }
const order = ['News', 'Deals', 'The REview', 'Videos', 'LA Commercial'];
const groups = order.filter((t) => out[t]).map((t) => ({
@@ -528,7 +537,7 @@ app.get('/api/search', (req, res) => {
});
// ── CRE Market Pulse — analytics layer over the tracked deals feed. ──
-app.get('/api/pulse', (_req, res) => {
+app.get('/api/pulse', adminOnly, (_req, res) => {
const file = readJSON('deals.json', {});
const deals = asArr(file.deals);
res.set('Cache-Control', 'public, max-age=300');
@@ -675,7 +684,7 @@ app.delete('/api/social/draft/:id', adminOnly, (req, res) => {
// The data APIs above are already admin-only; this additionally blocks user-tier
// logins from loading any INTERNAL static shell/asset directly (desk, audience,
// admin, versions, consulting, press). Front-page assets pass straight through.
-const INTERNAL_STATIC = /^\/(desk(\.html)?$|desk-assets\/|desk-admin|audience\.html|admin(\/|$|\.html)|versions(\/|$)|consulting(\/|$)|press(\/|$)|social(\.html)?$)/i;
+const INTERNAL_STATIC = /^\/(desk(\.html)?$|desk-assets\/|desk-admin|audience\.html|admin(\/|$|\.html)|versions(\/|$)|consulting(\/|$)|press(\/|$)|social(\.html)?$|la-commercial(\.html)?$|pulse(\.html)?$|sector(\.html)?$|hub(\.html)?$|brief(\.html)?$)/i;
app.use((req, res, next) => {
if (req.role === 'admin') return next();
if (INTERNAL_STATIC.test(req.path)) return res.status(403).send('Admin only — this area requires an admin login.');
← d9294f44 Master Reel: replace bed with crossfade-looped real music (f
·
back to Rentv 2026
·
Master Reel: brighten+lift music bed so gaps carry on laptop 6d46d5c4 →