[object Object]

← back to Rentv

Content Studio: copyright Option 1 — outside-wire stories save as draft (UI + server-enforced), RENTV-sourced publish live

163f9fff6d93b3f500efaf059e7dd647feb8a37b · 2026-08-04 20:03:36 -0700 · steve

Files touched

Diff

commit 163f9fff6d93b3f500efaf059e7dd647feb8a37b
Author: steve <steve@designerwallcoverings.com>
Date:   Tue Aug 4 20:03:36 2026 -0700

    Content Studio: copyright Option 1 — outside-wire stories save as draft (UI + server-enforced), RENTV-sourced publish live
---
 public/admin/pr-intelligence/content-studio.html | 22 +++++++++++++++++-----
 server.js                                        |  7 ++++++-
 2 files changed, 23 insertions(+), 6 deletions(-)

diff --git a/public/admin/pr-intelligence/content-studio.html b/public/admin/pr-intelligence/content-studio.html
index 6edab7f0..eb1cac42 100644
--- a/public/admin/pr-intelligence/content-studio.html
+++ b/public/admin/pr-intelligence/content-studio.html
@@ -130,7 +130,7 @@
       <ul class="hl" id="hl"></ul>
     </div>
     <div class="cs-card" id="blogCard" style="display:none">
-      <h3>Blog entry</h3><div class="sub">Publishing writes it live to <code>/blog</code> immediately.</div>
+      <h3>Blog entry</h3><div class="sub" id="blognote">Publishing writes it live to <code>/blog</code> immediately.</div>
       <div class="cs-field"><label>Headline</label><input id="b_title"></div>
       <div class="cs-row">
         <div class="cs-field" style="flex:1;min-width:180px"><label>Category</label>
@@ -200,6 +200,13 @@
       $('s_li').value = j.linkedin || ''; $('s_x').value = j.x || '';
       document.getElementById('blogCard').style.display = '';
       document.getElementById('socialCard').style.display = '';
+      // Copyright policy (Steve, Option 1): only RENTV-sourced stories publish LIVE; outside wires
+      // save as a DRAFT for review (rewriting another outlet's story and publishing it live is the exposure).
+      const isRentv = (selected.source || 'RENTV') === 'RENTV';
+      $('publish').textContent = isRentv ? '🚀 Publish to blog' : '💾 Save as draft';
+      $('blognote').innerHTML = isRentv
+        ? 'Publishing writes it live to <code>/blog</code> immediately.'
+        : '📝 Outside-wire story → saves as a <b>draft</b> for review (not published live). Only RENTV-sourced stories publish directly.';
     } finally { gen.disabled = false; }
   }));
 
@@ -207,16 +214,21 @@
   $('publish').addEventListener('click', () => PR.guard(async () => {
     const title = $('b_title').value.trim();
     if (!title) { PR.toast('Headline required', true); return; }
-    if (!confirm('Publish this entry LIVE to /blog now?')) return;
+    const isRentv = !!(selected && (selected.source || 'RENTV') === 'RENTV');
+    const status = isRentv ? 'published' : 'draft';
+    if (!confirm(isRentv ? 'Publish this entry LIVE to /blog now?' : 'Save this outside-wire story as a DRAFT (not published live)?')) return;
     $('publish').disabled = true;
     try {
       const r = await PR.api('/../posts', { method: 'POST', body: {
         title, cat: $('b_cat').value, author: $('b_author').value.trim() || 'RENTV Staff',
-        dek: $('b_dek').value.trim(), image: $('b_image').value.trim(), body: $('b_body').value, status: 'published',
+        dek: $('b_dek').value.trim(), image: $('b_image').value.trim(), body: $('b_body').value, status,
+        source: selected ? (selected.source || 'RENTV') : 'RENTV',
       } });
       const url = '/post/' + r.post.id;
-      $('pubmeta').innerHTML = `<span class="cs-ok">✅ Published</span> — <a href="${url}" target="_blank" rel="noopener noreferrer">${url}</a>`;
-      PR.toast('Published to blog');
+      $('pubmeta').innerHTML = isRentv
+        ? `<span class="cs-ok">✅ Published</span> — <a href="${url}" target="_blank" rel="noopener noreferrer">${url}</a>`
+        : `<span class="cs-ok">✅ Saved as draft</span> — review + publish it from the blog admin when ready.`;
+      PR.toast(isRentv ? 'Published to blog' : 'Saved as draft');
     } finally { $('publish').disabled = false; }
   }, null));
 
diff --git a/server.js b/server.js
index 76fa2178..6b848c24 100644
--- a/server.js
+++ b/server.js
@@ -246,11 +246,16 @@ app.post('/api/posts', adminOnly, async (req, res) => {
   // Never hotlink a third-party CDN image on the live blog — download it locally (fails closed to '').
   let image = clean(b.image, 500);
   if (image && /^https?:\/\//i.test(image)) image = await localizeImage(image);
+  // Copyright policy (Option 1): a story sourced from an OUTSIDE wire can never auto-publish live —
+  // it is forced to draft server-side regardless of the requested status. Only RENTV-origin publishes.
+  const src = clean(b.source, 80);
+  let status = b.status === 'published' ? 'published' : 'draft';
+  if (src && src !== 'RENTV') status = 'draft';
   const post = {
     id: 'rp' + Date.now().toString(36),
     title: clean(b.title, 200), cat: clean(b.cat, 40) || 'RENTV', author: clean(b.author, 80) || 'RENTV Staff',
     dek: clean(b.dek, 300), image,
-    body: clean(b.body, 40000), status: b.status === 'published' ? 'published' : 'draft',
+    body: clean(b.body, 40000), status,
     created_at: now, updated_at: now,
   };
   const a = readPosts(); a.push(post);

← bb10f92e auto-save: 2026-08-04T19:36:08 (3 files) — data/markets.json  ·  back to Rentv  ·  auto-save: 2026-08-04T20:06:17 (6 files) — data/markets.json 2c32774c →