Skip to content

feat: 用户信息接口支持关系查询#233

Open
ntgmc wants to merge 3 commits into
ZOOT-Plus:devfrom
ntgmc:dev
Open

feat: 用户信息接口支持关系查询#233
ntgmc wants to merge 3 commits into
ZOOT-Plus:devfrom
ntgmc:dev

Conversation

@ntgmc
Copy link
Copy Markdown

@ntgmc ntgmc commented May 30, 2026

新增文件:

  • RelationType.kt — 枚举:SELF / NONE / FOLLOWING / FOLLOWED_BY / MUTUAL

新增接口:

  • GET /user/me — 获取当前登录用户信息
  • GET /user/batch — 批量获取用户信息(带关系)

增强接口:

  • GET /user/info — 新增 relation 字段
  • GET /follow/followingList — 新增 relation + followedAt
  • GET /follow/fansList — 新增 relation + followedAt

新增 Repository 方法:

  • getFollowCreatedAtMap / getFansCreatedAtMap / isFollowing / getFollowedTargetIds / getFollowerTargetIds

Summary by Sourcery

添加具备关系感知能力的用户信息获取 API,并在关注列表中丰富关系元数据。

新增功能:

  • 暴露 GET /user/me,用于获取当前已登录用户的信息。
  • 暴露 GET /user/batch,用于获取多个用户的信息,并可选地附带这些用户与当前用户的关系数据。

改进:

  • 扩展 MaaUserInfo,增加关系类型和关注时间戳字段,以提供更丰富的社交图谱上下文。
  • 更新 GET /user/info,在可用时返回请求用户与当前用户之间的关系信息。
  • 基于新的批量关注关系查询,为关注列表和粉丝列表响应增加关系状态和关注时间戳。
  • 新增仓储方法,用于高效计算用户之间的关注/粉丝关系及对应时间戳。
  • 在注册和资料更新流程中通过限制用户名最大长度来收紧用户名校验规则。
Original summary in English

Summary by Sourcery

Add relationship-aware user info retrieval APIs and enrich follow lists with relation metadata.

New Features:

  • Expose GET /user/me to fetch the current logged-in user info.
  • Expose GET /user/batch to fetch multiple users with optional relationship data to the current user.

Enhancements:

  • Extend MaaUserInfo with relation type and followed-at timestamp fields for richer social graph context.
  • Update GET /user/info to include the relationship between the requested user and the current user when available.
  • Enrich following and fans list responses with relation status and follow timestamp based on new bulk follow lookups.
  • Add repository methods to efficiently compute follow/fan relationships and timestamps between users.
  • Tighten username validation by enforcing a maximum length in registration and profile update flows.

Copy link
Copy Markdown

@sourcery-ai sourcery-ai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hey - 我发现了 3 个问题,并给出了一些整体性反馈:

  • UserController.getBatchUserInfo 中,请求参数 size 除了默认值以外从未被使用;建议要么删除它,要么真正使用它(例如限制 ids.size 或用于分页),以避免产生困惑和无效参数。
  • 用户名长度校验在 registerupdateUserInfo 中都被拆成了最小值和最大值两次独立检查;你可以把这些逻辑合并成单次区间校验,从而让逻辑和错误处理更简单、也更不易出错。
  • UserService 中的 resolveRelation 方法看起来只在内部使用;把它改为 private(或者至少非 public)可以缩小公共 API 面,并更清晰地表达它的预期用途。
Prompt for AI Agents
Please address the comments from this code review:

## Overall Comments
- In `UserController.getBatchUserInfo`, the `size` request parameter is never used except for its default value; consider either removing it or actually applying it (e.g., to limit `ids.size` or pagination) to avoid confusion and dead parameters.
- The username length validation is duplicated as two separate checks for min and max in both `register` and `updateUserInfo`; you could consolidate these into a single range check to keep the logic and error handling simpler and less error-prone.
- The `resolveRelation` method in `UserService` appears to be used only internally; making it `private` (or at least non-public) would reduce the public API surface and clarify its intended usage.

## Individual Comments

