pediatric-ai-scribe-v3/migrations/1781300000000_resource-shares.js
Daniel eb9fdfef35
Some checks failed
Forgejo Docker Build / Root app tests (push) Successful in 48s
Forgejo Docker Build / Build Docker image (push) Successful in 6s
Forgejo Docker Build / End-to-end (browser) (push) Failing after 7s
feat: share a resource with people on this site — by email, or with everyone
A resource was private with no way out but the author's own Nextcloud.
Share opens reading — open, preview, download — to one person at a time by
exact email (no account is ever listed) or to everyone signed in with one
switch; what others share appears in your library marked "Shared by …".
Writing never travels: modify, re-skin, delete and the share list stay the
author's, every write still filtered on user_id, and the read routes go
through one reader rule. Rows follow the resource and the person.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Dv6sqaY6Vq3ChZHMem3cnU
2026-09-13 15:13:28 +02:00

27 lines
1.3 KiB
JavaScript

// Sharing a resource with other people on this site.
//
// A resource was private to its author with no way out but the author's own
// Nextcloud. A share is a row per (resource, person): the person can open,
// preview and download it — not modify, re-skin or delete it — and the author
// can withdraw it. shared_with_all opens a resource to every signed-in account
// without naming them.
//
// Rows go with the resource and with the person: a deleted account leaves no
// dangling grant, and a deleted resource leaves no orphan share.
exports.up = pgm => pgm.sql(`
ALTER TABLE user_resources ADD COLUMN IF NOT EXISTS shared_with_all BOOLEAN NOT NULL DEFAULT FALSE;
CREATE TABLE IF NOT EXISTS user_resource_shares (
resource_id INTEGER NOT NULL REFERENCES user_resources(id) ON DELETE CASCADE,
user_id INTEGER NOT NULL REFERENCES users(id) ON DELETE CASCADE,
shared_by INTEGER REFERENCES users(id) ON DELETE SET NULL,
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
PRIMARY KEY (resource_id, user_id)
);
CREATE INDEX IF NOT EXISTS idx_resource_shares_user ON user_resource_shares (user_id);
`);
exports.down = pgm => pgm.sql(`
DROP TABLE IF EXISTS user_resource_shares;
ALTER TABLE user_resources DROP COLUMN IF EXISTS shared_with_all;
`);