Add three new QuoteRepository trait methods and a seed helper:
- update_admin_auth_code(current, new_code): replaces the admin code if
`current` matches; generates a fresh passphrase when new_code is None;
returns DbError::Forbidden on mismatch.
- get_submissions_locked(): reads the submissions_locked key from
admin_config; returns false when the key is absent.
- set_submissions_locked(locked): upserts "1"/"0" into admin_config.
- seed_submissions_locked(): INSERT OR IGNORE "0" — safe to call on every
startup without clobbering an active lock.
Implemented in both NativeRepository (rusqlite) and D1Repository (wasm32).
Updated startup seeding in main.rs (native and wasm32 paths) to call
seed_submissions_locked after the existing admin auth code seeding.
Added 7 unit tests in db/native.rs covering all four specified scenarios:
default false, set-then-get, seed does not overwrite, correct code succeeds,
None new_code generates passphrase, wrong code returns Forbidden, stored
code unchanged after Forbidden.
MockRepo in handlers/mod.rs updated with stub implementations of all four
new trait methods to satisfy the trait bound.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Add 6 optional query parameters to GET /api/quotes:
date_after_year/month/day and date_before_year/month/day
Changes:
- QuoteRepository::list_quotes gains date_after and date_before params
- NativeRepository and D1Repository build ISO date prefix WHERE clauses;
quotes with NULL date are excluded when any bound is set
- list_handler validates component ordering (month requires year, etc.)
and returns 400 on invalid combinations
- build_date_bound helper converts y/m/d components to ISO prefix strings
- UI api::list_quotes and browse page gain From/To year filter inputs
- author page call updated to pass None for the new date params
- openapi.yaml extended with 6 new query parameter entries
- 6 new integration tests covering after, before, range, and 400 cases
- 1 new native DB unit test covering all filter combinations
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Add an admin_config table storing a single admin auth code that
bypasses per-quote auth checks for update and delete operations.
The code is auto-generated on first startup and printed to stderr.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Gate native Tokio/Axum main() with #[cfg(not(target_arch = "wasm32"))]
- Add #![cfg_attr(target_arch = "wasm32", no_main)] to suppress missing-main error
- Add #[worker::event(fetch)] entry point using worker::HttpRequest / http::Response<axum::body::Body>
- Enable `http` feature on worker dep so fetch handler uses standard http types
- Add axum (json+query features), tower-service, and http to wasm32 deps
- Move async-trait to shared [dependencies] so both targets have it
- Make db::d1 module pub so main.rs can access D1Repository on wasm32
- Fix worker::d1::Database → D1Database and PreparedStatement → D1PreparedStatement
- Add #[cfg_attr(target_arch = "wasm32", worker::send)] to all 7 handler fns
so their futures satisfy Axum's Handler<Send> bound on single-threaded wasm32
- Remove redundant #![cfg(target_arch="wasm32")] from d1.rs (module
declaration in mod.rs already gates it)
- Remove unused D1Repository re-export from db/mod.rs
- Drop unused page/total_count fields from UI ListResponse struct
(only total_pages is consumed by the browse page)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Replace all 7 stub methods in src/bin/api/db/d1.rs with full working
implementations using the Cloudflare D1 API from workers-rs 0.5.
Implements:
- run_migrations: executes four DDL statements via db.exec()
- list_quotes: dynamic WHERE clause with positional params, COUNT query,
paginated SELECT, per-quote tag fetch
- get_quote: prepared statement with first::<QuoteRow>()
- get_random_quote: ORDER BY RANDOM() LIMIT 1
- create_quote: INSERT + batch tag insert + read-back for timestamps
- update_quote: auth check, dynamic SET clause, optional tag replacement,
read-back of updated row
- delete_quote: auth check, DELETE, returns DeleteResult enum
Also adds helper structs (QuoteRow, AuthRow, TagRow, CountRow),
fetch_tags() helper method, and unsafe Send/Sync impls required for
Arc<dyn QuoteRepository + Send + Sync> on single-threaded wasm32.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>