Address code review findings across API, web and deployment
release gate / check (push) Failing after 6m43s
release gate / check (push) Failing after 6m43s
High severity: - wire TRUSTED_PROXY through Compose/deploy/docs and warn at web startup - bucket public rate limits on effective client IP, add per-bookmark budget, and forward the signed browser identity from the share page - disable first-run bootstrap in server deployments and document seeding - serialize last-admin demotion in one advisory-locked transaction Medium/low: - cap and batch share recipient inserts - add a shared outbound budget for preview/CardDAV/IMAP/signal work - pin CardDAV dials to 443 and bound IMAP logout - fix rightward kanban column drags and normalize cards on column delete - classify backend outages in auth guards, add request timeouts and an error boundary, remove the dead login route, surface throttling - enforce pinned/unpinned page reorder grouping server-side - avoid preview work for stale bookmark versions; drop duplicate dialog fetch - sequence-guard collection/tag/calendar/quick-find loads - validate property config and fix MULTI_SELECT/DATE filter inputs - document index maintenance; apply same-origin check to sign-out - trim signup names, unique shared dates and kanban keys (migration 010), reset reference cache on identity changes, hide OIDC issuer, return 413 for oversized direct bodies, escape Markdown link destinations - remove dead template files and duplicate test helper Verified with go build/vet, full PostgreSQL race suite, db convergence, tsc, both ESLint configs and a Next production build.
This commit is contained in:
@@ -131,6 +131,52 @@ func HandlePagesCreate(w http.ResponseWriter, r *http.Request) {
|
||||
})
|
||||
respond(w, 201, v, e)
|
||||
}
|
||||
|
||||
// reorderPages enforces the pinned/unpinned grouping invariant server-side
|
||||
// (review M-9). The list orders by pinned DESC, position, so a permutation
|
||||
// that interleaves the groups could never be displayed as requested. Rather
|
||||
// than mutating meaningless positions, positions are normalized INSIDE each
|
||||
// group: the submitted order determines the order of pinned pages among
|
||||
// pinned pages and unpinned among unpinned, regardless of interleaving.
|
||||
func reorderPages(r *http.Request, order []string) error {
|
||||
return db.Transaction(r.Context(), database(r), func(tx *sql.Tx) error {
|
||||
if e := lockUser(r, tx); e != nil {
|
||||
return e
|
||||
}
|
||||
rows, e := db.Many(r.Context(), tx, `SELECT jsonb_build_object('id',id,'pinned',pinned) FROM "Page" WHERE "ownerId"=$1`, user(r))
|
||||
if e != nil {
|
||||
return e
|
||||
}
|
||||
if len(rows) != len(order) {
|
||||
return bad("Order must contain every record exactly once")
|
||||
}
|
||||
pinnedByID := make(map[string]bool, len(rows))
|
||||
for _, row := range rows {
|
||||
isPinned, _ := row["pinned"].(bool)
|
||||
pinnedByID[str(row, "id")] = isPinned
|
||||
}
|
||||
groups := map[bool][]string{}
|
||||
seen := make(map[string]bool, len(order))
|
||||
for _, id := range order {
|
||||
isPinned, ok := pinnedByID[id]
|
||||
if !ok || seen[id] {
|
||||
return bad("Order must contain every record exactly once")
|
||||
}
|
||||
seen[id] = true
|
||||
groups[isPinned] = append(groups[isPinned], id)
|
||||
}
|
||||
for _, ids := range [][]string{groups[true], groups[false]} {
|
||||
if len(ids) == 0 {
|
||||
continue
|
||||
}
|
||||
if _, e := tx.ExecContext(r.Context(), `UPDATE "Page" AS p SET position=t.ord-1 FROM unnest($1::text[]) WITH ORDINALITY AS t(pid,ord) WHERE p.id=t.pid AND p."ownerId"=$2`, ids, user(r)); e != nil {
|
||||
return e
|
||||
}
|
||||
}
|
||||
return nil
|
||||
})
|
||||
}
|
||||
|
||||
func HandlePagesReorder(w http.ResponseWriter, r *http.Request) {
|
||||
b, ok := read(w, r)
|
||||
if !ok {
|
||||
@@ -138,7 +184,7 @@ func HandlePagesReorder(w http.ResponseWriter, r *http.Request) {
|
||||
}
|
||||
list, e := ids(b, "order")
|
||||
if e == nil {
|
||||
e = reorder(r, "Page", "ownerId", list)
|
||||
e = reorderPages(r, list)
|
||||
}
|
||||
respond(w, 200, OK{true}, e)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user