openvibers/openvibe.network Commits

Remove pronouns from public pages and the profile API (#700)

OP OpenVibers committed 4 days ago · 3c430a2758 · 4 files, +11 −24

The owner (11-09): no pronoun feature on the platform. openvibe.my's public page editor no longer has the field,
the profile API ignores public_page_pronouns, and the person page (HTML and JSON) neither reads nor shows it. Nobody
had set one (0 rows). The column stays until a contract migration can drop it without holding Network's other
migrations (0052 public_person_pages applied 11-08 18:41 UTC, so on or after 11-16).

Changes

ddiff --git a/public/js/my/profile.js b/public/js/my/profile.js
iindex 37d08842..32546a03 100644
---- a/public/js/my/profile.js
++++ b/public/js/my/profile.js
@@@ -216,7 +216,6 @@ function renderProfile(user) {
const pageBio = document.getElementById('public-page-bio');
if (pageBio) {
const unavailable = !!user.is_anon;
-- document.getElementById('public-page-pronouns').value = user.public_page_pronouns || '';
pageBio.value = user.public_page_bio || '';
let links = []; try { links = typeof user.public_page_links === 'string' ? JSON.parse(user.public_page_links) : (user.public_page_links || []); } catch {}
document.getElementById('public-page-links').value = (Array.isArray(links) ? links : []).map(x => `${x.label} | ${x.url}`).join('\n');
@@@ -224,7 +223,7 @@ function renderProfile(user) {
for (const key of ['live', 'media', 'space', 'community']) document.getElementById(`public-place-${key}`).checked = places[key] !== false;
const pageUrl = document.getElementById('public-page-url');
if (user.username && !user.is_anon) { pageUrl.href = `https://openvibe.network/@${encodeURIComponent(user.username)}`; pageUrl.textContent = `openvibe.network/@${user.username}`; }
-- for (const id of ['public-page-pronouns', 'public-page-bio', 'public-page-links', 'public-place-live', 'public-place-media', 'public-place-space', 'public-place-community', 'public-page-preview-toggle', 'public-page-save']) document.getElementById(id).disabled = unavailable;
++ for (const id of ['public-page-bio', 'public-page-links', 'public-place-live', 'public-place-media', 'public-place-space', 'public-place-community', 'public-page-preview-toggle', 'public-page-save']) document.getElementById(id).disabled = unavailable;
if (unavailable) document.getElementById('public-page-msg').textContent = 'Sign in to edit your public page.';
}
if (!user.is_anon) {
@@@ -330,8 +329,6 @@ document.getElementById('profile-form').addEventListener('submit', async (e) =>
const box = document.getElementById('public-page-preview'); box.hidden = false;
box.replaceChildren();
const h = document.createElement('h4'); h.textContent = currentUser?.display_name || currentUser?.username || 'Your name'; box.append(h);
-- const pronouns = document.getElementById('public-page-pronouns').value;
-- if (pronouns) { const byline = document.createElement('p'); byline.textContent = pronouns; box.append(byline); }
const bio = document.createElement('p'); bio.textContent = document.getElementById('public-page-bio').value; box.append(bio);
for (const row of document.getElementById('public-page-links').value.split('\n').filter(Boolean)) { const a = document.createElement('p'); a.textContent = row; box.append(a); }
};
@@@ -343,7 +340,7 @@ document.getElementById('profile-form').addEventListener('submit', async (e) =>
const places = Object.fromEntries(['live', 'media', 'space', 'community'].map(key => [key, document.getElementById(`public-place-${key}`).checked]));
save.disabled = true; msg.textContent = 'Saving…';
try {
-- const data = await apiFetch('/api/auth/profile', { method: 'PUT', body: JSON.stringify({ public_page_bio: document.getElementById('public-page-bio').value, public_page_pronouns: document.getElementById('public-page-pronouns').value, public_page_links: links, public_page_places: places }) });
++ const data = await apiFetch('/api/auth/profile', { method: 'PUT', body: JSON.stringify({ public_page_bio: document.getElementById('public-page-bio').value, public_page_links: links, public_page_places: places }) });
currentUser = data.user; msg.textContent = 'Your public page is saved.'; preview();
} catch (err) { msg.textContent = err.message || 'Could not save your public page.'; }
save.disabled = false;
ddiff --git a/public/my.html b/public/my.html
iindex bf08fdd1..96ed9d1d 100644
---- a/public/my.html
++++ b/public/my.html
@@@ -225,10 +225,6 @@
<h3><span class="icon"><i class="fa-solid fa-address-card"></i></span> Your public page</h3>
<p class="muted">A link-in-bio page at <a id="public-page-url" href="https://openvibe.network/" target="_blank" rel="noopener">openvibe.network/@you</a>. Only information already public while signed out can appear here.</p>
<!-- The same fields as Edit Profile above (.form-field): they were bare labels and boxes in a line (11-09). -->
-- <div class="form-field">
-- <label for="public-page-pronouns">Pronouns</label><input id="public-page-pronouns" maxlength="40" autocomplete="off">
-- <div class="hint">Up to 40 characters.</div>
-- </div>
<div class="form-field">
<label for="public-page-bio">Bio</label><textarea id="public-page-bio" maxlength="280" rows="3"></textarea>
<div class="hint">Up to 280 characters.</div>
ddiff --git a/server/auth/routes.js b/server/auth/routes.js
iindex e3b81d24..67398287 100644
---- a/server/auth/routes.js
++++ b/server/auth/routes.js
@@@ -408,7 +408,7 @@ router.get('/me', requireAuth, async (req, res) => {
// ── Update Profile ───────────────────────────────────────────
router.put('/profile', requireAuth, async (req, res) => {
const db = await getDb(req);
-- const { display_name, bio, avatar_url, email, profile_color, profile_public, public_page_bio, public_page_pronouns, public_page_links, public_page_places } = req.body;
++ const { display_name, bio, avatar_url, email, profile_color, profile_public, public_page_bio, public_page_links, public_page_places } = req.body;
const updates = [];
const params = [];
@@@ -444,11 +444,6 @@ router.put('/profile', requireAuth, async (req, res) => {
if (text.length > 280) return res.status(400).json({ error: 'Your public page bio can be up to 280 characters' });
updates.push('public_page_bio = ?'); params.push(text);
}
-- if (public_page_pronouns !== undefined) {
-- const text = String(public_page_pronouns || '').trim();
-- if (text.length > 40) return res.status(400).json({ error: 'Pronouns can be up to 40 characters' });
-- updates.push('public_page_pronouns = ?'); params.push(text);
-- }
if (public_page_links !== undefined) {
if (!Array.isArray(public_page_links) || public_page_links.length > 8) return res.status(400).json({ error: 'Add up to 8 links' });
const links = [];
@@@ -470,8 +465,8 @@ router.put('/profile', requireAuth, async (req, res) => {
if (updates.length === 0) return res.status(400).json({ error: 'No fields to update' });
-- const publicPageTouched = public_page_bio !== undefined || public_page_pronouns !== undefined || public_page_links !== undefined || public_page_places !== undefined || profile_public !== undefined;
-- const beforePage = publicPageTouched ? await db.prepare('SELECT username, profile_public, public_page_bio, public_page_pronouns, public_page_links, public_page_places FROM users WHERE id = ?').get(req.user.id) : null;
++ const publicPageTouched = public_page_bio !== undefined || public_page_links !== undefined || public_page_places !== undefined || profile_public !== undefined;
++ const beforePage = publicPageTouched ? await db.prepare('SELECT username, profile_public, public_page_bio, public_page_links, public_page_places FROM users WHERE id = ?').get(req.user.id) : null;
updates.push('updated_at = ov_now()');
params.push(req.user.id);
@@@ -488,7 +483,6 @@ router.put('/profile', requireAuth, async (req, res) => {
if (beforePage && publicPageTouched) {
const json = (value) => { try { return typeof value === 'string' ? JSON.parse(value) : value; } catch { return null; } };
const changed = String(beforePage.public_page_bio || '') !== String(user.public_page_bio || '')
-- || String(beforePage.public_page_pronouns || '') !== String(user.public_page_pronouns || '')
|| JSON.stringify(json(beforePage.public_page_links) || []) !== JSON.stringify(json(user.public_page_links) || [])
|| JSON.stringify(json(beforePage.public_page_places) || {}) !== JSON.stringify(json(user.public_page_places) || {})
|| Number(beforePage.profile_public) !== Number(user.profile_public);
ddiff --git a/server/profile/public.js b/server/profile/public.js
iindex 54fabf47..031e70a0 100644
---- a/server/profile/public.js
++++ b/server/profile/public.js
@@@ -284,7 +284,7 @@ function createPublicProfiles({ db, selfToken = () => null, inventoryUrl = 'http
const rec = await usernames.lookup(db, name);
if (!rec) return null;
if (rec.renamed) return { moved: rec.current };
-- const u = await db.prepare(`SELECT id, username, display_name, bio, public_page_bio, public_page_pronouns, public_page_links, public_page_places, profile_color, created_at, subject_id, profile_public,
++ const u = await db.prepare(`SELECT id, username, display_name, bio, public_page_bio, public_page_links, public_page_places, profile_color, created_at, subject_id, profile_public,
is_anon, merged_into, deleted_at FROM users WHERE id = ?`).get(rec.network_id);
if (!u || Number(u.is_anon) || u.merged_into || u.deleted_at) return null;
return { user: u };
@@@ -295,7 +295,7 @@ function createPublicProfiles({ db, selfToken = () => null, inventoryUrl = 'http
try { links = typeof u.public_page_links === 'string' ? JSON.parse(u.public_page_links) : (u.public_page_links || []); } catch {}
try { choices = { ...choices, ...(typeof u.public_page_places === 'string' ? JSON.parse(u.public_page_places) : (u.public_page_places || {})) }; } catch {}
const places = Number(u.profile_public) ? await placesOf(u.username, choices) : { spaces: [], community: [], videos: [] };
-- return { username: u.username, display_name: u.display_name || u.username, pronouns: Number(u.profile_public) ? String(u.public_page_pronouns || '').slice(0, 40) : '', avatar_url: avatarUrl(u.username), profile_url: `${SITE}/@${encodeURIComponent(u.username)}`, bio: Number(u.profile_public) ? String(u.public_page_bio || '').slice(0, 280) : '', links: Number(u.profile_public) && Array.isArray(links) ? links.slice(0, 8) : [], places };
++ return { username: u.username, display_name: u.display_name || u.username, avatar_url: avatarUrl(u.username), profile_url: `${SITE}/@${encodeURIComponent(u.username)}`, bio: Number(u.profile_public) ? String(u.public_page_bio || '').slice(0, 280) : '', links: Number(u.profile_public) && Array.isArray(links) ? links.slice(0, 8) : [], places };
}
/** profile@1: what every site may show about a person. */
@@@ -340,7 +340,7 @@ function createPublicProfiles({ db, selfToken = () => null, inventoryUrl = 'http
res.set('Cache-Control', cache.htmlHeaders({ maxAge: 60 }));
// A person's public profile lives on openvibe.network (the owner, 11-08: "OpenVibe.My is for users' stuff,
// the profiles should be on .Network"). openvibe.my is the person's own hub: /@name there moves here.
-- res.send(renderPage(u, inv, SITE, page.places, page.pronouns));
++ res.send(renderPage(u, inv, SITE, page.places));
} catch (err) { next(err); }
}
@@@ -453,7 +453,7 @@ ${sorted.map((g) => {
<p class="pf-note"><a href="${esc(all)}">${inv.more ? 'Every item' : 'This inventory'} on OpenVibe.Inventory</a> · <a href="${INVENTORY_SITE}/items">Every item there is</a></p></section>`;
}
--function renderPage(u, inv, origin = SITE, places = { spaces: [], community: [], videos: [] }, pronouns = '') {
++function renderPage(u, inv, origin = SITE, places = { spaces: [], community: [], videos: [] }) {
const canonicalUrl = `${origin}/@${encodeURIComponent(u.username)}`;
const name = u.display_name || u.username;
const isPublic = !!inv;
@@@ -524,7 +524,7 @@ a{color:var(--accent)}
.pf-who{flex:1;min-width:200px;padding-top:56px}
.pf-who h1{margin:0;font-size:clamp(1.5rem,4vw,2.1rem);line-height:1.15;overflow-wrap:anywhere}
.pf-name-badge{width:.85em;height:.85em;margin-right:.25em;vertical-align:-.08em;border-radius:6px;object-fit:contain}
--.pf-handle{margin:.2em 0 0;color:var(--text-secondary)}.pf-pronouns{display:inline-block;margin-left:6px;padding:1px 9px;border:1px solid var(--border);border-radius:999px;font-size:.82em;vertical-align:1px}.pf-places a .pf-live{display:inline-flex;align-items:center;gap:6px;color:var(--live-red,#e5484d);font-weight:700}.pf-live::before{content:'';width:8px;height:8px;border-radius:50%;background:currentColor}
++.pf-handle{margin:.2em 0 0;color:var(--text-secondary)}.pf-places a .pf-live{display:inline-flex;align-items:center;gap:6px;color:var(--live-red,#e5484d);font-weight:700}.pf-live::before{content:'';width:8px;height:8px;border-radius:50%;background:currentColor}
.pf-bio{margin:0;padding:0 24px 18px;color:var(--text-primary);line-height:1.6;white-space:pre-line;overflow-wrap:anywhere;max-width:72ch}
.pf-stats{list-style:none;display:flex;flex-wrap:wrap;gap:8px;margin:0;padding:0 24px 22px}
.pf-stats li{display:flex;flex-direction:column;gap:2px;padding:8px 14px;border:1px solid var(--border);border-radius:12px;background:var(--bg-card);min-width:110px}
@@@ -578,7 +578,7 @@ ${require('openvibe-shared/frame').noscriptNav({ name: 'OpenVibe.Network', links
<div class="pf-banner" aria-hidden="true"></div>
<div class="pf-head">
<div class="pf-pic"><img class="pf-avatar" src="${esc(avatarUrl(u.username))}" alt="" width="112" height="112">${hatGlyph ? `<span class="pf-hat" title="${esc(hat.name)}" aria-hidden="true">${esc(hatGlyph)}</span>` : ''}</div>
--<div class="pf-who"><h1>${badgeId ? `<img class="pf-name-badge" src="https://openvibe.media/o/${badgeId}" alt="" title="${esc(badge.name)}" width="32" height="32">` : ''}${fxClass ? `<span class="ov-fx ${fxClass}" title="${esc(fx.name)}">${esc(name)}</span>` : esc(name)}</h1><p class="pf-handle">@${esc(u.username)}${isPublic && pronouns ? ` <span class="pf-pronouns">${esc(pronouns)}</span>` : ''}</p></div>
++<div class="pf-who"><h1>${badgeId ? `<img class="pf-name-badge" src="https://openvibe.media/o/${badgeId}" alt="" title="${esc(badge.name)}" width="32" height="32">` : ''}${fxClass ? `<span class="ov-fx ${fxClass}" title="${esc(fx.name)}">${esc(name)}</span>` : esc(name)}</h1><p class="pf-handle">@${esc(u.username)}</p></div>
</div>
${bio ? `<p class="pf-bio">${esc(bio)}</p>` : ''}
${isPublic && Array.isArray(publicLinks) && publicLinks.length ? `<nav aria-label="${esc(name)}'s links"><ul class="pf-links">${publicLinks.slice(0, 8).map((link) => { let href = ''; try { const parsed = new URL(link.url); if (parsed.protocol === 'https:' && !parsed.username && !parsed.password) href = parsed.href; } catch {} return href ? `<li><a rel="me noopener noreferrer" href="${esc(href)}">${esc(String(link.label || '').slice(0, 40))}</a></li>` : ''; }).join('')}</ul></nav>` : ''}