From f2734ab5b26a308f8cfbe2ca9e58093834ca2154 Mon Sep 17 00:00:00 2001 From: Paul Trowbridge Date: Fri, 18 Sep 2026 13:29:52 -0400 Subject: [PATCH] Scope the table-info counts to the territory table-info feeds two things and was scoped for neither: the status bar's "total rows", and the figure the load progress promises while it waits. So an account that can see a fraction of the table was told the whole size of it -- jbukowski's 542k rows reported as 2.8M. It only showed on the larger territories. The seeded figure is replaced by X-Row-Count when the headers arrive, and on a small territory the aggregate returns fast enough that the wrong number barely appears. Co-Authored-By: Claude Opus 5 (1M context) --- routes/versions.js | 20 +++++++++++++++++--- 1 file changed, 17 insertions(+), 3 deletions(-) diff --git a/routes/versions.js b/routes/versions.js index 1750a46..f62f0c3 100644 --- a/routes/versions.js +++ b/routes/versions.js @@ -1,6 +1,7 @@ const express = require('express'); const { fcTable, mapType } = require('../lib/utils'); -const { sessionUser } = require('../lib/auth'); +const { sessionUser, sessionTerritory } = require('../lib/auth'); +const { buildTerritoryClause } = require('../lib/sql_generator'); module.exports = function(pool) { const router = express.Router(); @@ -194,7 +195,7 @@ ${colDefs}, router.get('/versions/:id/table-info', async (req, res) => { try { const verResult = await pool.query(` - SELECT v.id, v.name, v.status, s.schema, s.tname + SELECT v.id, v.name, v.status, s.schema, s.tname, s.id AS source_id FROM pf.version v JOIN pf.source s ON s.id = v.source_id WHERE v.id = $1 @@ -210,10 +211,23 @@ ${colDefs}, ); const exists = existsResult.rows[0].exists; + // Scoped like every other read. Unscoped it reported the whole + // table to an account that can see a fraction of it -- the status + // bar's row count, and the figure the load progress promises, both + // came from here: a rep with 330k rows was told the load was + // fetching 2.8M. + const terrCol = (await pool.query( + `SELECT cname FROM pf.col_meta WHERE source_id = $1 AND is_territory LIMIT 1`, + [v.source_id] + )).rows[0]?.cname || null; + const terr = buildTerritoryClause(sessionTerritory(req), terrCol); + let rows = null, byIter = []; if (exists) { const countResult = await pool.query( - `SELECT pf_iter, count(*)::int AS n FROM ${fc} GROUP BY pf_iter ORDER BY pf_iter` + `SELECT pf_iter, count(*)::int AS n FROM ${fc} + ${terr ? `WHERE ${terr}` : ''} + GROUP BY pf_iter ORDER BY pf_iter` ); byIter = countResult.rows; rows = byIter.reduce((a, r) => a + r.n, 0);