Skip to content

James Postadan | Oct2025-2 | Module Legacy Code | Sprint 1 | Extra long blooms - #4

Open
japostadan wants to merge 4 commits into
mainfrom
issue-04-bloom-length-limit
Open

James Postadan | Oct2025-2 | Module Legacy Code | Sprint 1 | Extra long blooms#4
japostadan wants to merge 4 commits into
mainfrom
issue-04-bloom-length-limit

Conversation

@japostadan

@japostadan japostadan commented Jun 16, 2026

Copy link
Copy Markdown
Owner

🎯 Summary

  • Fixed: the backend now rejects blooms longer than 280 characters with a 400 response
  • Trimmed AS's over-limit seed bloom in populate.py (375 → 246 chars) so fresh seeds stay valid
  • Added backend regression tests: exactly-280 accepted, 281 rejected, error body mentions "280"

🧾 Changelist

  • Root cause: POST /bloom in endpoints.py had no server-side length validation. The frontend enforces maxlength="280" on the textarea, but any client bypassing the browser (curl, populate.py, scripts) could post blooms of arbitrary length. AS's seeded bloom was 375 characters as a result.
  • Fix: added BLOOM_MAX_LENGTH = 280 constant and a length check in send_bloom() that returns {"success": false, "message": "Blooms must be 280 characters or fewer"} with HTTP 400 when exceeded. Pattern follows the existing MINIMUM_PASSWORD_LENGTH guard in register().
  • populate.py: truncated AS's essay to a sentence boundary (246 chars) so the seed script doesn't fail after validation is added.
  • Tests: backend/endpoints_test.py uses stdlib urllib (no extra deps) and hits the real running backend. Three cases: 280-char bloom accepted (200), 281-char bloom rejected (400), rejected response body contains "280". Run with python3 -m unittest endpoints_test from backend/.

Questions

  • The database column has no character limit set — should a VARCHAR(280) constraint be added to the schema as a second line of defence, or is the application-level check sufficient?

🙌 Notes for Reviewers

  • Upstream issue: Purple Forest: Bug Report: Extra long blooms? CodeYourFuture/Module-Legacy-Code#4
  • To verify locally: docker compose up -d, then curl -X POST http://localhost:3000/bloom -H "Authorization: Bearer <token>" -H "Content-Type: application/json" -d '{"content":"'"$(python3 -c "print('a'*281)")"'"}' — should return 400.
  • The existing database still contains AS's 375-char bloom from before the fix; a docker compose down -v && docker compose up -d followed by docker compose exec backend python populate.py will reseed with the corrected data.

The profile view wired the login handler to a click on a non-existent
[data-action="proxy.php?url=https%3A%2F%2Fgithub.com%2Fjapostadan%2FModule-Legacy-Code%2Fpull%2Flogin"] element, so the login form rendered on a profile
page had no submit handler. Submitting it triggered a native form POST
to the static file server (501 on python http.server, 405 on nginx)
instead of authenticating.

- Wire the profile-page login form to its submit event, matching the
  home login view (lib uses handleLogin which preventDefaults).
- Add a Playwright regression test: login -> view profile -> logout ->
  log back in from the profile page.
hashtagView called getBloomsByHashtag() without awaiting it. When the
fetch resolved, state.updateState() dispatched a state-change event,
which triggered handleRouteChange() → hashtagView() again → another
fetch → infinite loop. destroy() on every iteration caused the visible
blank flash.

- Guard the fetch on state.currentHashtag so we only fetch when the
  hashtag actually changes; re-renders triggered by unrelated state-change
  events skip the fetch and just re-render from existing state.
- Add Playwright regression tests: verifies exactly one fetch per
  navigation and that heading + blooms are visible and stable.
The frontend already enforces maxlength="280" on the textarea, but the
POST /bloom endpoint had no server-side validation, so any client (curl,
populate.py, etc.) could submit blooms of arbitrary length. AS's seeded
bloom was 375 characters as a result.

- Add BLOOM_MAX_LENGTH = 280 constant and reject content over the limit
  with a 400 and a descriptive error message, matching the pattern used
  for MINIMUM_PASSWORD_LENGTH in register().
- Trim AS's seeded bloom in populate.py to 246 chars so it stays valid.
- Add backend/endpoints_test.py: three tests against the live backend —
  exactly-280 accepted, 281 rejected, error body contains "280".
@japostadan japostadan self-assigned this Jun 16, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant