Skip to content

feat: allow users to delete their own comments#932

Merged
imaegoo merged 3 commits into
mainfrom
feat/user-delete-own-comment
May 6, 2026
Merged

feat: allow users to delete their own comments#932
imaegoo merged 3 commits into
mainfrom
feat/user-delete-own-comment

Conversation

@imaegoo

@imaegoo imaegoo commented May 6, 2026

Copy link
Copy Markdown
Member

Add a delete button to TkAction that is only visible when the current user owns the comment (determined by the server-side isOwner field in toCommentDto). The server validates ownership via uid comparison before allowing deletion. All 5 server backends (CloudBase, self-hosted LokiJS, self-hosted MongoDB, Vercel, EdgeOne Pages) are supported.

由 Sourcery 提供的摘要

允许终端用户删除自己的评论,在所有后端通过服务器端的所有权验证,并提供相应的 UI 控件。

新功能:

  • 在评论 UI 中添加用户主动发起的评论删除操作,仅对评论所有者可见。
  • 在所有受支持的服务器后端中暴露新的 COMMENT_DELETE_FOR_USER API/事件,用于处理自助评论删除。

增强:

  • 在评论 DTO 中包含 isOwner 标志,以指示当前用户是否拥有各条评论。
Original summary in English

Summary by Sourcery

Allow end users to delete their own comments with server-side ownership validation across all backends and corresponding UI controls.

New Features:

  • Add a user-initiated comment deletion action to the comment UI, visible only to the comment owner.
  • Expose a new COMMENT_DELETE_FOR_USER API/event on all supported server backends to handle self-service comment deletion.

Enhancements:

  • Include an isOwner flag in comment DTOs to indicate whether the current user owns each comment.

Add a delete button to TkAction that is only visible when the current
user owns the comment (determined by the server-side `isOwner` field in
toCommentDto). The server validates ownership via uid comparison before
allowing deletion. All 5 server backends (CloudBase, self-hosted LokiJS,
self-hosted MongoDB, Vercel, EdgeOne Pages) are supported.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
@sourcery-ai

sourcery-ai Bot commented May 6, 2026

Copy link
Copy Markdown
Contributor

