private structures
This commit is contained in:
parent
1f7dbf21e0
commit
e179814859
6 changed files with 243 additions and 18 deletions
72
db.js
72
db.js
|
|
@ -203,10 +203,74 @@ function createStructure(name, userId) {
|
|||
const stmt = db.prepare(
|
||||
"INSERT INTO structures (name, user_id) VALUES (?, ?)",
|
||||
);
|
||||
const info = stmt.run(name, userId);
|
||||
const info = stmt.run(name, userId ?? null);
|
||||
return info.lastInsertRowid; // Returns the structure_id of the newly created structure
|
||||
}
|
||||
|
||||
// ---- access control (private structures) --------------------------------
|
||||
//
|
||||
// A structure is public unless `private` is set. Access to a private structure
|
||||
// is exactly its member list (structure_members) — a flat set of equals, no
|
||||
// creator or owner. Anyone on the list can reach it, edit it, manage the list,
|
||||
// or make it public again. This is the single source of truth the platform
|
||||
// consults before serving a user route, mounting a db, or opening the workshop
|
||||
// — never the structure's own code.
|
||||
|
||||
function isMember(structureId, userId) {
|
||||
return !!db
|
||||
.prepare(
|
||||
"SELECT 1 FROM structure_members WHERE structure_id = ? AND user_id = ?",
|
||||
)
|
||||
.get(structureId, userId);
|
||||
}
|
||||
|
||||
function canAccessStructure(userId, structureId) {
|
||||
const s = getStructure(structureId);
|
||||
if (!s) return false;
|
||||
if (!s.private) return true;
|
||||
if (userId == null) return false;
|
||||
return isMember(structureId, userId);
|
||||
}
|
||||
|
||||
// Members of a structure, with their usernames, for the settings UI.
|
||||
function getMembers(structureId) {
|
||||
return db
|
||||
.prepare(
|
||||
`SELECT sv.user_id, u.username, sv.created_at
|
||||
FROM structure_members sv
|
||||
JOIN users u ON u.id = sv.user_id
|
||||
WHERE sv.structure_id = ?
|
||||
ORDER BY sv.created_at ASC`,
|
||||
)
|
||||
.all(structureId);
|
||||
}
|
||||
|
||||
function addMember(structureId, userId) {
|
||||
db.prepare(
|
||||
"INSERT OR IGNORE INTO structure_members (structure_id, user_id) VALUES (?, ?)",
|
||||
).run(structureId, userId);
|
||||
}
|
||||
|
||||
function removeMember(structureId, userId) {
|
||||
db.prepare(
|
||||
"DELETE FROM structure_members WHERE structure_id = ? AND user_id = ?",
|
||||
).run(structureId, userId);
|
||||
}
|
||||
|
||||
// Set a structure's privacy. Anyone may lock any structure down; the actor is
|
||||
// added to the member list so they don't shut themselves out. (Access is purely
|
||||
// the member set, so without this the person who flipped it private would lose
|
||||
// the very structure they just privatized.)
|
||||
function setStructurePrivacy(structureId, isPrivate, actorUserId) {
|
||||
const s = getStructure(structureId);
|
||||
if (!s) return;
|
||||
db.prepare("UPDATE structures SET private = ? WHERE id = ?").run(
|
||||
isPrivate ? 1 : 0,
|
||||
structureId,
|
||||
);
|
||||
if (isPrivate && actorUserId != null) addMember(structureId, actorUserId);
|
||||
}
|
||||
|
||||
function createRoute(verb, path, structureId, handler) {
|
||||
path = encodeURI(path);
|
||||
|
||||
|
|
@ -769,6 +833,12 @@ module.exports = {
|
|||
getStructures,
|
||||
getStructure,
|
||||
createStructure,
|
||||
canAccessStructure,
|
||||
isMember,
|
||||
getMembers,
|
||||
addMember,
|
||||
removeMember,
|
||||
setStructurePrivacy,
|
||||
createRoute,
|
||||
getRoutes,
|
||||
getRoute,
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue