Commit graph

3 commits

Author SHA1 Message Date
Emi Griffith
21f7ef4d19 Group regression tests by domain (#215)
Move the flat backend/tests/*.py into domain subfolders so the suite
mirrors the code's concerns:
  data/          climate, grading, scoring, grid, places, store
  web/           api, content, homepage, views
  notifications/ notify, digest, discord (+ dm/interactions/link)
  accounts/      api_accounts
  core/          metrics, singleton, dashboard

conftest.py stays at the tests/ root, so its sys.path setup and shared
fixtures still apply to every subfolder. The four tests that derive repo
paths from __file__ get their depth bumped one level to match their new
location. Pytest discovers the subfolders recursively; the CI command
(python -m pytest backend/tests) is unchanged.

Claude-Session: https://claude.ai/code/session_01XXxmNFy9cZ6Gh8Y9thZn62
2026-07-20 04:50:01 +00:00
Emi Griffith
c9abad3e13 Show 'Link Discord' only when Discord linking is configured (#213)
The account menu offered 'Link Discord' to every signed-in user even on a
server with no Discord OAuth app configured, where it dead-ends (the start route
303-bounces to /alerts). Add GET /api/v2/discord/config reporting whether linking
is enabled, and have the menu render the entry only when it is. On a server
without Discord set up nothing surfaces; setting the OAuth env vars later makes
the entry appear on its own — no code change needed to turn it on.
2026-07-20 04:36:44 +00:00
Emi Griffith
41e84060ab Link a Thermograph account to Discord via OAuth2 (#208)
Lets a signed-in user connect their Discord account (OAuth2 identify), storing the
Discord user id that a later feature (DM alerts) will deliver to. Standard
authorization-code flow, all server-side:

- backend/discord_link.py: /discord/link/start redirects to Discord's consent
  screen; /discord/link/callback exchanges the code, reads the Discord user id, and
  stores it; /discord/unlink forgets it. The `state` is signed with the app auth
  secret (stdlib hmac, no new dependency) and carries the Thermograph user id, so a
  callback can't be replayed or bound to another account. Every route requires an
  active session, so linking acts on whoever is actually logged in.
- models.py: User.discord_id (unique, nullable). schemas.py exposes it on UserRead
  so the frontend can show link state.
- app.py: the router under /api/v2/discord.
- account.js: a "Link Discord" / "Unlink Discord" control in the account popover.
- deploy/migrations/001-user-discord-id.sql: the manual column add for the existing
  prod accounts DB. This project has no Alembic — create_all only makes missing
  tables, so an added column needs a hand-applied migration (documented in-file).
- env example: THERMOGRAPH_DISCORD_CLIENT_SECRET + the redirect to register.

Claude-Session: https://claude.ai/code/session_013dRZmX9D3JEntfMKWMTWZ8
2026-07-20 02:26:33 +00:00