Skip to content

refactor(llc)!: route user blocking through the generated client - #3050

Draft
VelikovPetar wants to merge 7 commits into
refactor/flu-935_unread_counts_openapi_migrationfrom
refactor/flu-937_user_blocking_openapi_migration
Draft

VelikovPetar wants to merge 7 commits into
refactor/flu-935_unread_counts_openapi_migrationfrom
refactor/flu-937_user_blocking_openapi_migration

Conversation

@VelikovPetar

@VelikovPetar VelikovPetar commented Oct 7, 2026 •

Copy link
Copy Markdown
Contributor

Submit a pull request

Linear: FLU-937
Github Issue: -

CLA

  • I have signed the Stream CLA (required).
  • The code changes follow best practices
  • Code changes are tested (add some information if not applicable)

Description of the pull request

Moves blocking and unblocking a user, and listing the blocked users, onto the OpenAPI-generated client, as new plan group 19 (User Blocking), split out of group 09 (Users). Stacked on #3049 (group 18).

  • blockUser returns Result<BlockUsersResponse>, unblockUser Result<UnblockUsersResponse>, and queryBlockedUsers is renamed getBlockedUsers and returns Result<GetBlockedUsersResponse> — none of them throw any more. On success they still update the current user's blockedUserIds (via result.onSuccess); a failure leaves it unchanged and is still logged (via result.onFailure).
  • The three envelopes live in models/response/ as freezed classes with a non-null duration.
  • UserBlock becomes a freezed plain model without fromJson/toJson, and its blockedUser, userId, blockedUserId and createdAt are now required and non-null.
  • UsersRepository gains the three calls; the mappers go in the existing user_mapper.dart.
  • StreamChatApi.user.blockUser, unblockUser and queryBlockedUsers, UserBlockResponse and BlockedUsersResponse are removed.
Generated Public
DefaultApi.blockUsers (POST /api/v2/users/block) StreamChatClient.blockUser (kept)
DefaultApi.unblockUsers (POST /api/v2/users/unblock) StreamChatClient.unblockUser (kept)
DefaultApi.getBlockedUsers (GET /api/v2/users/block) StreamChatClient.getBlockedUsers (was queryBlockedUsers)
BlockUsersResponse BlockUsersResponse (was UserBlockResponse)
UnblockUsersResponse UnblockUsersResponse (new; was EmptyResponse)
GetBlockedUsersResponse GetBlockedUsersResponse (was BlockedUsersResponse)
BlockedUserResponse UserBlock (kept)
— UsersRepository (internal)

Why

The migration moves every endpoint onto the generated client, which returns a Result for every call. Blocking and unblocking are a pair and the list refreshes the same state, so they move together. They need none of group 09's User restructuring: they embed User only through the existing mappers, and nothing persists them.

Notes for reviewers

Important

Singular methods, plural envelopes — please weigh in. blockUser and unblockUser (one user id each) return BlockUsersResponse and UnblockUsersResponse, the spec's plural names. The backend controllers are already BlockUsers/UnblockUsers, and if the API later blocks several users in one call on the same operation, these envelopes can gain a field (e.g. blocks) additively and a new blockUsers(List<String>) can return the same type — no rename, no break. Singular envelope names (BlockUserResponse, the first iteration of this PR) would have forced either a breaking rename or two near-identical public types. The trade-off: today a single-user call answers a plural-named type.

Other decision points:

  • Method names. blockUser/unblockUser keep their names rather than the spec's plural blockUsers/unblockUsers, since each takes one user id; a batch method would be added beside them. queryBlockedUsers takes the spec's getBlockedUsers, since the call has no filter, sort or pagination. Hard renames, no deprecated aliases.
  • unblockUser gets an envelope rather than Result<void>: the generated response is a named UnblockUsersResponse, not DurationResponse, so a field the server adds later stays additive.
  • UserBlock is tightened to non-null. An extra break beyond the plan's rule that nullability follows v10; the server always sends every field (an unresolvable user arrives as a deleted-user placeholder), so callers no longer handle nulls that never arrive.

Backend:

  • Same handlers. lib/chat/routes.go mounts one userBlockRoutes table (v1.BlockUsers, v1.UnblockUsers, v1.GetBlockedUsers) both at the root and under /api/v2/; only the JSON encoding differs. None is feature-flagged, in beta or deprecated.
  • v2 sends created_at as epoch nanoseconds rather than RFC 3339; the generated converter handles both.
  • The stream_chat_flutter and sample-app callers compile unchanged; they never awaited the result, so a failure stays silently ignored, as before.

Testing

  • melos run analyze clean across all packages, sample_app included; stream_chat suite green, flutter_core and persistence green; generate_plan.py --check reports 0 problems.
  • copywith_audit.py UserBlock (from refactor(llc)!: route polls through the generated client #3037) on the pre-migration tree: no call site in lib or tests changes behaviour or stops compiling. UserBlock.copyWith now takes non-nullable values, recorded in the CHANGELOG and the guide.
  • New client_block_user_test.dart, client_unblock_user_test.dart, client_get_blocked_users_test.dart: the full envelope against a fully populated generated response and the exact request sent, the blockedUserIds update (add without duplicates, remove, replace), the failure without throwing, and the ids left unchanged on failure.
  • Live v1 vs v2 parity on the demo app: blocked and unblocked a user that shares no channel with the blocker through each surface; both list the same blocks, the block list ends where it started, and the real v2 bodies decode through the generated models and mappers with the same instants as v1.

Screenshots / Videos

Not applicable: no visible UI change.

🤖 Generated with Claude Code

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@coderabbitai

coderabbitai Bot commented Oct 7, 2026 •

Copy link
Copy Markdown
Contributor

Important

Draft PR not reviewed

Draft PRs are not automatically reviewed by default.

  • Trigger a manual review

To automatically review draft PRs, update your CodeRabbit configuration:

reviews:
  auto_review:
    drafts: true
  • Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

…onses

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
VelikovPetar and others added 5 commits October 9, 2026 14:27
…refactor/flu-937_user_blocking_openapi_migration
…refactor/flu-937_user_blocking_openapi_migration
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…refactor/flu-937_user_blocking_openapi_migration

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

This branch has not been deployed

No deployments
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