some basic statistics and invite tree, plus watch new data
This commit is contained in:
+135
@@ -1,5 +1,140 @@
|
||||
# Changelog
|
||||
|
||||
## [Unreleased] — 2026-04-10
|
||||
|
||||
### New feature — Per-instance user limit
|
||||
|
||||
Operators can now cap the maximum number of registered users on an instance.
|
||||
|
||||
- **`bincio/serve/db.py`**
|
||||
- New `settings` table (key/value, upsert-safe via `ON CONFLICT DO UPDATE`).
|
||||
- `count_users(db)` — returns total number of rows in `users`.
|
||||
- `get_setting(db, key)` / `set_setting(db, key, value)` — generic persistent settings store.
|
||||
|
||||
- **`bincio/serve/server.py`** — `POST /api/register` now reads the `max_users` setting; if
|
||||
set to N > 0 and the current user count is already ≥ N, registration is rejected with
|
||||
HTTP 403 and a clear message. Imports `count_users` and `get_setting`.
|
||||
|
||||
- **`bincio/serve/init_cmd.py`** — new `--max-users N` flag (default 0 = unlimited). Saves
|
||||
the value to the `settings` table via `set_setting`. Printed in the init summary.
|
||||
|
||||
- **`bincio/serve/cli.py`** — new `--max-users N` flag on `bincio serve`. Writes to the DB
|
||||
on startup (lets operators change the limit without re-running `bincio init`). Startup
|
||||
banner now shows `Users: max N` or `Users: unlimited`.
|
||||
|
||||
---
|
||||
|
||||
### New feature — Original file storage option (upload & Strava sync)
|
||||
|
||||
Users can now choose whether to keep their source files on the server after processing.
|
||||
Keeping originals allows reprocessing if the pipeline improves; discarding them is the
|
||||
privacy-conscious choice. Previously, uploaded files were always deleted after processing.
|
||||
|
||||
- **`bincio/serve/db.py`** — `store_originals` is stored as a settings key. `bincio init`
|
||||
writes `store_originals=true` on first run.
|
||||
|
||||
- **`bincio/serve/server.py`** — `POST /api/upload` accepts a new `store_original: bool`
|
||||
form field. On success, if true, the staged file is moved to `{user_dir}/originals/`
|
||||
instead of being deleted. `GET /api/me` now includes `store_originals_default: bool`
|
||||
(read from the instance setting) so the frontend can pre-populate the checkbox.
|
||||
`POST /api/strava/sync` checks the `store_originals` instance setting; if true, creates
|
||||
`{user_dir}/originals/strava/` and passes it as `originals_dir` to `run_strava_sync`.
|
||||
|
||||
- **`bincio/edit/server.py`** — `POST /api/upload` gains the same `store_original` form
|
||||
field with identical behaviour (originals stored in `{data_dir}/originals/`).
|
||||
|
||||
- **`bincio/edit/ops.py`** — `run_strava_sync` gains an `originals_dir: Optional[Path]`
|
||||
parameter, passed through to `ingest.strava_sync`.
|
||||
|
||||
- **`bincio/extract/ingest.py`** — `strava_sync` gains `originals_dir: Optional[Path]`.
|
||||
When set, saves `{"meta": …, "streams": …}` as JSON to
|
||||
`originals_dir/{activity_id}.json` before processing each activity. This preserves the
|
||||
raw Strava API response for future reprocessing without needing another API call.
|
||||
|
||||
- **`bincio/serve/init_cmd.py`** — sets `store_originals=true` in the settings table on
|
||||
first init (skipped if the key already exists, so re-running init doesn't override
|
||||
an operator's choice).
|
||||
|
||||
- **`site/src/layouts/Base.astro`** — upload modal file view gains a "Keep original file on
|
||||
server" checkbox. Defaults to unchecked; pre-checked after login if the instance setting
|
||||
is `true` (read from `store_originals_default` in the `/api/me` response). The checkbox
|
||||
value is sent as the `store_original` form field.
|
||||
|
||||
- **`bincio/serve/server.py`** and **`bincio/edit/server.py`** — `Form` added to the
|
||||
FastAPI imports (was missing, causing a startup `NameError`).
|
||||
|
||||
---
|
||||
|
||||
### New feature — About page (multilingual)
|
||||
|
||||
New static `/about/` page explaining the project, with a Ko-fi donation button, data
|
||||
storage disclaimer, and early-software caveats. Available in four languages.
|
||||
|
||||
- **`site/src/pages/about/index.astro`** — English
|
||||
- **`site/src/pages/about/it/index.astro`** — Italian
|
||||
- **`site/src/pages/about/es/index.astro`** — Spanish
|
||||
- **`site/src/pages/about/ca/index.astro`** — Catalan
|
||||
|
||||
All four pages share the same structure:
|
||||
- Language switcher (EN / IT / ES / CA) in the top-right corner.
|
||||
- Ko-fi donation button (`https://ko-fi.com/brutsalvadi`) at the top.
|
||||
- **Community stats section** — fetches `GET /api/stats` on load; shown only in
|
||||
multi-user mode (silently hidden in single-user mode where the endpoint doesn't exist).
|
||||
Displays total member count and an indented invitation tree: each row shows display name,
|
||||
`@handle`, membership duration (days / months), and either "founder" or "invited by @X".
|
||||
UI labels are fully translated per language.
|
||||
- Sections: What is this · Your data on this server · Early-stage software · Disclaimer ·
|
||||
Open source.
|
||||
- All pages use `public={true}` so they bypass the instance auth wall.
|
||||
|
||||
"About" link added to the main nav bar (visible when not on a public page).
|
||||
The upload modal's "Keep original file" checkbox links to `/about/` for context.
|
||||
|
||||
---
|
||||
|
||||
### New feature — Community stats API
|
||||
|
||||
- **`bincio/serve/db.py`** — `get_member_tree(db)` joins `users` with `invites` (on
|
||||
`used_by`) to reconstruct the invitation graph. Returns a list ordered oldest-first with
|
||||
`handle`, `display_name`, `created_at`, and `invited_by` (inviter handle or `None` for
|
||||
the founder/admin).
|
||||
|
||||
- **`bincio/serve/server.py`** — new public `GET /api/stats` endpoint (no auth required).
|
||||
Returns `user_count` and a `members` array where each entry includes `handle`,
|
||||
`display_name`, `member_since` (Unix timestamp), `member_for_days`, and `invited_by`.
|
||||
|
||||
---
|
||||
|
||||
### Fix — `bincio dev` now watches data directory for live re-merge
|
||||
|
||||
Previously, editing a sidecar or running `bincio extract` while `bincio dev` was running
|
||||
required a manual restart to pick up changes. Now a background watcher thread re-merges
|
||||
automatically.
|
||||
|
||||
- **`bincio/dev.py`** — new `_watch_data(data)` function, started as a daemon thread
|
||||
alongside `bincio serve`. Uses `watchfiles` (already bundled with `uvicorn[standard]`,
|
||||
no new dependency) for OS-level file event watching — no polling.
|
||||
- Watches every `{user_dir}/edits/` and `{user_dir}/activities/` directory.
|
||||
- On any change, identifies which users were affected and calls `merge_all(user_dir)`
|
||||
for each.
|
||||
- Skips churn files written by merge itself (`.timeseries.json`, `.geojson`,
|
||||
`index.json`) to avoid re-triggering.
|
||||
- Prints `↺ {handle}: merged` on each successful re-merge; warns on failure.
|
||||
- Astro dev picks up the result automatically since `public/data` is a symlink into
|
||||
the live data directory.
|
||||
|
||||
---
|
||||
|
||||
### Tests
|
||||
|
||||
- **`tests/test_server_imports.py`** (new) — smoke tests that import `bincio.serve.server`
|
||||
and `bincio.edit.server` at module level, catching `NameError`, missing imports, and
|
||||
syntax errors before they reach the runtime. Also asserts that key routes (`/api/me`,
|
||||
`/api/upload`, `/api/strava/sync`, `/api/register`, `/api/activity/{activity_id}`) are
|
||||
registered on each app.
|
||||
|
||||
---
|
||||
|
||||
## [Unreleased] — 2026-04-06
|
||||
|
||||
### New feature — Strava sync from UI
|
||||
|
||||
Reference in New Issue
Block a user