Repository navigation
Add POST and GET /internal/listener-requests (BS#2662) - #3729
Open
jakebromberg wants to merge 1 commit into
Open
jakebromberg wants to merge 1 commit into
jakebromberg wants to merge 1 commit into
Conversation
…S#2662) request-o-matic creates the listener_requests row before posting to Slack and reads replyable off the response (anonymous_user_id IS NOT NULL, this service's verdict). GET returns the pre-filtered, newest-first list behind /reply, hard-capped at 20, with the on-air window read from the stored expires_at. Adds LISTENER_REPLY_WINDOW_MINUTES (default 30).
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.
Closes #2662
Adds
POSTandGET /internal/listener-requestsas a sibling router under/internal, with theX-Internal-Key/ROM_INTERNAL_KEYgate, per-IP limiter, UUID regex and length caps copied frominternal-bans.route.ts. AddsLISTENER_REPLY_WINDOW_MINUTES(default 30) and itsdocs/env-vars.mdentry. The route ships dark: nothing calls it until request-o-matic's client lands behind its own flag, so no merge here needs an ops step.POSTcreates the row and returns{ id, expires_at, replyable }with 201.replyableisanonymous_user_id !== null, this service's verdict. SQLSTATE23503onanonymous_user_idmaps to 400.GETreturns{ items }, newest first, hard-capped at 20 with no limit parameter. Both audiences scope toslack_channel_id, requireanonymous_user_id IS NOT NULL, and exclude requests with an active reply (retracted_at IS NULL).on_airfilters onexpires_at > now()andstatus = 'posted';moderatoroncreated_at > now() - interval '24 hours'andstatus in ('posted','hidden').LISTENER_REPLY_WINDOW_MINUTESis read per request throughrequirePositiveInt, so a bad value fails that POST with a 500 and no write rather than stopping the API at boot. It is not inset-ec2-env-var.yml,dev_env/docker-compose.ymlortest.yml.Acceptance criteria and how each is tested
Unit tests in
tests/unit/routes/internal-listener-requests.route.test.ts(29 cases), written first and seen failing with module-not-found before the route existed:slack_channel_id, non-string/empty/over-255anonymous_user_id(one parameterized table, each asserting the error names the field and no insert happened).replyablefalse (omitted andnull) and true; response keys are exactlyexpires_at,id,replyable.expires_atis stamped fromLISTENER_REPLY_WINDOW_MINUTES(default 30, and an override of 5); an invalid value gives 500 with no insert.23503, both drizzle-wrapped and bare; 500 on other DB errors.slack_channel_id, absentreplyable_for, andreplyable_for=nobody; 200{ items }for both audiences;limit(20)even when?limit=500is passed; 500 on DB error.internalListenerRequestsRoutelines inapp.ts, nocreated_at-derived window, zero hits for the env var inset-ec2-env-var.yml, zero hits for the path inapp.yaml.Mutation check: reverting each of the cap, the
replyableexpression, the23503arm, the default window, the env read, thereplyable_forvalidation and the key gate made at least one test fail.Not pinned by a unit test: the GET
WHEREpredicates themselves (channel scope,anonymous_user_id IS NOT NULL, no active reply, the per-audience window and status filters). The unit suite's@wxyc/databasedouble stores columns as strings, so an assertion on them would compare the mock to itself. I rendered the real query against the real schema with drizzle'stoSQL()and checked the SQL by eye, but it has not run against a live Postgres, and I did not add an integration spec.Local checks:
npm run test:unit(760 suites, all passing),typecheck,format:check,lint:migrations,check:db-mock-sync, and eslint on the touched files (0 errors). The fullnpm run lintwas not run. No migration is added.Mirrors: none found. The route is deliberately not in
wxyc-shared/api.yamlorapps/backend/app.yaml, matching the two existing internal routers.