private structures

This commit is contained in:
Your Name 2026-08-19 09:51:07 -04:00
parent 1f7dbf21e0
commit e179814859
6 changed files with 243 additions and 18 deletions

View file

@ -11,6 +11,16 @@ const model = require("./db");
const router = express.Router();
// Private structures are invisible through the plumbing too. Every structure-
// scoped route carries :id, so one param guard covers them all; a caller who
// isn't on the member list gets a 404, same as the workshop.
router.param("id", (req, res, next, id) => {
if (!model.canAccessStructure(req.session && req.session.userId, id)) {
return res.status(404).json({ error: "not found" });
}
next();
});
// Wrap a handler so thrown errors come back as JSON instead of an HTML stack.
function json(handler) {
return (req, res) => {
@ -26,10 +36,17 @@ function json(handler) {
};
}
// All structures.
// All structures the caller is allowed to see (private ones they aren't a
// member of are omitted).
router.get(
"/structures",
json(() => model.getStructures()),
json((req) =>
model
.getStructures()
.filter((s) =>
model.canAccessStructure(req.session && req.session.userId, s.id),
),
),
);
// One structure with everything the sidebar shows, in one call.
@ -87,10 +104,23 @@ router.get(
json((req) => model.getVersions("db", req.params.dbId)),
);
// One version, including its full snapshot (the versioned fields).
// One version, including its full snapshot (the versioned fields). Not scoped
// by :id, so it carries its own access check against the version's structure.
router.get(
"/versions/:versionId",
json((req) => model.getVersion(req.params.versionId)),
json((req) => {
const version = model.getVersion(req.params.versionId);
if (!version) return null;
if (
!model.canAccessStructure(
req.session && req.session.userId,
version.structure_id,
)
) {
return null;
}
return version;
}),
);
// Logs for a route. ?since=<id> returns only newer rows (for polling).