Skip to content

fix(connections): apply the block filter to GET and paginate the list - #388

Merged
singh-odyssey merged 1 commit into
TravellersMeet:mainfrom
MOHITKOURAV01:fix/383-connections-block-filter
Aug 19, 2026
Merged

fix(connections): apply the block filter to GET and paginate the list#388
singh-odyssey merged 1 commit into
TravellersMeet:mainfrom
MOHITKOURAV01:fix/383-connections-block-filter

Conversation

@MOHITKOURAV01

Copy link
Copy Markdown
Contributor

Closes #383

The problem

Blocking is only half-applied on this endpoint. POST does the right thing — isBlockedBetween() guards both send and accept. GET never consulted src/lib/blocking.ts at all.

So after A blocks B:

  • GET /api/conversations correctly drops the thread
  • GET /api/connections still returns B under connections, with name, photo, bio and location
  • a pending request from B still sits in A's incoming list, and accepting it 403s — which just looks broken
  • B still sees A in their list too, because blocking is symmetric here

The sidebar hides the person while the connections page keeps rendering them, which defeats the point of the feature and is confusing on both sides.

The same handler also ran three unbounded findMany calls serially, each with included user records, on every dashboard load.

What this changes

Block filter. getBlockedUserIds() resolved once, applied to all three lists. For the accepted list the filter has to sit inside each OR branch, because the counterpart is the receiver when the caller sent the request and the sender when they received it:

OR: [
  { senderId: userId,   receiverId: { notIn: blockedUserIds } },
  { receiverId: userId, senderId:   { notIn: blockedUserIds } },
]

Concurrency. The three queries don't depend on each other, so they run in one Promise.all instead of each await blocking the next.

Bounds. The two pending lists cap at 100. The accepted list is cursor-paginated with the shared src/lib/pagination.ts helpers.

Stable ordering. orderBy: { updatedAt: "desc" } alone is not a stable sort — two rows accepted in the same transaction can swap places between requests, which would make the new cursor skip or repeat a row. Adds an id tiebreaker, matching what /api/messages and /api/routes do.

Backwards compatibility

incoming, outgoing and connections keep their shapes and their keys, so ChatInterface and DashboardMatches need no changes. pagination is additive — a follow-up can wire a "load more" onto it.

Tests

The existing file was for GET (2 cases) and POST (4 cases). The POST cases are unchanged; the two GET cases now pass a real NextRequest, since the handler reads searchParams. 14 new GET cases on top.

Worth noting: the block tests drive prisma.block.findMany rather than stubbing getBlockedUserIds, so the real symmetry logic stays under test — blockedWith() alternates the direction of each Block row on purpose.

The concurrency test holds the first query's promise open and asserts all three have started, which fails against the serial version.

Verification

  • npx vitest run src/app/api/connections — 20 passed (4 pre-existing POST cases + 16)
  • Full suite unchanged from main's baseline: 9 failing files / 23 failing tests before and after
  • npx tsc --noEmit reports nothing new for this path

Note on the base branch

main does not currently typecheck (#366, fixed by #379). Nothing here touches those files.

@github-actions

Copy link
Copy Markdown

Thanks for opening this PR, @MOHITKOURAV01! 👋

Our maintainers will review it shortly. Estimate Time is 5-8 hrs .Meanwhile please:

  • Ensure CI is green (lint, typecheck, build).
  • Hit the star ⭐ button to show your support!
  • Confirm the PR template checklist is complete.
  • Add screenshots for UI changes.

If anything changes, feel free to push updates—this thread will stay open.

Blocking is only half-applied on this endpoint. POST guards `send` and
`accept` with isBlockedBetween(), but GET never consulted src/lib/blocking.ts
at all, so after a block:

- the blocked user stayed in the caller's connections list with their name,
  photo, bio and location
- a pending request from someone the caller blocked still sat in their
  incoming list, and accepting it 403s, which just looks broken
- the person who blocked the caller was still listed too, since blocking is
  symmetric here

The sidebar hid the thread (/api/conversations already filters with
getBlockedUserIds) while the connections page kept rendering the person.
Same helper, resolved once, applied to all three lists. For the accepted
list the filter has to sit inside each OR branch, because the counterpart is
the receiver when the caller sent the request and the sender when they
received it.

The handler also ran three unbounded findMany calls serially, each with
included user records, even though none depends on the others. They now run
in one Promise.all, the two pending lists are bounded at 100, and the
accepted list is cursor-paginated with the shared src/lib/pagination.ts
helpers. Its ordering gains an id tiebreaker — `updatedAt` alone is not
stable, so two rows accepted in the same transaction could swap places
between requests and make the cursor skip or repeat a row.

The incoming/outgoing/connections response keys are unchanged, so
ChatInterface and DashboardMatches keep working; `pagination` is additive.

Closes TravellersMeet#383
@MOHITKOURAV01
MOHITKOURAV01 force-pushed the fix/383-connections-block-filter branch from c67b172 to d9bada5 Compare August 10, 2026 14:48
@MOHITKOURAV01

Copy link
Copy Markdown
Contributor Author

On the red build-and-lint

The failure is inherited from main, not introduced here. The typecheck step reports 23 errors, all in files this PR does not touch:

Same 23 errors on main at 39e71eb, and the same failure on #376, #377 and #367. npx tsc --noEmit on this branch adds nothing beyond that set.

Test suite on this branch: no regressions against the main baseline of 9 failing files / 23 failing tests.

CI should go green here once #379 and #378 land — no rebase needed, this branch merges cleanly with both.

@singh-odyssey
singh-odyssey merged commit 3b8d7d0 into TravellersMeet:main Aug 19, 2026
1 check failed
@singh-odyssey singh-odyssey added ECSoC26 Elite coders summer of code good-pr elite coders labels Aug 19, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

ECSoC26-L3 ECSoC26 Elite coders summer of code good-pr elite coders

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Bug] GET /api/connections still lists blocked users and runs three unbounded queries

2 participants