Outline: share as a read-only link
- Share on the Outline page opens a sheet: create / copy / turn off a read-only link, share the link with the system share sheet, or send the outline as text - The link has its own token (separate from the whole-study share link) and the public endpoint returns only the outlines, rebuilt field by field: no observations, interpretations, applications, scripts or word notes - Opening the link shows the outline(s) with no sign-in, a switcher between the whole-study and per-chunk outlines, and Print / PDF - New outline_share_token column (added automatically on start) Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
2ca79730f1
commit
d7a1601f80
11 files changed
+444
-10
No files matched your search
@@ -83,6 +83,10 @@ export function initDb() {
|
||||
if (!projectCols.some((c) => c.name === 'share_token')) {
|
||||
db.exec('ALTER TABLE projects ADD COLUMN share_token TEXT');
|
||||
}
|
||||
if (!projectCols.some((c) => c.name === 'outline_share_token')) {
|
||||
db.exec('ALTER TABLE projects ADD COLUMN outline_share_token TEXT');
|
||||
}
|
||||
db.exec('CREATE UNIQUE INDEX IF NOT EXISTS idx_projects_outline_share_token ON projects(outline_share_token) WHERE outline_share_token IS NOT NULL');
|
||||
db.exec('CREATE UNIQUE INDEX IF NOT EXISTS idx_projects_share_token ON projects(share_token) WHERE share_token IS NOT NULL');
|
||||
|
||||
// Reader ink — one row per user + book + chapter, stored as JSON
|
||||
@@ -414,6 +418,28 @@ export function clearShareToken(id, userId) {
|
||||
db.prepare('UPDATE projects SET share_token = NULL WHERE id = ? AND user_id = ?').run(id, userId);
|
||||
}
|
||||
|
||||
// ---- read-only outline links: a separate token, so sharing an outline never shares the whole study ----
|
||||
|
||||
export function getOutlineShareToken(id, userId) {
|
||||
const row = db.prepare('SELECT outline_share_token AS t FROM projects WHERE id = ? AND user_id = ?').get(id, userId);
|
||||
return row?.t ?? null;
|
||||
}
|
||||
|
||||
export function setOutlineShareToken(id, userId, token) {
|
||||
return db.prepare('UPDATE projects SET outline_share_token = ? WHERE id = ? AND user_id = ?').run(token, id, userId).changes > 0;
|
||||
}
|
||||
|
||||
export function clearOutlineShareToken(id, userId) {
|
||||
db.prepare('UPDATE projects SET outline_share_token = NULL WHERE id = ? AND user_id = ?').run(id, userId);
|
||||
}
|
||||
|
||||
/** Public lookup: the project data behind an outline link (callers must only ever send the outlines on). */
|
||||
export function getProjectByOutlineToken(token) {
|
||||
const row = db.prepare('SELECT data FROM projects WHERE outline_share_token = ?').get(token);
|
||||
if (!row) return null;
|
||||
try { return JSON.parse(row.data); } catch { return null; }
|
||||
}
|
||||
|
||||
/** Public lookup: returns the full project data for a valid share token, or null. No ownership check — this is the point. */
|
||||
export function getProjectByShareToken(token) {
|
||||
const row = db.prepare('SELECT data FROM projects WHERE share_token = ?').get(token);
|
||||
|
||||
Reference in new issue
Block a user