审阅者指南(Reviewer's Guide)

通过新增 COMMENT_DELETE_FOR_USER API、在服务端强制进行 UID 校验,并且仅在评论 DTO 的 isOwner 为 true 时暴露删除操作,实现了用户本人拥有的评论删除能力,覆盖所有后端以及客户端 UI。

用户本人评论删除流程的时序图(Sequence diagram)

sequenceDiagram
  actor User
  participant TkComment
  participant TkAction
  participant ClientAPI
  participant Server
  participant DB

  User->>TkAction: click_delete_button
  TkAction->>TkComment: emit_delete
  TkComment->>User: show_confirm_dialog
  User-->>TkComment: confirm_deletion
  TkComment->>ClientAPI: call COMMENT_DELETE_FOR_USER(id)
  ClientAPI->>Server: event COMMENT_DELETE_FOR_USER with id and accessToken
  Server->>DB: find comment by id
  DB-->>Server: comment(uid)
  alt uid_matches
    Server->>DB: delete comment by id
    DB-->>Server: deleted_count
    Server-->>ClientAPI: code SUCCESS, deleted
    ClientAPI-->>TkComment: success_response
    TkComment->>TkComment: emit_load_to_refresh_comments
  else uid_does_not_match_or_not_found
    Server-->>ClientAPI: code FAIL, message
    ClientAPI-->>TkComment: error_response
    TkComment->>User: show_error_message
  end
Loading

TkAction、TkComment 和 CommentDto 的更新后类图(Class diagram)

classDiagram
  class TkAction {
    +Number likeCount
    +Number dislikeCount
    +Number repliesCount
    +Boolean showDislike
    +Boolean showDelete
    +onLike()
    +onDislike()
    +onReply()
    +onDelete()
  }

  class TkComment {
    +Object comment
    +Object config
    +String pid
    +onLike()
    +onDislike()
    +onReply(id)
    +onDelete()
    +onReplyReply(id)
  }

  class CommentDto {
    +String id
    +String pid
    +String uid
    +String ruser
    +Boolean top
    +Boolean isSpam
    +Boolean isOwner
    +Number created
    +Number updated
  }

  TkComment --> TkAction : uses
  CommentDto <.. TkComment : renders_comment_with_isOwner
  CommentDto : isOwner = uid_equals_current_user_uid
Loading

文件级变更(File-Level Changes)

Change Details Files
在所有服务端后端新增按用户维度的评论删除 API,在删除前校验评论归属。
  • 将新的 COMMENT_DELETE_FOR_USER 事件通过主请求处理器路由,与现有的管理员评论操作放在一起处理。
  • 实现 commentDeleteForUser 处理函数:校验输入的 id,通过访问令牌或辅助方法解析当前用户 UID,加载目标评论,如果未找到或评论不属于请求方则失败,若校验通过则删除评论。
  • 返回标准化响应对象,包括 RES_CODE、错误信息,以及在删除成功时标记删除数量的字段。
src/server/self-hosted/index.js
src/server/self-hosted/mongo.js
src/server/vercel/api/index.js
src/server/function/twikoo/index.js
src/server/eo-pages/node-functions/index.js
在评论 UI 中暴露删除操作,仅对评论所有者可见,并调用新的用户删除 API。
  • 扩展 TkAction 组件以渲染删除按钮(普通/实心垃圾桶图标),接收新的 showDelete prop,并在点击时发出 delete 事件。
  • 更新 TkComment:根据 comment.isOwner 传递 show-delete,处理 delete 事件时弹出用户确认框,调用 COMMENT_DELETE_FOR_USER,并在成功后重新加载评论。
  • 在服务端将 isOwner 加入评论 DTO,通过比较 comment.uid 与当前用户 uid,使客户端可以决定是否显示删除按钮。
src/client/view/components/TkAction.vue
src/client/view/components/TkComment.vue
src/server/function/twikoo/utils/index.js

可能关联的 Issue(Possibly linked issues)

  • #: Issue 要求用户能删自己评论,PR 在所有后端与前端完整实现该能力

Tips and commands

与 Sourcery 交互(Interacting with Sourcery)

  • 触发新的代码审查: 在 pull request 中评论 @sourcery-ai review
  • 继续讨论: 直接回复 Sourcery 的审查评论。
  • 从审查评论生成 GitHub issue: 在某条审查评论下回复,请求 Sourcery 从该评论创建 issue。你也可以直接回复 @sourcery-ai issue 来基于该评论创建 issue。
  • 生成 pull request 标题: 在 pull request 标题中任意位置写上 @sourcery-ai 即可随时生成标题。也可以在 pull request 中评论 @sourcery-ai title 来(重新)生成标题。
  • 生成 pull request 总结: 在 pull request 正文中任意位置写上 @sourcery-ai summary,即可在指定位置生成 PR 总结。也可以在 pull request 中评论 @sourcery-ai summary 来在任意时间(重新)生成总结。
  • 生成审阅者指南: 在 pull request 中评论 @sourcery-ai guide,即可在任意时间(重新)生成审阅者指南。
  • 一次性解决所有 Sourcery 评论: 在 pull request 中评论 @sourcery-ai resolve,将所有 Sourcery 评论标记为已解决。如果你已经处理完所有评论且不想再看到它们会很有用。
  • 忽略所有 Sourcery 审查: 在 pull request 中评论 @sourcery-ai dismiss,以忽略所有现有的 Sourcery 审查。尤其适用于你想从一次全新的审查开始——别忘了再评论 @sourcery-ai review 来触发新的审查!

自定义你的体验(Customizing Your Experience)

进入你的 dashboard 可以:

  • 启用或禁用审查功能,例如 Sourcery 生成的 PR 总结、审阅者指南等。
  • 修改审查语言。
  • 添加、删除或编辑自定义审查指令。
  • 调整其他审查相关设置。

获取帮助(Getting Help)

Original review guide in English

Reviewer's Guide

Implements user-owned comment deletion across all backends and the client UI by adding a COMMENT_DELETE_FOR_USER API, enforcing server-side UID checks, and exposing a delete action only when isOwner is true on the comment DTO.

Sequence diagram for user-owned comment deletion flow

sequenceDiagram
  actor User
  participant TkComment
  participant TkAction
  participant ClientAPI
  participant Server
  participant DB

  User->>TkAction: click_delete_button
  TkAction->>TkComment: emit_delete
  TkComment->>User: show_confirm_dialog
  User-->>TkComment: confirm_deletion
  TkComment->>ClientAPI: call COMMENT_DELETE_FOR_USER(id)
  ClientAPI->>Server: event COMMENT_DELETE_FOR_USER with id and accessToken
  Server->>DB: find comment by id
  DB-->>Server: comment(uid)
  alt uid_matches
    Server->>DB: delete comment by id
    DB-->>Server: deleted_count
    Server-->>ClientAPI: code SUCCESS, deleted
    ClientAPI-->>TkComment: success_response
    TkComment->>TkComment: emit_load_to_refresh_comments
  else uid_does_not_match_or_not_found
    Server-->>ClientAPI: code FAIL, message
    ClientAPI-->>TkComment: error_response
    TkComment->>User: show_error_message
  end
Loading

Updated class diagram for TkAction, TkComment, and CommentDto

classDiagram
  class TkAction {
    +Number likeCount
    +Number dislikeCount
    +Number repliesCount
    +Boolean showDislike
    +Boolean showDelete
    +onLike()
    +onDislike()
    +onReply()
    +onDelete()
  }

  class TkComment {
    +Object comment
    +Object config
    +String pid
    +onLike()
    +onDislike()
    +onReply(id)
    +onDelete()
    +onReplyReply(id)
  }

  class CommentDto {
    +String id
    +String pid
    +String uid
    +String ruser
    +Boolean top
    +Boolean isSpam
    +Boolean isOwner
    +Number created
    +Number updated
  }

  TkComment --> TkAction : uses
  CommentDto <.. TkComment : renders_comment_with_isOwner
  CommentDto : isOwner = uid_equals_current_user_uid
Loading

File-Level Changes

Change Details Files
Add a per-user comment deletion API on all server backends that validates ownership before deleting.
  • Route new COMMENT_DELETE_FOR_USER event through the main request handler alongside existing admin comment actions.
  • Implement commentDeleteForUser handlers that validate the input id, resolve the current user UID (via access token or helper), load the target comment, fail if not found or not owned by the requester, and delete the comment on success.
  • Return a standardized response object with RES_CODE, error messages, and a deleted count flag for successful deletions.
src/server/self-hosted/index.js
src/server/self-hosted/mongo.js
src/server/vercel/api/index.js
src/server/function/twikoo/index.js
src/server/eo-pages/node-functions/index.js
Expose a delete action in the comment UI that is visible only to comment owners and calls the new user delete API.
  • Extend TkAction component to render a delete button with regular/solid trash icons, accept a new showDelete prop, and emit a delete event on click.
  • Update TkComment to pass show-delete based on comment.isOwner, handle the delete event by confirming with the user, calling COMMENT_DELETE_FOR_USER, and reloading comments on success.
  • Add isOwner to the comment DTO on the server by comparing comment.uid with the current user uid so the client can determine delete visibility.
src/client/view/components/TkAction.vue
src/client/view/components/TkComment.vue
src/server/function/twikoo/utils/index.js

Possibly linked issues

  • #: Issue 要求用户能删自己评论,PR 在所有后端与前端完整实现该能力

Tips and commands

Interacting with Sourcery

  • Trigger a new review: Comment @sourcery-ai review on the pull request.
  • Continue discussions: Reply directly to Sourcery's review comments.
  • Generate a GitHub issue from a review comment: Ask Sourcery to create an
    issue from a review comment by replying to it. You can also reply to a
    review comment with @sourcery-ai issue to create an issue from it.
  • Generate a pull request title: Write @sourcery-ai anywhere in the pull
    request title to generate a title at any time. You can also comment
    @sourcery-ai title on the pull request to (re-)generate the title at any time.
  • Generate a pull request summary: Write @sourcery-ai summary anywhere in
    the pull request body to generate a PR summary at any time exactly where you
    want it. You can also comment @sourcery-ai summary on the pull request to
    (re-)generate the summary at any time.
  • Generate reviewer's guide: Comment @sourcery-ai guide on the pull
    request to (re-)generate the reviewer's guide at any time.
  • Resolve all Sourcery comments: Comment @sourcery-ai resolve on the
    pull request to resolve all Sourcery comments. Useful if you've already
    addressed all the comments and don't want to see them anymore.
  • Dismiss all Sourcery reviews: Comment @sourcery-ai dismiss on the pull
    request to dismiss all existing Sourcery reviews. Especially useful if you
    want to start fresh with a new review - don't forget to comment
    @sourcery-ai review to trigger a new review!

Customizing Your Experience

Access your dashboard to:

  • Enable or disable review features such as the Sourcery-generated pull request
    summary, the reviewer's guide, and others.
  • Change the review language.
  • Add, remove or edit custom review instructions.
  • Adjust other review settings.

Getting Help

@imaegoo imaegoo linked an issue May 6, 2026 that may be closed by this pull request

@sourcery-ai sourcery-ai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Hey - 我发现了 1 个问题,并且留了一些整体性的反馈:

  • TkComment.vue 中,删除确认对话使用的是 ADMIN_COMMENT_DELETE_CONFIRM 这个 i18n key,但这是用户自行发起的删除操作;建议新增一个专门面向普通用户的删除确认文案(例如 COMMENT_DELETE_CONFIRM),避免带有“管理员”语气的文案泄露到普通用户界面中。
  • 对于 COMMENT_DELETE_FOR_USER 的归属检查和删除逻辑,目前在所有后端中都有小差异的重复实现;建议抽取一个小的公共 helper(或者至少统一错误信息/常量),以保持行为一致并降低维护成本。
给 AI Agent 的提示
Please address the comments from this code review:

## Overall Comments
- In `TkComment.vue`, the delete confirmation uses the `ADMIN_COMMENT_DELETE_CONFIRM` i18n key for a user-initiated delete; consider introducing a dedicated user-facing confirmation string (e.g. `COMMENT_DELETE_CONFIRM`) to avoid admin-specific wording leaking into the regular UI.
- The ownership-check and delete logic for `COMMENT_DELETE_FOR_USER` is duplicated with only small variations across all backends; consider extracting a small shared helper (or at least centralizing the error messages/constants) to keep the behavior consistent and reduce maintenance overhead.

## Individual Comments

### Comment 1
<location path="src/client/view/components/TkComment.vue" line_range="264-267" />
<code_context>
     },
