Skip to content

feat: /project/reorder + /project/create#19

Merged
Aliothmoon merged 4 commits into
mainfrom
feat/projects
Jun 7, 2026
Merged

feat: /project/reorder + /project/create#19
Aliothmoon merged 4 commits into
mainfrom
feat/projects

Conversation

@MistEO

@MistEO MistEO commented Jun 5, 2026

Copy link
Copy Markdown
Contributor

Summary by Sourcery

添加经过认证的管理员端点,用于管理项目排序和创建,并扩展配置以支持管理员密钥。

New Features:

  • 暴露 POST /project/reorder 端点,用于更新现有项目的显示顺序。
  • 暴露 POST /project/create 端点,用于创建带有可配置元数据的新项目。

Enhancements:

  • 在项目重新排序或创建后使内存中的项目缓存失效,以保持查询结果的一致性。
  • 扩展应用设置,增加 admin_secret 值,用于授权敏感的项目管理操作。
Original summary in English

Summary by Sourcery

Add authenticated admin endpoints for managing project ordering and creation while extending configuration to support an admin secret.

New Features:

  • Expose a POST /project/reorder endpoint to update the display order of existing projects.
  • Expose a POST /project/create endpoint to create new projects with configurable metadata.

Enhancements:

  • Invalidate the in-memory project cache after project reordering or creation to keep query results consistent.
  • Extend application settings with an admin_secret value used to authorize sensitive project management operations.

@sourcery-ai sourcery-ai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Hey - 我发现了 2 个问题,并留下了一些高层次的反馈:

  • /project/reorder/{secret}/project/create/{secret} 这两个接口中,如果 admin_secret 未设置或为空,当前的 admin_secret 校验会静默拒绝所有调用;建议在服务启动时快速失败,或者记录清晰的配置错误日志,而不是在这种情况下返回通用的 403。
  • reorder 接口目前会静默过滤掉未知的 rid;建议将 req.rid_listdb_rids 做校验,并在出现意外或重复 ID 时返回 4xx 错误(或至少记录日志),这样可以更容易发现客户端的错误。
  • create_project 中调用 Project.create 时,没有检查是否已经存在具有相同 rid 的项目;建议在模型层强制唯一性,或者显式处理冲突,以避免造成让人困惑的部分失败。
供 AI Agents 使用的提示词
Please address the comments from this code review:

## Overall Comments
- In both `/project/reorder/{secret}` and `/project/create/{secret}`, the `admin_secret` check will silently reject all calls if `admin_secret` is unset or empty; consider failing fast at startup or logging a clear configuration error instead of returning a generic 403 in this case.
- The reorder endpoint currently filters unknown `rid`s out silently; consider validating `req.rid_list` against `db_rids` and returning a 4xx error (or at least logging) when unexpected or duplicate IDs are provided to make client mistakes easier to detect.
- In `create_project`, `Project.create` is called without checking whether a project with the same `rid` already exists; consider either enforcing uniqueness at the model level or explicitly handling collisions to avoid confusing partial failures.

## Individual Comments

### Comment 1
<location path="src/project/__init__.py" line_range="75-80" />
<code_context>
+    all_projects = list(Project.select())
+    db_rids = {p.rid for p in all_projects}
+
+    ordered_rids = [rid for rid in req.rid_list if rid in db_rids]
+    remaining_rids = [p.rid for p in sorted(all_projects, key=lambda p: p.proj_index) if p.rid not in set(ordered_rids)]
+    final_order = ordered_rids + remaining_rids
+
</code_context>
<issue_to_address>
**suggestion:** Guard against duplicate rids in the reorder request to avoid assigning multiple indices to the same project.

If `req.rid_list` contains duplicates, the same `rid` will appear multiple times in `final_order`, so its `proj_index` is reassigned several times. While the end state is consistent, it makes the ordering logic harder to reason about and debug. Consider deduplicating `req.rid_list` while preserving first-seen order (e.g., building `ordered_rids` via an ordered-set pattern) so each project is assigned exactly one index.

```suggestion
    all_projects = list(Project.select())
    db_rids = {p.rid for p in all_projects}

    seen_rids = set()
    ordered_rids = []
    for rid in req.rid_list:
        if rid in db_rids and rid not in seen_rids:
            seen_rids.add(rid)
            ordered_rids.append(rid)

    remaining_rids = [
        p.rid
        for p in sorted(all_projects, key=lambda p: p.proj_index)
        if p.rid not in seen_rids
    ]
    final_order = ordered_rids + remaining_rids
```
</issue_to_address>

