Admin Members: show the sponsor's username, note share-code joins, flag dead sponsor links
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
This commit is contained in:
+1
-1
@@ -316,6 +316,6 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<script src="/assets/common.js?v=20260910c"></script>
|
<script src="/assets/common.js?v=20260910c"></script>
|
||||||
<script src="/assets/admin.js?v=20260911c"></script>
|
<script src="/assets/admin.js?v=20260911d"></script>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|||||||
@@ -289,7 +289,7 @@
|
|||||||
+ list.map(a => '<tr><td>' + esc(a.email) + '</td><td>' + (a.username ? '@' + esc(a.username) : '<span class="muted">none</span>') + '</td>'
|
+ list.map(a => '<tr><td>' + esc(a.email) + '</td><td>' + (a.username ? '@' + esc(a.username) : '<span class="muted">none</span>') + '</td>'
|
||||||
+ '<td>' + (a.memberId ? '#' + a.memberId : '<span class="muted">free</span>') + '</td>'
|
+ '<td>' + (a.memberId ? '#' + a.memberId : '<span class="muted">free</span>') + '</td>'
|
||||||
+ '<td class="mono small">' + (a.address ? esc(a.address.slice(0, 8) + '…' + a.address.slice(-6)) : '<span class="muted">none</span>') + '</td>'
|
+ '<td class="mono small">' + (a.address ? esc(a.address.slice(0, 8) + '…' + a.address.slice(-6)) : '<span class="muted">none</span>') + '</td>'
|
||||||
+ '<td>' + esc(a.sponsorRef || '') + '</td><td class="small" title="linked Qualified Start positions' + (a.positionIds && a.positionIds.length ? ': #' + a.positionIds.join(', #') : '') + '">' + (a.positions ? a.positions : '<span class="muted">0</span>') + '</td><td class="small muted">' + esc(a.joinedVia || '') + '</td><td class="mono small">' + esc(a.code || '') + '</td>'
|
+ '<td>' + (a.sponsorName ? esc(a.sponsorName) + (a.sponsorVia === 'code' ? ' <span class="muted small" title="joined through this share code">via code ' + esc(a.sponsorRef) + '</span>' : a.sponsorVia === 'member #' ? ' <span class="muted small">via #' + esc(a.sponsorRef) + '</span>' : '') : a.sponsorRef ? '<span class="badge amber" title="this token points at nobody; the member will move to the holding tank">dead link: ' + esc(a.sponsorRef) + '</span>' : '<span class="muted">none</span>') + '</td><td class="small" title="linked Qualified Start positions' + (a.positionIds && a.positionIds.length ? ': #' + a.positionIds.join(', #') : '') + '">' + (a.positions ? a.positions : '<span class="muted">0</span>') + '</td><td class="small muted">' + esc(a.joinedVia || '') + '</td><td class="mono small">' + esc(a.code || '') + '</td>'
|
||||||
+ '<td class="small muted when">' + when(a.created) + '</td>'
|
+ '<td class="small muted when">' + when(a.created) + '</td>'
|
||||||
+ '<td class="act"><button class="btn small sec" data-spon="' + esc(a.email) + '" data-cur="' + esc(a.sponsorRef || '') + '">Sponsor</button></td></tr>').join('');
|
+ '<td class="act"><button class="btn small sec" data-spon="' + esc(a.email) + '" data-cur="' + esc(a.sponsorRef || '') + '">Sponsor</button></td></tr>').join('');
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1779,6 +1779,15 @@ const server = http.createServer(async (req, res) => {
|
|||||||
if (p === '/api/admin/members' && req.method === 'GET') {
|
if (p === '/api/admin/members' && req.method === 'GET') {
|
||||||
if (!isAdmin(req)) return json(res, 401, { error: 'auth' });
|
if (!isAdmin(req)) return json(res, 401, { error: 'auth' });
|
||||||
const members = await accounts.listAll(500);
|
const members = await accounts.listAll(500);
|
||||||
|
// resolve each sponsor token (username, share code or member #) to the sponsor's name
|
||||||
|
const byTok = {};
|
||||||
|
for (const m of members) for (const t of [m.username, m.code, m.memberId ? String(m.memberId) : null]) if (t) byTok[String(t).toLowerCase()] = m;
|
||||||
|
for (const m of members) {
|
||||||
|
const t = String(m.sponsorRef || '').toLowerCase();
|
||||||
|
const sp = t ? byTok[t] : null;
|
||||||
|
m.sponsorName = sp ? (sp.username ? '@' + sp.username : (sp.memberId ? 'member #' + sp.memberId : sp.email)) : null;
|
||||||
|
m.sponsorVia = sp ? (t === String(sp.username || '').toLowerCase() ? 'username' : t === String(sp.code || '').toLowerCase() ? 'code' : 'member #') : (t ? 'unresolved' : '');
|
||||||
|
}
|
||||||
for (const m of members) { try { const ps = await accounts.positions(m.email); m.positions = ps.length; m.positionIds = ps.map(p => p.memberId).filter(Boolean); } catch (e) { m.positions = 0; } }
|
for (const m of members) { try { const ps = await accounts.positions(m.email); m.positions = ps.length; m.positionIds = ps.map(p => p.memberId).filter(Boolean); } catch (e) { m.positions = 0; } }
|
||||||
return json(res, 200, { members });
|
return json(res, 200, { members });
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user