feat(appconfig): admin 可调的 disable_user_create_space 开关#4
Open
an9xyz wants to merge 6 commits into
Open
Conversation
…ininglamp-OSS#177) This PR adds the `edited` event to the `pull_request_target.types` trigger in both `check-sprint.yml` and `auto-add-to-project.yml`, enabling the Issue-first Sprint check flow to work correctly when a developer adds a `Closes #<issue>` reference to a PR description after opening. Co-authored-by: Octo Bot <bot@mininglamp.com>
…ininglamp-OSS#184) Two changes for local ASR config reset flow: 1. **Add POST /local-config/reset proxy endpoint** - proxies reset request to octo-speech service, preserving enabled state while resetting other fields to defaults. 2. **Fix 404 handling** - when octo-speech returns 404 (config not found), voice adapter now returns 200 with empty/default response instead of propagating the error, since 'not found' means 'using defaults'. Closes Mininglamp-OSS#185
## Summary
Adds the source-of-truth marker generator that Phase 2 module rollouts
depend on. Without 100% recall here, every Phase 2 PR has to either
hand-author TOML keys (drift risk) or accept silent runtime
`DefaultMessage` fallback (translation gap).
This PR is pure tooling — no runtime code changes.
## What ships
- **`pkg/i18n/cmd/octo-i18n-extract`** — Go AST extractor that walks
`pkg/i18n/codes` and `pkg/errcode`, recognizing both
`Register(Code{...})` and `register(codes.Code{...})` call shapes.
Strict by design:
- `ID` and `DefaultMessage` MUST be basic string literals; computed
values are rejected at extraction time, not papered over.
- Duplicate IDs are a hard error (across files and across roots).
- Test files and dot/underscore-prefixed dirs are skipped.
- **100% recall guarantee** — `main.go` side-effect imports `codes` +
`errcode` and asserts the AST-discovered ID set equals `codes.All()`
exactly. Missing-from-AST or extra-only-in-AST surfaces a sorted diff
and a non-zero exit code, so a `Register` call that `init()` somehow
skipped (build tag, dead branch) cannot pass silently.
- **Marker routing by ID prefix** (architecture decision D18):
- `err.shared.*` → `tools/i18nmarkers/shared/active.en-US.toml`
- `err.server.*` / `msg.*` →
`tools/i18nmarkers/server/active.en-US.toml`
- Unknown prefixes are rejected so adding a third namespace forces an
explicit routing decision plus a `codes/registry.go` `idPattern`
update.
- **Deterministic output** — sorted keys, `strconv`-quoted strings,
fixed header. Re-running the extractor on an unchanged repo produces
byte-identical files. `WriteMarkerFile` only writes when content
differs; `-check` mode reports diffs via exit code 3 for CI use.
- **Makefile entries**:
- `make i18n-extract` — regenerate marker files
- `make i18n-extract-check` — CI guard (no writes; exit 3 on diff)
- `make i18n-merge` — optional convenience that shells out to the
upstream `goi18n` CLI
## Tests
Table-driven, all green under `-race`:
- `Register` / `register` call detection across both shapes
- Non-`Code` composite literals ignored
- Non-string-literal fields rejected
- Duplicate ID rejected
- Test files skipped
- Prefix routing including unknown-prefix error
- `RenderTOML` stability + escape correctness
- `WriteMarkerFile` idempotency (second write reports unchanged)
## Out of scope
CI integration (the lint job that fails PRs which forget to re-run
`extract`) lands in the §0.10 lint batch alongside the other 5 lint
rules. This PR ships the extractor + Makefile entrypoints only.
## Test plan
- [x] `go test -race ./pkg/i18n/cmd/octo-i18n-extract/`
- [x] `go vet ./pkg/i18n/cmd/octo-i18n-extract/`
- [x] `make i18n-extract` → writes 9 + 18 markers
- [x] `make i18n-extract` (second run) → reports unchanged
- [x] `make i18n-extract-check` → exit 0 on clean tree
- [x] `go test ./pkg/i18n/... ./pkg/errcode/...` (no regressions)
---------
Co-authored-by: an9xyz <an9xyz@users.noreply.github.com>
…glamp-OSS#187) Add two new caller workflows per PR notification split design. Reusable workflows in .github PR Mininglamp-OSS#49. --------- Co-authored-by: Octo Bot <bot@mininglamp.com>
…etting Promote the "禁用普通用户创建空间" toggle from env-only (DM_SPACE_DISABLE_USER_CREATE) to a system_setting KV-backed value so SuperAdmin can switch it at runtime without redeploying. - common: SpaceDisableUserCreate getter (DB → env → false), schema entry (space, disable_user_create, bool); appConfigResp.disable_user_create_space surfaced on both /v1/common/appconfig branches (incl. version short-circuit). - space: createSpace now consults SystemSettings; legacy env path preserved as fallback / low-level parser. - tests: unit (getter fallback chain incl. DB empty), HTTP (appconfig default / DB override / version short-circuit), createSpace 403 on DB-set, plus end-to-end (manager write → appconfig → createSpace gate).
Jerry-Xin pointed out (PR Mininglamp-OSS#189 review) that the docstring claimed an unknown DB literal falls back to env, but the implementation delegates to getBool which falls back to false. Align the doc with the actual behavior; behavior unchanged.
560400c to
3b0547c
Compare
an9xyz
added a commit
that referenced
this pull request
May 29, 2026
…n gates ## Summary Phase 0 close-out: fills the three remaining §0.9 verification scenarios that lacked explicit coverage, and lands the first batch of §0.10 CI gates that Phase 2 module migrations depend on. No runtime code changes — everything is tests, two AST lint tools under `tools/`, and CI wiring. This is a follow-up to the i18n migration pilots (`modules/thread` PR Mininglamp-OSS#176, `modules/user/api.go` PR Mininglamp-OSS#188). ## Commits 1. **`test(i18n): close Phase 0 §0.9 verification gaps`** - `pkg/i18n/renderer_test.go`: TransportStatus≠SemanticStatus divergence (D14 — wire/body status fixed at 400, `error.http_status` carries the real semantic status); dual-envelope parity regardless of the `X-Octo-Error-Envelope` request header (v7.2/D12 — byte-identical body with and without the header). - `modules/user/language_multidevice_test.go`: multi-device language convergence (§0.9 "A 端切语言 B 端下次请求即生效") plus the clear-to-default inverse. `fakeLangDB.UpdateLanguageByUID` now writes through to its read map so read-after-write is observable; existing tests assert on the separate `updates` map and are unaffected. 2. **`feat(lint): add D23 direct-error-response ratchet (0.10 Mininglamp-OSS#5)`** - `tools/lint-direct-error-response`: AST-counts `c.AbortWithStatusJSON` / `c.AbortWithStatus` per non-test file and compares against a committed `baseline.txt`. **Baseline ratchet, not a hard block** — the Phase 0.1 inventory found ~120 pre-existing sites in unmigrated modules, so a zero-gate would red-light main. The lint fails only on regressions (a file exceeding its count, or a new file introducing any) and emits a tighten-advisory when a migrated file drops below baseline. Per-file counts (not line numbers, which churn); documented net-zero-churn limitation. 3. **`feat(lint): block inline codes bypassing the registry (0.10 #3)`** - `tools/lint-unregistered-code`: forbids inline `codes.Code{...}` literals as the `httperr.ResponseErrorL` code argument. Such a literal never passes `codes.Register`, so the 0.8 extractor emits no marker and `respond.go` silently downgrades it to `err.shared.internal`. Single-file AST scope is documented (two-step var smuggle is still caught at runtime + by the 0.8 recall check). 4. **`ci(i18n): wire Phase 0.10 extract-check + lint gates`** - Two CI jobs following the existing `personal-msgsendreq-lint` template: "i18n Extract Check" (`make i18n-extract-check`, closes the last open Phase 0.8 item) and "i18n Lint" (the two new gates). Adds a `make i18n-lint` target for local runs. ## Phase 0.10 scope note This PR lands lint **#1 (extract diff)**, **#3 (unregistered code)**, **Mininglamp-OSS#5 (AbortWithStatusJSON)**. The remaining 0.10 gates — #4 (Params sensitive-key), Mininglamp-OSS#6 (token-cache split), #2 (bare-string) — and the Prometheus counters follow in a sibling PR, to keep this reviewable in one sitting. ## Test plan - [x] `go test -race -count=1 ./pkg/i18n/ ./tools/lint-direct-error-response/ ./tools/lint-unregistered-code/` — pass - [x] `go test -race -count=1 ./modules/user/` (full DB E2E, drop+recreate test DB + FLUSHALL) — pass - [x] `make i18n-extract-check` / `make i18n-lint` — all green against current tree - [x] `go build ./...` / `go vet ./tools/... ./pkg/i18n/...` — clean - [x] CI YAML validated ## Baseline note for reviewers `tools/lint-direct-error-response/baseline.txt` is seeded from the 2026-05-29 snapshot (17 files). It deliberately still tolerates the 8 `AbortWithStatusJSON` sites in `modules/user/api.go` — those are the avatar-permission / bot-token direct responses that PR Mininglamp-OSS#188 left as a documented follow-up (PR Mininglamp-OSS#188 migrated `ResponseError`/`ResponseErrorf`, not `AbortWithStatusJSON`). As each module migrates, drop its row. --------- Co-authored-by: an9xyz <an9xyz@users.noreply.github.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
把「禁用普通用户创建空间」从 env-only (
DM_SPACE_DISABLE_USER_CREATE) 升级为system_settingKV 表驱动,SuperAdmin 可在管理台实时切换、无需重启;v1/common/appconfig同步返回新字段disable_user_create_space给客户端按需隐藏「创建空间」入口。
改动
SpaceDisableUserCreate()getter:DB → env → false 三级回落,DB 路径委托getBool与其它 bool 设置共用解析规则systemSettingSchema新增一行(space, disable_user_create, bool)—不 ALTER TABLE,admin UI 自动渲染
appConfigResp.disable_user_create_space在 handler 两个分支(含 version短路)都下发,避免老客户端被缓存住
createSpace改走(*Space).isUserCreateDisabled()→ SystemSettingsIsUserCreateDisabled()+ env 常量作 fallback / 老调用方兼容设计要点
Reload()本实例生效;其它实例 60s 内自动 reload 收敛appconfig字段默认0前端对接
GET /v1/common/appconfig→ 读disable_user_create_space(0/1)POST /v1/manager/common/system_setting,items 含{category: "space", key: "disable_user_create", value: "0|1"}Test plan
go test -race ./modules/common/— 通过go test -race ./modules/space/— 通过回落 env / env 正负样例)