feat(afdian): add sponsor thank-you page to sidebar nav (AFD-004) - #7
Merged
Conversation
…view AFD-001 review pass on b1728f5: single-source URL config, external-link rel/target, SUP-004 copy, and keyboard/a11y all check out. Site is dark-only (no prefers-color-scheme / data-theme), so button reuses the existing --app-* vars consistently. Only nit: .donate-afdian-btn used var(--app-text-bright) with no fallback while --app-text-bright is undefined site-wide; align it with the existing var(--app-text-bright, #fff) usage in the same file. Docs: assign AFD-001 Review AI, add changelog WAVE-20260804-02. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01LjBDHnJYAW4ETrLWFyj9he
…FD-002) Add ohmywod/afdian.py: a tiny stdlib-only (urllib/hashlib/json, no new dependency) read-only client for the sponsor wall. sign() implements md5(token+"params"+params+"ts"+ts+"user_id"+user_id); query_sponsor() POSTs query-sponsor with a 5s timeout and translates every network / HTTP / decode / ec!=200 failure into AfdianError without leaking the token; fetch_all_sponsors() paginates under a MAX_PAGES bound. Credentials come from Flask config (AFDIAN_USER_ID / AFDIAN_TOKEN); empty or unrendered "<secret:...>" values are treated as unconfigured so dev/unprovisioned environments degrade to an empty wall instead of raising. config.py DefaultConfig gains the two keys as an empty schema reference (runtime uses local_config.py, rendered by ohmywod-ops). tests/test_afdian.py (8): signing vector, unconfigured->empty, placeholder rejection, pagination, MAX_PAGES bound, and two token-non-leak error paths. Full suite 120 passed. Docs: AFD-002 assessing -> in_progress with scaffold evidence, changelog WAVE-20260804-03. Real-credential query still pending to reach done. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01LjBDHnJYAW4ETrLWFyj9he
…2 done Real query-sponsor call with provisioned credentials revealed afdian.com sits behind Cloudflare, which 403-bans the default Python-urllib UA with "error code: 1010". Send a browser User-Agent (and Accept: application/json) so the API answers; afdian.com is the correct host (afdian.net no longer resolves). Verified end-to-end: HTTP 200, ec=200, signature accepted, is_configured()=True, fetch_all_sponsors()=[] (account has 0 sponsors). Add test_query_sponsor_sends_browser_user_agent to guard the regression; test_afdian 9 pass, full suite 121 pass. Docs: AFD-002 in_progress -> done with real-call evidence, changelog WAVE-20260804-04. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01LjBDHnJYAW4ETrLWFyj9he
Add get_sponsors(): serves a fresh Redis copy (AFDIAN_CACHE_TTL, default 1h) on hit; on miss pulls from Afdian and refreshes both a fresh (TTL) and a long-lived last-good copy. When Afdian is unreachable it degrades to the last-good copy, else an empty list — logs a warning, never raises, never blocks the page. Afdian stays the single source of truth: no SQLite writes, no models/migrations, nothing enters the litestream/DR chain. config.py gains AFDIAN_CACHE_TTL (overridable). tests/test_afdian.py adds 4 cache cases (miss->fetch->hit, degrade-to-last-good, degrade-to-empty, unconfigured->empty); test_afdian 13 pass, full suite 122. Docs: AFD-003 todo -> done, changelog WAVE-20260804-05. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01LjBDHnJYAW4ETrLWFyj9he
Privacy-first, nickname-only wall completing Wave 2. Per the chosen policy: show only the Afdian nickname (no amount, no tier, no id/avatar); a sponsor with a blank/missing/malformed nickname is shown as "匿名支持者"; the wall lives on a standalone /thanks page linked from the landing support panel. - afdian.sponsor_display_names() maps the AFD-003 cached source to display nicknames, anonymising anything without a usable name and never raising. - frontend.thanks_page (GET /thanks) renders thanks.html: nickname chips or a restrained empty state; copy states nickname-only / no amount and does not imply support buys features (SUP-004/006). - Third-party nicknames are HTML-escaped by Jinja autoescape (test asserts <script> is neutralised). tests/test_afdian.py +4 (mapping/anonymise, empty, /thanks empty-state, /thanks list+XSS-escape); test_afdian 17 pass, full suite 129. Docs: AFD-004 assessing -> done, decisions #3/#4/#6 recorded, Wave 2 all done, changelog WAVE-20260804-06. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01LjBDHnJYAW4ETrLWFyj9he
Surface /thanks from the global left sidebar (heart icon) so the wall is reachable site-wide, not only from the landing support panel. Verified on the running dev server with cache-seeded demo sponsors: chips render, blank name -> "匿名支持者", third-party nickname HTML-escaped. Docs: AFD-004 evidence updated (sidebar entry). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01LjBDHnJYAW4ETrLWFyj9he
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
No description provided.