test: integration coverage for dues_payment_methods RLS and dispatcher skip
- dues_payment_methods RLS: member read, admin-only write, cross-space denial, 046 unverified-admin status gate (4 cases). - notification dispatcher: a muted category becomes 'skipped' while billing always sends; no pref row sends (default on). First real exercise of the skip path (cron is gated off in prod). - Fix integration/db.ts rowsAsUser: the SELECT must be the last psql -c statement or its output is swallowed (it was never used before). - Dues card: hide "No active dues subscription" for spaces without Stripe, where it read as confusing.
This commit is contained in:
+15
-4
@@ -58,14 +58,25 @@ export function rows<T = Record<string, unknown>>(selectSql: string): T[] {
|
||||
|
||||
export function rowsAsUser<T = Record<string, unknown>>(uid: string, selectSql: string): T[] {
|
||||
const claims = JSON.stringify({ sub: uid }).replace(/'/g, "''")
|
||||
// The SELECT must be the LAST statement: psql -c with several statements
|
||||
// only prints the final command's result, so a trailing `commit` would
|
||||
// swallow the SELECT output. Use session-level `set` (the one-shot psql
|
||||
// connection exits afterward) and end on the SELECT.
|
||||
const r = run([
|
||||
'-tAc',
|
||||
`begin; set local role authenticated; set local "request.jwt.claims" = '${claims}';` +
|
||||
`select coalesce(json_agg(t),'[]'::json)::text from (${selectSql}) t; commit;`,
|
||||
`set role authenticated; set "request.jwt.claims" = '${claims}'; ` +
|
||||
`select coalesce(json_agg(t),'[]'::json)::text from (${selectSql}) t;`,
|
||||
])
|
||||
if (!r.ok) throw new Error(r.err)
|
||||
// last non-empty line is the json (BEGIN/SET/COMMIT print nothing with -tA)
|
||||
const line = r.out.trim().split('\n').filter(Boolean).pop() ?? '[]'
|
||||
// json_agg(coalesce(...,'[]')) yields a line starting with '['; pick it and
|
||||
// ignore any psql command tags (SET) that may print around it.
|
||||
const line =
|
||||
r.out
|
||||
.trim()
|
||||
.split('\n')
|
||||
.map(l => l.trim())
|
||||
.filter(l => l.startsWith('['))
|
||||
.pop() ?? '[]'
|
||||
return JSON.parse(line) as T[]
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user