Commit Graph
16 Commits
Author SHA1 Message Date
Donkie c8be881e03 fix(sort): keep never-used spools and filaments at the bottom
Sorting the library by "last used" led with everything that had never been
used, on PostgreSQL and CockroachDB. Those two default to NULLS FIRST on
DESC, while SQLite and MySQL treat NULL as the lowest value and put it last;
`last_used` is NULL until a spool is first used, so the default library
ordering came out inverted for half the supported databases (#984, #985).
Grouped views showed it worst: a group's date is the max over its spools, so
a filament holding nothing but unused spools aggregates to NULL and floated
to the top, above filaments used minutes ago.

order_by_clauses() now orders on an explicit "is it null" flag ahead of the
field itself, so an absent value sorts last in both directions everywhere.
It is written as `expr IS NULL` rather than SQLAlchemy's nullslast(), which
renders a literal NULLS LAST that MySQL and MariaDB reject. Applied to every
sort site -- spools, groups, filaments, vendors, extra fields -- so ordering
no longer depends on which database is underneath.

Verified against all four: 438 integration tests pass on SQLite, PostgreSQL,
MariaDB and CockroachDB, and both new regression tests fail on PostgreSQL
without the fix.

Claude-Session: https://claude.ai/code/session_01EaLK21WpQYDE1DkKwZHK3P
2026-07-31 14:38:50 +02:00
Donkie 72daa29cd2 security: finish the audit's low-severity items
Task 10: config.js JSON-encodes the base path, so a backslash cannot
escape the string literal the way the old " check allowed; search.py
escapes LIKE wildcards at both its call sites, using a helper moved into
database/utils.py so it and extra_field_query share one implementation.

Task 9 was a pair of decisions rather than fixes. /info keeps its paths:
both clients render them and removing response fields breaks API v1, while
the disclosure buys nothing against an API that is unauthenticated anyway.
/metrics keeps its shape but now says what it publishes when switched on.

Also pins the unit tests to a throwaway data directory -- importing
spoolman.main creates one as a side effect, and it was the real one.
2026-07-31 09:42:32 +02:00
Donkie 5d812e269e fix: return 400 instead of 500 for malformed sort parameters
Each list endpoint parsed `sort` inline with a bare split(":"), so `?sort=name`
raised "not enough values to unpack" and `?sort=name:sideways` a KeyError from
SortOrder[...]. Both surfaced as a 500 (todo.md task 8).

parse_nested_field also gated on hasattr, so any attribute that merely existed
passed through to order_by() -- `?sort=metadata:asc` got as far as calling
.asc() on the MetaData object. It now checks the SQLAlchemy mapper's columns,
so only real columns are accepted; relationship traversal through filament. and
vendor. still works.

Sort parsing moves into a shared parse_sort() used by all four call sites, which
tolerates surrounding whitespace and rejects a missing colon, an empty field
name or an unknown direction with a message saying what was expected.

database/vendor.py turned out not to use parse_nested_field at all -- it did a
bare getattr(models.Vendor, fieldstr) -- so /vendor kept returning 500 even
after the helper was fixed. It now uses the shared helper like filament.py.

All three endpoints verified end-to-end: 400 for each malformed form, 200 for
valid single and multi-field sorts, and no unhandled exceptions in the log.
2026-07-27 20:03:14 +02:00
Donkie b942d1f8a1 Replaced pdm with uv, updated backend deps, python 3.10 minimum, simplified install script 2026-01-07 22:01:02 +01:00
inukiwi 1f3c1c0ad5 Do not ignore empty lists in database selects 2025-01-15 23:14:09 +01:00
Donkie b00075ab87 Added backend support to perform exact matches 2024-05-25 20:56:22 +02:00
Donkie cf8d7472f5 Added backend filament search by similar color 2023-12-19 21:37:07 +01:00
Donkie 597dca7c28 Fixed combining empty and non-empty filter
Previously it would then act as a wildcard filter
2023-09-20 21:02:49 +02:00
Donkie 6ee3b8df70 Added support for multiple int where's 2023-09-16 11:13:30 +02:00
Donkie 6d68a40313 Added support for multiple string where's 2023-09-16 11:13:30 +02:00
Donkie e436aa4975 Added tests for spool find sorting 2023-09-16 11:13:30 +02:00
Donkie f47eacd2a9 Added support for finding empty vendor fields 2023-09-16 11:13:30 +02:00
Donkie de16dd7be0 Added database support for finding empty fields 2023-09-16 11:13:30 +02:00
Donkie e2d937aaf1 Added x-total-count response header 2023-09-16 11:13:30 +02:00
Donkie 9d51ee49ed Serverside sort and limit for vendor and filaments 2023-09-16 11:13:30 +02:00
Donkie 4fdea75e3f Serverside spool sorting 2023-09-16 11:13:30 +02:00