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
27 lines
1.3 KiB
JavaScript
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;
|
|
`);
|