Add per-artifact public sharing
Any artifact can now be made publicly viewable via a share link, no login required - opt-in per artifact, toggled from the feed UI next to Keep. - Artifact.share_token: nullable, unique, high-entropy (secrets.token_urlsafe(32)). NULL = not shared; SQL treats each NULL as distinct so uniqueness still holds for the many not-shared rows. - New public route GET /s/<token> (shared_artifact_view), completely unauthenticated, serving the same rendered/raw content as the owner route via a shared serve_artifact_file() helper. - toggle_artifact_share: generates/clears the token: mirrors toggle_artifact_keep's pattern. - Fixed a real gap this surfaced: embedded images in a shared artifact's content would otherwise break for an anonymous visitor, since asset_view was owner-only. It now also allows access when the asset's parent artifact is currently shared - unattached (orphaned) assets stay private regardless. - serialize_artifact now reports is_shared/share_url so the API reflects sharing status (read-only for now; toggling stays UI-only). - Feed UI: Share button (mirrors Keep's toggle interaction), a copyable share-link box that appears when shared, and a "shared" badge on the artifact row - distinct blue accent from Keep's green so both can be visible on the same row without confusion. Verified live end-to-end (toggle on/off, public access, fake-token 404, old-link-dies-on-unshare, embedded-asset access before/after sharing) before writing the 12 automated tests in tests/views/test_sharing.py. Also fixed two unrelated stale spots noticed in docs/api.md while adding the Sharing section: the example response was missing is_kept/size_bytes, and the raw-content table didn't list json/csv (added earlier this session but never documented there). Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
parent
e137725cab
commit
91ea19d26b
10 changed files with 414 additions and 4 deletions
32
docs/api.md
32
docs/api.md
|
|
@ -196,7 +196,11 @@ Response shape:
|
|||
"model": "gpt-5.5",
|
||||
"run_id": "brief-001"
|
||||
},
|
||||
"read_at": null
|
||||
"read_at": null,
|
||||
"is_kept": false,
|
||||
"is_shared": false,
|
||||
"share_url": null,
|
||||
"size_bytes": 702
|
||||
}
|
||||
```
|
||||
|
||||
|
|
@ -429,9 +433,35 @@ Raw currently exists for:
|
|||
|---|---|
|
||||
| `markdown` | Preserved `.md` source. |
|
||||
| `html_full` | Stored HTML file served as text. |
|
||||
| `json` | Preserved original JSON text. |
|
||||
| `csv` | Preserved original CSV text. |
|
||||
|
||||
If raw content is unavailable, Daybook returns a small HTML fallback page.
|
||||
|
||||
## Sharing
|
||||
|
||||
Any artifact can be made publicly viewable — no login or token required —
|
||||
via a per-artifact share link. This is toggled from the feed UI (a "Share"
|
||||
button next to "Keep"), not through the ingest API; there's no `PATCH`
|
||||
field to set it programmatically yet.
|
||||
|
||||
```http
|
||||
GET /s/{share_token}
|
||||
```
|
||||
|
||||
- `share_token` is a high-entropy random string (unrelated to the artifact's
|
||||
own `id`), generated when sharing is turned on and cleared when turned
|
||||
off — turning sharing off immediately invalidates the old link.
|
||||
- The public route serves the same rendered content as `GET /a/{id}`
|
||||
(including `?raw=1`), but with no authentication check at all — anyone
|
||||
with the link can view it.
|
||||
- Images embedded in a shared artifact's content are also served
|
||||
unauthenticated while that artifact is shared, so inline images don't
|
||||
break for a visitor without a Daybook account.
|
||||
- `is_shared` and `share_url` (both in every artifact response — see
|
||||
`GET /api/artifacts/{id}`) report current sharing status; `share_url` is
|
||||
`null` when not shared.
|
||||
|
||||
## Capabilities
|
||||
|
||||
Endpoint:
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue