Commit Graph
55 Commits
Author SHA1 Message Date
zhangwenjian c0ca07c95b fix🐛: refuse generator names that cannot be path components
The package, table and business names a table's configuration carries
become directories and file names, and nothing on the server checked
them; the config page's patterns were the only check.

Each is now checked against what it becomes: a package name is
lowercase letters and digits, a table name letters, digits and
underscores, a business name an identifier starting with a lowercase
letter. None allows a dot or a separator, and none is stricter than
the config page. The check runs on import, where a list holding one
bad name is refused whole, on save, and again before generating, so a
configuration saved before this check existed is refused rather than
trusted.
2026-09-27 19:43:04 +08:00
zhangwenjian afa8513d4b fix🐛: keep the code generator's writes inside their roots
The generator joins a table's package, table and business names into
the paths it writes, and wrote them with os.MkdirAll and os.WriteFile.
A name carrying "..", or a symlink under the target directory pointing
elsewhere, took the write wherever it led.

Every file is now written through os.Root: backend files under the
working directory, frontend files under gen.frontpath. A path that
resolves outside its root is refused, symlinks included, and the
request reports the write failure without writing anything outside.
2026-09-27 19:42:35 +08:00
zhangwenjian 2642d0959d fix🐛: leave the form out of a generated page with nothing to enter
A table whose columns are all its key and ones the framework fills in
got an add button and an edit link opening an empty form. The page now
leaves out both, the dialog, useForm and the API calls only the form
used. A page with anything to enter is generated byte for byte as
before.
2026-09-27 16:07:10 +08:00
zhangwenjian 8cbbd6eddd feat✨: show created_at and updated_at on the generator's config page
The config page hid both columns along with the ones the framework
fills in, so a generated page could not list or filter by when a row
was created or last changed without editing sys_columns by hand. They
are now shown; id, create_by, update_by and deleted_at stay hidden.
The templates already keep both out of the create/edit form.

The test imports a table, ticks list and query on created_at through
the config page's own endpoints, generates it, and filters the
generated list with the value the generated date picker sends.
2026-09-27 16:07:10 +08:00
zhangwenjian 77fddfa356 test✅: hard-delete the generator fixtures, as the delete endpoint does
dropFixture soft-deleted the sys_tables rows it cleaned up. The config
page's business-name check counts soft-deleted rows, so a second test
importing the same table could not save its configuration. The delete
endpoint removes these rows with Unscoped; the fixture now does too.
2026-09-27 16:07:07 +08:00
zhangwenjian d89e0cd8eb chore⬆️: upgrade go-admin-core to v2.11.0
v2.11.0 makes pkg.FileCreate return its error instead of ending the
process when the file cannot be created. Two comments in the code
generator described the old behaviour in the present tense.
2026-09-27 14:01:48 +08:00
zhangwenjian d84e30afb8 fix🐛: report a table the generator cannot read
Preview, GenCode, GenApiToFile and GenMenuAndApi read a table's
configuration with tab, _ := table.Get(...), so an id that matched nothing,
or a failed query, carried on with an empty table. GenCode and Preview then
refused it as having no primary key, and GenMenuAndApi went on to seed menus
and APIs for it.

Each now answers with the lookup's error.
2026-09-26 14:17:22 +08:00
zhangwenjian 83064f0b37 fix🐛: render every generated file before writing any, and check both
Preview, NOActionsGen and genApiToFile assigned each template's Execute
error to err and never read it - 19 times - so a template failing part-way
left a truncated file behind it and the request reported success. The
files were written through pkg.FileCreate, which returns no error at all:
when it cannot create a file it closes a nil *os.File and calls
log.Fatalln, ending the server process. Four of the directories it writes
into were created with _ = pkg.PathCreate(...).

Every template now renders into memory first; if any fails, nothing is
written and the response names the template. Files are then written
through writeGenerated, which creates the directory and returns any error
instead of exiting. NOActionsGen and genApiToFile report whether they
succeeded, so GenCode and GenApiToFile no longer follow an error response
with "Code generated successfully".
2026-09-26 14:17:22 +08:00
zhangwenjian 0ff5f1a027 test✅: import and generate every primary-key shape, then drive the result
The generator had no test that compiled what it writes; test/gen_test.go is
commented out. This one goes through the real path end to end: fixture
tables in MySQL, the import handler, GenCode writing its files, the files
compiled into this module's own packages through a -overlay, and a CRUD
test run over HTTP against the generated handlers.

The shapes are an int key named id, an int key named otherwise, a string
key, no key and a composite key. The last two must be refused with nothing
written. For the rest: read and update through the path parameter, a
missing key neither found nor created by an update, a key of "1=1" read as
a value, and delete by key.