+    async onDelete () {
+      if (!confirm(t('ADMIN_COMMENT_DELETE_CONFIRM'))) return
+      const result = await call(this.$tcb, 'COMMENT_DELETE_FOR_USER', {
+        id: this.comment.id
+      })
+      if (!result.code) {
+        this.$emit('load')
+      }
</code_context>
<issue_to_address>
**suggestion:** Handle and surface backend errors for comment deletion instead of silently ignoring them.

Currently, a non-zero `COMMENT_DELETE_FOR_USER` `code` is ignored. Please handle this case by surfacing an error (e.g., toast or inline message) so users understand why the comment wasn’t deleted.

Suggested implementation:

```
    async onDelete () {
      if (!confirm(t('ADMIN_COMMENT_DELETE_CONFIRM'))) return
      try {
        const result = await call(this.$tcb, 'COMMENT_DELETE_FOR_USER', {
          id: this.comment.id
        })

        if (!result || result.code) {
          // Surface backend error to the user
          const message =
            (result && (result.message || result.errorMsg)) ||
            t('ADMIN_COMMENT_DELETE_FAILED')
          // TODO: replace alert with project-standard toast/notification
          alert(message)
          return
        }

        this.$emit('load')
      } catch (e) {
        console.error('COMMENT_DELETE_FOR_USER failed', e)
        // TODO: replace alert with project-standard toast/notification
        alert(t('ADMIN_COMMENT_DELETE_FAILED'))
      }
    },

```

1. Add a translation key `ADMIN_COMMENT_DELETE_FAILED` to your i18n resources (e.g., `"ADMIN_COMMENT_DELETE_FAILED": "Failed to delete comment. Please try again later."` or similar).
2. Replace the `alert(...)` calls with your app’s standard mechanism for surfacing errors (e.g., `this.$toast.error(message)`, `this.$message.error(message)`, or a dedicated inline error component), following existing patterns elsewhere in the codebase.
3. If your backend uses a different property than `message`/`errorMsg` for error text, adjust the error extraction logic accordingly.
</issue_to_address>

Sourcery 对开源项目是免费的——如果你觉得我们的代码评审有帮助,欢迎分享 ✨
帮我变得更有用!请在每条评论上点 👍 或 👎,我会根据你的反馈改进后续的评审质量。
Original comment in English

Hey - I've found 1 issue, and left some high level feedback:

  • In TkComment.vue, the delete confirmation uses the ADMIN_COMMENT_DELETE_CONFIRM i18n key for a user-initiated delete; consider introducing a dedicated user-facing confirmation string (e.g. COMMENT_DELETE_CONFIRM) to avoid admin-specific wording leaking into the regular UI.
  • The ownership-check and delete logic for COMMENT_DELETE_FOR_USER is duplicated with only small variations across all backends; consider extracting a small shared helper (or at least centralizing the error messages/constants) to keep the behavior consistent and reduce maintenance overhead.
Prompt for AI Agents
Please address the comments from this code review:

## Overall Comments
- In `TkComment.vue`, the delete confirmation uses the `ADMIN_COMMENT_DELETE_CONFIRM` i18n key for a user-initiated delete; consider introducing a dedicated user-facing confirmation string (e.g. `COMMENT_DELETE_CONFIRM`) to avoid admin-specific wording leaking into the regular UI.
- The ownership-check and delete logic for `COMMENT_DELETE_FOR_USER` is duplicated with only small variations across all backends; consider extracting a small shared helper (or at least centralizing the error messages/constants) to keep the behavior consistent and reduce maintenance overhead.

## Individual Comments

### Comment 1
<location path="src/client/view/components/TkComment.vue" line_range="264-267" />
<code_context>
     },
+    async onDelete () {
+      if (!confirm(t('ADMIN_COMMENT_DELETE_CONFIRM'))) return
+      const result = await call(this.$tcb, 'COMMENT_DELETE_FOR_USER', {
+        id: this.comment.id
+      })
+      if (!result.code) {
+        this.$emit('load')
+      }
</code_context>
<issue_to_address>
**suggestion:** Handle and surface backend errors for comment deletion instead of silently ignoring them.

Currently, a non-zero `COMMENT_DELETE_FOR_USER` `code` is ignored. Please handle this case by surfacing an error (e.g., toast or inline message) so users understand why the comment wasn’t deleted.

Suggested implementation:

```
    async onDelete () {
      if (!confirm(t('ADMIN_COMMENT_DELETE_CONFIRM'))) return
      try {
        const result = await call(this.$tcb, 'COMMENT_DELETE_FOR_USER', {
          id: this.comment.id
        })

        if (!result || result.code) {
          // Surface backend error to the user
          const message =
            (result && (result.message || result.errorMsg)) ||
            t('ADMIN_COMMENT_DELETE_FAILED')
          // TODO: replace alert with project-standard toast/notification
          alert(message)
          return
        }

        this.$emit('load')
      } catch (e) {
        console.error('COMMENT_DELETE_FOR_USER failed', e)
        // TODO: replace alert with project-standard toast/notification
        alert(t('ADMIN_COMMENT_DELETE_FAILED'))
      }
    },

```

1. Add a translation key `ADMIN_COMMENT_DELETE_FAILED` to your i18n resources (e.g., `"ADMIN_COMMENT_DELETE_FAILED": "Failed to delete comment. Please try again later."` or similar).
2. Replace the `alert(...)` calls with your app’s standard mechanism for surfacing errors (e.g., `this.$toast.error(message)`, `this.$message.error(message)`, or a dedicated inline error component), following existing patterns elsewhere in the codebase.
3. If your backend uses a different property than `message`/`errorMsg` for error text, adjust the error extraction logic accordingly.
</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/client/view/components/TkComment.vue Outdated
imaegoo and others added 2 commits May 6, 2026 17:40
- Move delete button to first position in TkAction
- Add dedicated COMMENT_DELETE_CONFIRM i18n key for user-facing text
- Extract checkCommentOwnership helper in twikoo-func/utils to unify
  ownership validation across all 5 server backends
- Show backend error messages to user via alert() instead of silently
  ignoring non-zero response codes

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
@imaegoo imaegoo merged commit 975ab4a into main May 6, 2026
2 checks passed
@imaegoo imaegoo deleted the feat/user-delete-own-comment branch May 6, 2026 09:53
@imaegoo imaegoo linked an issue May 6, 2026 that may be closed by this pull request
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