rh: add REST endpoint that triggers DHCR form submission [sc-14556]#2510
Draft
aidencullo wants to merge 9 commits into
Draft
rh: add REST endpoint that triggers DHCR form submission [sc-14556]#2510aidencullo wants to merge 9 commits into
aidencullo wants to merge 9 commits into
Conversation
Adds /rh/submit and /rh/send-email POST endpoints so the website and TextIt flow can post rent history requests over HTTP, alongside the existing GraphQL mutations. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
views.py:
- submit() now copies phone_number, address, borough, zipcode, and
address_verified from RhForm.cleaned_data onto the model. RhForm
only listed first_name/last_name/apartment_number in Meta.fields,
so ModelForm.save() was silently dropping the rest.
- 404 -> 400 for "id not found" in send-email to dodge Django's
LocaleMiddleware redirect-on-404 turning the response into a 302.
dhcr_portal_submit.py (new):
- Stub Playwright submission to portal.hcr.ny.gov/app/ask, the HCR
public inquiry portal.
- DRY-RUN BY DEFAULT (DHCR_PORTAL_DRY_RUN=1). Fills the form but
does not click Submit. Flip to "0" for live submission once HCR
has confirmed third-party programmatic access.
- Returns a structured SubmissionResult so callers can record
success/error on the row.
Notes for review:
- Selectors are best-guess against a Power Pages portal; verify
against live DOM before flipping DRY_RUN.
- Not yet wired into any view. Caller integration deferred until
we add a submission-status column on RentalHistoryRequest.
- Adds a runtime dependency on playwright (not yet in Pipfile).
`pipenv run python manage.py test_dhcr_portal_empty` drives the portal.hcr.ny.gov/app/ask form in headless Chromium, clicks SUBMIT without filling any fields, and prints the server-side validation banner that comes back. Confirms reachability + selector hygiene without ever creating a real DHCR record. Requires playwright + chromium in the image; cleanly errors with a guidance message when missing so it doesn't break existing runs.
sc-14556 is a single endpoint to trigger DHCR form submission. The parallel send-email REST endpoint duplicates the existing GraphQL RhSendEmail mutation and isn't part of the new portal path. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
After a successful portal submission, HCR's success page shows "Use this reference number for follow up: #YYMMDD-NNNNNN." SubmissionResult now exposes that as `reference_number` so the caller can persist it on the RentalHistoryRequest row. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
df20f9e to
e19ced7
Compare
Sequence: validate form -> save row -> trigger Playwright submission.
Portal call is dry-run by default (DHCR_PORTAL_DRY_RUN=1), so no
traffic to HCR until that flag is explicitly flipped. Response now
includes portal.{success, dry_run, reference_number, error} so the
caller can record the HCR reference.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
submit_via_portal() promised "never raises on portal failures" but pw.chromium.launch() sat before the try block, so a launch failure (e.g. missing Chromium binary) escaped the function and turned POST /rh/submit into a 500 -- after a row was already saved. Move launch/context/page setup inside the try and guard the finally so the failure is captured as portal.error and the endpoint returns 201. Add rh/tests/test_views.py covering the view (400 on missing field, 201 + saved row on valid input, portal called with the saved request) and the regression (launch failure returns a SubmissionResult, never raises) plus reference-number extraction. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Collaborator
Author
|
stale |
Collaborator
Author
|
Update since the original summary: The PR now wires Also added:
Still not included:
Important local behavior: |
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.
Shortcut: sc-14556
Summary
POST /rh/submit— validatesRhForm, creates aRentalHistoryRequest, returns the row id.path("rh/", include("rh.urls"))intoproject/urls.py.ModelForm.save()was silently dropping (phone, address, borough, zipcode, address_verified) becauseRhForm.Meta.fieldsonly declares three.rh/dhcr_portal_submit.py) for the eventual DHCR portal channel referenced in sc-14556. Dry-run by default (DHCR_PORTAL_DRY_RUN=1); no live submission happens without HCR sign-off.#YYMMDD-NNNNNN) from the post-submit success page and returns it onSubmissionResult.reference_numberfor the caller to persist.manage.py test_dhcr_portal_emptysmoke command that opens portal.hcr.ny.gov/app/ask, clicks Submit on an empty form, and prints the server-side validation banner — confirms reachability without creating a record.How it works at a high level
/rh/submit→ Django saves aRentalHistoryRequestrow, returns its id.portal.hcr.ny.gov/app/ask, clicks Submit, scrapes the reference number off the success page.The end-to-end Playwright pipeline (fill → submit → success-banner wait → body scrape → regex match
r"#(\\d{6}-\\d{6})") has been validated against a real HCR submission and successfully extracted a live reference.Test plan
curl -X POST :8000/rh/submitwith no body → 400 with{"errors": {...}}.curl -X POST :8000/rh/submit -H 'Content-Type: application/json' -d '{...full form...}'→ 201 with{"id": <pk>}, row appears inrh_rentalhistoryrequestwith all fields persisted.pipenv run python manage.py test_dhcr_portal_emptyafter installing playwright + chromium → reports validation banner, no record created at HCR.Not in this PR
/rh/submit— the sibling REST endpoints (/gce/upload,/efnyc/upload,/mailchimp/subscribe) gate access withauthorize_with_token(...)+ a CORS allowlist./rh/submitshould follow that pattern before going public.playwrightis not added to Pipfile; the management command + portal submitter require an ad-hoc install. Production use needs Chromium baked into the Dockerfile.dhcr_reference_number/portal_submitted_atcolumns onRentalHistoryRequestyet — needed before wiringsubmit_via_portalinto the/rh/submitview so the reference can be persisted.DHCR_PORTAL_DRY_RUN=0must not be flipped until that's in writing.🤖 Generated with Claude Code