The importer only reads MySQL, so the test needs GO_ADMIN_TEST_MYSQL_DSN;
without it the test skips locally and fails under CI. It also asserts each
generated CRUD test actually ran, since a -run pattern that matches nothing
exits 0.
2026-09-25 20:00:40 +08:00
zhangwenjian 99d22249ef fix🐛: refuse to generate a table whose key is not one column
The templates address a row by a single key: one field on the model, one
path parameter, one value per row in a delete. A table with no primary key
rendered a model whose GetId returned an empty field name, and a composite
key was silently narrowed to whichever of its columns the importer read
last. Both wrote files that break the build of the whole module.

Preview and NOActionsGen now check first and return an error naming the
table and, for a composite key, its columns. Nothing is written.
2026-09-25 20:00:30 +08:00
zhangwenjian 05661e2f3e fix🐛: jsonField format check relaxed to any legal identifier
jsonFieldPattern copied businessName's rule (^[a-z][A-Za-z]+$: at least
two letters, no digits) on the theory that jsonField should tighten to
the same identifier shape. That does not hold: businessName is typed
by a person on genInfoForm.vue, so a strict pattern is a reasonable
guardrail on human input. jsonField is computed by the importer from
the column name (sys_tables.go's namelist/JsonField loop) - nobody
types it, so the same pattern only rejected names the importer
legitimately produces: a single-letter column ("x") or one whose last
segment ends in a digit ("address2", "a1") both collapse to a single
camelCase word with nothing left to re-capitalize, and both failed the
old check.

The blast radius is wider than "this one column can't be edited":
validateAndSanitizeColumns runs over every column on every Update, so
a table that merely contains one such column could not save any
config change at all, including edits with nothing to do with that
column.

Relaxed to ^[a-z][A-Za-z0-9]*$ - any legal JS/TS identifier starting
with a lowercase letter. Still rejects what has to be rejected: empty,
whitespace/punctuation, and leading-digit names, since those cannot be
unquoted object keys in the generated interface/lang file at all.
Uniqueness and the expression-content check on defaultValue are
unchanged - defaultValue is genuinely user-typed (F6's config page),
so tightening it was the right call to begin with; this was the only
place a human-input rule had been copied onto machine-generated data.

Verified against the real import path, not hand-typed jsonField values:
built a table with columns id/x/address2/a1 in a fake information_schema,
ran it through the real SysTable.Insert, confirmed the importer computes
exactly jsonField x/address2/a1, then submitted an update through the
real SysTable.Update changing only tableComment (nothing about those
columns). Confirmed red first - 500, "jsonField 格式不合法:\"x\"" - a
change unrelated to any of the three columns was rejected solely because
they existed on the table. Restored the fix - 200, "修改成功".
2026-09-19 20:37:01 +08:00
zhangwenjian 5bb211afcd fix🐛: Preview now sets tab.MLTBName before rendering, matching NOActionsGen
MLTBName (table_name with underscores turned to dashes, e.g. "user_profile"
-> "user-profile") is a gorm:"-" field - table.Get never fills it in, the
caller has to. NOActionsGen has done so since it existed; Preview never
did, so every template's import path that reads it
(from '@/api/{PackageName}/{MLTBName}' in vue.go.template, present in
both the pre-Vue3 template and F4's rewrite) rendered with the module
segment missing - "from '@/api/admin/'" - in the preview dialog only.
The real generated file was always correct.

Pre-existing, not introduced by this PRD, but worth fixing now: F3/F9
added two more Preview panes (the language packs) on top of an assumption
- that Preview's output stands in for what NOActionsGen actually writes -
that was never true for this field. Checked the rest of gen.go for the
same "only set on the write path" shape; MLTBName is the only one -
every other field Preview's templates read comes straight off the
sys_tables/sys_columns rows table.Get already loads.

Verified with a throwaway harness driving Gen.Preview through a real gin
Context and sqlite-backed db, parsing the JSON response and reading back
template/vue.go.template's import line. Confirmed red first (temporarily
removed the added line): "from '@/api/verify010/'". Restored it: "from
'@/api/verify010/verify-widget'".
2026-09-19 15:18:29 +08:00
zhangwenjian 545453c93e feat✨: infer column width from column_type before rendering (PRD 010 R2)
vue.go.template (F4) only had a flat fallback for an unconfigured
colWidth: 110 for datetime, 120 for everything else. R2 asks for a
precise per-type inference instead - varchar(n) tiered by n, tinyint(1)
narrower than a general integer, text/blob wide - sized so a typical
table's list columns land inside go-admin-ui's ~580px text-column
budget. text/template cannot parse "varchar(255)" itself, so this has
to run in gen.go before the template executes, not in the template.

Judgment is columnType, not goType, same as F1/F2's earlier reversal
(API契约.md §1.1): sys_tables.go:323-338 gives every non-primary-key
int/tinyint/bigint/decimal column goType "string", so goType alone
cannot tell a boolean flag from a bigint from a name column.

InferColumnWidth(columnType string) int is exported and pure per
测试用例.md §2.5's own request, so it can be pinned with an exact
input/output table rather than only asserting "the rendered page
happens not to overflow" - see column_width_test.go, including the
tinyint(1)-vs-tinyint(4) and the varchar tier-boundary cases.
applyInferredColumnWidths only touches a column already at the 0
sentinel, wired into both Preview and NOActionsGen ahead of the
template execute calls; a column already configured (by the user or F6)
is left untouched, also pinned by a test.

Verified against the real NOActionsGen call path (not just the unit
test): generated a table mixing every branch (tinyint(1), datetime,
decimal, varchar at three tiers, text, and one pre-configured column)
and printed the resulting tab.Columns[i].ColWidth after generation -
every value matched InferColumnWidth's own table, and the
pre-configured column's 333 was left untouched.
2026-09-19 14:16:37 +08:00
zhangwenjian d65b21baf6 feat✨: field-level validation for sys_tables.go:357's Update (PRD 010 F10)
That bind-and-save path had zero field-level validation (API契约.md
§1.2/§2.1, decision D6), which left four ways to silently corrupt the
generator's own metadata or the language packs it writes:

  - jsonField had no format rule at all, unlike tableName/className/
    businessName, which all have a pattern check. A jsonField with a
    dot, a leading digit, or anything not matching lower camelCase
    still saved, and would land verbatim as a key segment in
    gen/{PackageName}/{BusinessName}.ts.
  - jsonField had no per-table uniqueness check. Two columns retitled
    to the same jsonField overwrite each other's generated i18n key
    with no warning.
  - businessName had no cross-table uniqueness check within a
    packageName. Two tables sharing one write the same language pack
    path and the second's generation silently clobbers the first's.
  - defaultValue is spliced into the generated defaultModel() as a
    literal, never evaluated (API契约.md §2.1) - so content shaped
    like a function call or block does not do what it looks like it
    does, and previously saved without complaint either way.

colWidth is handled differently on purpose: API契约.md §2.1 says an
out-of-range value should fall back to the inferred width rather than
be rejected, so it is reset to the 0 sentinel in place instead of
failing the request - same outcome as if it had never been set.

G10 (colliding with the built-in admin/* i18n namespace) is not one of
the four: D9 already moved generated keys into their own gen/
namespace, so that collision no longer exists.

All four checks and colWidth's sanitize-in-place path are covered by
sys_tables_validate_test.go. Confirmed red first: swapped in a no-op
stand-in for both validators and reran - 13 sub-tests that should now
be rejected or sanitized passed straight through instead (jsonField
format x5, jsonField uniqueness x1, colWidth range x2, defaultValue
expression x4, businessName uniqueness x1). Restored the real
implementation and reran - all green.
2026-09-19 14:08:05 +08:00
zhangwenjian e2b6ddb290 feat✨: generate per-table zh-CN/en-US language packs (PRD 010 F3/F9)
Add lang-zh.go.template and lang-en.go.template, one key per column
keyed by JsonField, valued from ColumnComment (R3) with a fallback to
JsonField when ColumnComment is blank (G11) - both locales resolve to
the same zh-CN text today since D3 rules out machine translation and
go-admin-ui's parity test rejects blank values.

NOActionsGen writes both files to lang/{locale}/gen/{PackageName}/
{BusinessName}.ts, two levels deep so go-admin-ui's gen-namespace.ts
glob (./*/*.ts under each locale's gen/) picks them up; nesting under
PackageName (rather than a flat gen/{BusinessName}.ts) avoids two
tables in different packages silently overwriting each other's
translations, since BusinessName has no uniqueness check.

Output has to be single-quoted with no trailing comma to satisfy
go-admin-ui's eslint config, which text/template's builtin `printf "%q"`
does not produce, hence the small parseGenTemplate/singleQuote helper
shared by the two templates.

Verified end to end: generated a real table's output (including a
blank-ColumnComment column, to exercise the G11 fallback), copied the
two language packs into go-admin-ui and ran vue-tsc --noEmit and eslint
against them - both clean, comma-dangle/quotes included.
2026-09-19 13:56:34 +08:00
zhangwenjian 28eba92077 feat✨: generate a typed .ts API module instead of .js (PRD 010 F5)
Rewrite template/v4/js.go.template (renamed to ts.go.template) to emit
TypeScript matching go-admin-ui's src/api/demo/product.ts: an interface
per row and per query params, typed CRUD functions, and a del{Class}
that takes Id[] like useRemove expects. GoType maps to number for
int/int64/float32/float64 and string otherwise, since go-admin-ui's
request() types the {code,data,msg} envelope rather than the payload.

Preview's response map key changes from template/js.go.template to
template/api.ts.template so its Tab label matches the new content;
NOActionsGen writes the file with a .ts extension.

Verified end to end: generated a real table's output, copied it into
go-admin-ui and ran vue-tsc --noEmit and eslint against it - both clean.
2026-09-19 13:55:56 +08:00
zhangwenjian 5ecb1e6e4c style💄: run gofmt over the tree
`gofmt -l` listed 26 files. Seventeen of them were missing the newline at the
end of the file; the rest are indentation that used spaces where the file uses
tabs, a handful of call sites written `f(a,b)`, and the doc comment spacing
gofmt has rewritten since 1.19 (`//X` to `// X`).

Nothing here changes behaviour: `go build ./...` and `go vet ./...` are clean
and `go test ./common/...` passes, which is the half of the tree these files
are concentrated in.

Only the files gofmt named are touched, so the diff reads line by line rather
than as a reflow of the whole repository. `gofmt -l` is now empty, which is the
precondition for gating it in CI -- worth doing, but a separate change.
2026-09-18 18:55:19 +08:00
zhangwenjian d01cdc040f fix🐛: accept the import table list from a JSON body as well
The generator's import reads its comma-separated table list with
c.Request.FormValue("tables"), which on a request declaring itself as JSON reads
the URL query and nothing else. go-admin-ui v3.2.0 began sending that list in
the body, so the handler saw an empty string, asked information_schema for a
table named "", and every import failed with "table name cannot be empty!" —
on a fresh installation that is the first thing the generator is asked to do.

tablesToImport reads the query first and falls back to the body, so a front end
sending either works against this server. It also drops blank entries:
splitting "" yields one empty name rather than nothing at all, which is why the
old code reached a database query at all before failing.

The front end sends the list in the query again on its side; this half is what
lets an installation already running v3.2.0 recover without changing it.
2026-09-16 17:57:51 +08:00
zhangwenjian 92b9af17b7 refactor🎨: name the empty-table-name message once
The string was spelled out at each site that raises it, and once more in the
test file that asserts on it. A test holding its own copy cannot tell the
difference between the handler answering something else and the message having
been reworded: it goes on asserting a string the server no longer sends, and
goes on passing.

The three copies in app/other/models/tools are left alone; they are raised from
a different layer and nothing asserts on them.
2026-09-16 17:57:37 +08:00
zhangwenjian 898e1b023a refactor🎨: share the generator tests' engine and response decoding
newEngine takes the method, path and handler, so a second test file does not
have to restate the sqlite connection, the driver override and its cleanup, the
CustomError middleware and the two context keys. serveJSON does the same for
running one request and decoding the envelope.

Nothing about what is asserted changes; newColumnListEngine and columnListMsg
keep their names and their callers.
2026-09-16 17:57:28 +08:00
zhangwenjian 04c6a081ae fix🐛: source=3 uploaded to aliyun, and neither provider was ever configured
thirdUpload dispatched on the source parameter and then built the same
zero-value ALiYunOSS in both branches, so source=3 could not have
reached qiniu even with credentials.

Neither branch had credentials to use. OXS.Setup is the initialisation
path and nothing in the repository called it, and no configuration field
existed to fill. The store is now taken from extend.fileStore, and a
provider that was not configured says so rather than producing the
provider's own complaint about an empty bucket name.

The two handlers passed errors.New("") to e.Error, discarding what
actually went wrong; they now pass the error.
2026-08-24 13:25:54 +08:00
zhangwenjian 8ffde94433 chore🔧: move to go-admin-core v2
Every import of the module changes, not only the seven packages that
moved out of sdk/pkg: Go requires the major version in the path from v2
on. Both happen in one pass —

    go run github.com/go-admin-team/go-admin-core/tools/coreupgrade@v2.0.0 -w -v2 .
    go mod tidy

— which is the command the release notes give, run here as a consumer
would run it. 210 imports across 95 files.

The compatibility shims this used are gone in v2, so the paths that
moved had to move: sdk/pkg/captcha, sdk/pkg/jwtauth and its user
package, sdk/pkg/response and sdk/pkg/casbin.

The count of unformatted files is unchanged at 34, none of them touched
by this: the tool reformats a file only if it was already gofmt clean,
so a migration cannot disappear into whitespace.
2026-08-23 13:26:46 +08:00
zhangwenjian d16f5e7180 fix🐛: db columns endpoint rejected exactly the valid requests
pkg.Assert panics when its condition is false, so
Assert(TableName == "", "table name cannot be empty") rejected every
request that carried a table name and let the empty one through. The
model layer repeated the inversion with if TableName != "" { return
error }, so either one alone was enough to break the endpoint.

Flip both, and hoist the model guard out of the mysql branch so it
matches GetList ten lines below, which had it right all along.
2026-08-23 13:19:15 +08:00
wenjianzhang 817e34c6aa refactor🎨: 重构文件上传逻辑,拆分处理函数以提高可读性和维护性 2025-04-13 22:20:06 +08:00
wenjianzhang 952cd92648 refactor🎨: 清理 sys_server_monitor.go 文件,移除未使用的导入并格式化代码 2025-04-13 22:17:17 +08:00
wenjianzhang 6b1e961a7f refactor🎨: 重构系统监控代码,拆分功能为多个函数以提高可读性和维护性 2025-04-13 22:15:10 +08:00
wenjianzhang 5494353229 fix🐛: 修复获取本地主机IP的函数调用错误 2025-04-08 20:30:24 +08:00
无别 0315631b53 Fix:err is never used
Fix the problem that err is overwritten and becomes invalid
2024-09-29 15:32:36 +08:00
wenjianzhang 37a5963cd6 perf👌: Optimize go warnings 2023-08-01 22:38:41 +08:00
zhangwenjian f114424079 fix🐛: fix monitor macos env error 2022-02-13 00:23:20 +08:00
zhangwenjian a45113258c refactor🎨: update request mode name 2021-07-15 00:43:06 +08:00
zhangwenjian dd22d55ee7 refactor🎨: request name cancel 2021-07-14 09:14:44 +08:00
zhangwenjian 1130d20f14 refactor🎨: dto》request 2021-07-05 00:03:38 +08:00
zhangwenjian 37d318b4d9 feat✨: vue-cli@3 升级为 vue-cli@4、Change Node Sass to Dart Sass、代码生成工具
1. vue-cli@3 升级为 vue-cli@4
2. Change Node Sass to Dart Sass
3. 代码生成工具
2021-07-04 05:46:20 +08:00
G-Akiraka 007807e776 增加磁盘列表主机名称与当前时间
上一个pr提交作废
2021-07-02 10:06:48 +08:00
zhangwenjian eb8062d19b refactor🎨: 生成逻辑调整 2021-06-30 22:36:26 +08:00
zhangwenjian dd5f0c52fb refactor🎨: 修改错误信息提示 2021-06-29 16:33:03 +08:00
zhangwenjian 3fd34db3c1 docs📝: 修改接口文档 2021-06-29 16:30:47 +08:00
zhangwenjian 0f623521c4 refactor🎨:代码生成功能迁移 2021-06-25 11:33:41 +08:00
zhangwenjian 25472887c9 refactor🎨:移除内容管理、行政区管理和资源管理 2021-06-18 21:34:57 +08:00
zhangwenjian a911e73238 refactor🎨:调整行政区命名 2021-06-17 21:45:37 +08:00
wenjianzhang d32751ea5d refactor🎨:文件上传修改为本地路径 2021-06-16 18:34:51 +08:00
wenjianzhang 9fb23b45cd Merge branch 'dev' 2021-06-15 12:25:46 +08:00
zhangwenjian 7699d8cf42 refactor🎨: 调整行政区管理相关 2021-06-15 09:29:35 +08:00
zhangwenjian 273f2ba8b0 fix🐛: merge 的遗漏 2021-06-13 23:20:30 +08:00
zhangwenjian da15a2d3bb refactor🎨: 调整SysChinaAreaData Api的函数名称以及路由引用 2021-06-13 21:24:09 +08:00
zhangwenjian 4a2aa02210 refactor🎨: 批量修改通过id获取详情返回消息 2021-06-13 21:14:17 +08:00
zhangwenjian a54d4ba0c1 format🥚 代码格式化 2021-05-31 18:10:23 +08:00
wenjianzhang b565b72cd3 feat ✨ 上传文件去掉默认标识验证 2021-05-25 19:37:19 +08:00
wenjianzhang 7880151ef2 refactor🎨 系统监控更名Monitor》ServerMonitor 2021-05-24 10:37:16 +08:00