### Comment 2
<location path="src/project/__init__.py" line_range="92" />
<code_context>
+    return {"ec": 200, "msg": "ok"}
+
+
+@router.post("/project/create/{secret}")
+async def create_project(secret: str, req: CreateProjectRequest):
+    if not settings.admin_secret or secret != settings.admin_secret:
</code_context>
<issue_to_address>
**🚨 suggestion (security):** Embedding the admin secret in the URL path can leak it via logs and intermediaries.

Because `secret` is in the path, it will end up in server/reverse-proxy logs and possibly monitoring tools, increasing the likelihood of exposure. Prefer sending this secret in an HTTP header or request body field, where you can more easily control and scrub it from logs while preserving the same authorization behavior.
</issue_to_address>

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

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

  • In both /project/reorder/{secret} and /project/create/{secret}, the admin_secret check will silently reject all calls if admin_secret is unset or empty; consider failing fast at startup or logging a clear configuration error instead of returning a generic 403 in this case.
  • The reorder endpoint currently filters unknown rids out silently; consider validating req.rid_list against db_rids and returning a 4xx error (or at least logging) when unexpected or duplicate IDs are provided to make client mistakes easier to detect.
  • In create_project, Project.create is called without checking whether a project with the same rid already exists; consider either enforcing uniqueness at the model level or explicitly handling collisions to avoid confusing partial failures.
Prompt for AI Agents
Please address the comments from this code review:

## Overall Comments
- In both `/project/reorder/{secret}` and `/project/create/{secret}`, the `admin_secret` check will silently reject all calls if `admin_secret` is unset or empty; consider failing fast at startup or logging a clear configuration error instead of returning a generic 403 in this case.
- The reorder endpoint currently filters unknown `rid`s out silently; consider validating `req.rid_list` against `db_rids` and returning a 4xx error (or at least logging) when unexpected or duplicate IDs are provided to make client mistakes easier to detect.
- In `create_project`, `Project.create` is called without checking whether a project with the same `rid` already exists; consider either enforcing uniqueness at the model level or explicitly handling collisions to avoid confusing partial failures.

## Individual Comments

### Comment 1
<location path="src/project/__init__.py" line_range="75-80" />
<code_context>
+    all_projects = list(Project.select())
+    db_rids = {p.rid for p in all_projects}
+
+    ordered_rids = [rid for rid in req.rid_list if rid in db_rids]
+    remaining_rids = [p.rid for p in sorted(all_projects, key=lambda p: p.proj_index) if p.rid not in set(ordered_rids)]
+    final_order = ordered_rids + remaining_rids
+
</code_context>
<issue_to_address>
**suggestion:** Guard against duplicate rids in the reorder request to avoid assigning multiple indices to the same project.

If `req.rid_list` contains duplicates, the same `rid` will appear multiple times in `final_order`, so its `proj_index` is reassigned several times. While the end state is consistent, it makes the ordering logic harder to reason about and debug. Consider deduplicating `req.rid_list` while preserving first-seen order (e.g., building `ordered_rids` via an ordered-set pattern) so each project is assigned exactly one index.

```suggestion
    all_projects = list(Project.select())
    db_rids = {p.rid for p in all_projects}

    seen_rids = set()
    ordered_rids = []
    for rid in req.rid_list:
        if rid in db_rids and rid not in seen_rids:
            seen_rids.add(rid)
            ordered_rids.append(rid)

    remaining_rids = [
        p.rid
        for p in sorted(all_projects, key=lambda p: p.proj_index)
        if p.rid not in seen_rids
    ]
    final_order = ordered_rids + remaining_rids
```
</issue_to_address>

### Comment 2
<location path="src/project/__init__.py" line_range="92" />
<code_context>
+    return {"ec": 200, "msg": "ok"}
+
+
+@router.post("/project/create/{secret}")
+async def create_project(secret: str, req: CreateProjectRequest):
+    if not settings.admin_secret or secret != settings.admin_secret:
</code_context>
<issue_to_address>
**🚨 suggestion (security):** Embedding the admin secret in the URL path can leak it via logs and intermediaries.

Because `secret` is in the path, it will end up in server/reverse-proxy logs and possibly monitoring tools, increasing the likelihood of exposure. Prefer sending this secret in an HTTP header or request body field, where you can more easily control and scrub it from logs while preserving the same authorization behavior.
</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/project/__init__.py Outdated
Comment thread src/project/__init__.py Outdated
@Aliothmoon Aliothmoon merged commit 2c52f4a into main Jun 7, 2026
2 checks passed
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.

2 participants