Skip to content

Commit 3a864bc

Browse files
committed
feat: 添加可见性过滤功能,支持按公开/私密筛选回声
1 parent 7824669 commit 3a864bc

15 files changed

Lines changed: 187 additions & 10 deletions

File tree

CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,10 @@ For releases prior to v4.6.5, see the [GitHub releases page](https://github.com/
99

1010
## [Unreleased]
1111

12+
### Added
13+
14+
- **Quick search can now filter by visibility (public / private).** The command palette (⌘K) gains a three-state **Visibility** section — *All*, *Public only*, *Private only* — shown only to logged-in admins; anonymous visitors don't see it and the timeline behaves exactly as before. An active filter shows up as a clearable chip next to the search box, like date-range and tag filters. Server-side, `POST /api/echo/query` accepts an optional `private` boolean; requests without private-content permission have it silently ignored and keep getting public-only results, so nothing can leak.
15+
1216
### Changed
1317

1418
- **Built-in MCP server upgraded to protocol revision `2026-07-28`** (latest MCP spec, replacing `2025-11-25`) — **breaking for legacy MCP clients**. The server is now stateless per the new spec: the `initialize` handshake is gone (replaced by `server/discover`), every request must carry `params._meta` protocol metadata plus the `MCP-Protocol-Version` / `Mcp-Method` / `Mcp-Name` headers (validated with HTTP 400 + `-32020`/`-32022` on mismatch), unknown methods return HTTP 404, results carry `resultType` and `_meta.serverInfo`, and discover/list/read results include cache hints (`ttlMs` + `cacheScope`). `GET /mcp` (old status endpoint) and `DELETE /mcp` now return 405. Clients must speak `2026-07-28` — official SDKs (TypeScript v2, Go v1.7+, Python, C# v2) handle this automatically; legacy `initialize` clients receive a diagnostic naming the supported version.

go.sum

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -159,8 +159,6 @@ github.com/google/go-tpm v0.9.8/go.mod h1:h9jEsEECg7gtLis0upRBQU+GhYVH6jMjrFxI8u
159159
github.com/google/go-tpm-tools v0.3.13-0.20230620182252-4639ecce2aba h1:qJEJcuLzH5KDR0gKc0zcktin6KSAwL7+jWKBYceddTc=
160160
github.com/google/go-tpm-tools v0.3.13-0.20230620182252-4639ecce2aba/go.mod h1:EFYHy8/1y2KfgTAsx7Luu7NGhoxtuVHnNo8jE7FikKc=
161161
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
162-
github.com/google/subcommands v1.2.0 h1:vWQspBTo2nEqTUFita5/KeEWlUL8kQObDFbub/EN9oE=
163-
github.com/google/subcommands v1.2.0/go.mod h1:ZjhPrFU+Olkh9WazFPsl27BQ4UPiG37m3yTrtFlrHVk=
164162
github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
165163
github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
166164
github.com/google/wire v0.7.0 h1:JxUKI6+CVBgCO2WToKy/nQk0sS+amI9z9EjVmdaocj4=
@@ -308,8 +306,6 @@ golang.org/x/sys v0.47.0 h1:o7XGOvZQCADBQQ4Y7VNq2dRWQR7JmOUW8Kxx4ZsNgWs=
308306
golang.org/x/sys v0.47.0/go.mod h1:4GL1E5IUh+htKOUEOaiffhrAeqysfVGipDYzABqnCmw=
309307
golang.org/x/text v0.40.0 h1:Ub2Z6/xjgF1WrYQz2nuITOEegKFtiIy+rieRJ5lHZKs=
310308
golang.org/x/text v0.40.0/go.mod h1:hpnzDAfGV753zIKo+wk3u1bVKCGPbrnF7+7LBF/UHVY=
311-
golang.org/x/tools v0.47.0 h1:7Kn5x/d1svx/PzryTsqeoZN4TZwqeH5pGWjefhLi/1Q=
312-
golang.org/x/tools v0.47.0/go.mod h1:dFHnyTvFWY212G+h7ZY4Vsp/K3U4/7W9TyVaAul8uCA=
313309
google.golang.org/protobuf v1.36.11 h1:fV6ZwhNocDyBLK0dj+fg8ektcVegBBuEolpbTQyBNVE=
314310
google.golang.org/protobuf v1.36.11/go.mod h1:HTf+CrKn2C3g5S8VImy6tdcUvCska2kB7j23XfzDpco=
315311
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=

internal/model/common/common_dto.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,10 @@ type EchoQueryDto struct {
2626
// 0 或负数视为未设置。
2727
DateFrom int64 `json:"dateFrom"`
2828
DateTo int64 `json:"dateTo"`
29+
// Private:按可见性过滤的三态开关。nil 表示不过滤(现状行为:admin 公开+私密
30+
// 混合,匿名仅公开);true 仅私密、false 仅公开。仅当 viewer 具备私密可见权限
31+
// (admin)时生效,无权限的请求在仓储层被静默忽略、仍强制仅公开。
32+
Private *bool `json:"private,omitempty"`
2933
// UserID:按作者(echos.user_id)精确过滤。opt-in——空串表示不限定作者
3034
// (公开 /echo/query 等调用方留空即保持原行为);Copilot Chat 用它把检索
3135
// 收口到当前对话用户本人发布的 Echo。不暴露给前端 JSON 契约,仅服务内部设置。

internal/openapi/openapi.yaml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -374,6 +374,8 @@ components:
374374
pageSize:
375375
format: int64
376376
type: integer
377+
private:
378+
type: boolean
377379
search:
378380
type: string
379381
sortBy:

internal/repository/echo/echo.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -401,7 +401,10 @@ func (echoRepository *EchoRepository) QueryEchos(
401401
Where("echo_tags.tag_id IN ?", queryDto.TagIDs)
402402
}
403403
if !showPrivate {
404+
// 无私密可见权限:强制仅公开,dto.Private 被静默忽略(防泄漏兜底)。
404405
db = db.Where("echos.private = ?", false)
406+
} else if queryDto.Private != nil {
407+
db = db.Where("echos.private = ?", *queryDto.Private)
405408
}
406409
if queryDto.UserID != "" {
407410
db = db.Where("echos.user_id = ?", queryDto.UserID)

internal/repository/echo/query_echos_test.go

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,41 @@ func TestEchoRepository_QueryEchos_PrivateFilter(t *testing.T) {
8383
assert.Equal(t, int64(2), total)
8484
assert.Len(t, echos, 2)
8585
})
86+
87+
ptr := func(b bool) *bool { return &b }
88+
89+
t.Run("showPrivate=true + Private=true narrows to private only", func(t *testing.T) {
90+
echos, total, err := repo.QueryEchos(
91+
commonModel.EchoQueryDto{Page: 1, PageSize: 10, Private: ptr(true)},
92+
true,
93+
)
94+
require.NoError(t, err)
95+
assert.Equal(t, int64(1), total)
96+
require.Len(t, echos, 1)
97+
assert.Equal(t, "e-prv", echos[0].ID)
98+
})
99+
100+
t.Run("showPrivate=true + Private=false narrows to public only", func(t *testing.T) {
101+
echos, total, err := repo.QueryEchos(
102+
commonModel.EchoQueryDto{Page: 1, PageSize: 10, Private: ptr(false)},
103+
true,
104+
)
105+
require.NoError(t, err)
106+
assert.Equal(t, int64(1), total)
107+
require.Len(t, echos, 1)
108+
assert.Equal(t, "e-pub", echos[0].ID)
109+
})
110+
111+
t.Run("showPrivate=false ignores Private=true (anti-leak)", func(t *testing.T) {
112+
echos, total, err := repo.QueryEchos(
113+
commonModel.EchoQueryDto{Page: 1, PageSize: 10, Private: ptr(true)},
114+
false,
115+
)
116+
require.NoError(t, err)
117+
assert.Equal(t, int64(1), total)
118+
require.Len(t, echos, 1)
119+
assert.Equal(t, "e-pub", echos[0].ID)
120+
})
86121
}
87122

88123
func TestEchoRepository_QueryEchos_TagJoinDistinctCount(t *testing.T) {

web/src/locales/messages/de-DE.json

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -394,6 +394,11 @@
394394
"dateRangeLast7Days": "Letzte 7 Tage",
395395
"dateRangeLast30Days": "Letzte 30 Tage",
396396
"dateRangeThisYear": "Dieses Jahr",
397+
"visibilityLabel": "Sichtbarkeit",
398+
"visibilityAll": "Alle",
399+
"visibilityPublic": "Nur öffentlich",
400+
"visibilityPrivate": "Nur privat",
401+
"activeChipVisibilityPrefix": "Sichtbarkeit",
397402
"tagsLabel": "Tags",
398403
"tagsHint": "Beliebiges passt",
399404
"tagsEmpty": "Noch keine Tags",

web/src/locales/messages/en-US.json

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -394,6 +394,11 @@
394394
"dateRangeLast7Days": "Last 7 days",
395395
"dateRangeLast30Days": "Last 30 days",
396396
"dateRangeThisYear": "This year",
397+
"visibilityLabel": "Visibility",
398+
"visibilityAll": "All",
399+
"visibilityPublic": "Public only",
400+
"visibilityPrivate": "Private only",
401+
"activeChipVisibilityPrefix": "Visibility",
397402
"tagsLabel": "Tags",
398403
"tagsHint": "Match any",
399404
"tagsEmpty": "No tags yet",

web/src/locales/messages/ja-JP.json

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -394,6 +394,11 @@
394394
"dateRangeLast7Days": "直近 7 日",
395395
"dateRangeLast30Days": "直近 30 日",
396396
"dateRangeThisYear": "今年",
397+
"visibilityLabel": "公開範囲",
398+
"visibilityAll": "すべて",
399+
"visibilityPublic": "公開のみ",
400+
"visibilityPrivate": "非公開のみ",
401+
"activeChipVisibilityPrefix": "公開範囲",
397402
"tagsLabel": "タグ",
398403
"tagsHint": "いずれか一致",
399404
"tagsEmpty": "タグがありません",

web/src/locales/messages/zh-CN.json

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -394,6 +394,11 @@
394394
"dateRangeLast7Days": "最近 7 天",
395395
"dateRangeLast30Days": "最近 30 天",
396396
"dateRangeThisYear": "今年",
397+
"visibilityLabel": "可见性",
398+
"visibilityAll": "全部",
399+
"visibilityPublic": "仅公开",
400+
"visibilityPrivate": "仅私密",
401+
"activeChipVisibilityPrefix": "可见性",
397402
"tagsLabel": "标签",
398403
"tagsHint": "任一匹配",
399404
"tagsEmpty": "暂无标签",

0 commit comments

Comments
 (0)