### Comment 1
<location path="src/main/kotlin/plus/maa/backend/controller/UserController.kt" line_range="189-191" />
<code_context>
+    @GetMapping("/batch")
+    @Operation(summary = "批量获取用户信息")
+    @ApiResponse(description = "用户信息列表")
+    fun getBatchUserInfo(
+        @RequestParam ids: List<Long>,
+        @Max(50, message = "单次查询用户量不能超过50") @RequestParam(defaultValue = "50") size: Int,
+    ): MaaResult<List<MaaUserInfo>> {
+        if (ids.size > 50) {
</code_context>
<issue_to_address>
**issue:** The `size` request parameter is unused and the validation annotation likely belongs on `ids` instead.

`size` is annotated with `@Max(50)` but never referenced; the actual limit comes from `ids.size > 50`, which makes the annotation misleading. Either remove `size` or make it drive the behavior (e.g., pagination or max IDs). If the intent is to cap the number of IDs, consider a collection-level constraint such as `@Size(max = 50)` on `ids` instead.
</issue_to_address>

### Comment 2
<location path="src/main/kotlin/plus/maa/backend/service/UserService.kt" line_range="309-318" />
<code_context>
+    /**
+     * 批量获取用户信息(可选附带关系)
+     */
+    fun getBatchUserInfos(ids: List<Long>, currentUserId: Long?): List<MaaUserInfo> {
+        if (ids.isEmpty()) return emptyList()
+        val users = userKtormRepository.findAllById(ids)
+        if (currentUserId == null) {
+            return users.map { MaaUserInfo(it) }
+        }
+        // 当前用户关注了哪些目标
+        val iFollowIds = userKtormRepository.getFollowedTargetIds(currentUserId, ids)
+        // 哪些目标关注了当前用户
+        val theyFollowMeIds = userKtormRepository.getFollowerTargetIds(ids, currentUserId)
+        return users.map { user ->
+            val uid = user.userId
+            val iFollow = uid in iFollowIds
</code_context>
<issue_to_address>
**suggestion (bug_risk):** Result order may not match the input `ids` order, which can surprise API consumers.

This relies on `userKtormRepository.findAllById(ids)` preserving the order of `ids`, which many repository implementations do not guarantee. If the API contract implies order should match the input, you may want to build a map keyed by `userId` and then produce the result list by iterating over `ids` to enforce that ordering.
</issue_to_address>

### Comment 3
<location path="src/main/kotlin/plus/maa/backend/repository/ktorm/UserKtormRepository.kt" line_range="171-176" />
<code_context>
+    /**
+     * 查询 userId 关注了 targetIds 中的哪些用户,返回 followUserId -> updatedAt 的映射
+     */
+    fun getFollowCreatedAtMap(userId: Long, targetIds: List<Long>): Map<Long, LocalDateTime> {
+        if (targetIds.isEmpty()) return emptyMap()
+        return database.from(UserFollows)
+            .select(UserFollows.followUserId, UserFollows.updatedAt)
+            .where { (UserFollows.userId eq userId) and (UserFollows.followUserId inList targetIds) }
+            .map { row -> row[UserFollows.followUserId]!! to row[UserFollows.updatedAt]!! }
+            .toMap()
+    }
</code_context>
<issue_to_address>
**issue (bug_risk):** Method name/docs suggest "created" time, but the implementation returns `updatedAt`.

The method name and KDoc describe follow creation time, but the query uses `UserFollows.updatedAt`. If `updatedAt` can change (e.g., on later updates), the exposed `followedAt` semantics will be wrong. Please either use the actual creation timestamp column (if one exists) or rename the method/docs to clarify that `updatedAt` is being returned.
</issue_to_address>

Sourcery is free for open source - if you like our reviews please consider sharing them ✨
Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.
Original comment in English

Hey - I've found 3 issues, and left some high level feedback:

  • In UserController.getBatchUserInfo, the size request parameter is never used except for its default value; consider either removing it or actually applying it (e.g., to limit ids.size or pagination) to avoid confusion and dead parameters.
  • The username length validation is duplicated as two separate checks for min and max in both register and updateUserInfo; you could consolidate these into a single range check to keep the logic and error handling simpler and less error-prone.
  • The resolveRelation method in UserService appears to be used only internally; making it private (or at least non-public) would reduce the public API surface and clarify its intended usage.
Prompt for AI Agents
Please address the comments from this code review:

## Overall Comments
- In `UserController.getBatchUserInfo`, the `size` request parameter is never used except for its default value; consider either removing it or actually applying it (e.g., to limit `ids.size` or pagination) to avoid confusion and dead parameters.
- The username length validation is duplicated as two separate checks for min and max in both `register` and `updateUserInfo`; you could consolidate these into a single range check to keep the logic and error handling simpler and less error-prone.
- The `resolveRelation` method in `UserService` appears to be used only internally; making it `private` (or at least non-public) would reduce the public API surface and clarify its intended usage.

## Individual Comments

### Comment 1
<location path="src/main/kotlin/plus/maa/backend/controller/UserController.kt" line_range="189-191" />
<code_context>
+    @GetMapping("/batch")
+    @Operation(summary = "批量获取用户信息")
+    @ApiResponse(description = "用户信息列表")
+    fun getBatchUserInfo(
+        @RequestParam ids: List<Long>,
+        @Max(50, message = "单次查询用户量不能超过50") @RequestParam(defaultValue = "50") size: Int,
+    ): MaaResult<List<MaaUserInfo>> {
+        if (ids.size > 50) {
</code_context>
<issue_to_address>
**issue:** The `size` request parameter is unused and the validation annotation likely belongs on `ids` instead.

`size` is annotated with `@Max(50)` but never referenced; the actual limit comes from `ids.size > 50`, which makes the annotation misleading. Either remove `size` or make it drive the behavior (e.g., pagination or max IDs). If the intent is to cap the number of IDs, consider a collection-level constraint such as `@Size(max = 50)` on `ids` instead.
</issue_to_address>

### Comment 2
<location path="src/main/kotlin/plus/maa/backend/service/UserService.kt" line_range="309-318" />
<code_context>
+    /**
+     * 批量获取用户信息(可选附带关系)
+     */
+    fun getBatchUserInfos(ids: List<Long>, currentUserId: Long?): List<MaaUserInfo> {
+        if (ids.isEmpty()) return emptyList()
+        val users = userKtormRepository.findAllById(ids)
+        if (currentUserId == null) {
+            return users.map { MaaUserInfo(it) }
+        }
+        // 当前用户关注了哪些目标
+        val iFollowIds = userKtormRepository.getFollowedTargetIds(currentUserId, ids)
+        // 哪些目标关注了当前用户
+        val theyFollowMeIds = userKtormRepository.getFollowerTargetIds(ids, currentUserId)
+        return users.map { user ->
+            val uid = user.userId
+            val iFollow = uid in iFollowIds
</code_context>
<issue_to_address>
**suggestion (bug_risk):** Result order may not match the input `ids` order, which can surprise API consumers.

This relies on `userKtormRepository.findAllById(ids)` preserving the order of `ids`, which many repository implementations do not guarantee. If the API contract implies order should match the input, you may want to build a map keyed by `userId` and then produce the result list by iterating over `ids` to enforce that ordering.
</issue_to_address>

### Comment 3
<location path="src/main/kotlin/plus/maa/backend/repository/ktorm/UserKtormRepository.kt" line_range="171-176" />
<code_context>
+    /**
+     * 查询 userId 关注了 targetIds 中的哪些用户,返回 followUserId -> updatedAt 的映射
+     */
+    fun getFollowCreatedAtMap(userId: Long, targetIds: List<Long>): Map<Long, LocalDateTime> {
+        if (targetIds.isEmpty()) return emptyMap()
+        return database.from(UserFollows)
+            .select(UserFollows.followUserId, UserFollows.updatedAt)
+            .where { (UserFollows.userId eq userId) and (UserFollows.followUserId inList targetIds) }
+            .map { row -> row[UserFollows.followUserId]!! to row[UserFollows.updatedAt]!! }
+            .toMap()
+    }
</code_context>
<issue_to_address>
**issue (bug_risk):** Method name/docs suggest "created" time, but the implementation returns `updatedAt`.

The method name and KDoc describe follow creation time, but the query uses `UserFollows.updatedAt`. If `updatedAt` can change (e.g., on later updates), the exposed `followedAt` semantics will be wrong. Please either use the actual creation timestamp column (if one exists) or rename the method/docs to clarify that `updatedAt` is being returned.
</issue_to_address>

Sourcery is free for open source - if you like our reviews please consider sharing them ✨
Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.

Comment thread src/main/kotlin/plus/maa/backend/controller/UserController.kt Outdated
Comment thread src/main/kotlin/plus/maa/backend/service/UserService.kt
Comment thread src/main/kotlin/plus/maa/backend/repository/ktorm/UserKtormRepository.kt Outdated
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