Compare commits

...

168 Commits

Author SHA1 Message Date
renovate[bot] c547b00a5f chore(deps): Update module github.com/tnb-labs/acmez/v3 to v3.0.0-20250707093727-dc5aedd96413 (#868)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-07-07 20:07:40 +08:00
耗子 e5f837799f l10n: update translations (#867)
* New translations frontend.pot (Chinese Simplified)
Update translations (Chinese Simplified) frontend.pot

* New translations frontend.pot (Chinese Traditional)
Update translations (Chinese Traditional) frontend.pot

* New translations frontend.pot (Chinese Simplified)
Update translations (Chinese Simplified) frontend.pot

* New translations frontend.pot (Chinese Traditional)
Update translations (Chinese Traditional) frontend.pot

* New translations backend.pot (Chinese Simplified)
Update translations (Chinese Simplified) backend.pot

* New translations backend.pot (Chinese Traditional)
Update translations (Chinese Traditional) backend.pot
2025-07-07 18:35:01 +08:00
devhaozi 25194d8c50 chore: update mocks 2025-07-07 09:29:34 +00:00
devhaozi e1f6b291bb chore(l10n): update pot files 2025-07-07 09:29:31 +00:00
耗子 df9425b202 Merge remote-tracking branch 'origin/main' 2025-07-07 17:28:46 +08:00
耗子 c50a33f323 feat: 支持修改用户名,close #803 2025-07-07 17:28:40 +08:00
devhaozi b264381b84 chore(l10n): update pot files 2025-07-07 09:19:25 +00:00
耗子 d5ee789a61 Merge remote-tracking branch 'origin/main' 2025-07-07 17:18:40 +08:00
耗子 5fa4219a31 feat: 新增证书到期时间显示,close #836 2025-07-07 17:18:35 +08:00
devhaozi 430640e93c chore(l10n): update pot files 2025-07-07 08:50:36 +00:00
耗子 135c5c844f Merge remote-tracking branch 'origin/main' 2025-07-07 16:49:59 +08:00
耗子 05721dbb47 feat: 优化注销时session处理 2025-07-07 16:49:53 +08:00
renovate[bot] 0235679821 chore(deps): Update dependency @iconify/json to v2.2.356 (#866)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-07-07 15:59:50 +08:00
devhaozi 11e206b41a chore(l10n): update pot files 2025-07-07 07:19:51 +00:00
耗子 4985eb2e1f feat: remove CleanPath middleware 2025-07-07 15:19:15 +08:00
耗子 2181653ff7 Merge remote-tracking branch 'origin/main' 2025-07-07 15:01:37 +08:00
耗子 26f7edaa24 feat: remove CleanPath middleware 2025-07-07 15:01:31 +08:00
renovate[bot] 75078c88d9 chore(deps): Lock file maintenance (#865)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-07-07 05:28:46 +00:00
耗子 329aecb444 chore: fix typo 2025-07-07 04:27:53 +08:00
耗子 1559c9f8d3 chore: Update SECURITY.md 2025-07-07 04:26:00 +08:00
renovate[bot] 26add61117 chore(deps): Update dependency vue-tsc to v3.0.1 (#864)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-07-07 03:59:10 +08:00
renovate[bot] 763c625b83 chore(deps): Update dependency vue-tsc to v3 (#857)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-07-07 03:44:01 +08:00
renovate[bot] 1375de2caa chore(deps): Update dependency cronstrue to v3 (#856)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-07-07 03:43:51 +08:00
耗子 c4b84632b4 Merge remote-tracking branch 'origin/main' 2025-07-07 03:04:26 +08:00
耗子 c20bfdc3ea fix: sqlite dsn error 2025-07-07 03:04:20 +08:00
devhaozi cc55aef306 chore(l10n): update pot files 2025-07-06 18:48:45 +00:00
耗子 ed5c74c753 fix: 优化路由路径获取方式 2025-07-07 02:47:59 +08:00
renovate[bot] 5a9ccddabd chore(deps): Update non-major dependencies to v66.3.3 (#863)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-07-06 12:50:23 +00:00
renovate[bot] e6b82ab9ae chore(deps): Update non-major dependencies (#861)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-07-04 16:35:31 +00:00
renovate[bot] 8868a125e2 chore(deps): Update non-major dependencies (#860)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-07-03 19:53:11 +00:00
renovate[bot] 04474acf5f chore(deps): Update non-major dependencies (#859)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-07-02 21:51:46 +00:00
renovate[bot] 6a17173b3b chore(deps): Update non-major dependencies (#858)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-07-02 07:13:02 +00:00
renovate[bot] 711fb33b48 chore(deps): Update non-major dependencies (#855)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-06-30 23:30:16 +00:00
renovate[bot] 3ed8fb4f95 chore(deps): Lock file maintenance (#854)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-06-30 06:26:07 +00:00
renovate[bot] 65944a72ec chore(deps): Update module go.yaml.in/yaml/v3 to v3.0.4 (#853)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-06-30 03:41:36 +08:00
renovate[bot] 24d18df86b chore(deps): Update dependency unplugin-vue-components to v28.8.0 (#852)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-06-29 06:12:30 +00:00
renovate[bot] b330763746 chore(deps): Update dependency pinia-plugin-persistedstate to v4.4.0 (#851)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-06-28 22:27:00 +00:00
renovate[bot] 2e914ea41a chore(deps): Update dependency @types/node to v22.15.34 (#850)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-06-28 12:40:54 +00:00
renovate[bot] 85a5d22861 chore(deps): Update dependency eslint to v9.30.0 (#849)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-06-28 02:13:54 +00:00
renovate[bot] 9f31a2061d chore(deps): Update non-major dependencies (#847)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-06-27 22:14:08 +08:00
renovate[bot] d1b54c2690 chore(deps): Update dependency marked to v16 (#848)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-06-27 22:13:59 +08:00
renovate[bot] 029f86d9d5 chore(deps): Update non-major dependencies (#846)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-06-26 21:56:28 +00:00
renovate[bot] 9de30f30b8 chore(deps): Update non-major dependencies to v66.3.2 (#845)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-06-26 06:10:46 +00:00
renovate[bot] 8582bfc36b chore(deps): Update non-major dependencies (#844)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-06-25 19:22:49 +00:00
renovate[bot] 4a2af3434c chore(deps): Update dependency @types/node to v22.15.33 (#843)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-06-25 01:10:46 +00:00
renovate[bot] 7f697ca734 chore(deps): Update dependency @vitejs/plugin-vue to v6 (#841)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-06-24 23:15:50 +08:00
renovate[bot] 7f08ee92ff chore(deps): Update dependency vite to v7 (#842)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-06-24 22:30:31 +08:00
renovate[bot] 2f09043915 chore(deps): Update dependency @iconify/json to v2.2.352 (#840)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-06-24 13:58:06 +00:00
renovate[bot] 50aab262a8 chore(deps): Update module github.com/ncruces/go-sqlite3 to v0.26.2 (#839)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-06-24 16:08:41 +08:00
renovate[bot] 99b033f070 chore(deps): Update non-major dependencies (#838)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-06-23 10:49:59 +00:00
renovate[bot] 6277a17d53 chore(deps): Lock file maintenance (#837)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-06-23 15:25:46 +08:00
耗子 8bb6bd1882 feat: 替换弃用的gopkg.in/yaml.v3包 2025-06-22 20:14:27 +08:00
dependabot[bot] 3161c61001 chore(deps): bump github.com/go-chi/chi/v5 (#834)
Bumps the go_modules group with 1 update in the / directory: [github.com/go-chi/chi/v5](https://github.com/go-chi/chi).


Updates `github.com/go-chi/chi/v5` from 5.2.1 to 5.2.2
- [Release notes](https://github.com/go-chi/chi/releases)
- [Changelog](https://github.com/go-chi/chi/blob/master/CHANGELOG.md)
- [Commits](https://github.com/go-chi/chi/compare/v5.2.1...v5.2.2)

---
updated-dependencies:
- dependency-name: github.com/go-chi/chi/v5
  dependency-version: 5.2.2
  dependency-type: direct:production
  dependency-group: go_modules
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-06-21 03:25:49 +08:00
renovate[bot] e68a882e75 chore(deps): Update non-major dependencies (#833)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-06-20 17:01:30 +00:00
耗子 24066f05fc l10n: update translations (#832)
* New translations backend.pot (Chinese Simplified)
Update translations (Chinese Simplified) backend.pot

* New translations backend.pot (Chinese Traditional)
Update translations (Chinese Traditional) backend.pot
2025-06-20 13:36:39 +08:00
renovate[bot] 28325f4af6 chore(deps): Update non-major dependencies (#831)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-06-19 23:04:31 +00:00
renovate[bot] 0c57e9d628 chore(deps): Update dependency vue to v3.5.17 (#830)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-06-19 03:14:04 +00:00
renovate[bot] 8fb7ddcf7a chore(deps): Update dependency @iconify/json to v2.2.350 (#829)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-06-18 12:56:47 +00:00
renovate[bot] 76185a97f3 chore(deps): Update non-major dependencies to v66.2.3 (#828)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-06-18 01:11:14 +00:00
renovate[bot] 567ef561c7 chore(deps): Update non-major dependencies to v66.2.2 (#827)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-06-17 21:03:27 +08:00
renovate[bot] b70b9df0b7 chore(deps): Update dependency @vue/eslint-config-typescript to v14.5.1 (#826)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-06-17 20:56:24 +08:00
耗子 0e4fbea166 Merge remote-tracking branch 'origin/main' 2025-06-17 20:03:26 +08:00
耗子 6cf4e0c0cc feat: 数据库添加_txlock=immediate参数 2025-06-17 20:03:07 +08:00
耗子 68da337cc0 Merge remote-tracking branch 'origin/main' 2025-06-17 09:06:23 +08:00
耗子 c492639897 fix: 优化手动dns签发 2025-06-17 09:06:05 +08:00
renovate[bot] 5e10b2267e chore(deps): Update non-major dependencies (#824)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-06-16 22:43:54 +00:00
renovate[bot] 68bbbc76e2 chore(deps): Lock file maintenance (#823)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-06-16 05:34:04 +00:00
renovate[bot] 7cd1c764d2 chore(deps): Update non-major dependencies (#821)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-06-16 00:06:33 +08:00
耗子 a053a4212a feat: 屏蔽github.com/libdns/cloudns更新 2025-06-15 23:54:34 +08:00
耗子 2d0974a5d5 Merge remote-tracking branch 'origin/main' 2025-06-14 18:00:35 +08:00
耗子 d90396c8ea fix: 出站规则下,必须指定具体的地址,否则会添加成入站规则,close #822 2025-06-14 18:00:28 +08:00
renovate[bot] 877d9c57c8 chore(deps): Update non-major dependencies (#820)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-06-13 21:32:05 +00:00
devhaozi 275760c18a chore(l10n): update pot files 2025-06-13 05:35:09 +00:00
dependabot[bot] 9dd6063611 chore(deps): bump brace-expansion (#817)
Bumps the npm_and_yarn group with 1 update in the /web directory: [brace-expansion](https://github.com/juliangruber/brace-expansion).


Updates `brace-expansion` from 1.1.11 to 1.1.12
- [Release notes](https://github.com/juliangruber/brace-expansion/releases)
- [Commits](https://github.com/juliangruber/brace-expansion/compare/1.1.11...v1.1.12)

---
updated-dependencies:
- dependency-name: brace-expansion
  dependency-version: 1.1.12
  dependency-type: indirect
  dependency-group: npm_and_yarn
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-06-13 13:34:32 +08:00
耗子 0acbb05d3f fix: 安全登录启用时,可能出现反复跳转登录页的问题 2025-06-13 02:42:20 +08:00
renovate[bot] d860e9361a chore(deps): Update non-major dependencies (#819)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-06-13 00:56:30 +08:00
renovate[bot] 97d76f62ae chore(deps): Update non-major dependencies (#816)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-06-12 12:51:30 +00:00
renovate[bot] 910a2d92cc chore(deps): Update non-major dependencies (#815)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-06-11 17:05:57 +08:00
renovate[bot] 76ef54fe0e chore(deps): Update stefanzweifel/git-auto-commit-action action to v6 (#813)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-06-11 16:42:36 +08:00
renovate[bot] bf41b98339 chore(deps): Update dependency tsx to v4.20.0 (#814)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-06-11 06:54:10 +00:00
renovate[bot] f3cec5e476 chore(deps): Update non-major dependencies (#812)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-06-10 13:28:58 +00:00
renovate[bot] bb5b66958c chore(deps): Update non-major dependencies (#811)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-06-09 22:59:48 +00:00
renovate[bot] 04fb0a1de8 chore(deps): Lock file maintenance (#810)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-06-09 07:43:45 +00:00
renovate[bot] f7752387da chore(deps): Update non-major dependencies (#809)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-06-09 00:28:06 +00:00
耗子 a7420eef34 l10n: update translations (#808)
* New translations frontend.pot (Chinese Simplified)
Update translations (Chinese Simplified) frontend.pot

* New translations frontend.pot (Chinese Traditional)
Update translations (Chinese Traditional) frontend.pot
2025-06-08 15:54:56 +08:00
耗子 28847bcc1f l10n: update translations (#807)
* New translations frontend.pot (Chinese Simplified)
Update translations (Chinese Simplified) frontend.pot

* New translations frontend.pot (Chinese Traditional)
Update translations (Chinese Traditional) frontend.pot

* New translations backend.pot (Chinese Simplified)
Update translations (Chinese Simplified) backend.pot

* New translations backend.pot (Chinese Traditional)
Update translations (Chinese Traditional) backend.pot

* New translations frontend.pot (Chinese Simplified)
Update translations (Chinese Simplified) frontend.pot

* New translations frontend.pot (Chinese Traditional)
Update translations (Chinese Traditional) frontend.pot
2025-06-08 15:53:38 +08:00
devhaozi cb24946aea chore(l10n): update pot files 2025-06-08 07:37:44 +00:00
耗子 371424114a Merge remote-tracking branch 'origin/main' 2025-06-08 15:36:57 +08:00
耗子 60086b9839 fix: 优化翻译 2025-06-08 15:36:50 +08:00
devhaozi 6d55088a0d chore(l10n): update pot files 2025-06-08 07:33:51 +00:00
耗子 c4234a11f2 Merge remote-tracking branch 'origin/main' 2025-06-08 15:32:51 +08:00
耗子 7644e1a5f6 feat: 优化防火墙创建规则 2025-06-08 15:32:45 +08:00
renovate[bot] f8a54b2860 chore(deps): Update non-major dependencies (#805)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-06-08 06:41:01 +00:00
renovate[bot] 8c1813b9e5 chore(deps): Update non-major dependencies (#804)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-06-08 01:45:07 +08:00
renovate[bot] 7a9a803451 chore(deps): Update non-major dependencies (#802)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-06-07 02:49:15 +00:00
renovate[bot] 681d0b5324 chore(deps): Update dependency @iconify/json to v2.2.346 (#801)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-06-05 16:24:31 +00:00
devhaozi a33490b316 chore(l10n): update pot files 2025-06-05 03:24:31 +00:00
耗子 fb95ff2861 fix: 登录后访问安全入口404 2025-06-05 11:23:18 +08:00
renovate[bot] 326c2585f3 chore(deps): Update module github.com/golang-cz/httplog to v0.0.2 (#800)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-06-04 20:57:18 +00:00
renovate[bot] 61cc26cdb0 chore(deps): Update non-major dependencies (#798)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-06-05 00:38:46 +08:00
devhaozi 2ecd3a020b chore(l10n): update pot files 2025-06-03 20:21:46 +00:00
耗子 c5b23feeac fix: 模态窗点击遮罩关闭时自动重置数据 2025-06-04 04:20:51 +08:00
renovate[bot] 4f39f62208 chore(deps): Update module github.com/expr-lang/expr to v1.17.5 (#797)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-06-04 03:46:32 +08:00
renovate[bot] 146401e9f9 chore(deps): Update github.com/golang-cz/httplog digest to 1a554d4 (#796)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-06-03 22:53:14 +08:00
renovate[bot] d544ca6a90 chore(deps): Update dependency md-editor-v3 to v5.6.1 (#795)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-06-03 22:27:14 +08:00
renovate[bot] 43248c1d88 chore(deps): Update non-major dependencies (#794)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-06-02 21:59:27 +00:00
renovate[bot] 2b5bb04bbd chore(deps): Lock file maintenance (#793)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-06-02 21:46:38 +08:00
renovate[bot] 30a5427778 chore(deps): Update non-major dependencies (#792)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-06-02 21:36:42 +08:00
耗子 c547200c05 l10n: update translations (#790)
* New translations backend.pot (Chinese Simplified)
Update translations (Chinese Simplified) backend.pot

* New translations backend.pot (Chinese Traditional)
Update translations (Chinese Traditional) backend.pot
2025-05-31 20:45:22 +08:00
耗子 7f223812dc ci: 优化l10n工作流 2025-05-31 19:55:39 +08:00
耗子 0e86c77d6d Merge remote-tracking branch 'origin/main' 2025-05-31 19:54:29 +08:00
耗子 fb24407cd1 ci: 优化l10n工作流 2025-05-31 19:54:24 +08:00
devhaozi ec7791b73d chore(l10n): update frontend pot files 2025-05-31 11:51:39 +00:00
耗子 7987cec9b9 feat: 优化编排删除 2025-05-31 19:51:09 +08:00
耗子 7be3e799be l10n: update translations (#789)
* New translations frontend.pot (Chinese Simplified)
Update translations (Chinese Simplified) frontend.pot

* New translations frontend.pot (Chinese Traditional)
Update translations (Chinese Traditional) frontend.pot

* New translations frontend.pot (Chinese Simplified)
Update translations (Chinese Simplified) frontend.pot

* New translations backend.pot (Chinese Simplified)
Update translations (Chinese Simplified) backend.pot

* New translations backend.pot (Chinese Traditional)
Update translations (Chinese Traditional) backend.pot

* New translations frontend.pot (Chinese Simplified)
Update translations (Chinese Simplified) frontend.pot

* New translations frontend.pot (Chinese Traditional)
Update translations (Chinese Traditional) frontend.pot

* New translations backend.pot (Chinese Simplified)
Update translations (Chinese Simplified) backend.pot

* New translations backend.pot (Chinese Traditional)
Update translations (Chinese Traditional) backend.pot

* New translations backend.pot (Chinese Simplified)
Update translations (Chinese Simplified) backend.pot

* New translations backend.pot (Chinese Traditional)
Update translations (Chinese Traditional) backend.pot
2025-05-31 19:41:34 +08:00
devhaozi 5667bb236f chore(l10n): update backend pot files 2025-05-31 11:25:35 +00:00
devhaozi 5a391a459e chore(l10n): update frontend pot files 2025-05-31 11:22:36 +00:00
耗子 60b0761de2 Merge remote-tracking branch 'origin/main' 2025-05-31 19:22:07 +08:00
耗子 952546f845 fix: 优化编排显示 2025-05-31 19:22:01 +08:00
devhaozi b7c055c43f chore(l10n): update backend pot files 2025-05-31 10:48:42 +00:00
耗子 ba4df0c76f feat: 调试模式下安装应用不检查面板版本 2025-05-31 18:48:06 +08:00
耗子 dfae3f1d8d Merge remote-tracking branch 'origin/main' 2025-05-31 17:35:43 +08:00
耗子 310d83a2aa fix: 面板容器管理界面无法删除卷,close #786 2025-05-31 17:35:37 +08:00
devhaozi 77eb802076 chore(l10n): update frontend pot files 2025-05-31 09:24:21 +00:00
耗子 913a6776dc Merge remote-tracking branch 'origin/main' 2025-05-31 17:23:53 +08:00
耗子 f245ff06c5 fix: 创建数据库用户时如果赋予权限的数据库不存在时显示异常,close #785 2025-05-31 17:23:47 +08:00
devhaozi 79901878e6 chore(l10n): update frontend pot files 2025-05-31 08:37:59 +00:00
耗子 c597e6b99c fix: 创建用户界面里的服务器数据库选择列表重复显示,close #784 2025-05-31 16:37:24 +08:00
devhaozi 3c98e6ff37 chore(l10n): update frontend pot files 2025-05-31 07:43:11 +00:00
耗子 447b0332e3 fix: 容器端口映射显示相反,close #788 2025-05-31 15:42:40 +08:00
renovate[bot] 1459b287fa chore(deps): Update non-major dependencies (#783)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-05-31 04:44:27 +00:00
renovate[bot] 252b67ce36 chore(deps): Update dependency @types/node to v22.15.28 (#782)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-05-31 01:46:07 +08:00
renovate[bot] 8119eca0c6 chore(deps): Update non-major dependencies to v66.1.3 (#781)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-05-31 01:30:04 +08:00
renovate[bot] f0b96417bf chore(deps): Update non-major dependencies (#779)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-05-30 15:06:46 +08:00
renovate[bot] b8018284c6 chore(deps): Update dependency vue to v3.5.16 (#778)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-05-29 05:22:29 +00:00
renovate[bot] 737986f218 chore(deps): Update dependency @types/node to v22.15.24 (#777)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-05-29 04:13:25 +08:00
renovate[bot] 200815bf10 chore(deps): Update non-major dependencies (#775)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-05-28 14:01:11 +08:00
renovate[bot] 8cff4e3575 chore(deps): Update non-major dependencies (#772)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-05-28 03:27:10 +00:00
耗子 64c39bd462 Merge remote-tracking branch 'origin/main' 2025-05-27 00:02:22 +08:00
耗子 4a5e629ab1 feat: 更新文档链接 2025-05-27 00:02:16 +08:00
renovate[bot] 368519f3fa chore(deps): Update dependency vue to v3.5.15 (#771)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-05-26 23:59:12 +08:00
耗子 8fa7f4a22b l10n: update translations (#770)
* New translations frontend.pot (Chinese Simplified)
Update translations (Chinese Simplified) frontend.pot

* New translations frontend.pot (Chinese Traditional)
Update translations (Chinese Traditional) frontend.pot

* New translations backend.pot (Chinese Simplified)
Update translations (Chinese Simplified) backend.pot

* New translations backend.pot (Chinese Traditional)
Update translations (Chinese Traditional) backend.pot
2025-05-26 23:37:38 +08:00
耗子 a8e4360c29 feat: 调整排版 2025-05-26 20:19:50 +08:00
耗子 719a9a580d feat: 添加安装脚本到文档 2025-05-26 20:18:44 +08:00
耗子 fb32151b76 feat: 优化排版 2025-05-26 20:15:09 +08:00
耗子 c50d892e52 Merge remote-tracking branch 'origin/main' 2025-05-26 20:11:32 +08:00
耗子 b31ccace85 feat: 更新logo 2025-05-26 20:11:27 +08:00
耗子 e57da7e41a l10n: update translations (#769)
* New translations backend.pot (Chinese Simplified)
Update translations (Chinese Simplified) backend.pot

* New translations backend.pot (Chinese Traditional)
Update translations (Chinese Traditional) backend.pot
2025-05-26 19:59:53 +08:00
耗子 38141c3f4e l10n: update translations (#768)
* New translations frontend.pot (Chinese Simplified)
Update translations (Chinese Simplified) frontend.pot

* New translations frontend.pot (Chinese Traditional)
Update translations (Chinese Traditional) frontend.pot
2025-05-26 16:29:23 +08:00
renovate[bot] 69d39e6c67 chore(deps): Update non-major dependencies (#767)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-05-26 15:50:46 +08:00
devhaozi 4d8a330644 chore(l10n): update frontend pot files 2025-05-26 07:36:35 +00:00
耗子 26c417f18d ci: fix pnpm 2025-05-26 15:36:05 +08:00
耗子 f6b7fcb4af Merge remote-tracking branch 'origin/main' 2025-05-26 15:32:29 +08:00
耗子 212e989782 feat: 更新包 2025-05-26 15:32:23 +08:00
devhaozi d0ece55dd1 chore(l10n): update backend pot files 2025-05-25 16:35:01 +00:00
耗子 03c0b191fe feat: 支持cidr,close #764 2025-05-26 00:34:24 +08:00
耗子 adacee1851 l10n: update translations (#763)
* New translations frontend.pot (Chinese Simplified)
Update translations (Chinese Simplified) frontend.pot

* New translations frontend.pot (Chinese Traditional)
Update translations (Chinese Traditional) frontend.pot
2025-05-24 23:48:42 +08:00
devhaozi 2725c4902d chore(l10n): update frontend pot files 2025-05-24 14:44:55 +00:00
耗子 77d7539880 feat: 优化登录翻译 2025-05-24 22:44:24 +08:00
耗子 560b80038e fix: 404时标题为undefined 2025-05-24 22:38:12 +08:00
耗子 c9d4c79bf8 l10n: update translations (#761)
* New translations backend.pot (Chinese Simplified)
Update translations (Chinese Simplified) backend.pot

* New translations backend.pot (Chinese Traditional)
Update translations (Chinese Traditional) backend.pot
2025-05-24 15:29:53 +08:00
devhaozi 905f13f0d3 chore(l10n): update backend pot files 2025-05-24 07:16:29 +00:00
耗子 e7128c65d9 Merge remote-tracking branch 'origin/main' 2025-05-24 15:16:02 +08:00
耗子 c15e3cc3ae fix: 优化访问入口检查 2025-05-24 15:15:57 +08:00
devhaozi d9f1145d93 chore(l10n): update backend pot files 2025-05-24 07:10:58 +00:00
耗子 0aafe8baa3 fix: 优化访问入口检查 2025-05-24 15:10:30 +08:00
devhaozi 7b0e9db8dc chore(l10n): update backend pot files 2025-05-24 06:58:24 +00:00
耗子 07881311b3 fix: 优化访问入口检查,fix #760 2025-05-24 14:57:53 +08:00
75 changed files with 3131 additions and 3418 deletions
Binary file not shown.

Before

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 42 KiB

+1
View File
@@ -13,6 +13,7 @@ jobs:
- name: Setup pnpm
uses: pnpm/action-setup@v4
with:
version: latest
run_install: true
package_json_file: web/package.json
- name: Setup Node.js
+1
View File
@@ -21,6 +21,7 @@ jobs:
- name: Setup pnpm
uses: pnpm/action-setup@v4
with:
version: latest
run_install: true
package_json_file: web/package.json
- name: Setup Node.js
+16 -29
View File
@@ -4,11 +4,23 @@ on:
branches:
- main
jobs:
xgotext:
l10n:
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Setup pnpm
uses: pnpm/action-setup@v4
with:
version: latest
run_install: true
package_json_file: web/package.json
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: 22
cache: 'pnpm'
cache-dependency-path: web/pnpm-lock.yaml
- name: Setup Go
uses: actions/setup-go@v5
with:
@@ -20,33 +32,8 @@ jobs:
- name: Generate pot files
run: |
~/go/bin/xgotext -default backend -pkg-tree ./cmd/web -out ./pkg/embed/locales
git pull
- uses: stefanzweifel/git-auto-commit-action@v5
cd web && pnpm run gettext:extract
- uses: stefanzweifel/git-auto-commit-action@v6
name: Commit changes
with:
commit_message: "chore(l10n): update backend pot files"
vue3-gettext:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Setup pnpm
uses: pnpm/action-setup@v4
with:
run_install: true
package_json_file: web/package.json
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: 22
cache: 'pnpm'
cache-dependency-path: web/pnpm-lock.yaml
- name: Generate pot files and merge po files
working-directory: web
run: |
pnpm run gettext:extract
git pull
- uses: stefanzweifel/git-auto-commit-action@v5
name: Commit changes
with:
commit_message: "chore(l10n): update frontend pot files"
commit_message: "chore(l10n): update pot files"
+1
View File
@@ -46,6 +46,7 @@ jobs:
- name: Setup pnpm
uses: pnpm/action-setup@v4
with:
version: latest
run_install: true
package_json_file: web/package.json
- name: Setup Node.js
+1 -1
View File
@@ -21,7 +21,7 @@ jobs:
run: |
~/go/bin/mockery
git pull
- uses: stefanzweifel/git-auto-commit-action@v5
- uses: stefanzweifel/git-auto-commit-action@v6
name: Commit changes
with:
commit_message: "chore: update mocks"
+1 -1
View File
@@ -57,7 +57,7 @@ upx:
archives:
- id: panel
builds:
ids:
- web
- cli
formats: ["zip"]
+28 -30
View File
@@ -26,45 +26,43 @@
3. **追随时代:** 整体设计走在时代前沿,对新系统兼容性好,在同类产品中处于领先地位
4. **高效运维:** 功能完善,自定义能力强,既可快速部署小型网站,也可基于定制化需求部署复杂应用
5. **离线运行:** 支持离线模式,甚至可以在部署完成后停止面板进程,不会对已有服务造成任何影响
6. **安全稳定:** 面板采用业界多种技术保障本体安全性,已在我们的多个生环境中长期稳定运行
6. **安全稳定:** 面板采用业界多种技术保障本体安全性,已在我们的多个生环境中长期稳定运行
7. **全面开源:** 少有的全开源面板,您可以在遵守开源协议的前提下对面板自由修改、二次开发
8. **全面开源:** 承诺面板本体未来不会引入任何收费/授权功能,永久免费使用
8. **永久免费:** 承诺面板本体未来不会引入任何收费/授权功能,永久免费使用
## 快速安装
支持 `amd64` | `arm64` 架构下的干净的主流系统,具体支持的系统请参考[安装文档](https://ratpanel.github.io/zh_CN/quickstart/install)。
```shell
curl -fsLm 10 -o install.sh https://dl.cdn.haozi.net/panel/install.sh && bash install.sh
```
## UI 截图
![UI 截图](.github/assets/ui.png)
## 快速安装
[https://ratpanel.github.io/quickstart/install.html](https://ratpanel.github.io/quickstart/install.html)
## 合作伙伴
如果耗子面板对您有帮助,欢迎赞助我们,同时感谢以下支持者/赞助商的支持:
如果耗子面板对您有帮助,欢迎[赞助我们](https://github.com/tnb-labs/panel/issues/90),同时感谢以下支持者/赞助商的支持:
![支付宝](https://github.com/user-attachments/assets/d000b147-6da1-467a-9d80-9a3e8078602a) ![微信](https://github.com/user-attachments/assets/a53ff212-7076-487e-88bd-c93f6e98df1d)
<a href="https://www.weixiaoduo.com/">
<img height="80" src=".github/assets/wxd.png" alt="微晓朵">
</a>
<a href="https://www.dkdun.cn/aff/MQZZNVHQ">
<img height="80" src=".github/assets/dk.png" alt="林枫云">
</a>
<a href="https://su.sctes.com/register?code=8st689ujpmm2p">
<img height="80" src=".github/assets/sctes.png" alt="无畏云加速">
</a>
<a href="https://su.sctes.com/register?code=8st689ujpmm2p">
<img height="80" src=".github/assets/wafpro.png" alt="WAFPRO">
</a>
<a href="https://scdn.ddunyun.com/">
<img height="80" src=".github/assets/ddunyun.png" alt="盾云SCDN">
</a>
<a href="https://hongtoutong.com">
<img height="80" src=".github/assets/htt.png" alt="红透通">
</a>
<a href="https://1ms.run">
<img height="80" src=".github/assets/1ms.svg" alt="毫秒镜像提供经过审核的 Docker 镜像加速服务">
</a>
<p align="center">
<a href="https://www.weixiaoduo.com/">
<img height="60" src=".github/assets/wxd.png" alt="微晓朵">
</a>
<a href="https://www.dkdun.cn/aff/MQZZNVHQ">
<img height="60" src=".github/assets/dk.png" alt="林枫云">
</a>
<a href="https://waf.pro/">
<img height="60" src=".github/assets/wafpro.png" alt="WAFPRO">
</a>
<a href="https://scdn.ddunyun.com/">
<img height="60" src=".github/assets/ddunyun.png" alt="盾云SCDN">
</a>
<a href="https://1ms.run/">
<img height="60" src=".github/assets/1ms.svg" alt="毫秒镜像">
</a>
</p>
<p align="center">
<a target="_blank" href="https://afdian.com/a/tnblabs">
+26 -28
View File
@@ -30,41 +30,39 @@ Website: [panel.haozi.net](https://panel.haozi.net) | QQ group: [12370907](https
7. **Fully Open Source:** Few fully open source panels, you can freely modify and develop the panel on the premise of complying with the open source agreement
8. **Permanently free:** Commit to the panel body will not introduce any charging/authorization functions in the future, and will be permanently free to use
## Quick Install
Supported clean mainstream systems under `amd64` | `arm64` architecture, please refer to the [installation documentation](https://ratpanel.github.io/quickstart/install) for specific supported systems.
```shell
curl -fsLm 10 -o install.sh https://dl.cdn.haozi.net/panel/install.sh && bash install.sh
```
## UI Screenshots
![UI Screenshots](.github/assets/ui.png)
## Quick Install
[https://ratpanel.github.io/quickstart/install.html](https://ratpanel.github.io/quickstart/install.html)
## Partners
If the Rat Panel is helpful to you, welcome to sponsor us, also thanks to the following supporters/sponsors:
If the Rat Panel is helpful to you, welcome to [sponsor us](https://github.com/tnb-labs/panel/issues/90), also thanks to the following supporters/sponsors:
![Alipay](https://github.com/user-attachments/assets/d000b147-6da1-467a-9d80-9a3e8078602a) ![WeChat](https://github.com/user-attachments/assets/a53ff212-7076-487e-88bd-c93f6e98df1d)
<a href="https://www.weixiaoduo.com/">
<img height="80" src=".github/assets/wxd.png" alt="微晓朵">
</a>
<a href="https://www.dkdun.cn/aff/MQZZNVHQ">
<img height="80" src=".github/assets/dk.png" alt="林枫云">
</a>
<a href="https://su.sctes.com/register?code=8st689ujpmm2p">
<img height="80" src=".github/assets/sctes.png" alt="无畏云加速">
</a>
<a href="https://su.sctes.com/register?code=8st689ujpmm2p">
<img height="80" src=".github/assets/wafpro.png" alt="WAFPRO">
</a>
<a href="https://scdn.ddunyun.com/">
<img height="80" src=".github/assets/ddunyun.png" alt="盾云SCDN">
</a>
<a href="https://hongtoutong.com">
<img height="80" src=".github/assets/htt.png" alt="红透通">
</a>
<a href="https://1ms.run">
<img height="80" src=".github/assets/1ms.svg" alt="毫秒镜像提供经过审核的 Docker 镜像加速服务">
</a>
<p align="center">
<a href="https://www.weixiaoduo.com/">
<img height="60" src=".github/assets/wxd.png" alt="微晓朵">
</a>
<a href="https://www.dkdun.cn/aff/MQZZNVHQ">
<img height="60" src=".github/assets/dk.png" alt="林枫云">
</a>
<a href="https://waf.pro/">
<img height="60" src=".github/assets/wafpro.png" alt="WAFPRO">
</a>
<a href="https://scdn.ddunyun.com/">
<img height="60" src=".github/assets/ddunyun.png" alt="盾云SCDN">
</a>
<a href="https://1ms.run/">
<img height="60" src=".github/assets/1ms.svg" alt="毫秒镜像">
</a>
</p>
<p align="center">
<a target="_blank" href="https://afdian.com/a/tnblabs">
+2 -2
View File
@@ -9,7 +9,7 @@
提前感谢您的支持与帮助!
致某些安全初学者:通过面板 `session` / `access_token` 执行的任何操作(包括且不限于:获取 root 权限、读取/写入系统敏感文件、执行任意 shell 命令等)均不被认为是安全问题,请不要刷此类报告浪费彼此的时间,这类低水平的报告对你的简历也没有任何帮助
致某些安全初学者:通过已登录面板 `session` / `access_token` 执行的任何操作(包括且不限于:获取 root 权限、读取/写入系统敏感文件、执行任意 shell 命令等)均不被认为是安全问题,请不要刷此类报告浪费彼此的时间。
## Security Policy
@@ -22,4 +22,4 @@ If you find any security issues while using the panel, please do not submit an I
Thank you in advance for your support and help!
To some security beginners: Any operation performed through the panel `session` / `access_token` (including but not limited to: obtaining root permissions, reading/writing sensitive system files, executing arbitrary shell commands, etc.) is not considered a security issue. Please do not waste each other's time by submitting such reports. Such low-level reports are of no help to your resume.
To some security beginners: Any operation performed through an already logged-in panel's `session` / `access_token` (including but not limited to: obtaining root permissions, reading/writing sensitive system files, executing arbitrary shell commands, etc.) is not considered a security issue. Please do not waste each other's time by submitting such reports.
-3
View File
@@ -1,3 +0,0 @@
# cmd
cmd 目录存放应用的入口文件。
+1 -1
View File
@@ -61,7 +61,7 @@ func initCli() (*app.Cli, error) {
cacheRepo := data.NewCacheRepo(db)
queue := bootstrap.NewQueue()
taskRepo := data.NewTaskRepo(locale, db, logger, queue)
appRepo := data.NewAppRepo(locale, db, cacheRepo, taskRepo)
appRepo := data.NewAppRepo(locale, koanf, db, cacheRepo, taskRepo)
userRepo := data.NewUserRepo(locale, db)
settingRepo := data.NewSettingRepo(locale, db, koanf, taskRepo)
databaseServerRepo := data.NewDatabaseServerRepo(locale, db, logger)
+1 -1
View File
@@ -67,7 +67,7 @@ func initWeb() (*app.Web, error) {
cacheRepo := data.NewCacheRepo(db)
queue := bootstrap.NewQueue()
taskRepo := data.NewTaskRepo(locale, db, logger, queue)
appRepo := data.NewAppRepo(locale, db, cacheRepo, taskRepo)
appRepo := data.NewAppRepo(locale, koanf, db, cacheRepo, taskRepo)
userTokenRepo := data.NewUserTokenRepo(locale, db)
middlewares := middleware.NewMiddlewares(koanf, logger, manager, appRepo, userTokenRepo)
userRepo := data.NewUserRepo(locale, db)
+23 -22
View File
@@ -7,26 +7,26 @@ require (
github.com/beevik/ntp v1.4.3
github.com/creack/pty v1.1.24
github.com/devhaozi/westcn v0.0.0-20250407083704-b49375823872
github.com/expr-lang/expr v1.17.2
github.com/go-chi/chi/v5 v5.2.1
github.com/expr-lang/expr v1.17.5
github.com/go-chi/chi/v5 v5.2.2
github.com/go-gormigrate/gormigrate/v2 v2.1.4
github.com/go-rat/chix v1.2.0
github.com/go-rat/gormstore v1.0.6
github.com/go-rat/sessions v1.1.0
github.com/go-rat/utils v1.1.5
github.com/go-resty/resty/v2 v2.16.5
github.com/go-sql-driver/mysql v1.9.2
github.com/golang-cz/httplog v0.0.0-20241002114323-98e09d6f537a
github.com/go-sql-driver/mysql v1.9.3
github.com/golang-cz/httplog v0.0.2
github.com/gomodule/redigo v1.9.2
github.com/google/wire v0.6.0
github.com/gookit/color v1.5.4
github.com/gookit/validate v1.5.4
github.com/gookit/validate v1.5.5
github.com/gorilla/websocket v1.5.3
github.com/hashicorp/go-version v1.7.0
github.com/knadh/koanf/parsers/yaml v1.0.0
github.com/knadh/koanf/parsers/yaml v1.1.0
github.com/knadh/koanf/providers/file v1.2.0
github.com/knadh/koanf/v2 v2.2.0
github.com/leonelquinteros/gotext v1.7.1
github.com/knadh/koanf/v2 v2.2.1
github.com/leonelquinteros/gotext v1.7.2
github.com/lib/pq v1.10.9
github.com/libdns/alidns v1.0.4
github.com/libdns/cloudflare v0.1.3
@@ -38,30 +38,30 @@ require (
github.com/libdns/huaweicloud v0.3.5
github.com/libdns/libdns v0.2.3
github.com/libdns/linode v0.4.1
github.com/libdns/namecheap v0.0.0-20250228022813-d8b4b66c5072
github.com/libdns/namecheap v0.0.0-20250523201144-144eb6168d52
github.com/libdns/namedotcom v0.3.3
github.com/libdns/namesilo v0.1.2
github.com/libdns/porkbun v0.2.0
github.com/libdns/tencentcloud v1.2.0
github.com/libdns/vercel v0.0.2
github.com/mholt/acmez/v3 v3.1.2
github.com/ncruces/go-sqlite3 v0.25.2
github.com/ncruces/go-sqlite3 v0.26.3
github.com/ncruces/go-sqlite3/gormlite v0.24.0
github.com/orandin/slog-gorm v1.4.0
github.com/pquerna/otp v1.4.1-0.20241231231527-5971b1ef1d66
github.com/pquerna/otp v1.5.0
github.com/robfig/cron/v3 v3.0.1
github.com/samber/lo v1.50.0
github.com/samber/lo v1.51.0
github.com/sethvargo/go-limiter v1.0.1-0.20250412144437-fa26982c7e1a
github.com/shirou/gopsutil v3.21.11+incompatible
github.com/spf13/cast v1.8.0
github.com/spf13/cast v1.9.2
github.com/stretchr/testify v1.10.0
github.com/tufanbarisyildirim/gonginx v0.0.0-20250429180229-7e931b1d4276
github.com/urfave/cli/v3 v3.3.3
golang.org/x/crypto v0.38.0
golang.org/x/net v0.40.0
github.com/tufanbarisyildirim/gonginx v0.0.0-20250620092546-c3e307e36701
github.com/urfave/cli/v3 v3.3.8
go.yaml.in/yaml/v3 v3.0.4
golang.org/x/crypto v0.39.0
golang.org/x/net v0.41.0
gopkg.in/natefinch/lumberjack.v2 v2.2.1
gopkg.in/yaml.v3 v3.0.1
gorm.io/gorm v1.26.1
gorm.io/gorm v1.30.0
)
require (
@@ -100,10 +100,11 @@ require (
github.com/xo/terminfo v0.0.0-20220910002029-abceb7e1c41e // indirect
github.com/yusufpapurcu/wmi v1.2.4 // indirect
golang.org/x/exp v0.0.0-20250305212735-054e65f0b394 // indirect
golang.org/x/sync v0.14.0 // indirect
golang.org/x/sync v0.15.0 // indirect
golang.org/x/sys v0.33.0 // indirect
golang.org/x/text v0.25.0 // indirect
golang.org/x/text v0.26.0 // indirect
gopkg.in/ini.v1 v1.67.0 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
)
replace github.com/mholt/acmez/v3 => github.com/tnb-labs/acmez/v3 v3.0.0-20250416074048-0e9f6b5f8ec5
replace github.com/mholt/acmez/v3 => github.com/tnb-labs/acmez/v3 v3.0.0-20250707093727-dc5aedd96413
+46 -46
View File
@@ -51,8 +51,8 @@ github.com/devhaozi/westcn v0.0.0-20250407083704-b49375823872 h1:cns0Vj69pUuQ+bf
github.com/devhaozi/westcn v0.0.0-20250407083704-b49375823872/go.mod h1:3DfSvYwyUHt1JtN+JCWAGtOLFWlRXz19wJa/Xk159ao=
github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ=
github.com/dgryski/go-sip13 v0.0.0-20181026042036-e10d5fee7954/go.mod h1:vAd38F8PWV+bWy6jNmig1y/TA+kYO4g3RSRF0IAv0no=
github.com/expr-lang/expr v1.17.2 h1:o0A99O/Px+/DTjEnQiodAgOIK9PPxL8DtXhBRKC+Iso=
github.com/expr-lang/expr v1.17.2/go.mod h1:8/vRC7+7HBzESEqt5kKpYXxrxkr31SaO8r40VO/1IT4=
github.com/expr-lang/expr v1.17.5 h1:i1WrMvcdLF249nSNlpQZN1S6NXuW9WaOfF5tPi3aw3k=
github.com/expr-lang/expr v1.17.5/go.mod h1:8/vRC7+7HBzESEqt5kKpYXxrxkr31SaO8r40VO/1IT4=
github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4=
github.com/frankban/quicktest v1.14.6 h1:7Xjx+VpznH+oBnejlPUj8oUpdxnVs4f8XU8WnHkI4W8=
github.com/frankban/quicktest v1.14.6/go.mod h1:4ptaffx2x8+WTWXmUCuVU6aPUX1/Mz7zb5vbUoiM6w0=
@@ -62,8 +62,8 @@ github.com/fsnotify/fsnotify v1.9.0/go.mod h1:8jBTzvmWwFyi3Pb8djgCCO5IBqzKJ/Jwo8
github.com/gabriel-vasile/mimetype v1.4.8 h1:FfZ3gj38NjllZIeJAmMhr+qKL8Wu+nOoI3GqacKw1NM=
github.com/gabriel-vasile/mimetype v1.4.8/go.mod h1:ByKUIKGjh1ODkGM1asKUbQZOLGrPjydw3hYPU2YU9t8=
github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
github.com/go-chi/chi/v5 v5.2.1 h1:KOIHODQj58PmL80G2Eak4WdvUzjSJSm0vG72crDCqb8=
github.com/go-chi/chi/v5 v5.2.1/go.mod h1:L2yAIGWB3H+phAw1NxKwWM+7eUH/lU8pOMm5hHcoops=
github.com/go-chi/chi/v5 v5.2.2 h1:CMwsvRVTbXVytCk1Wd72Zy1LAsAh9GxMmSNWLHCG618=
github.com/go-chi/chi/v5 v5.2.2/go.mod h1:L2yAIGWB3H+phAw1NxKwWM+7eUH/lU8pOMm5hHcoops=
github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU=
github.com/go-gormigrate/gormigrate/v2 v2.1.4 h1:KOPEt27qy1cNzHfMZbp9YTmEuzkY4F4wrdsJW9WFk1U=
github.com/go-gormigrate/gormigrate/v2 v2.1.4/go.mod h1:y/6gPAH6QGAgP1UfHMiXcqGeJ88/GRQbfCReE1JJD5Y=
@@ -85,8 +85,8 @@ github.com/go-rat/utils v1.1.5 h1:nB5qNU4TxqG9BJe7PdeDzznmh6lk+GIWb7hZcvAY4FQ=
github.com/go-rat/utils v1.1.5/go.mod h1:SUy4Xw44VkZvo2FaURgiIiJlL6Kukll85fVKMp/50+8=
github.com/go-resty/resty/v2 v2.16.5 h1:hBKqmWrr7uRc3euHVqmh1HTHcKn99Smr7o5spptdhTM=
github.com/go-resty/resty/v2 v2.16.5/go.mod h1:hkJtXbA2iKHzJheXYvQ8snQES5ZLGKMwQ07xAwp/fiA=
github.com/go-sql-driver/mysql v1.9.2 h1:4cNKDYQ1I84SXslGddlsrMhc8k4LeDVj6Ad6WRjiHuU=
github.com/go-sql-driver/mysql v1.9.2/go.mod h1:qn46aNg1333BRMNU69Lq93t8du/dwxI64Gl8i5p1WMU=
github.com/go-sql-driver/mysql v1.9.3 h1:U/N249h2WzJ3Ukj8SowVFjdtZKfu9vlLZxjPXV1aweo=
github.com/go-sql-driver/mysql v1.9.3/go.mod h1:qn46aNg1333BRMNU69Lq93t8du/dwxI64Gl8i5p1WMU=
github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
github.com/go-viper/mapstructure/v2 v2.2.1 h1:ZAaOCxANMuZx5RCeg0mBdEZk7DZasvvZIxtHqx8aGss=
github.com/go-viper/mapstructure/v2 v2.2.1/go.mod h1:oJDH3BJKyqBA2TXFhDsKDGDTlndYOZ6rGS0BRZIxGhM=
@@ -94,8 +94,8 @@ github.com/gofiber/schema v1.3.0 h1:K3F3wYzAY+aivfCCEHPufCthu5/13r/lzp1nuk6mr3Q=
github.com/gofiber/schema v1.3.0/go.mod h1:YYwj01w3hVfaNjhtJzaqetymL56VW642YS3qZPhuE6c=
github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4=
github.com/golang-cz/httplog v0.0.0-20241002114323-98e09d6f537a h1:BAyyIK6rc6Tq9vT2KVlPJXD8EVv/LpaFwn4fgfLwtHg=
github.com/golang-cz/httplog v0.0.0-20241002114323-98e09d6f537a/go.mod h1:bgk4Ij/0OQ89UeoFFAQrSNhbbr4rKJ0fwWfo7wc+TCc=
github.com/golang-cz/httplog v0.0.2 h1:3d8iScWLeMWQG5/bfMZ5Dizh+zvRfNmLBZMe5N2HrGU=
github.com/golang-cz/httplog v0.0.2/go.mod h1:bgk4Ij/0OQ89UeoFFAQrSNhbbr4rKJ0fwWfo7wc+TCc=
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
github.com/golang/groupcache v0.0.0-20190129154638-5b532d6fd5ef/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
@@ -132,8 +132,8 @@ github.com/gookit/filter v1.2.2 h1:LSBQLk4M4fpfhaOG0hJ/GJ+qu+2+lLddgxlGfzcd8VQ=
github.com/gookit/filter v1.2.2/go.mod h1:y4xpiqM/fV9g9yT/Vg5OWUq4q9siPj0UlH9O57xYuGs=
github.com/gookit/goutil v0.6.18 h1:MUVj0G16flubWT8zYVicIuisUiHdgirPAkmnfD2kKgw=
github.com/gookit/goutil v0.6.18/go.mod h1:AY/5sAwKe7Xck+mEbuxj0n/bc3qwrGNe3Oeulln7zBA=
github.com/gookit/validate v1.5.4 h1:nwBo6vULnVUeNFCOde6RKFRbOCKJXVMnWR0ghedacLg=
github.com/gookit/validate v1.5.4/go.mod h1:p9sRPfpvYB4vXICBpEPzv8FoAky+XhUOhWQghgmmat4=
github.com/gookit/validate v1.5.5 h1:jzMrwAYy9tbQa0mH8YFnv3C3JQR/0N4pRTsYiySwRJM=
github.com/gookit/validate v1.5.5/go.mod h1:p9sRPfpvYB4vXICBpEPzv8FoAky+XhUOhWQghgmmat4=
github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=
github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
github.com/gorilla/websocket v1.5.3 h1:saDtZ6Pbx/0u+bgYQ3q96pZgCzfhKXGPqt7kZ72aNNg=
@@ -183,12 +183,12 @@ github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvW
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
github.com/knadh/koanf/maps v0.1.2 h1:RBfmAW5CnZT+PJ1CVc1QSJKf4Xu9kxfQgYVQSu8hpbo=
github.com/knadh/koanf/maps v0.1.2/go.mod h1:npD/QZY3V6ghQDdcQzl1W4ICNVTkohC8E73eI2xW4yI=
github.com/knadh/koanf/parsers/yaml v1.0.0 h1:PXyeHCRhAMKyfLJaoTWsqUTxIFeDMmdAKz3XVEslZV4=
github.com/knadh/koanf/parsers/yaml v1.0.0/go.mod h1:Q63VAOh/s6XaQs6a0TB2w9GFUuuPGvfYrCSWb9eWAQU=
github.com/knadh/koanf/parsers/yaml v1.1.0 h1:3ltfm9ljprAHt4jxgeYLlFPmUaunuCgu1yILuTXRdM4=
github.com/knadh/koanf/parsers/yaml v1.1.0/go.mod h1:HHmcHXUrp9cOPcuC+2wrr44GTUB0EC+PyfN3HZD9tFg=
github.com/knadh/koanf/providers/file v1.2.0 h1:hrUJ6Y9YOA49aNu/RSYzOTFlqzXSCpmYIDXI7OJU6+U=
github.com/knadh/koanf/providers/file v1.2.0/go.mod h1:bp1PM5f83Q+TOUu10J/0ApLBd9uIzg+n9UgthfY+nRA=
github.com/knadh/koanf/v2 v2.2.0 h1:FZFwd9bUjpb8DyCWARUBy5ovuhDs1lI87dOEn2K8UVU=
github.com/knadh/koanf/v2 v2.2.0/go.mod h1:PSFru3ufQgTsI7IF+95rf9s8XA1+aHxKuO/W+dPoHEY=
github.com/knadh/koanf/v2 v2.2.1 h1:jaleChtw85y3UdBnI0wCqcg1sj1gPoz6D3caGNHtrNE=
github.com/knadh/koanf/v2 v2.2.1/go.mod h1:PSFru3ufQgTsI7IF+95rf9s8XA1+aHxKuO/W+dPoHEY=
github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
github.com/kr/fs v0.1.0/go.mod h1:FFnZGqtBN9Gxj7eW1uZ42v5BccTP0vu6NEaFoC2HwRg=
github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc=
@@ -199,8 +199,8 @@ github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
github.com/leonelquinteros/gotext v1.7.1 h1:/JNPeE3lY5JeVYv2+KBpz39994W3W9fmZCGq3eO9Ri8=
github.com/leonelquinteros/gotext v1.7.1/go.mod h1:I0WoFDn9u2D3VbPnnDPT8mzZu0iSXG8iih+AH2fHHqg=
github.com/leonelquinteros/gotext v1.7.2 h1:bDPndU8nt+/kRo1m4l/1OXiiy2v7Z7dfPQ9+YP7G1Mc=
github.com/leonelquinteros/gotext v1.7.2/go.mod h1:9/haCkm5P7Jay1sxKDGJ5WIg4zkz8oZKw4ekNpALob8=
github.com/lib/pq v1.10.9 h1:YXG7RB+JIjhP29X+OtkiDnYaXQwpS4JEWq7dtCCRUEw=
github.com/lib/pq v1.10.9/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o=
github.com/libdns/alidns v1.0.4 h1:Rc3Yy2SzMoho+3q3+fNy9vOVr2h9dcL8OLTgNKgxYbU=
@@ -225,8 +225,8 @@ github.com/libdns/libdns v0.2.3 h1:ba30K4ObwMGB/QTmqUxf3H4/GmUrCAIkMWejeGl12v8=
github.com/libdns/libdns v0.2.3/go.mod h1:4Bj9+5CQiNMVGf87wjX4CY3HQJypUHRuLvlsfsZqLWQ=
github.com/libdns/linode v0.4.1 h1:Fr22y3aWBzaj3AlFbCQ743eC+5Hss+sJ+OEjtlK61AA=
github.com/libdns/linode v0.4.1/go.mod h1:BqAJnQxzpnQgy4GDVYf3hQvhLGDc3n8BRwMZ0/9m2y0=
github.com/libdns/namecheap v0.0.0-20250228022813-d8b4b66c5072 h1:hCPOoLd9Mr5kAWLofhSCuGYZxAVVy0CV9zgbahzIeSg=
github.com/libdns/namecheap v0.0.0-20250228022813-d8b4b66c5072/go.mod h1:jo2LWZSD/g/scevxNSp2kWtdMIXfsgWxrtSc3Z0Yy/I=
github.com/libdns/namecheap v0.0.0-20250523201144-144eb6168d52 h1:kV0L03h9sbiZInF9L+V3Cb5SDD9jnA0mitzKkCg6TDk=
github.com/libdns/namecheap v0.0.0-20250523201144-144eb6168d52/go.mod h1:jo2LWZSD/g/scevxNSp2kWtdMIXfsgWxrtSc3Z0Yy/I=
github.com/libdns/namedotcom v0.3.3 h1:R10C7+IqQGVeC4opHHMiFNBxdNBg1bi65ZwqLESl+jE=
github.com/libdns/namedotcom v0.3.3/go.mod h1:GbYzsAF2yRUpI0WgIK5fs5UX+kDVUPaYCFLpTnKQm0s=
github.com/libdns/namesilo v0.1.2 h1:ySW4QiWx2vMWw1xBD7kTnTWVY/CLIaCgko6ZbmOufbk=
@@ -261,14 +261,12 @@ github.com/mitchellh/reflectwalk v1.0.2/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=
github.com/ncruces/go-sqlite3 v0.25.2 h1:suu3C7y92hPqozqO8+w3K333Q1VhWyN6K3JJKXdtC2U=
github.com/ncruces/go-sqlite3 v0.25.2/go.mod h1:46HIzeCQQ+aNleAxCli+vpA2tfh7ttSnw24kQahBc1o=
github.com/ncruces/go-sqlite3 v0.26.3 h1:WFkQj4KNMhbqiBPGDrVpK74w1DzcxQu3wYpmdWAvfYM=
github.com/ncruces/go-sqlite3 v0.26.3/go.mod h1:XFTPtFIo1DmGCh+XVP8KGn9b/o2f+z0WZuT09x2N6eo=
github.com/ncruces/go-sqlite3/gormlite v0.24.0 h1:81sHeq3CCdhjoqAB650n5wEdRlLO9VBvosArskcN3+c=
github.com/ncruces/go-sqlite3/gormlite v0.24.0/go.mod h1:vXfVWdBfg7qOgqQqHpzUWl9LLswD0h+8mK4oouaV2oc=
github.com/ncruces/julianday v1.0.0 h1:fH0OKwa7NWvniGQtxdJRxAgkBMolni2BjDHaWTxqt7M=
github.com/ncruces/julianday v1.0.0/go.mod h1:Dusn2KvZrrovOMJuOt0TNXL6tB7U2E8kvza5fFc9G7g=
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e h1:fD57ERR4JtEqsWbfPhv4DMiApHyliiK5xCTNVSPiaAs=
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno=
github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U=
github.com/orandin/slog-gorm v1.4.0 h1:FgA8hJufF9/jeNSYoEXmHPPBwET2gwlF3B85JdpsTUU=
github.com/orandin/slog-gorm v1.4.0/go.mod h1:MoZ51+b7xE9lwGNPYEhxcUtRNrYzjdcKvA8QXQQGEPA=
@@ -282,8 +280,8 @@ github.com/pkg/sftp v1.10.1/go.mod h1:lYOWFsE0bwd1+KfKJaKeuokY15vzFx25BLbzYYoAxZ
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI=
github.com/pquerna/otp v1.4.1-0.20241231231527-5971b1ef1d66 h1:7pccJSb6/BRgd5BKejX/dgzinfq0K5HPwj35+saHuCU=
github.com/pquerna/otp v1.4.1-0.20241231231527-5971b1ef1d66/go.mod h1:dkJfzwRKNiegxyNb54X/3fLwhCynbMspSyWKnvi1AEg=
github.com/pquerna/otp v1.5.0 h1:NMMR+WrmaqXU4EzdGJEE1aUUI0AMRzsp96fFFWNPwxs=
github.com/pquerna/otp v1.5.0/go.mod h1:dkJfzwRKNiegxyNb54X/3fLwhCynbMspSyWKnvi1AEg=
github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw=
github.com/prometheus/client_golang v0.9.3/go.mod h1:/TN21ttK/J9q6uSwhBd54HahCDft0ttaMvbicHlPoso=
github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo=
@@ -301,8 +299,8 @@ github.com/rogpeppe/go-internal v1.9.0 h1:73kH8U+JUqXU8lRuOHeVHaa/SZPifC7BkcraZV
github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs=
github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts=
github.com/samber/lo v1.50.0 h1:XrG0xOeHs+4FQ8gJR97zDz5uOFMW7OwFWiFVzqopKgY=
github.com/samber/lo v1.50.0/go.mod h1:RjZyNk6WSnUFRKK6EyOhsRJMqft3G+pg7dCWHQCWvsc=
github.com/samber/lo v1.51.0 h1:kysRYLbHy/MB7kQZf5DSN50JHmMsNEdeY24VzJFu7wI=
github.com/samber/lo v1.51.0/go.mod h1:4+MXEGsJzbKGaUEQFKBq2xtfuznW9oz/WrgyzMzRoM0=
github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc=
github.com/sethvargo/go-limiter v1.0.1-0.20250412144437-fa26982c7e1a h1:CdCoDHVynJVAQWN7ZQrAUOp0SV5TmRwNOSkF5KedDko=
github.com/sethvargo/go-limiter v1.0.1-0.20250412144437-fa26982c7e1a/go.mod h1:01b6tW25Ap+MeLYBuD4aHunMrJoNO5PVUFdS9rac3II=
@@ -317,8 +315,8 @@ github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasO
github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ=
github.com/spf13/afero v1.4.1/go.mod h1:Ai8FlHk4v/PARR026UzYexafAt9roJ7LcLMAmO6Z93I=
github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE=
github.com/spf13/cast v1.8.0 h1:gEN9K4b8Xws4EX0+a0reLmhq8moKn7ntRlQYgjPeCDk=
github.com/spf13/cast v1.8.0/go.mod h1:ancEpBxwJDODSW/UG4rDrAqiKolqNNh2DX3mk86cAdo=
github.com/spf13/cast v1.9.2 h1:SsGfm7M8QOFtEzumm7UZrZdLLquNdzFYfIbEXntcFbE=
github.com/spf13/cast v1.9.2/go.mod h1:jNfB8QC9IA6ZuY2ZjDp0KtFO2LZZlg4S/7bzP6qqeHo=
github.com/spf13/cobra v1.1.1/go.mod h1:WnodtKOvamDL/PwE2M4iKs8aMDBZ5Q5klgD3qfVJQMI=
github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo=
github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
@@ -348,12 +346,12 @@ github.com/tklauser/go-sysconf v0.3.14/go.mod h1:1ym4lWMLUOhuBOPGtRcJm7tEGX4SCYN
github.com/tklauser/numcpus v0.9.0 h1:lmyCHtANi8aRUgkckBgoDk1nHCux3n2cgkJLXdQGPDo=
github.com/tklauser/numcpus v0.9.0/go.mod h1:SN6Nq1O3VychhC1npsWostA+oW+VOQTxZrS604NSRyI=
github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U=
github.com/tnb-labs/acmez/v3 v3.0.0-20250416074048-0e9f6b5f8ec5 h1:eeJt90c4buPPC4JjfP5EaTFwlARgOaaXqewHFqZJJag=
github.com/tnb-labs/acmez/v3 v3.0.0-20250416074048-0e9f6b5f8ec5/go.mod h1:L1wOU06KKvq7tswuMDwKdcHeKpFFgkppZy/y0DFxagQ=
github.com/tufanbarisyildirim/gonginx v0.0.0-20250429180229-7e931b1d4276 h1:928VpvLiMWSulfjhKUYj57f70HhOE1ImsQHaeDC2jVc=
github.com/tufanbarisyildirim/gonginx v0.0.0-20250429180229-7e931b1d4276/go.mod h1:ALbEe81QPWOZjDKCKNWodG2iqCMtregG8+ebQgjx2+4=
github.com/urfave/cli/v3 v3.3.3 h1:byCBaVdIXuLPIDm5CYZRVG6NvT7tv1ECqdU4YzlEa3I=
github.com/urfave/cli/v3 v3.3.3/go.mod h1:FJSKtM/9AiiTOJL4fJ6TbMUkxBXn7GO9guZqoZtpYpo=
github.com/tnb-labs/acmez/v3 v3.0.0-20250707093727-dc5aedd96413 h1:M1ubPXmO7ez2Ay/4J0MVS3HjkKEnWhHXfHvOOi7IMj8=
github.com/tnb-labs/acmez/v3 v3.0.0-20250707093727-dc5aedd96413/go.mod h1:L1wOU06KKvq7tswuMDwKdcHeKpFFgkppZy/y0DFxagQ=
github.com/tufanbarisyildirim/gonginx v0.0.0-20250620092546-c3e307e36701 h1:JgeHIJzRSEdcuLXufZrni5+a4yDnBhQG+DdKhqCFhq0=
github.com/tufanbarisyildirim/gonginx v0.0.0-20250620092546-c3e307e36701/go.mod h1:ALbEe81QPWOZjDKCKNWodG2iqCMtregG8+ebQgjx2+4=
github.com/urfave/cli/v3 v3.3.8 h1:BzolUExliMdet9NlJ/u4m5vHSotJ3PzEqSAZ1oPMa/E=
github.com/urfave/cli/v3 v3.3.8/go.mod h1:FJSKtM/9AiiTOJL4fJ6TbMUkxBXn7GO9guZqoZtpYpo=
github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU=
github.com/xo/terminfo v0.0.0-20220910002029-abceb7e1c41e h1:JVG44RsyaB9T2KIHavMF/ppJZNG9ZpyihvCd0w101no=
github.com/xo/terminfo v0.0.0-20220910002029-abceb7e1c41e/go.mod h1:RbqR21r5mrJuqunuUZ/Dhy/avygyECGrLceyNeo4LiM=
@@ -366,6 +364,8 @@ go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8=
go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE=
go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0=
go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q=
go.yaml.in/yaml/v3 v3.0.4 h1:tfq32ie2Jv2UxXFdLJdh3jXuOzWiL1fo0bu/FbuKpbc=
go.yaml.in/yaml/v3 v3.0.4/go.mod h1:DhzuOOF2ATzADvBadXxruRBLzYTpT36CKvDb3+aBEFg=
golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
golang.org/x/crypto v0.0.0-20181029021203-45a5f77698d3/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
@@ -376,8 +376,8 @@ golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8U
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
golang.org/x/crypto v0.13.0/go.mod h1:y6Z2r+Rw4iayiXXAIxJIDAJ1zMW4yaTpebo8fPOliYc=
golang.org/x/crypto v0.18.0/go.mod h1:R0j02AL6hcrfOiy9T4ZYp/rcWeMxM3L6QYxlOuEG1mg=
golang.org/x/crypto v0.38.0 h1:jt+WWG8IZlBnVbomuhg2Mdq0+BBQaHbtqHEFEigjUV8=
golang.org/x/crypto v0.38.0/go.mod h1:MvrbAqul58NNYPKnOra203SB9vpuZW0e+RRZV+Ggqjw=
golang.org/x/crypto v0.39.0 h1:SHs+kF4LP+f+p14esP5jAoDpHU8Gu/v9lFRK6IT5imM=
golang.org/x/crypto v0.39.0/go.mod h1:L+Xg3Wf6HoL4Bn4238Z6ft6KfEpN0tJGo53AAPC632U=
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8=
@@ -424,8 +424,8 @@ golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg=
golang.org/x/net v0.15.0/go.mod h1:idbUs1IY1+zTqbi8yxTbhexhEEk5ur9LInksu6HrEpk=
golang.org/x/net v0.20.0/go.mod h1:z8BVo6PvndSri0LbOE3hAn0apkU+1YvI6E70E9jsnvY=
golang.org/x/net v0.40.0 h1:79Xs7wF06Gbdcg4kdCCIQArK11Z1hr5POQ6+fIYHNuY=
golang.org/x/net v0.40.0/go.mod h1:y0hY0exeL2Pku80/zKK7tpntoX23cqL3Oa6njdgRtds=
golang.org/x/net v0.41.0 h1:vBTly1HeNPEn3wtREYfy4GZ/NECgw2Cnl+nK6Nz3uvw=
golang.org/x/net v0.41.0/go.mod h1:B/K4NNqkfmg07DQYrbwvSluqCJOOXwUjeb/5lOisjbA=
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
@@ -438,8 +438,8 @@ golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJ
golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.3.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y=
golang.org/x/sync v0.6.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
golang.org/x/sync v0.14.0 h1:woo0S4Yywslg6hp4eUFjTVOyKt0RookbpAHG4c1HmhQ=
golang.org/x/sync v0.14.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA=
golang.org/x/sync v0.15.0 h1:KWH3jNZsfyT6xfAfKiz6MRNmd46ByHDYaZ7KSkCtdW8=
golang.org/x/sync v0.15.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA=
golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
@@ -483,8 +483,8 @@ golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=
golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE=
golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
golang.org/x/text v0.25.0 h1:qVyWApTSYLk/drJRO5mDlNYskwQznZmkpV2c8q9zls4=
golang.org/x/text v0.25.0/go.mod h1:WEdwpYrmk1qmdHvhkSTNPm3app7v4rsT8F2UD6+VHIA=
golang.org/x/text v0.26.0 h1:P42AVeLghgTYr4+xUnTRKDMqpar+PtX7KWuNQL21L8M=
golang.org/x/text v0.26.0/go.mod h1:QK15LZJUUQVJxhz7wXgxSy/CJaTFjd0G+YLonydOVQA=
golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.6.0 h1:eTDhh4ZXt5Qf0augr54TN6suAUudPcawVZeIAPU7D4U=
@@ -539,8 +539,8 @@ google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ij
gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f h1:BLraFXnmrev5lT+xlilqcH8XK9/i0At2xKjWk4p6zsU=
gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 h1:YR8cESwS4TdDjEe65xsg0ogRM/Nc3DYOhEAlW+xobZo=
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
gopkg.in/ini.v1 v1.51.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
gopkg.in/ini.v1 v1.67.0 h1:Dgnx+6+nfE+IfzjUEISNeydPJh9AXNNsWbGP9KzCsOA=
@@ -557,8 +557,8 @@ gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C
gopkg.in/yaml.v3 v3.0.0-20200615113413-eeeca48fe776/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gorm.io/gorm v1.26.1 h1:ghB2gUI9FkS46luZtn6DLZ0f6ooBJ5IbVej2ENFDjRw=
gorm.io/gorm v1.26.1/go.mod h1:8Z33v652h4//uMA76KjeDH8mJXPm1QNCYrMeatR0DOE=
gorm.io/gorm v1.30.0 h1:qbT5aPv1UH8gI99OsRlvDToLxW5zR7FzS9acZDOZcgs=
gorm.io/gorm v1.30.0/go.mod h1:8Z33v652h4//uMA76KjeDH8mJXPm1QNCYrMeatR0DOE=
gotest.tools/v3 v3.5.1 h1:EENdUnS3pdur5nybKYIh2Vfgc8IUNBjxDPSjtiJcOzU=
gotest.tools/v3 v3.5.1/go.mod h1:isy3WKz7GK6uNw/sbHzfKBLvlvXwUyV06n6brMxxopU=
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
+4 -1
View File
@@ -104,7 +104,10 @@ func (s *App) Load(w http.ResponseWriter, r *http.Request) {
service.Error(w, http.StatusInternalServerError, s.t.Get("failed to get MySQL status: %v", err))
return
}
_ = os.Unsetenv("MYSQL_PWD")
if err = os.Unsetenv("MYSQL_PWD"); err != nil {
service.Error(w, http.StatusInternalServerError, s.t.Get("failed to unset MYSQL_PWD env: %v", err))
return
}
var load []map[string]string
expressions := []struct {
+1
View File
@@ -24,6 +24,7 @@ type UserRepo interface {
List(page, limit uint) ([]*User, int64, error)
Get(id uint) (*User, error)
Create(username, password, email string) (*User, error)
UpdateUsername(id uint, username string) error
UpdatePassword(id uint, password string) error
UpdateEmail(id uint, email string) error
Delete(id uint) error
+2
View File
@@ -19,6 +19,8 @@ type Website struct {
CreatedAt time.Time `json:"created_at"`
UpdatedAt time.Time `json:"updated_at"`
CertExpire string `gorm:"-:all" json:"cert_expire"` // 仅显示
Cert *Cert `gorm:"foreignKey:WebsiteID" json:"cert"`
}
+1 -1
View File
@@ -17,7 +17,7 @@ import (
func NewDB(conf *koanf.Koanf, log *slog.Logger) (*gorm.DB, error) {
// You can use any other database, like MySQL or PostgreSQL.
return gorm.Open(gormlite.Open(filepath.Join(app.Root, "panel/storage/app.db")), &gorm.Config{
return gorm.Open(gormlite.Open("file:"+filepath.Join(app.Root, "panel/storage/app.db?_txlock=immediate")), &gorm.Config{
Logger: sloggorm.New(sloggorm.WithHandler(log.Handler())),
SkipDefaultTransaction: true,
DisableForeignKeyConstraintWhenMigrating: true,
+7 -4
View File
@@ -9,6 +9,7 @@ import (
"github.com/expr-lang/expr"
"github.com/go-rat/utils/collect"
"github.com/hashicorp/go-version"
"github.com/knadh/koanf/v2"
"github.com/leonelquinteros/gotext"
"github.com/spf13/cast"
"gorm.io/gorm"
@@ -21,14 +22,16 @@ import (
type appRepo struct {
t *gotext.Locale
conf *koanf.Koanf
db *gorm.DB
cache biz.CacheRepo
task biz.TaskRepo
}
func NewAppRepo(t *gotext.Locale, db *gorm.DB, cache biz.CacheRepo, task biz.TaskRepo) biz.AppRepo {
func NewAppRepo(t *gotext.Locale, conf *koanf.Koanf, db *gorm.DB, cache biz.CacheRepo, task biz.TaskRepo) biz.AppRepo {
return &appRepo{
t: t,
conf: conf,
db: db,
cache: cache,
task: task,
@@ -166,7 +169,7 @@ func (r *appRepo) Install(channel, slug string) error {
continue
}
if ch.Slug == channel {
if vs.GreaterThan(panel) {
if vs.GreaterThan(panel) && !r.conf.Bool("app.debug") {
return errors.New(r.t.Get("app %s requires panel version %s, current version %s", item.Name, ch.Panel, app.Version))
}
shellUrl = ch.Install
@@ -221,7 +224,7 @@ func (r *appRepo) UnInstall(slug string) error {
continue
}
if ch.Slug == installed.Channel {
if vs.GreaterThan(panel) {
if vs.GreaterThan(panel) && !r.conf.Bool("app.debug") {
return errors.New(r.t.Get("app %s requires panel version %s, current version %s", item.Name, ch.Panel, app.Version))
}
shellUrl = ch.Uninstall
@@ -276,7 +279,7 @@ func (r *appRepo) Update(slug string) error {
continue
}
if ch.Slug == installed.Channel {
if vs.GreaterThan(panel) {
if vs.GreaterThan(panel) && !r.conf.Bool("app.debug") {
return errors.New(r.t.Get("app %s requires panel version %s, current version %s", item.Name, ch.Panel, app.Version))
}
shellUrl = ch.Update
+1 -1
View File
@@ -326,7 +326,7 @@ func (r *certRepo) ManualDNS(id uint) ([]acme.DNSRecord, error) {
return nil, err
}
client.UseManualDns(len(cert.Domains))
client.UseManualDns()
records, err := client.GetDNSRecords(context.Background(), cert.Domains, acme.KeyType(cert.Type))
if err != nil {
return nil, err
+10 -1
View File
@@ -19,9 +19,11 @@ func NewContainerComposeRepo() biz.ContainerComposeRepo {
return &containerComposeRepo{}
}
// List 列出所有编排文件名
// List 列出所有编排
func (r *containerComposeRepo) List() ([]types.ContainerCompose, error) {
_ = os.Setenv("PODMAN_COMPOSE_WARNING_LOGS", "false") // 禁用 Podman Compose 的警告日志
raw, err := shell.Execf("docker compose ls -a --format json")
_ = os.Unsetenv("PODMAN_COMPOSE_WARNING_LOGS")
if err != nil {
return nil, err
}
@@ -142,19 +144,26 @@ func (r *containerComposeRepo) Up(name string, force bool) error {
if force {
cmd += " --pull always" // 强制拉取镜像
}
_ = os.Setenv("PODMAN_COMPOSE_WARNING_LOGS", "false") // 禁用 Podman Compose 的警告日志
_, err := shell.Execf(cmd, file)
_ = os.Unsetenv("PODMAN_COMPOSE_WARNING_LOGS")
return err
}
// Down 停止编排
func (r *containerComposeRepo) Down(name string) error {
file := filepath.Join(app.Root, "server", "compose", name, "docker-compose.yml")
_ = os.Setenv("PODMAN_COMPOSE_WARNING_LOGS", "false") // 禁用 Podman Compose 的警告日志
_, err := shell.Execf("docker compose -f %s down", file)
_ = os.Unsetenv("PODMAN_COMPOSE_WARNING_LOGS")
return err
}
// Remove 删除编排
func (r *containerComposeRepo) Remove(name string) error {
if err := r.Down(name); err != nil {
return err
}
dir := filepath.Join(app.Root, "server", "compose", name)
return os.RemoveAll(dir)
}
+12
View File
@@ -78,6 +78,9 @@ func (r databaseUserRepo) Create(req *request.DatabaseUserCreate) error {
return err
}
for name := range slices.Values(req.Privileges) {
if err = mysql.DatabaseCreate(name); err != nil {
return err
}
if err = mysql.PrivilegesGrant(req.Username, name, req.Host); err != nil {
return err
}
@@ -99,6 +102,9 @@ func (r databaseUserRepo) Create(req *request.DatabaseUserCreate) error {
return err
}
for name := range slices.Values(req.Privileges) {
if err = postgres.DatabaseCreate(name); err != nil {
return err
}
if err = postgres.PrivilegesGrant(req.Username, name); err != nil {
return err
}
@@ -145,6 +151,9 @@ func (r databaseUserRepo) Update(req *request.DatabaseUserUpdate) error {
}
}
for name := range slices.Values(req.Privileges) {
if err = mysql.DatabaseCreate(name); err != nil {
return err
}
if err = mysql.PrivilegesGrant(user.Username, name, user.Host); err != nil {
return err
}
@@ -163,6 +172,9 @@ func (r databaseUserRepo) Update(req *request.DatabaseUserUpdate) error {
}
}
for name := range slices.Values(req.Privileges) {
if err = postgres.DatabaseCreate(name); err != nil {
return err
}
if err = postgres.PrivilegesGrant(user.Username, name); err != nil {
return err
}
+16 -14
View File
@@ -9,7 +9,7 @@ import (
"github.com/knadh/koanf/v2"
"github.com/leonelquinteros/gotext"
"github.com/spf13/cast"
"gopkg.in/yaml.v3"
"go.yaml.in/yaml/v3"
"gorm.io/gorm"
"github.com/tnb-labs/panel/internal/app"
@@ -19,6 +19,7 @@ import (
"github.com/tnb-labs/panel/pkg/firewall"
"github.com/tnb-labs/panel/pkg/io"
"github.com/tnb-labs/panel/pkg/os"
"github.com/tnb-labs/panel/pkg/systemctl"
"github.com/tnb-labs/panel/pkg/types"
)
@@ -310,6 +311,20 @@ func (r *settingRepo) UpdatePanel(req *request.SettingPanel) (bool, error) {
if os.TCPPortInUse(req.Port) {
return false, errors.New(r.t.Get("port is already in use"))
}
// 放行端口
if ok, _ := systemctl.IsEnabled("firewalld"); ok {
fw := firewall.NewFirewall()
err = fw.Port(firewall.FireInfo{
Type: firewall.TypeNormal,
PortStart: config.HTTP.Port,
PortEnd: config.HTTP.Port,
Direction: firewall.DirectionIn,
Strategy: firewall.StrategyAccept,
}, firewall.OperationAdd)
if err != nil {
return false, err
}
}
}
config.App.Locale = req.Locale
@@ -321,19 +336,6 @@ func (r *settingRepo) UpdatePanel(req *request.SettingPanel) (bool, error) {
config.HTTP.BindUA = req.BindUA
config.Session.Lifetime = req.Lifetime
// 放行端口
fw := firewall.NewFirewall()
err = fw.Port(firewall.FireInfo{
Type: firewall.TypeNormal,
PortStart: config.HTTP.Port,
PortEnd: config.HTTP.Port,
Direction: firewall.DirectionIn,
Strategy: firewall.StrategyAccept,
}, firewall.OperationAdd)
if err != nil {
return false, err
}
encoded, err := yaml.Marshal(config)
if err != nil {
return false, err
+10
View File
@@ -62,6 +62,16 @@ func (r *userRepo) Create(username, password, email string) (*biz.User, error) {
return user, nil
}
func (r *userRepo) UpdateUsername(id uint, username string) error {
user, err := r.Get(id)
if err != nil {
return err
}
user.Username = username
return r.db.Save(user).Error
}
func (r *userRepo) UpdatePassword(id uint, password string) error {
value, err := r.hasher.Make(password)
if err != nil {
+21 -2
View File
@@ -11,7 +11,7 @@ import (
"io"
"net"
"net/http"
"slices"
"strings"
"time"
"github.com/go-rat/utils/str"
@@ -144,7 +144,26 @@ func (r userTokenRepo) ValidateReq(req *http.Request) (uint, error) {
if err != nil {
ip = req.RemoteAddr
}
if !slices.Contains(userToken.IPs, ip) {
allowed := false
requestIP := net.ParseIP(ip)
if requestIP != nil {
for _, allowedIP := range userToken.IPs {
if strings.Contains(allowedIP, "/") {
// CIDR
if _, ipNet, err := net.ParseCIDR(allowedIP); err == nil && ipNet.Contains(requestIP) {
allowed = true
break
}
} else {
// IP
if allowedIP == ip {
allowed = true
break
}
}
}
}
if !allowed {
return 0, errors.New(r.t.Get("invalid request ip: %s", ip))
}
}
+9
View File
@@ -223,6 +223,15 @@ func (r *websiteRepo) List(page, limit uint) ([]*biz.Website, int64, error) {
return nil, 0, err
}
// 取证书剩余有效时间
for _, website := range websites {
crt, _ := io.Read(filepath.Join(app.Root, "server/vhost/cert", website.Name+".pem"))
if decode, err := cert.ParseCert(crt); err == nil {
hours := time.Until(decode.NotAfter).Hours()
website.CertExpire = fmt.Sprintf("%.2f", hours/24)
}
}
return websites, total, nil
}
+41 -46
View File
@@ -11,8 +11,6 @@ import (
"github.com/go-rat/sessions"
"github.com/knadh/koanf/v2"
"github.com/leonelquinteros/gotext"
"github.com/spf13/cast"
"github.com/tnb-labs/panel/pkg/punycode"
)
@@ -22,19 +20,11 @@ func Entrance(t *gotext.Locale, conf *koanf.Koanf, session *sessions.Manager) fu
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
sess, err := session.GetSession(r)
if err != nil {
render := chix.NewRender(w)
defer render.Release()
render.Status(http.StatusInternalServerError)
render.JSON(chix.M{
"msg": err.Error(),
})
Abort(w, http.StatusInternalServerError, "%v", err)
return
}
entrance := strings.TrimSuffix(conf.String("http.entrance"), "/")
if entrance == "" {
entrance = "/"
}
if !strings.HasPrefix(entrance, "/") {
entrance = "/" + entrance
}
@@ -50,44 +40,54 @@ func Entrance(t *gotext.Locale, conf *koanf.Koanf, session *sessions.Manager) fu
}
}
if len(conf.Strings("http.bind_domain")) > 0 && !slices.Contains(conf.Strings("http.bind_domain"), host) {
render := chix.NewRender(w)
defer render.Release()
render.Status(http.StatusTeapot)
render.JSON(chix.M{
"msg": t.Get("invalid request domain: %s", r.Host),
})
Abort(w, http.StatusTeapot, t.Get("invalid request domain: %s", r.Host))
return
}
ip, _, err := net.SplitHostPort(r.RemoteAddr)
if err != nil {
ip = r.RemoteAddr
}
if len(conf.Strings("http.bind_ip")) > 0 && !slices.Contains(conf.Strings("http.bind_ip"), ip) {
render := chix.NewRender(w)
defer render.Release()
render.Status(http.StatusTeapot)
render.JSON(chix.M{
"msg": t.Get("invalid request ip: %s", ip),
})
return
if len(conf.Strings("http.bind_ip")) > 0 {
allowed := false
requestIP := net.ParseIP(ip)
if requestIP != nil {
for _, allowedIP := range conf.Strings("http.bind_ip") {
if strings.Contains(allowedIP, "/") {
// CIDR
if _, ipNet, err := net.ParseCIDR(allowedIP); err == nil && ipNet.Contains(requestIP) {
allowed = true
break
}
} else {
// IP
if allowedIP == ip {
allowed = true
break
}
}
}
}
if !allowed {
Abort(w, http.StatusTeapot, t.Get("invalid request ip: %s", ip))
return
}
}
if len(conf.Strings("http.bind_ua")) > 0 && !slices.Contains(conf.Strings("http.bind_ua"), r.UserAgent()) {
render := chix.NewRender(w)
defer render.Release()
render.Status(http.StatusTeapot)
render.JSON(chix.M{
"msg": t.Get("invalid request user agent: %s", r.UserAgent()),
})
Abort(w, http.StatusTeapot, t.Get("invalid request user agent: %s", r.UserAgent()))
return
}
// 情况二:请求路径与入口路径相同,标记通过验证并重定向到登录页面
if strings.TrimSuffix(r.URL.Path, "/") == entrance {
// 情况二:请求路径与入口路径相同或未设置访问入口,标记通过验证并重定向
if (strings.TrimSuffix(r.URL.Path, "/") == entrance || entrance == "/") &&
r.Header.Get("Authorization") == "" {
sess.Put("verify_entrance", true)
render := chix.NewRender(w, r)
defer render.Release()
render.Redirect("/login")
return
// 设置入口的情况下进行重定向
if entrance != "/" {
render := chix.NewRender(w, r)
defer render.Release()
render.Redirect("/login")
return
}
}
// 情况三:通过APIKey+入口路径访问,重写请求路径并跳过验证
@@ -96,23 +96,18 @@ func Entrance(t *gotext.Locale, conf *koanf.Koanf, session *sessions.Manager) fu
if entrance != "/" {
if rctx := chi.RouteContext(r.Context()); rctx != nil {
rctx.RoutePath = strings.TrimPrefix(rctx.RoutePath, entrance)
r.URL.Path = strings.TrimPrefix(r.URL.Path, entrance)
}
r.URL.Path = strings.TrimPrefix(r.URL.Path, entrance)
}
next.ServeHTTP(w, r)
return
}
// 情况:非调试模式且未通过验证的请求,返回错误
// 情况:非调试模式且未通过验证的请求,返回错误
if !conf.Bool("app.debug") &&
!cast.ToBool(sess.Get("verify_entrance", false)) &&
sess.Missing("verify_entrance") &&
r.URL.Path != "/robots.txt" {
render := chix.NewRender(w)
defer render.Release()
render.Status(http.StatusTeapot)
render.JSON(chix.M{
"msg": t.Get("invalid access entrance"),
})
Abort(w, http.StatusTeapot, t.Get("invalid access entrance"))
return
}
+21
View File
@@ -0,0 +1,21 @@
package middleware
import (
"fmt"
"net/http"
"github.com/go-rat/chix"
)
func Abort(w http.ResponseWriter, code int, format string, args ...any) {
render := chix.NewRender(w)
defer render.Release()
render.Header(chix.HeaderContentType, chix.MIMEApplicationJSONCharsetUTF8) // must before Status()
render.Status(code)
if len(args) > 0 {
format = fmt.Sprintf(format, args...)
}
render.JSON(chix.M{
"msg": format,
})
}
+3 -5
View File
@@ -39,16 +39,14 @@ func NewMiddlewares(conf *koanf.Koanf, log *slog.Logger, session *sessions.Manag
// Globals is a collection of global middleware that will be applied to every request.
func (r *Middlewares) Globals(t *gotext.Locale, mux *chi.Mux) []func(http.Handler) http.Handler {
return []func(http.Handler) http.Handler{
sessionmiddleware.StartSession(r.session),
middleware.Recoverer,
//middleware.SupressNotFound(mux),// bug https://github.com/go-chi/chi/pull/940
middleware.CleanPath,
middleware.StripSlashes,
middleware.Compress(5),
httplog.RequestLogger(r.log, &httplog.Options{
Level: slog.LevelInfo,
LogRequestHeaders: []string{"User-Agent"},
}),
middleware.Recoverer,
middleware.Compress(5),
sessionmiddleware.StartSession(r.session),
Status(t),
Entrance(t, r.conf, r.session),
MustLogin(t, r.session, r.userToken),
+2 -13
View File
@@ -4,7 +4,6 @@ import (
"net/http"
"strings"
"github.com/go-rat/chix"
"github.com/leonelquinteros/gotext"
"github.com/tnb-labs/panel/internal/biz"
@@ -22,12 +21,7 @@ func MustInstall(t *gotext.Locale, app biz.AppRepo) func(next http.Handler) http
} else if strings.HasPrefix(r.URL.Path, "/api/apps/") {
pathArr := strings.Split(r.URL.Path, "/")
if len(pathArr) < 4 {
render := chix.NewRender(w)
defer render.Release()
render.Status(http.StatusForbidden)
render.JSON(chix.M{
"msg": t.Get("app not found"),
})
Abort(w, http.StatusForbidden, t.Get("app not found"))
return
}
slugs = append(slugs, pathArr[3])
@@ -41,12 +35,7 @@ func MustInstall(t *gotext.Locale, app biz.AppRepo) func(next http.Handler) http
}
}
if !flag && len(slugs) > 0 {
render := chix.NewRender(w)
defer render.Release()
render.Status(http.StatusForbidden)
render.JSON(chix.M{
"msg": t.Get("app %s not installed", slugs),
})
Abort(w, http.StatusForbidden, t.Get("app %s not installed", slugs))
return
}
+7 -37
View File
@@ -9,7 +9,6 @@ import (
"slices"
"strings"
"github.com/go-rat/chix"
"github.com/go-rat/sessions"
"github.com/leonelquinteros/gotext"
"github.com/spf13/cast"
@@ -32,12 +31,7 @@ func MustLogin(t *gotext.Locale, session *sessions.Manager, userToken biz.UserTo
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
sess, err := session.GetSession(r)
if err != nil {
render := chix.NewRender(w)
defer render.Release()
render.Status(http.StatusInternalServerError)
render.JSON(chix.M{
"msg": err.Error(),
})
Abort(w, http.StatusInternalServerError, "%v", err)
return
}
@@ -51,32 +45,17 @@ func MustLogin(t *gotext.Locale, session *sessions.Manager, userToken biz.UserTo
if r.Header.Get("Authorization") != "" {
// 禁止访问 ws 相关的接口
if strings.HasPrefix(r.URL.Path, "/api/ws") {
render := chix.NewRender(w)
defer render.Release()
render.Status(http.StatusForbidden)
render.JSON(chix.M{
"msg": t.Get("ws not allowed"),
})
Abort(w, http.StatusForbidden, t.Get("ws not allowed"))
return
}
// API 请求验证
if userID, err = userToken.ValidateReq(r); err != nil {
render := chix.NewRender(w)
defer render.Release()
render.Status(http.StatusUnauthorized)
render.JSON(chix.M{
"msg": err.Error(),
})
Abort(w, http.StatusUnauthorized, "%v", err)
return
}
} else {
if sess.Missing("user_id") {
render := chix.NewRender(w)
defer render.Release()
render.Status(http.StatusUnauthorized)
render.JSON(chix.M{
"msg": t.Get("session expired, please login again"),
})
Abort(w, http.StatusUnauthorized, t.Get("session expired, please login again"))
return
}
@@ -86,12 +65,8 @@ func MustLogin(t *gotext.Locale, session *sessions.Manager, userToken biz.UserTo
ip, _, _ := net.SplitHostPort(strings.TrimSpace(r.RemoteAddr))
clientHash := fmt.Sprintf("%x", sha256.Sum256([]byte(ip)))
if safeClientHash != clientHash || safeClientHash == "" {
render := chix.NewRender(w)
defer render.Release()
render.Status(http.StatusUnauthorized)
render.JSON(chix.M{
"msg": t.Get("client ip/ua changed, please login again"),
})
sess.Forget("user_id") // 清除 user_id,否则会来回跳转
Abort(w, http.StatusUnauthorized, t.Get("client ip/ua changed, please login again"))
return
}
}
@@ -100,12 +75,7 @@ func MustLogin(t *gotext.Locale, session *sessions.Manager, userToken biz.UserTo
}
if userID == 0 {
render := chix.NewRender(w)
defer render.Release()
render.Status(http.StatusUnauthorized)
render.JSON(chix.M{
"msg": t.Get("invalid user id, please login again"),
})
Abort(w, http.StatusUnauthorized, "%v", t.Get("invalid user id, please login again"))
return
}
+4 -25
View File
@@ -3,7 +3,6 @@ package middleware
import (
"net/http"
"github.com/go-rat/chix"
"github.com/leonelquinteros/gotext"
"github.com/tnb-labs/panel/internal/app"
@@ -15,36 +14,16 @@ func Status(t *gotext.Locale) func(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
switch app.Status {
case app.StatusUpgrade:
render := chix.NewRender(w)
defer render.Release()
render.Status(http.StatusServiceUnavailable)
render.JSON(chix.M{
"msg": t.Get("panel is upgrading, please refresh later"),
})
Abort(w, http.StatusServiceUnavailable, t.Get("panel is upgrading, please refresh later"))
return
case app.StatusMaintain:
render := chix.NewRender(w)
defer render.Release()
render.Status(http.StatusServiceUnavailable)
render.JSON(chix.M{
"msg": t.Get("panel is maintaining, please refresh later"),
})
Abort(w, http.StatusServiceUnavailable, t.Get("panel is maintaining, please refresh later"))
return
case app.StatusClosed:
render := chix.NewRender(w)
defer render.Release()
render.Status(http.StatusForbidden)
render.JSON(chix.M{
"msg": t.Get("panel is closed"),
})
Abort(w, http.StatusServiceUnavailable, t.Get("panel is closed"))
return
case app.StatusFailed:
render := chix.NewRender(w)
defer render.Release()
render.Status(http.StatusInternalServerError)
render.JSON(chix.M{
"msg": t.Get("panel run error, please check or contact support"),
})
Abort(w, http.StatusInternalServerError, t.Get("panel run error, please check or contact support"))
return
default:
next.ServeHTTP(w, r)
+1 -1
View File
@@ -25,7 +25,7 @@ type SettingPanel struct {
func (r *SettingPanel) Rules(_ *http.Request) map[string]string {
return map[string]string{
"BindDomain.*": "required",
"BindIP.*": "required|ip",
"BindIP.*": "required|ipcidr",
"BindUA.*": "required",
}
}
+5
View File
@@ -21,6 +21,11 @@ type UserCreate struct {
Email string `json:"email" validate:"required|email"`
}
type UserUpdateUsername struct {
ID uint `json:"id" validate:"required|exists:users,id"`
Username string `json:"username" validate:"required|notExists:users,username"`
}
type UserUpdatePassword struct {
ID uint `json:"id" validate:"required|exists:users,id"`
Password string `json:"password" validate:"required|password"`
+2 -2
View File
@@ -15,7 +15,7 @@ type UserTokenCreate struct {
func (r *UserTokenCreate) Rules(_ *http.Request) map[string]string {
return map[string]string{
"IPs.*": "required|ip",
"IPs.*": "required|ipcidr",
}
}
@@ -27,6 +27,6 @@ type UserTokenUpdate struct {
func (r *UserTokenUpdate) Rules(_ *http.Request) map[string]string {
return map[string]string{
"IPs.*": "required|ip",
"IPs.*": "required|ipcidr",
}
}
+22
View File
@@ -0,0 +1,22 @@
package rule
import "net"
// IPCIDR 验证一个值是否是一个有效的 IP 或 CIDR 格式
type IPCIDR struct{}
func NewIPCIDR() *IPCIDR {
return &IPCIDR{}
}
func (r *IPCIDR) Passes(val any, options ...any) bool {
if str, ok := val.(string); ok {
if ip := net.ParseIP(str); ip != nil {
return true // 是有效的 IP
}
if _, _, err := net.ParseCIDR(str); err == nil {
return true // 是有效的 CIDR
}
}
return false // 既不是 IP 也不是 CIDR
}
+2
View File
@@ -11,11 +11,13 @@ func GlobalRules(db *gorm.DB) {
"notExists": NewNotExists(db).Passes,
"password": NewPassword().Passes,
"cron": NewCron().Passes,
"ipcidr": NewIPCIDR().Passes,
})
validate.AddGlobalMessages(map[string]string{
"exists": "{field} 不存在",
"notExists": "{field} 已存在",
"password": "密码不满足要求(8-20位,至少包含字母、数字、特殊字符中的两种)",
"cron": "Cron 表达式不合法",
"ipcidr": "IP 或 CIDR 格式不合法",
})
}
+1
View File
@@ -127,6 +127,7 @@ func (route *Http) Register(r *chi.Mux) {
r.Route("/users", func(r chi.Router) {
r.Get("/", route.user.List)
r.Post("/", route.user.Create)
r.Post("/{id}/username", route.user.UpdateUsername)
r.Post("/{id}/password", route.user.UpdatePassword)
r.Post("/{id}/email", route.user.UpdateEmail)
r.Get("/{id}/2fa", route.user.GenerateTwoFA)
+1 -1
View File
@@ -17,7 +17,7 @@ import (
"github.com/leonelquinteros/gotext"
"github.com/spf13/cast"
"github.com/urfave/cli/v3"
"gopkg.in/yaml.v3"
"go.yaml.in/yaml/v3"
"gorm.io/gorm"
"github.com/tnb-labs/panel/internal/app"
+5 -10
View File
@@ -3,7 +3,6 @@ package service
import (
"net/http"
"slices"
"strings"
"github.com/go-rat/chix"
@@ -179,15 +178,11 @@ func (s *FirewallService) CreateIPRule(w http.ResponseWriter, r *http.Request) {
return
}
// rich rule 下,address 不支持多个地址,需要单独添加
addresses := strings.Split(req.Address, ",")
for address := range slices.Values(addresses) {
if err = s.firewall.RichRules(firewall.FireInfo{
Family: req.Family, Address: address, Protocol: firewall.Protocol(req.Protocol), Strategy: firewall.Strategy(req.Strategy), Direction: firewall.Direction(req.Direction),
}, firewall.OperationAdd); err != nil {
Error(w, http.StatusInternalServerError, "%v", err)
return
}
if err = s.firewall.RichRules(firewall.FireInfo{
Family: req.Family, Address: req.Address, Protocol: firewall.Protocol(req.Protocol), Strategy: firewall.Strategy(req.Strategy), Direction: firewall.Direction(req.Direction),
}, firewall.OperationAdd); err != nil {
Error(w, http.StatusInternalServerError, "%v", err)
return
}
Success(w, nil)
+22 -5
View File
@@ -120,13 +120,15 @@ func (s *UserService) Login(w http.ResponseWriter, r *http.Request) {
func (s *UserService) Logout(w http.ResponseWriter, r *http.Request) {
sess, err := s.session.GetSession(r)
if err == nil {
if err = sess.Invalidate(); err != nil {
Error(w, http.StatusInternalServerError, "%v", err)
return
}
if err != nil {
Error(w, http.StatusInternalServerError, "%v", err)
}
sess.Forget("user_id")
sess.Forget("key")
sess.Forget("safe_login")
sess.Forget("safe_client")
Success(w, nil)
}
@@ -206,6 +208,21 @@ func (s *UserService) Create(w http.ResponseWriter, r *http.Request) {
Success(w, user)
}
func (s *UserService) UpdateUsername(w http.ResponseWriter, r *http.Request) {
req, err := Bind[request.UserUpdateUsername](r)
if err != nil {
Error(w, http.StatusUnprocessableEntity, "%v", err)
return
}
if err = s.userRepo.UpdateUsername(req.ID, req.Username); err != nil {
Error(w, http.StatusInternalServerError, "%v", err)
return
}
Success(w, nil)
}
func (s *UserService) UpdatePassword(w http.ResponseWriter, r *http.Request) {
req, err := Bind[request.UserUpdatePassword](r)
if err != nil {
+47
View File
@@ -582,6 +582,53 @@ func (_c *UserRepo_UpdateTwoFA_Call) RunAndReturn(run func(uint, string, string)
return _c
}
// UpdateUsername provides a mock function with given fields: id, username
func (_m *UserRepo) UpdateUsername(id uint, username string) error {
ret := _m.Called(id, username)
if len(ret) == 0 {
panic("no return value specified for UpdateUsername")
}
var r0 error
if rf, ok := ret.Get(0).(func(uint, string) error); ok {
r0 = rf(id, username)
} else {
r0 = ret.Error(0)
}
return r0
}
// UserRepo_UpdateUsername_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'UpdateUsername'
type UserRepo_UpdateUsername_Call struct {
*mock.Call
}
// UpdateUsername is a helper method to define mock.On call
// - id uint
// - username string
func (_e *UserRepo_Expecter) UpdateUsername(id interface{}, username interface{}) *UserRepo_UpdateUsername_Call {
return &UserRepo_UpdateUsername_Call{Call: _e.mock.On("UpdateUsername", id, username)}
}
func (_c *UserRepo_UpdateUsername_Call) Run(run func(id uint, username string)) *UserRepo_UpdateUsername_Call {
_c.Call.Run(func(args mock.Arguments) {
run(args[0].(uint), args[1].(string))
})
return _c
}
func (_c *UserRepo_UpdateUsername_Call) Return(_a0 error) *UserRepo_UpdateUsername_Call {
_c.Call.Return(_a0)
return _c
}
func (_c *UserRepo_UpdateUsername_Call) RunAndReturn(run func(uint, string) error) *UserRepo_UpdateUsername_Call {
_c.Call.Return(run)
return _c
}
// NewUserRepo creates a new instance of UserRepo. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations.
// The first argument is typically a *testing.T value.
func NewUserRepo(t interface {
+14 -12
View File
@@ -35,14 +35,16 @@ func (c *Client) UseDns(dnsType DnsType, param DNSParam) {
}
// UseManualDns 使用手动 DNS 验证
func (c *Client) UseManualDns(total int, check ...bool) {
func (c *Client) UseManualDns(check ...bool) {
c.controlChan = make(chan struct{})
c.dataChan = make(chan any)
c.dnsChan = make(chan any)
c.certChan = make(chan any)
c.zClient.ChallengeSolvers = map[string]acmez.Solver{
acme.ChallengeTypeDNS01: &manualDNSSolver{
check: len(check) > 0 && check[0],
controlChan: c.controlChan,
dataChan: c.dataChan,
dnsChan: c.dnsChan,
certChan: c.certChan,
records: []DNSRecord{},
},
}
@@ -84,13 +86,13 @@ func (c *Client) ObtainCertificateManual() (Certificate, error) {
// 发送信号,开始验证
c.controlChan <- struct{}{}
// 等待验证完成
data := <-c.dataChan
certs := <-c.certChan
if err, ok := data.(error); ok {
if err, ok := certs.(error); ok {
return Certificate{}, err
}
return data.(Certificate), nil
return certs.(Certificate), nil
}
// RenewCertificate 续签 SSL 证书
@@ -107,22 +109,22 @@ func (c *Client) RenewCertificate(ctx context.Context, certUrl string, domains [
func (c *Client) GetDNSRecords(ctx context.Context, domains []string, keyType KeyType) ([]DNSRecord, error) {
go func(ctx context.Context, domains []string, keyType KeyType) {
certs, err := c.ObtainCertificate(ctx, domains, keyType)
// 将证书和错误信息发送到 dataChan
// 将证书和错误信息发送到 certChan
if err != nil {
c.dataChan <- err
c.certChan <- err
return
}
c.dataChan <- certs
c.certChan <- certs
}(ctx, domains, keyType)
// 这里要少一次循环,因为需要卡住最后一次的 dataChan,等待手动 DNS 验证完成
// 这里要少一次循环,因为需要卡住最后一次的 dnsChan,等待手动 DNS 验证完成
for i := 1; i < len(domains); i++ {
<-c.dataChan
<-c.dnsChan
c.controlChan <- struct{}{}
}
// 因为上面少了一次循环,所以这里接收到的即为完整的 DNS 记录切片
data := <-c.dataChan
data := <-c.dnsChan
if err, ok := data.(error); ok {
return nil, err
}
+6 -4
View File
@@ -267,9 +267,10 @@ type DNSProvider interface {
}
type manualDNSSolver struct {
check bool
check bool // 是否检查 DNS 解析,目前没写
controlChan chan struct{}
dataChan chan any
dnsChan chan any
certChan chan any
records []DNSRecord
}
@@ -286,7 +287,7 @@ func (s *manualDNSSolver) Present(ctx context.Context, challenge acme.Challenge)
Domain: domain,
Value: keyAuth,
})
s.dataChan <- s.records
s.dnsChan <- s.records
select {
case <-s.controlChan:
@@ -301,7 +302,8 @@ func (s *manualDNSSolver) CleanUp(_ context.Context, _ acme.Challenge) error {
_ = recover()
}()
close(s.controlChan)
close(s.dataChan)
close(s.dnsChan)
close(s.certChan)
return nil
}
+9 -1
View File
@@ -71,7 +71,15 @@ func (r *Postgres) Prepare(query string) (*sql.Stmt, error) {
}
func (r *Postgres) DatabaseCreate(name string) error {
_, err := r.Exec(fmt.Sprintf("CREATE DATABASE %s", name))
// postgres 不支持 CREATE DATABASE IF NOT EXISTS,但是为了保持与 MySQL 一致,先检查数据库是否存在
exist, err := r.DatabaseExist(name)
if err != nil {
return err
}
if exist {
return nil
}
_, err = r.Exec(fmt.Sprintf("CREATE DATABASE %s", name))
return err
}
+85 -81
View File
@@ -7,8 +7,8 @@ msgstr ""
"Language: \n"
"X-Generator: xgotext\n"
#: internal/data/website.go:270
#: internal/data/website.go:643
#: internal/data/website.go:279
#: internal/data/website.go:652
msgid "# Rewrite rule"
msgstr ""
@@ -28,7 +28,7 @@ msgstr ""
msgid "Accepted Connections"
msgstr ""
#: internal/apps/mysql/app.go:121
#: internal/apps/mysql/app.go:124
msgid "Active Connections"
msgstr ""
@@ -56,7 +56,7 @@ msgstr ""
msgid "Already initialized"
msgstr ""
#: internal/data/app.go:347
#: internal/data/app.go:350
msgid "App %s %s"
msgstr ""
@@ -134,13 +134,13 @@ msgstr ""
msgid "Bind domain disabled"
msgstr ""
#: internal/apps/mysql/app.go:120
#: internal/apps/mysql/app.go:139
#: internal/apps/mysql/app.go:123
#: internal/apps/mysql/app.go:142
msgid "Bytes Received"
msgstr ""
#: internal/apps/mysql/app.go:119
#: internal/apps/mysql/app.go:139
#: internal/apps/mysql/app.go:122
#: internal/apps/mysql/app.go:142
msgid "Bytes Sent"
msgstr ""
@@ -460,11 +460,11 @@ msgstr ""
msgid "Forumhttps://bbs.haozi.net"
msgstr ""
#: internal/apps/mysql/app.go:127
#: internal/apps/mysql/app.go:130
msgid "Full Joins without Index"
msgstr ""
#: internal/apps/mysql/app.go:128
#: internal/apps/mysql/app.go:131
msgid "Full Range Joins without Index"
msgstr ""
@@ -544,7 +544,7 @@ msgstr ""
msgid "ImageMagick is free software for creating, editing, and composing images"
msgstr ""
#: internal/apps/mysql/app.go:123
#: internal/apps/mysql/app.go:126
msgid "Index Hit Rate"
msgstr ""
@@ -559,7 +559,7 @@ msgstr ""
msgid "Initialize panel (use only under guidance)"
msgstr ""
#: internal/apps/mysql/app.go:124
#: internal/apps/mysql/app.go:127
msgid "Innodb Index Hit Rate"
msgstr ""
@@ -567,7 +567,7 @@ msgstr ""
msgid "Install PHP-%d %s extension"
msgstr ""
#: internal/data/app.go:191
#: internal/data/app.go:194
msgid "Install app %s"
msgstr ""
@@ -732,7 +732,7 @@ msgstr ""
msgid "Old username cannot be empty"
msgstr ""
#: internal/apps/mysql/app.go:126
#: internal/apps/mysql/app.go:129
msgid "Open Tables"
msgstr ""
@@ -807,7 +807,7 @@ msgstr ""
msgid "Path where the website is hosted (default path if not filled)"
msgstr ""
#: internal/apps/mysql/app.go:122
#: internal/apps/mysql/app.go:125
msgid "Peak Connections"
msgstr ""
@@ -911,7 +911,7 @@ msgstr ""
msgid "Restart panel service"
msgstr ""
#: internal/apps/mysql/app.go:118
#: internal/apps/mysql/app.go:121
msgid "Rollbacks per Second"
msgstr ""
@@ -983,7 +983,7 @@ msgstr ""
msgid "Slow Requests"
msgstr ""
#: internal/apps/mysql/app.go:130
#: internal/apps/mysql/app.go:133
msgid "Sort Merge Passes"
msgstr ""
@@ -1004,7 +1004,7 @@ msgstr ""
msgid "Storage Usage"
msgstr ""
#: internal/apps/mysql/app.go:129
#: internal/apps/mysql/app.go:132
msgid "Subqueries without Index"
msgstr ""
@@ -1040,7 +1040,7 @@ msgstr ""
msgid "TCP Port"
msgstr ""
#: internal/apps/mysql/app.go:131
#: internal/apps/mysql/app.go:134
msgid "Table Locks Waited"
msgstr ""
@@ -1048,7 +1048,7 @@ msgstr ""
msgid "Tasks cleared successfully"
msgstr ""
#: internal/apps/mysql/app.go:125
#: internal/apps/mysql/app.go:128
msgid "Temporary Tables Created on Disk"
msgstr ""
@@ -1076,7 +1076,7 @@ msgstr ""
msgid "Total Commands Processed"
msgstr ""
#: internal/apps/mysql/app.go:116
#: internal/apps/mysql/app.go:119
#: internal/apps/postgresql/app.go:143
msgid "Total Connections"
msgstr ""
@@ -1093,7 +1093,7 @@ msgstr ""
msgid "Total Processes"
msgstr ""
#: internal/apps/mysql/app.go:115
#: internal/apps/mysql/app.go:118
msgid "Total Queries"
msgstr ""
@@ -1109,7 +1109,7 @@ msgstr ""
msgid "Total requests"
msgstr ""
#: internal/apps/mysql/app.go:117
#: internal/apps/mysql/app.go:120
msgid "Transactions per Second"
msgstr ""
@@ -1128,7 +1128,7 @@ msgstr ""
msgid "Uninstall PHP-%d %s extension"
msgstr ""
#: internal/data/app.go:246
#: internal/data/app.go:249
msgid "Uninstall app %s"
msgstr ""
@@ -1144,7 +1144,7 @@ msgstr ""
msgid "Unzip panel data failed: %v"
msgstr ""
#: internal/data/app.go:301
#: internal/data/app.go:304
msgid "Update app %s"
msgstr ""
@@ -1156,7 +1156,7 @@ msgstr ""
msgid "Update panel"
msgstr ""
#: internal/apps/mysql/app.go:114
#: internal/apps/mysql/app.go:117
msgid "Uptime"
msgstr ""
@@ -1270,38 +1270,38 @@ msgstr ""
msgid "Zip is a library for handling ZIP files"
msgstr ""
#: internal/data/app.go:159
#: internal/data/app.go:162
msgid "app %s already installed"
msgstr ""
#: internal/data/app.go:56
#: internal/data/app.go:59
msgid "app %s not found"
msgstr ""
#: internal/data/app.go:210
#: internal/data/app.go:265
#: internal/http/middleware/must_install.go:48
#: internal/data/app.go:213
#: internal/data/app.go:268
#: internal/http/middleware/must_install.go:38
msgid "app %s not installed"
msgstr ""
#: internal/data/app.go:179
#: internal/data/app.go:289
#: internal/data/app.go:182
#: internal/data/app.go:292
msgid "app %s not support current panel version"
msgstr ""
#: internal/data/app.go:170
#: internal/data/app.go:225
#: internal/data/app.go:280
#: internal/data/app.go:173
#: internal/data/app.go:228
#: internal/data/app.go:283
msgid "app %s requires panel version %s, current version %s"
msgstr ""
#: internal/http/middleware/must_install.go:29
#: internal/http/middleware/must_install.go:24
msgid "app not found"
msgstr ""
#: internal/data/setting.go:282
#: internal/data/setting.go:343
#: internal/data/setting.go:356
#: internal/data/setting.go:283
#: internal/data/setting.go:345
#: internal/data/setting.go:358
msgid "background task is running, modifying some settings is prohibited, please try again later"
msgstr ""
@@ -1323,7 +1323,7 @@ msgstr ""
msgid "can't download a directory"
msgstr ""
#: internal/data/website.go:371
#: internal/data/website.go:380
msgid "can't find %s database server, please add it first"
msgstr ""
@@ -1332,7 +1332,7 @@ msgstr ""
msgid "check server connection failed"
msgstr ""
#: internal/http/middleware/must_login.go:93
#: internal/http/middleware/must_login.go:69
msgid "client ip/ua changed, please login again"
msgstr ""
@@ -1359,11 +1359,11 @@ msgstr ""
msgid "database does not exist: %s"
msgstr ""
#: internal/data/website.go:725
#: internal/data/website.go:734
msgid "default document comment count is incorrect, expected 1, actual %d"
msgstr ""
#: internal/data/website.go:722
#: internal/data/website.go:731
msgid "default document comment not found"
msgstr ""
@@ -1431,7 +1431,7 @@ msgstr ""
msgid "failed to get %s service running status: %v"
msgstr ""
#: internal/data/website.go:306
#: internal/data/website.go:315
msgid "failed to get 404 template file: %v"
msgstr ""
@@ -1504,7 +1504,7 @@ msgstr ""
msgid "failed to get home apps: %v"
msgstr ""
#: internal/data/website.go:294
#: internal/data/website.go:303
msgid "failed to get index template file: %v"
msgstr ""
@@ -1580,28 +1580,28 @@ msgstr ""
msgid "failed to get total banned list"
msgstr ""
#: internal/data/app.go:234
#: internal/data/app.go:237
msgid "failed to get uninstall script for app %s"
msgstr ""
#: internal/apps/mysql/app.go:188
#: internal/apps/mysql/app.go:191
#: internal/apps/mysql/app.go:83
msgid "failed to load MySQL root password: %v"
msgstr ""
#: internal/data/cert.go:92
#: internal/data/setting.go:287
#: internal/data/setting.go:359
#: internal/data/website.go:475
#: internal/data/website.go:764
#: internal/data/setting.go:288
#: internal/data/setting.go:361
#: internal/data/website.go:484
#: internal/data/website.go:773
msgid "failed to parse certificate: %v"
msgstr ""
#: internal/data/cert.go:95
#: internal/data/setting.go:290
#: internal/data/setting.go:362
#: internal/data/website.go:478
#: internal/data/website.go:767
#: internal/data/setting.go:291
#: internal/data/setting.go:364
#: internal/data/website.go:487
#: internal/data/website.go:776
msgid "failed to parse private key: %v"
msgstr ""
@@ -1697,6 +1697,10 @@ msgstr ""
msgid "failed to unmount: %v"
msgstr ""
#: internal/apps/mysql/app.go:108
msgid "failed to unset MYSQL_PWD env: %v"
msgstr ""
#: internal/service/toolbox_system.go:63
msgid "failed to update DNS: %v"
msgstr ""
@@ -1717,13 +1721,13 @@ msgstr ""
msgid "get service port failed, please check if it is installed"
msgstr ""
#: internal/data/user.go:170
#: internal/data/user.go:189
#: internal/data/user.go:180
#: internal/data/user.go:199
#: internal/service/user.go:96
msgid "invalid 2FA code"
msgstr ""
#: internal/http/middleware/entrance.go:114
#: internal/http/middleware/entrance.go:110
msgid "invalid access entrance"
msgstr ""
@@ -1735,16 +1739,16 @@ msgstr ""
msgid "invalid key, please refresh the page"
msgstr ""
#: internal/http/middleware/entrance.go:57
#: internal/http/middleware/entrance.go:43
msgid "invalid request domain: %s"
msgstr ""
#: internal/data/user_token.go:148
#: internal/http/middleware/entrance.go:70
#: internal/data/user_token.go:167
#: internal/http/middleware/entrance.go:71
msgid "invalid request ip: %s"
msgstr ""
#: internal/http/middleware/entrance.go:79
#: internal/http/middleware/entrance.go:76
msgid "invalid request user agent: %s"
msgstr ""
@@ -1754,7 +1758,7 @@ msgstr ""
msgid "invalid signature"
msgstr ""
#: internal/http/middleware/must_login.go:107
#: internal/http/middleware/must_login.go:78
msgid "invalid user id, please login again"
msgstr ""
@@ -1795,7 +1799,7 @@ msgstr ""
msgid "mysql not support database comment"
msgstr ""
#: internal/data/website.go:795
#: internal/data/website.go:804
msgid "not support one-key obtain wildcard certificate, please use Cert menu to obtain it with DNS method"
msgstr ""
@@ -1803,19 +1807,19 @@ msgstr ""
msgid "open file error: %v"
msgstr ""
#: internal/http/middleware/status.go:38
#: internal/http/middleware/status.go:23
msgid "panel is closed"
msgstr ""
#: internal/http/middleware/status.go:30
#: internal/http/middleware/status.go:20
msgid "panel is maintaining, please refresh later"
msgstr ""
#: internal/http/middleware/status.go:22
#: internal/http/middleware/status.go:17
msgid "panel is upgrading, please refresh later"
msgstr ""
#: internal/http/middleware/status.go:46
#: internal/http/middleware/status.go:26
msgid "panel run error, please check or contact support"
msgstr ""
@@ -1840,7 +1844,7 @@ msgstr ""
msgid "phpMyAdmin port not found"
msgstr ""
#: internal/data/user.go:96
#: internal/data/user.go:106
#: internal/service/file.go:135
#: internal/service/file.go:222
#: internal/service/file.go:251
@@ -1851,7 +1855,7 @@ msgstr ""
msgid "please retry the manual obtain operation"
msgstr ""
#: internal/data/setting.go:311
#: internal/data/setting.go:312
msgid "port is already in use"
msgstr ""
@@ -1871,20 +1875,20 @@ msgstr ""
msgid "rule not found"
msgstr ""
#: internal/data/website.go:712
#: internal/data/website.go:721
msgid "runtime directory comment count is incorrect, expected 1, actual %d"
msgstr ""
#: internal/data/website.go:709
#: internal/data/website.go:718
msgid "runtime directory comment not found"
msgstr ""
#: internal/data/website.go:449
#: internal/data/website.go:716
#: internal/data/website.go:458
#: internal/data/website.go:725
msgid "runtime directory does not exist"
msgstr ""
#: internal/http/middleware/must_login.go:78
#: internal/http/middleware/must_login.go:58
msgid "session expired, please login again"
msgstr ""
@@ -1982,17 +1986,17 @@ msgstr ""
msgid "upload file error: %v"
msgstr ""
#: internal/data/user.go:116
#: internal/data/user.go:123
#: internal/data/user.go:126
#: internal/data/user.go:133
#: internal/data/user.go:143
msgid "username or password error"
msgstr ""
#: internal/data/website.go:560
#: internal/data/website.go:569
msgid "website %s has bound certificates, please delete the certificate first"
msgstr ""
#: internal/data/website.go:456
#: internal/data/website.go:465
msgid "website directory does not exist"
msgstr ""
@@ -2005,7 +2009,7 @@ msgstr ""
msgid "write file error: %v"
msgstr ""
#: internal/http/middleware/must_login.go:58
#: internal/http/middleware/must_login.go:48
msgid "ws not allowed"
msgstr ""
+92 -88
View File
@@ -9,14 +9,14 @@ msgstr ""
"X-Crowdin-Project: ratpanel\n"
"X-Crowdin-Project-ID: 778640\n"
"X-Crowdin-Language: zh-CN\n"
"X-Crowdin-File: /main/pkg/embed/locales/backend.pot\n"
"X-Crowdin-File: /[tnb-labs.panel] main/pkg/embed/locales/backend.pot\n"
"X-Crowdin-File-ID: 922\n"
"Project-Id-Version: ratpanel\n"
"Language-Team: Chinese Simplified\n"
"PO-Revision-Date: 2025-05-18 18:00\n"
"PO-Revision-Date: 2025-07-07 10:34\n"
#: internal/data/website.go:270
#: internal/data/website.go:643
#: internal/data/website.go:279
#: internal/data/website.go:652
msgid "# Rewrite rule"
msgstr "# 伪静态规则"
@@ -36,7 +36,7 @@ msgstr "作者"
msgid "Accepted Connections"
msgstr "已接受连接"
#: internal/apps/mysql/app.go:121
#: internal/apps/mysql/app.go:124
msgid "Active Connections"
msgstr "活动连接"
@@ -64,7 +64,7 @@ msgstr "阿里云"
msgid "Already initialized"
msgstr "已经初始化过了"
#: internal/data/app.go:347
#: internal/data/app.go:350
msgid "App %s %s"
msgstr "应用 %s %s"
@@ -142,13 +142,13 @@ msgstr "绑定 UA 已禁用"
msgid "Bind domain disabled"
msgstr "绑定域名已禁用"
#: internal/apps/mysql/app.go:120
#: internal/apps/mysql/app.go:139
#: internal/apps/mysql/app.go:123
#: internal/apps/mysql/app.go:142
msgid "Bytes Received"
msgstr "已接收字节"
#: internal/apps/mysql/app.go:119
#: internal/apps/mysql/app.go:139
#: internal/apps/mysql/app.go:122
#: internal/apps/mysql/app.go:142
msgid "Bytes Sent"
msgstr "已发送字节"
@@ -468,11 +468,11 @@ msgstr "修复面板"
msgid "Forumhttps://bbs.haozi.net"
msgstr "论坛:https://bbs.haozi.net"
#: internal/apps/mysql/app.go:127
#: internal/apps/mysql/app.go:130
msgid "Full Joins without Index"
msgstr "没有使用索引的 Join"
#: internal/apps/mysql/app.go:128
#: internal/apps/mysql/app.go:131
msgid "Full Range Joins without Index"
msgstr "没有使用索引的范围 Join"
@@ -552,7 +552,7 @@ msgstr "Igbinary 是一个用于序列化和反序列化数据的库"
msgid "ImageMagick is free software for creating, editing, and composing images"
msgstr "ImageMagick 是一个创建、编辑、合成图片的免费软件"
#: internal/apps/mysql/app.go:123
#: internal/apps/mysql/app.go:126
msgid "Index Hit Rate"
msgstr "索引命中率"
@@ -567,7 +567,7 @@ msgstr "初始化失败:%v"
msgid "Initialize panel (use only under guidance)"
msgstr "初始化面板(仅在指导下使用)"
#: internal/apps/mysql/app.go:124
#: internal/apps/mysql/app.go:127
msgid "Innodb Index Hit Rate"
msgstr "Innodb 索引命中率"
@@ -575,7 +575,7 @@ msgstr "Innodb 索引命中率"
msgid "Install PHP-%d %s extension"
msgstr "安装 PHP-%d %s 扩展"
#: internal/data/app.go:191
#: internal/data/app.go:194
msgid "Install app %s"
msgstr "安装应用 %s"
@@ -740,7 +740,7 @@ msgstr "OPcache 将 PHP 脚本预编译的字节码存储到共享内存中来
msgid "Old username cannot be empty"
msgstr "旧用户名不能为空"
#: internal/apps/mysql/app.go:126
#: internal/apps/mysql/app.go:129
msgid "Open Tables"
msgstr "已打开的表"
@@ -815,7 +815,7 @@ msgstr "密码:%s"
msgid "Path where the website is hosted (default path if not filled)"
msgstr "网站托管的路径(不填则使用默认路径)"
#: internal/apps/mysql/app.go:122
#: internal/apps/mysql/app.go:125
msgid "Peak Connections"
msgstr "峰值连接数"
@@ -919,7 +919,7 @@ msgstr "移除网站"
msgid "Restart panel service"
msgstr "重启面板服务"
#: internal/apps/mysql/app.go:118
#: internal/apps/mysql/app.go:121
msgid "Rollbacks per Second"
msgstr "每秒回滚"
@@ -991,7 +991,7 @@ msgstr "设置不存在"
msgid "Slow Requests"
msgstr "慢请求"
#: internal/apps/mysql/app.go:130
#: internal/apps/mysql/app.go:133
msgid "Sort Merge Passes"
msgstr "排序后的合并次数"
@@ -1012,7 +1012,7 @@ msgstr "停止面板服务"
msgid "Storage Usage"
msgstr "存储使用"
#: internal/apps/mysql/app.go:129
#: internal/apps/mysql/app.go:132
msgid "Subqueries without Index"
msgstr "没有索引的子查询"
@@ -1048,7 +1048,7 @@ msgstr "Sysvshm 是一个处理 V 共享内存的库"
msgid "TCP Port"
msgstr "TCP 端口"
#: internal/apps/mysql/app.go:131
#: internal/apps/mysql/app.go:134
msgid "Table Locks Waited"
msgstr "锁表次数"
@@ -1056,7 +1056,7 @@ msgstr "锁表次数"
msgid "Tasks cleared successfully"
msgstr "任务已成功清除"
#: internal/apps/mysql/app.go:125
#: internal/apps/mysql/app.go:128
msgid "Temporary Tables Created on Disk"
msgstr "创建临时表到磁盘"
@@ -1084,7 +1084,7 @@ msgstr "已分配内存总量"
msgid "Total Commands Processed"
msgstr "执行的命令总数"
#: internal/apps/mysql/app.go:116
#: internal/apps/mysql/app.go:119
#: internal/apps/postgresql/app.go:143
msgid "Total Connections"
msgstr "总连接数"
@@ -1101,7 +1101,7 @@ msgstr "内存使用总数"
msgid "Total Processes"
msgstr "总进程数"
#: internal/apps/mysql/app.go:115
#: internal/apps/mysql/app.go:118
msgid "Total Queries"
msgstr "查询总数"
@@ -1117,7 +1117,7 @@ msgstr "总握手数"
msgid "Total requests"
msgstr "总请求数"
#: internal/apps/mysql/app.go:117
#: internal/apps/mysql/app.go:120
msgid "Transactions per Second"
msgstr "每秒事务"
@@ -1136,7 +1136,7 @@ msgstr "无法在离线模式下更新应用列表缓存"
msgid "Uninstall PHP-%d %s extension"
msgstr "卸载 PHP-%d %s 扩展"
#: internal/data/app.go:246
#: internal/data/app.go:249
msgid "Uninstall app %s"
msgstr "卸载应用 %s"
@@ -1152,7 +1152,7 @@ msgstr "解压备份文件失败:%v"
msgid "Unzip panel data failed: %v"
msgstr "解压面板数据失败:%v"
#: internal/data/app.go:301
#: internal/data/app.go:304
msgid "Update app %s"
msgstr "更新应用 %s"
@@ -1164,7 +1164,7 @@ msgstr "更新应用"
msgid "Update panel"
msgstr "更新面板"
#: internal/apps/mysql/app.go:114
#: internal/apps/mysql/app.go:117
msgid "Uptime"
msgstr "运行时间"
@@ -1278,38 +1278,38 @@ msgstr "XSL 是用于处理 XML 文档的库"
msgid "Zip is a library for handling ZIP files"
msgstr "Zip 是一个用于处理 ZIP 文件的库"
#: internal/data/app.go:159
#: internal/data/app.go:162
msgid "app %s already installed"
msgstr "应用 %s 已安装"
#: internal/data/app.go:56
#: internal/data/app.go:59
msgid "app %s not found"
msgstr "找不到应用 %s"
#: internal/data/app.go:210
#: internal/data/app.go:265
#: internal/http/middleware/must_install.go:48
#: internal/data/app.go:213
#: internal/data/app.go:268
#: internal/http/middleware/must_install.go:38
msgid "app %s not installed"
msgstr "应用 %s 未安装"
#: internal/data/app.go:179
#: internal/data/app.go:289
#: internal/data/app.go:182
#: internal/data/app.go:292
msgid "app %s not support current panel version"
msgstr "应用 %s 不支持当前面板版本"
#: internal/data/app.go:170
#: internal/data/app.go:225
#: internal/data/app.go:280
#: internal/data/app.go:173
#: internal/data/app.go:228
#: internal/data/app.go:283
msgid "app %s requires panel version %s, current version %s"
msgstr "应用 %s 需要面板版本 %s,当前版本 %s"
#: internal/http/middleware/must_install.go:29
#: internal/http/middleware/must_install.go:24
msgid "app not found"
msgstr "应用未找到"
#: internal/data/setting.go:282
#: internal/data/setting.go:343
#: internal/data/setting.go:356
#: internal/data/setting.go:283
#: internal/data/setting.go:345
#: internal/data/setting.go:358
msgid "background task is running, modifying some settings is prohibited, please try again later"
msgstr "后台任务正在运行,禁止修改某些设置,请稍后再试"
@@ -1331,7 +1331,7 @@ msgstr "备份文件 %s 不存在"
msgid "can't download a directory"
msgstr "无法下载目录"
#: internal/data/website.go:371
#: internal/data/website.go:380
msgid "can't find %s database server, please add it first"
msgstr "找不到 %s 数据库服务器,请先添加"
@@ -1340,7 +1340,7 @@ msgstr "找不到 %s 数据库服务器,请先添加"
msgid "check server connection failed"
msgstr "检查服务器连接失败"
#: internal/http/middleware/must_login.go:93
#: internal/http/middleware/must_login.go:69
msgid "client ip/ua changed, please login again"
msgstr "客户端 IP/UA 已更改,请重新登录"
@@ -1367,11 +1367,11 @@ msgstr "cron 日志目录 %s 不存在"
msgid "database does not exist: %s"
msgstr "数据库不存在:%s"
#: internal/data/website.go:725
#: internal/data/website.go:734
msgid "default document comment count is incorrect, expected 1, actual %d"
msgstr "默认文档注释数量不正确,预期为1,实际为 %d"
#: internal/data/website.go:722
#: internal/data/website.go:731
msgid "default document comment not found"
msgstr "未找到默认文档注释"
@@ -1439,7 +1439,7 @@ msgstr "获取 %s 服务启用状态失败:%v"
msgid "failed to get %s service running status: %v"
msgstr "获取 %s 服务运行状态失败:%v"
#: internal/data/website.go:306
#: internal/data/website.go:315
msgid "failed to get 404 template file: %v"
msgstr "获取404模板文件失败:%v"
@@ -1512,7 +1512,7 @@ msgstr "获取磁盘空间失败: %v"
msgid "failed to get home apps: %v"
msgstr "获取主页应用失败: %v"
#: internal/data/website.go:294
#: internal/data/website.go:303
msgid "failed to get index template file: %v"
msgstr "获取首页模板文件失败:%v"
@@ -1588,28 +1588,28 @@ msgstr "获取时区失败: %v"
msgid "failed to get total banned list"
msgstr "获取全部被禁止的列表失败"
#: internal/data/app.go:234
#: internal/data/app.go:237
msgid "failed to get uninstall script for app %s"
msgstr "获取应用 %s 的卸载脚本失败"
#: internal/apps/mysql/app.go:188
#: internal/apps/mysql/app.go:191
#: internal/apps/mysql/app.go:83
msgid "failed to load MySQL root password: %v"
msgstr "加载 MySQL root 密码失败: %v"
#: internal/data/cert.go:92
#: internal/data/setting.go:287
#: internal/data/setting.go:359
#: internal/data/website.go:475
#: internal/data/website.go:764
#: internal/data/setting.go:288
#: internal/data/setting.go:361
#: internal/data/website.go:484
#: internal/data/website.go:773
msgid "failed to parse certificate: %v"
msgstr "解析证书失败: %v"
#: internal/data/cert.go:95
#: internal/data/setting.go:290
#: internal/data/setting.go:362
#: internal/data/website.go:478
#: internal/data/website.go:767
#: internal/data/setting.go:291
#: internal/data/setting.go:364
#: internal/data/website.go:487
#: internal/data/website.go:776
msgid "failed to parse private key: %v"
msgstr "解析私钥失败: %v"
@@ -1675,7 +1675,7 @@ msgstr "运行命令失败: %v"
#: internal/apps/mysql/app.go:99
msgid "failed to set MYSQL_PWD env: %v"
msgstr "设置 MYSQL_PWD 环境变量失败: %v"
msgstr "设置 MYSQL_PWD 环境变量失败:%v"
#: internal/service/toolbox_system.go:159
msgid "failed to set SWAP permission: %v"
@@ -1705,6 +1705,10 @@ msgstr "停止 %s 服务失败: %v"
msgid "failed to unmount: %v"
msgstr "卸载失败: %v"
#: internal/apps/mysql/app.go:108
msgid "failed to unset MYSQL_PWD env: %v"
msgstr "取消设置 MYSQL_PWD 环境变量失败:%v"
#: internal/service/toolbox_system.go:63
msgid "failed to update DNS: %v"
msgstr "更新 DNS失败: %v"
@@ -1725,13 +1729,13 @@ msgstr "gRPC 是一个高性能、开源和通用的 RPC 框架"
msgid "get service port failed, please check if it is installed"
msgstr "获取服务端口失败,请检查是否安装"
#: internal/data/user.go:175
#: internal/data/user.go:198
#: internal/service/user.go:102
#: internal/data/user.go:180
#: internal/data/user.go:199
#: internal/service/user.go:96
msgid "invalid 2FA code"
msgstr "无效的两步验证代码"
#: internal/http/middleware/entrance.go:114
#: internal/http/middleware/entrance.go:110
msgid "invalid access entrance"
msgstr "无效的访问入口"
@@ -1739,20 +1743,20 @@ msgstr "无效的访问入口"
msgid "invalid header: %v"
msgstr "无效的请求头: %v"
#: internal/service/user.go:84
#: internal/service/user.go:82
msgid "invalid key, please refresh the page"
msgstr "无效的密钥,请刷新页面"
#: internal/http/middleware/entrance.go:57
#: internal/http/middleware/entrance.go:43
msgid "invalid request domain: %s"
msgstr "无效的请求域名:%s"
#: internal/data/user_token.go:148
#: internal/http/middleware/entrance.go:70
#: internal/data/user_token.go:167
#: internal/http/middleware/entrance.go:71
msgid "invalid request ip: %s"
msgstr "无效的请求 IP%s"
#: internal/http/middleware/entrance.go:79
#: internal/http/middleware/entrance.go:76
msgid "invalid request user agent: %s"
msgstr "无效的请求UA%s"
@@ -1762,7 +1766,7 @@ msgstr "无效的请求UA%s"
msgid "invalid signature"
msgstr "无效的签名"
#: internal/http/middleware/must_login.go:107
#: internal/http/middleware/must_login.go:78
msgid "invalid user id, please login again"
msgstr "无效的用户ID,请重新登录"
@@ -1803,7 +1807,7 @@ msgstr "挂载路径不为空"
msgid "mysql not support database comment"
msgstr "mysql 不支持数据库注释"
#: internal/data/website.go:795
#: internal/data/website.go:804
msgid "not support one-key obtain wildcard certificate, please use Cert menu to obtain it with DNS method"
msgstr "不支持一键获取通配符证书,请在证书菜单通过 DNS 方法获取"
@@ -1811,19 +1815,19 @@ msgstr "不支持一键获取通配符证书,请在证书菜单通过 DNS 方
msgid "open file error: %v"
msgstr "打开文件错误: %v"
#: internal/http/middleware/status.go:38
#: internal/http/middleware/status.go:23
msgid "panel is closed"
msgstr "面板已关闭"
#: internal/http/middleware/status.go:30
#: internal/http/middleware/status.go:20
msgid "panel is maintaining, please refresh later"
msgstr "面板正在维护,请稍后刷新"
#: internal/http/middleware/status.go:22
#: internal/http/middleware/status.go:17
msgid "panel is upgrading, please refresh later"
msgstr "面板正在升级,请稍后刷新"
#: internal/http/middleware/status.go:46
#: internal/http/middleware/status.go:26
msgid "panel run error, please check or contact support"
msgstr "面板运行错误,请检查或联系技术支持"
@@ -1848,7 +1852,7 @@ msgstr "没有找到 phpMyAdmin 目录"
msgid "phpMyAdmin port not found"
msgstr "没有找到 phpMyAdmin 端口"
#: internal/data/user.go:97
#: internal/data/user.go:106
#: internal/service/file.go:135
#: internal/service/file.go:222
#: internal/service/file.go:251
@@ -1859,7 +1863,7 @@ msgstr "请不要花样作死"
msgid "please retry the manual obtain operation"
msgstr "请重新操作手动签发"
#: internal/data/setting.go:311
#: internal/data/setting.go:312
msgid "port is already in use"
msgstr "端口已被占用"
@@ -1879,20 +1883,20 @@ msgstr "规则已存在"
msgid "rule not found"
msgstr "找不到规则"
#: internal/data/website.go:712
#: internal/data/website.go:721
msgid "runtime directory comment count is incorrect, expected 1, actual %d"
msgstr "运行时目录注释数量不正确,预期为1,实际为%d"
#: internal/data/website.go:709
#: internal/data/website.go:718
msgid "runtime directory comment not found"
msgstr "未找到运行目录注释"
#: internal/data/website.go:449
#: internal/data/website.go:716
#: internal/data/website.go:458
#: internal/data/website.go:725
msgid "runtime directory does not exist"
msgstr "运行目录不存在"
#: internal/http/middleware/must_login.go:78
#: internal/http/middleware/must_login.go:58
msgid "session expired, please login again"
msgstr "会话已过期,请重新登录"
@@ -1990,17 +1994,17 @@ msgstr "上传的证书无法设置为自动续签"
msgid "upload file error: %v"
msgstr "上传文件错误:%v"
#: internal/data/user.go:117
#: internal/data/user.go:124
#: internal/data/user.go:134
#: internal/data/user.go:126
#: internal/data/user.go:133
#: internal/data/user.go:143
msgid "username or password error"
msgstr "用户名或密码错误"
#: internal/data/website.go:560
#: internal/data/website.go:569
msgid "website %s has bound certificates, please delete the certificate first"
msgstr "网站 %s 已绑定证书,请先删除证书"
#: internal/data/website.go:456
#: internal/data/website.go:465
msgid "website directory does not exist"
msgstr "网站目录不存在"
@@ -2013,7 +2017,7 @@ msgstr "通配符域名不能使用 HTTP 验证"
msgid "write file error: %v"
msgstr "写入文件错误:%v"
#: internal/http/middleware/must_login.go:58
#: internal/http/middleware/must_login.go:48
msgid "ws not allowed"
msgstr "不允许 ws"
@@ -2194,7 +2198,7 @@ msgstr "|-运行更新后脚本……"
#: internal/data/backup.go:684
#: internal/data/backup.go:815
msgid "|-Set key file permissions..."
msgstr "|-设置密钥文件权限……"
msgstr "|-设置关键文件权限……"
#: internal/data/backup.go:577
msgid "|-Start fixing the panel..."
+91 -87
View File
@@ -9,14 +9,14 @@ msgstr ""
"X-Crowdin-Project: ratpanel\n"
"X-Crowdin-Project-ID: 778640\n"
"X-Crowdin-Language: zh-TW\n"
"X-Crowdin-File: /main/pkg/embed/locales/backend.pot\n"
"X-Crowdin-File: /[tnb-labs.panel] main/pkg/embed/locales/backend.pot\n"
"X-Crowdin-File-ID: 922\n"
"Project-Id-Version: ratpanel\n"
"Language-Team: Chinese Traditional\n"
"PO-Revision-Date: 2025-05-18 18:01\n"
"PO-Revision-Date: 2025-07-07 10:34\n"
#: internal/data/website.go:270
#: internal/data/website.go:643
#: internal/data/website.go:279
#: internal/data/website.go:652
msgid "# Rewrite rule"
msgstr "# 重寫規則"
@@ -36,7 +36,7 @@ msgstr "作者"
msgid "Accepted Connections"
msgstr "已接受連接"
#: internal/apps/mysql/app.go:121
#: internal/apps/mysql/app.go:124
msgid "Active Connections"
msgstr "活動連接"
@@ -64,7 +64,7 @@ msgstr "阿里雲"
msgid "Already initialized"
msgstr "已經初始化過了"
#: internal/data/app.go:347
#: internal/data/app.go:350
msgid "App %s %s"
msgstr "應用 %s %s"
@@ -142,13 +142,13 @@ msgstr "繫結 UA 已禁用"
msgid "Bind domain disabled"
msgstr "繫結網域已禁用"
#: internal/apps/mysql/app.go:120
#: internal/apps/mysql/app.go:139
#: internal/apps/mysql/app.go:123
#: internal/apps/mysql/app.go:142
msgid "Bytes Received"
msgstr "已接收字節"
#: internal/apps/mysql/app.go:119
#: internal/apps/mysql/app.go:139
#: internal/apps/mysql/app.go:122
#: internal/apps/mysql/app.go:142
msgid "Bytes Sent"
msgstr "已發送字節"
@@ -468,11 +468,11 @@ msgstr "修復面板"
msgid "Forumhttps://bbs.haozi.net"
msgstr "論壇:https://bbs.haozi.net"
#: internal/apps/mysql/app.go:127
#: internal/apps/mysql/app.go:130
msgid "Full Joins without Index"
msgstr "沒有使用索引的 Join"
#: internal/apps/mysql/app.go:128
#: internal/apps/mysql/app.go:131
msgid "Full Range Joins without Index"
msgstr "沒有使用索引的範圍 Join"
@@ -552,7 +552,7 @@ msgstr "Igbinary 是一個用於序列化和反序列化數據的庫"
msgid "ImageMagick is free software for creating, editing, and composing images"
msgstr "ImageMagick 是一個創建、編輯、合成圖片的免費軟件"
#: internal/apps/mysql/app.go:123
#: internal/apps/mysql/app.go:126
msgid "Index Hit Rate"
msgstr "索引命中率"
@@ -567,7 +567,7 @@ msgstr "初始化失敗:%v"
msgid "Initialize panel (use only under guidance)"
msgstr "初始化面板(僅在指導下使用)"
#: internal/apps/mysql/app.go:124
#: internal/apps/mysql/app.go:127
msgid "Innodb Index Hit Rate"
msgstr "Innodb 索引命中率"
@@ -575,7 +575,7 @@ msgstr "Innodb 索引命中率"
msgid "Install PHP-%d %s extension"
msgstr "安裝 PHP-%d %s 擴展"
#: internal/data/app.go:191
#: internal/data/app.go:194
msgid "Install app %s"
msgstr "安裝應用 %s"
@@ -740,7 +740,7 @@ msgstr "OPcache 將 PHP 腳本預編譯的位元組碼儲存到共享記憶體
msgid "Old username cannot be empty"
msgstr "舊用戶名不能為空"
#: internal/apps/mysql/app.go:126
#: internal/apps/mysql/app.go:129
msgid "Open Tables"
msgstr "已開啟的表"
@@ -815,7 +815,7 @@ msgstr "密碼:%s"
msgid "Path where the website is hosted (default path if not filled)"
msgstr "網站託管的路徑(不填則使用默認路徑)"
#: internal/apps/mysql/app.go:122
#: internal/apps/mysql/app.go:125
msgid "Peak Connections"
msgstr "峰值連接數"
@@ -919,7 +919,7 @@ msgstr "移除網站"
msgid "Restart panel service"
msgstr "重新啟動面板服務"
#: internal/apps/mysql/app.go:118
#: internal/apps/mysql/app.go:121
msgid "Rollbacks per Second"
msgstr "每秒回滾"
@@ -991,7 +991,7 @@ msgstr "設置不存在"
msgid "Slow Requests"
msgstr "慢請求"
#: internal/apps/mysql/app.go:130
#: internal/apps/mysql/app.go:133
msgid "Sort Merge Passes"
msgstr "排序後的合併次數"
@@ -1012,7 +1012,7 @@ msgstr "停止面板服務"
msgid "Storage Usage"
msgstr "存儲使用"
#: internal/apps/mysql/app.go:129
#: internal/apps/mysql/app.go:132
msgid "Subqueries without Index"
msgstr "沒有索引的子查詢"
@@ -1048,7 +1048,7 @@ msgstr "Sysvshm 是一個處理系統 V 共享記憶體的庫"
msgid "TCP Port"
msgstr "TCP 連接埠"
#: internal/apps/mysql/app.go:131
#: internal/apps/mysql/app.go:134
msgid "Table Locks Waited"
msgstr "等待表鎖定"
@@ -1056,7 +1056,7 @@ msgstr "等待表鎖定"
msgid "Tasks cleared successfully"
msgstr "任務已成功清除"
#: internal/apps/mysql/app.go:125
#: internal/apps/mysql/app.go:128
msgid "Temporary Tables Created on Disk"
msgstr "在磁碟上創建的臨時表"
@@ -1084,7 +1084,7 @@ msgstr "已分配記憶體總量"
msgid "Total Commands Processed"
msgstr "已處理的命令總數"
#: internal/apps/mysql/app.go:116
#: internal/apps/mysql/app.go:119
#: internal/apps/postgresql/app.go:143
msgid "Total Connections"
msgstr "總連接數"
@@ -1101,7 +1101,7 @@ msgstr "記憶體使用總量"
msgid "Total Processes"
msgstr "總進程數"
#: internal/apps/mysql/app.go:115
#: internal/apps/mysql/app.go:118
msgid "Total Queries"
msgstr "查詢總數"
@@ -1117,7 +1117,7 @@ msgstr "總握手數"
msgid "Total requests"
msgstr "總請求數"
#: internal/apps/mysql/app.go:117
#: internal/apps/mysql/app.go:120
msgid "Transactions per Second"
msgstr "每秒事務"
@@ -1136,7 +1136,7 @@ msgstr "無法在離線模式下更新應用程式列表快取"
msgid "Uninstall PHP-%d %s extension"
msgstr "卸載 PHP-%d %s 擴展"
#: internal/data/app.go:246
#: internal/data/app.go:249
msgid "Uninstall app %s"
msgstr "卸載應用 %s"
@@ -1152,7 +1152,7 @@ msgstr "解壓備份檔案失敗:%v"
msgid "Unzip panel data failed: %v"
msgstr "解壓面板數據失敗:%v"
#: internal/data/app.go:301
#: internal/data/app.go:304
msgid "Update app %s"
msgstr "更新應用 %s"
@@ -1164,7 +1164,7 @@ msgstr "更新應用"
msgid "Update panel"
msgstr "更新面板"
#: internal/apps/mysql/app.go:114
#: internal/apps/mysql/app.go:117
msgid "Uptime"
msgstr "運行時間"
@@ -1278,38 +1278,38 @@ msgstr "XSL 是用於處理 XML 文檔的庫"
msgid "Zip is a library for handling ZIP files"
msgstr "Zip 是一個用於處理 ZIP 文件的庫"
#: internal/data/app.go:159
#: internal/data/app.go:162
msgid "app %s already installed"
msgstr "應用 %s 已安裝"
#: internal/data/app.go:56
#: internal/data/app.go:59
msgid "app %s not found"
msgstr "找不到應用 %s"
#: internal/data/app.go:210
#: internal/data/app.go:265
#: internal/http/middleware/must_install.go:48
#: internal/data/app.go:213
#: internal/data/app.go:268
#: internal/http/middleware/must_install.go:38
msgid "app %s not installed"
msgstr "應用程式 %s 未安裝"
#: internal/data/app.go:179
#: internal/data/app.go:289
#: internal/data/app.go:182
#: internal/data/app.go:292
msgid "app %s not support current panel version"
msgstr "應用程式 %s 不支援目前面板版本"
#: internal/data/app.go:170
#: internal/data/app.go:225
#: internal/data/app.go:280
#: internal/data/app.go:173
#: internal/data/app.go:228
#: internal/data/app.go:283
msgid "app %s requires panel version %s, current version %s"
msgstr "應用程式 %s 需要面板版本 %s,目前版本 %s"
#: internal/http/middleware/must_install.go:29
#: internal/http/middleware/must_install.go:24
msgid "app not found"
msgstr "找不到應用"
#: internal/data/setting.go:282
#: internal/data/setting.go:343
#: internal/data/setting.go:356
#: internal/data/setting.go:283
#: internal/data/setting.go:345
#: internal/data/setting.go:358
msgid "background task is running, modifying some settings is prohibited, please try again later"
msgstr "後台任務正在運行,禁止修改某些設置,請稍後再試"
@@ -1331,7 +1331,7 @@ msgstr "備份檔案 %s 不存在"
msgid "can't download a directory"
msgstr "無法下載目錄"
#: internal/data/website.go:371
#: internal/data/website.go:380
msgid "can't find %s database server, please add it first"
msgstr "找不到 %s 數據庫服務器,請先添加"
@@ -1340,7 +1340,7 @@ msgstr "找不到 %s 數據庫服務器,請先添加"
msgid "check server connection failed"
msgstr "檢查伺服器連接失敗"
#: internal/http/middleware/must_login.go:93
#: internal/http/middleware/must_login.go:69
msgid "client ip/ua changed, please login again"
msgstr "客戶端 IP/UA 已更改,請重新登入"
@@ -1367,11 +1367,11 @@ msgstr "cron 日誌目錄 %s 不存在"
msgid "database does not exist: %s"
msgstr "資料庫不存在:%s"
#: internal/data/website.go:725
#: internal/data/website.go:734
msgid "default document comment count is incorrect, expected 1, actual %d"
msgstr "默認文檔註釋數量不正確,預期為1,實際為 %d"
#: internal/data/website.go:722
#: internal/data/website.go:731
msgid "default document comment not found"
msgstr "未找到預設文件註釋"
@@ -1439,7 +1439,7 @@ msgstr "無法獲取 %s 服務啟用狀態:%v"
msgid "failed to get %s service running status: %v"
msgstr "無法獲取 %s 服務運行狀態:%v"
#: internal/data/website.go:306
#: internal/data/website.go:315
msgid "failed to get 404 template file: %v"
msgstr "獲取404模板文件失敗:%v"
@@ -1512,7 +1512,7 @@ msgstr "無法獲取磁盤空間:%v"
msgid "failed to get home apps: %v"
msgstr "無法獲取主頁應用:%v"
#: internal/data/website.go:294
#: internal/data/website.go:303
msgid "failed to get index template file: %v"
msgstr "獲取首頁模板文件失敗:%v"
@@ -1588,28 +1588,28 @@ msgstr "無法獲取時區:%v"
msgid "failed to get total banned list"
msgstr "無法獲取全部被禁止的列表"
#: internal/data/app.go:234
#: internal/data/app.go:237
msgid "failed to get uninstall script for app %s"
msgstr "無法取得應用程式 %s 的解除安裝腳本"
#: internal/apps/mysql/app.go:188
#: internal/apps/mysql/app.go:191
#: internal/apps/mysql/app.go:83
msgid "failed to load MySQL root password: %v"
msgstr "無法載入 MySQL root 密碼:%v"
#: internal/data/cert.go:92
#: internal/data/setting.go:287
#: internal/data/setting.go:359
#: internal/data/website.go:475
#: internal/data/website.go:764
#: internal/data/setting.go:288
#: internal/data/setting.go:361
#: internal/data/website.go:484
#: internal/data/website.go:773
msgid "failed to parse certificate: %v"
msgstr "無法解析證書:%v"
#: internal/data/cert.go:95
#: internal/data/setting.go:290
#: internal/data/setting.go:362
#: internal/data/website.go:478
#: internal/data/website.go:767
#: internal/data/setting.go:291
#: internal/data/setting.go:364
#: internal/data/website.go:487
#: internal/data/website.go:776
msgid "failed to parse private key: %v"
msgstr "解析私鑰失敗:%v"
@@ -1705,6 +1705,10 @@ msgstr "停止 %s 服務失敗:%v"
msgid "failed to unmount: %v"
msgstr "卸載失敗:%v"
#: internal/apps/mysql/app.go:108
msgid "failed to unset MYSQL_PWD env: %v"
msgstr "取消設置 MYSQL_PWD 環境變量失敗:%v"
#: internal/service/toolbox_system.go:63
msgid "failed to update DNS: %v"
msgstr "更新 DNS 失敗: %v"
@@ -1725,13 +1729,13 @@ msgstr "gRPC 是一個高性能、開源和通用的 RPC 框架"
msgid "get service port failed, please check if it is installed"
msgstr "獲取服務端口失敗,請檢查是否安裝"
#: internal/data/user.go:175
#: internal/data/user.go:198
#: internal/service/user.go:102
#: internal/data/user.go:180
#: internal/data/user.go:199
#: internal/service/user.go:96
msgid "invalid 2FA code"
msgstr "無效的兩步驗證代碼"
#: internal/http/middleware/entrance.go:114
#: internal/http/middleware/entrance.go:110
msgid "invalid access entrance"
msgstr "無效的訪問入口"
@@ -1739,20 +1743,20 @@ msgstr "無效的訪問入口"
msgid "invalid header: %v"
msgstr "無效的請求標頭:%v"
#: internal/service/user.go:84
#: internal/service/user.go:82
msgid "invalid key, please refresh the page"
msgstr "無效的密鑰,請重新整理頁面"
#: internal/http/middleware/entrance.go:57
#: internal/http/middleware/entrance.go:43
msgid "invalid request domain: %s"
msgstr "無效的請求域名:%s"
#: internal/data/user_token.go:148
#: internal/http/middleware/entrance.go:70
#: internal/data/user_token.go:167
#: internal/http/middleware/entrance.go:71
msgid "invalid request ip: %s"
msgstr "無效的請求 IP%s"
#: internal/http/middleware/entrance.go:79
#: internal/http/middleware/entrance.go:76
msgid "invalid request user agent: %s"
msgstr "無效的請求UA%s"
@@ -1762,7 +1766,7 @@ msgstr "無效的請求UA%s"
msgid "invalid signature"
msgstr "無效的簽名"
#: internal/http/middleware/must_login.go:107
#: internal/http/middleware/must_login.go:78
msgid "invalid user id, please login again"
msgstr "無效的用戶ID,請重新登錄"
@@ -1803,7 +1807,7 @@ msgstr "掛載路徑不為空"
msgid "mysql not support database comment"
msgstr "mysql 不支援資料庫註釋"
#: internal/data/website.go:795
#: internal/data/website.go:804
msgid "not support one-key obtain wildcard certificate, please use Cert menu to obtain it with DNS method"
msgstr "不支持一鍵獲取通配符證書,請在證書菜單通過 DNS 方法獲取"
@@ -1811,19 +1815,19 @@ msgstr "不支持一鍵獲取通配符證書,請在證書菜單通過 DNS 方
msgid "open file error: %v"
msgstr "開啟檔案錯誤:%v"
#: internal/http/middleware/status.go:38
#: internal/http/middleware/status.go:23
msgid "panel is closed"
msgstr "面板已關閉"
#: internal/http/middleware/status.go:30
#: internal/http/middleware/status.go:20
msgid "panel is maintaining, please refresh later"
msgstr "面板正在維護,請稍後刷新"
#: internal/http/middleware/status.go:22
#: internal/http/middleware/status.go:17
msgid "panel is upgrading, please refresh later"
msgstr "面板正在升級,請稍後刷新"
#: internal/http/middleware/status.go:46
#: internal/http/middleware/status.go:26
msgid "panel run error, please check or contact support"
msgstr "面板運行錯誤,請檢查或聯繫技術支持"
@@ -1848,7 +1852,7 @@ msgstr "未找到 phpMyAdmin 目錄"
msgid "phpMyAdmin port not found"
msgstr "未找到 phpMyAdmin 端口"
#: internal/data/user.go:97
#: internal/data/user.go:106
#: internal/service/file.go:135
#: internal/service/file.go:222
#: internal/service/file.go:251
@@ -1859,7 +1863,7 @@ msgstr "請不要這樣做"
msgid "please retry the manual obtain operation"
msgstr "請重新操作手動簽發"
#: internal/data/setting.go:311
#: internal/data/setting.go:312
msgid "port is already in use"
msgstr "端口已被佔用"
@@ -1879,20 +1883,20 @@ msgstr "規則已存在"
msgid "rule not found"
msgstr "找不到規則"
#: internal/data/website.go:712
#: internal/data/website.go:721
msgid "runtime directory comment count is incorrect, expected 1, actual %d"
msgstr "運行時目錄註釋數量不正確,預期為1,實際為%d"
#: internal/data/website.go:709
#: internal/data/website.go:718
msgid "runtime directory comment not found"
msgstr "未找到運行目錄註釋"
#: internal/data/website.go:449
#: internal/data/website.go:716
#: internal/data/website.go:458
#: internal/data/website.go:725
msgid "runtime directory does not exist"
msgstr "運行目錄不存在"
#: internal/http/middleware/must_login.go:78
#: internal/http/middleware/must_login.go:58
msgid "session expired, please login again"
msgstr "會話已過期,請重新登錄"
@@ -1990,17 +1994,17 @@ msgstr "上傳的憑證無法設定為自動續簽"
msgid "upload file error: %v"
msgstr "上傳檔案錯誤:%v"
#: internal/data/user.go:117
#: internal/data/user.go:124
#: internal/data/user.go:134
#: internal/data/user.go:126
#: internal/data/user.go:133
#: internal/data/user.go:143
msgid "username or password error"
msgstr "使用者名稱或密碼錯誤"
#: internal/data/website.go:560
#: internal/data/website.go:569
msgid "website %s has bound certificates, please delete the certificate first"
msgstr "網站 %s 已綁定證書,請先刪除證書"
#: internal/data/website.go:456
#: internal/data/website.go:465
msgid "website directory does not exist"
msgstr "網站目錄不存在"
@@ -2013,7 +2017,7 @@ msgstr "萬用字元網域無法使用 HTTP 驗證"
msgid "write file error: %v"
msgstr "寫入檔案錯誤:%v"
#: internal/http/middleware/must_login.go:58
#: internal/http/middleware/must_login.go:48
msgid "ws not allowed"
msgstr "不允許 ws"
@@ -2194,7 +2198,7 @@ msgstr "|-執行更新後腳本……"
#: internal/data/backup.go:684
#: internal/data/backup.go:815
msgid "|-Set key file permissions..."
msgstr "|-設定金鑰檔案權限……"
msgstr "|-設定關鍵檔案權限……"
#: internal/data/backup.go:577
msgid "|-Start fixing the panel..."
+5
View File
@@ -207,6 +207,11 @@ func (r *Firewall) Port(rule FireInfo, operation Operation) error {
}
func (r *Firewall) RichRules(rule FireInfo, operation Operation) error {
// 出站规则下,必须指定具体的地址,否则会添加成入站规则
if rule.Direction == "out" && rule.Address == "" {
return fmt.Errorf("outbound rules must specify an address")
}
protocols := strings.Split(string(rule.Protocol), "/")
for protocol := range slices.Values(protocols) {
var ruleBuilder strings.Builder
+2 -1
View File
@@ -34,6 +34,7 @@
"github.com/libdns/cloudflare",
"github.com/libdns/tencentcloud",
"github.com/libdns/duckdns",
"github.com/libdns/gcore"
"github.com/libdns/gcore",
"github.com/libdns/cloudns"
]
}
+39 -40
View File
@@ -26,12 +26,12 @@
},
"dependencies": {
"@alova/adapter-xhr": "^2.1.1",
"@eslint/eslintrc": "^3.2.0",
"@fontsource-variable/jetbrains-mono": "^5.1.1",
"@guolao/vue-monaco-editor": "^1.5.4",
"@vavt/copy2clipboard": "^1.0.1",
"@vue-js-cron/naive-ui": "^2.0.9",
"@vueuse/core": "^13.0.0",
"@eslint/eslintrc": "^3.3.1",
"@fontsource-variable/jetbrains-mono": "^5.2.5",
"@guolao/vue-monaco-editor": "^1.5.5",
"@vavt/copy2clipboard": "^1.0.3",
"@vue-js-cron/naive-ui": "^2.0.11",
"@vueuse/core": "^13.2.0",
"@xterm/addon-attach": "^0.11.0",
"@xterm/addon-clipboard": "^0.1.0",
"@xterm/addon-fit": "^0.10.0",
@@ -39,60 +39,59 @@
"@xterm/addon-web-links": "^0.11.0",
"@xterm/addon-webgl": "^0.18.0",
"@xterm/xterm": "^5.5.0",
"alova": "^3.2.7",
"cronstrue": "^2.52.0",
"alova": "^3.2.11",
"cronstrue": "^3.0.0",
"echarts": "^5.6.0",
"install": "^0.13.0",
"lodash-es": "^4.17.21",
"luxon": "^3.5.0",
"marked": "^15.0.4",
"luxon": "^3.6.1",
"marked": "^16.0.0",
"mitt": "^3.0.1",
"node-forge": "^1.3.1",
"pinia": "^3.0.0",
"pinia-plugin-persistedstate": "^4.2.0",
"pinia": "^3.0.2",
"pinia-plugin-persistedstate": "^4.3.0",
"remove": "^0.1.5",
"vue": "^3.5.13",
"vue": "^3.5.14",
"vue-echarts": "^7.0.3",
"vue-router": "^4.5.0",
"vue-router": "^4.5.1",
"vue3-gettext": "4.0.0-alpha.8"
},
"devDependencies": {
"@iconify/json": "^2.2.290",
"@iconify/json": "^2.2.341",
"@iconify/vue": "^5.0.0",
"@rushstack/eslint-patch": "^1.10.4",
"@tsconfig/node22": "^22.0.0",
"@rushstack/eslint-patch": "^1.11.0",
"@tsconfig/node22": "^22.0.2",
"@types/lodash-es": "^4.17.12",
"@types/luxon": "^3.4.2",
"@types/node": "^22.10.2",
"@types/luxon": "^3.6.2",
"@types/node": "^22.15.21",
"@types/node-forge": "^1.3.11",
"@unocss/eslint-config": "^66.0.0",
"@vitejs/plugin-vue": "^5.2.1",
"@vue/eslint-config-prettier": "^10.1.0",
"@vue/eslint-config-typescript": "^14.2.0",
"@unocss/eslint-config": "^66.1.2",
"@vitejs/plugin-vue": "^6.0.0",
"@vue/eslint-config-prettier": "^10.2.0",
"@vue/eslint-config-typescript": "^14.5.0",
"@vue/tsconfig": "^0.7.0",
"colord": "^2.9.3",
"cpx2": "^8.0.0",
"eslint": "^9.17.0",
"eslint-plugin-vue": "^10.0.0",
"md-editor-v3": "^5.1.1",
"eslint": "^9.27.0",
"eslint-plugin-vue": "^10.1.0",
"md-editor-v3": "^5.6.0",
"monaco-editor": "^0.52.2",
"naive-ui": "^2.40.4",
"npm-run-all2": "^8.0.0",
"prettier": "^3.4.2",
"naive-ui": "^2.41.0",
"npm-run-all2": "^8.0.4",
"prettier": "^3.5.3",
"prettier-plugin-organize-imports": "^4.1.0",
"sass": "^1.83.0",
"tsx": "^4.19.2",
"sass": "^1.89.0",
"tsx": "^4.19.4",
"typescript": "5.8.3",
"unocss": "^66.0.0",
"unplugin-auto-import": "^19.0.0",
"unplugin-icons": "^22.0.0",
"unplugin-vue-components": "^28.0.0",
"vite": "^6.0.6",
"unocss": "^66.1.2",
"unplugin-auto-import": "^19.3.0",
"unplugin-icons": "^22.1.0",
"unplugin-vue-components": "^28.7.0",
"vite": "^7.0.0",
"vite-plugin-html": "^3.2.2",
"vite-plugin-mock": "^3.0.2",
"vite-plugin-static-copy": "^3.0.0",
"vite-plugin-vue-devtools": "^7.6.8",
"vue-tsc": "^2.2.0"
},
"packageManager": "pnpm@10.10.0+sha512.d615db246fe70f25dcfea6d8d73dee782ce23e2245e3c4f6f888249fb568149318637dca73c2c5c8ef2a4ca0d5657fb9567188bfab47f566d1ee6ce987815c39"
"vite-plugin-vue-devtools": "^7.7.6",
"vue-tsc": "^3.0.0"
}
}
+1372 -1916
View File
File diff suppressed because it is too large Load Diff
+3
View File
@@ -26,6 +26,9 @@ export default {
http.Post('/users', { username, password, email }),
// 删除用户
delete: (id: number): any => http.Delete(`/users/${id}`),
// 更新用户用户名
updateUsername: (id: number, username: string): any =>
http.Post(`/users/${id}/username`, { username }),
// 更新用户邮箱
updateEmail: (id: number, email: string): any => http.Post(`/users/${id}/email`, { email }),
// 更新用户密码
File diff suppressed because it is too large Load Diff
+264 -244
View File
File diff suppressed because it is too large Load Diff
+264 -244
View File
File diff suppressed because it is too large Load Diff
+1 -1
View File
@@ -6,7 +6,7 @@ import { useThemeStore } from '@/store'
export function createPageTitleGuard(router: Router) {
const themeStore = useThemeStore()
router.afterEach((to) => {
const pageTitle = translateTitle(String(to.meta.title))
const pageTitle = typeof to.meta.title === 'string' ? translateTitle(to.meta.title) : '404'
if (pageTitle) document.title = `${pageTitle} | ${themeStore.name}`
else document.title = themeStore.name
})
+1 -1
View File
@@ -15,7 +15,7 @@ export const basicRoutes: RoutesType = [
component: () => import('@/views/login/IndexView.vue'),
isHidden: true,
meta: {
title: $gettext('Login Page')
title: $gettext('Login')
}
}
]
+1
View File
@@ -68,6 +68,7 @@ const handleClose = () => {
:bordered="false"
:segmented="false"
@close="handleClose"
@mask-click="handleClose"
>
<n-form :model="model">
<n-form-item path="channel" :label="$gettext('Channel')">
+1
View File
@@ -568,6 +568,7 @@ onUnmounted(() => {
:bordered="false"
:segmented="false"
@close="handleShowModalClose"
@mask-click="handleShowModalClose"
>
<n-tabs type="line" animated>
<n-tab-pane name="cert" :tab="$gettext('Certificate')">
+14 -6
View File
@@ -57,7 +57,7 @@ const columns: any = [
{
title: $gettext('Status'),
key: 'status',
width: 150,
width: 250,
resizable: true,
ellipsis: { tooltip: true }
},
@@ -165,10 +165,18 @@ const columns: any = [
NPopconfirm,
{
onPositiveClick: () => {
useRequest(container.composeDown(row.name)).onSuccess(() => {
refresh()
window.$message.success($gettext('Stop successful'))
const messageReactive = window.$message.loading($gettext('Stopping...'), {
duration: 0
})
useRequest(container.composeDown(row.name))
.onSuccess(() => {
refresh()
forcePush.value = false
window.$message.success($gettext('Stop successful'))
})
.onComplete(() => {
messageReactive?.destroy()
})
}
},
{
@@ -290,10 +298,10 @@ onMounted(() => {
striped
remote
:loading="loading"
:scroll-x="1000"
:scroll-x="1100"
:data="data"
:columns="columns"
:row-key="(row: any) => row.id"
:row-key="(row: any) => row.name"
v-model:page="page"
v-model:pageSize="pageSize"
:pagination="{
@@ -132,6 +132,7 @@ onMounted(() => {
:bordered="false"
:segmented="false"
@close="handleClose"
@mask-click="handleClose"
>
<n-form :model="createModel">
<n-form-item path="name" :label="$gettext('Container Name')">
+6 -2
View File
@@ -69,8 +69,12 @@ const columns: any = [
default: () =>
row.ports.map((port: any) =>
h(NTag, null, {
default: () =>
`${port.host ? port.host + ':' : ''}${port.container_start}->${port.host_start}/${port.protocol}`
default: () => {
if (port.container_start == port.container_end) {
return `${port.host ? port.host + ':' : ''}${port.host_start}->${port.container_start}/${port.protocol}`
}
return `${port.host ? port.host + ':' : ''}${port.host_start}-${port.host_end}->${port.container_start}-${port.container_end}/${port.protocol}`
}
})
)
})
+2 -2
View File
@@ -107,7 +107,7 @@ const { loading, data, page, total, pageSize, pageCount, refresh } = usePaginati
)
const handleDelete = async (row: any) => {
useRequest(container.volumeRemove(row.id)).onSuccess(() => {
useRequest(container.volumeRemove(row.name)).onSuccess(() => {
refresh()
window.$message.success($gettext('Delete successful'))
})
@@ -155,7 +155,7 @@ onMounted(() => {
:scroll-x="1000"
:data="data"
:columns="columns"
:row-key="(row: any) => row.id"
:row-key="(row: any) => row.name"
v-model:checked-row-keys="selectedRowKeys"
v-model:page="page"
v-model:pageSize="pageSize"
@@ -34,7 +34,8 @@ watch(
() => show.value,
(value) => {
if (value) {
useRequest(database.serverList(1, 10000)).onSuccess(({ data }) => {
useRequest(database.serverList(1, 10000)).onSuccess(({ data }: { data: any }) => {
servers.value = []
for (const server of data.items) {
servers.value.push({
label: server.name,
+67 -59
View File
@@ -34,7 +34,8 @@ watch(
() => show.value,
(value) => {
if (value) {
useRequest(database.serverList(1, 10000)).onSuccess(({ data }) => {
useRequest(database.serverList(1, 10000)).onSuccess(({ data }: { data: any }) => {
servers.value = []
for (const server of data.items) {
servers.value.push({
label: server.name,
@@ -58,64 +59,71 @@ watch(
:segmented="false"
@close="show = false"
>
<n-form :model="createModel">
<n-form-item path="server_id" :label="$gettext('Server')">
<n-select
v-model:value="createModel.server_id"
@keydown.enter.prevent
:placeholder="$gettext('Select server')"
:options="servers"
/>
</n-form-item>
<n-form-item path="username" :label="$gettext('Username')">
<n-input
v-model:value="createModel.username"
type="text"
@keydown.enter.prevent
:placeholder="$gettext('Enter username')"
/>
</n-form-item>
<n-form-item path="password" :label="$gettext('Password')">
<n-input
v-model:value="createModel.password"
type="password"
show-password-on="click"
@keydown.enter.prevent
:placeholder="$gettext('Enter password')"
/>
</n-form-item>
<n-form-item path="host-select" :label="$gettext('Host (MySQL only)')">
<n-select
v-model:value="createModel.host"
@keydown.enter.prevent
:placeholder="$gettext('Select host')"
:options="hostType"
/>
</n-form-item>
<n-form-item v-if="createModel.host === ''" path="host" :label="$gettext('Specific Host')">
<n-input
v-model:value="createModel.host"
type="text"
@keydown.enter.prevent
:placeholder="$gettext('Enter supported host address')"
/>
</n-form-item>
<n-form-item path="privileges" :label="$gettext('Privileges')">
<n-dynamic-input
v-model:value="createModel.privileges"
:placeholder="$gettext('Enter database name')"
/>
</n-form-item>
<n-form-item path="remark" :label="$gettext('Comment')">
<n-input
v-model:value="createModel.remark"
type="textarea"
@keydown.enter.prevent
:placeholder="$gettext('Enter database user comment')"
/>
</n-form-item>
</n-form>
<n-button type="info" block @click="handleCreate">{{ $gettext('Submit') }}</n-button>
<n-flex vertical>
<n-alert type="info">
{{
$gettext('If the privilege databases does not exist, it will be created automatically.')
}}
</n-alert>
<n-form :model="createModel">
<n-form-item path="server_id" :label="$gettext('Server')">
<n-select
v-model:value="createModel.server_id"
@keydown.enter.prevent
:placeholder="$gettext('Select server')"
:options="servers"
/>
</n-form-item>
<n-form-item path="username" :label="$gettext('Username')">
<n-input
v-model:value="createModel.username"
type="text"
@keydown.enter.prevent
:placeholder="$gettext('Enter username')"
/>
</n-form-item>
<n-form-item path="password" :label="$gettext('Password')">
<n-input
v-model:value="createModel.password"
type="password"
show-password-on="click"
@keydown.enter.prevent
:placeholder="$gettext('Enter password')"
/>
</n-form-item>
<n-form-item path="host-select" :label="$gettext('Host (MySQL only)')">
<n-select
v-model:value="createModel.host"
@keydown.enter.prevent
:placeholder="$gettext('Select host')"
:options="hostType"
/>
</n-form-item>
<n-form-item v-if="createModel.host === ''" path="host" :label="$gettext('Specific Host')">
<n-input
v-model:value="createModel.host"
type="text"
@keydown.enter.prevent
:placeholder="$gettext('Enter supported host address')"
/>
</n-form-item>
<n-form-item path="privileges" :label="$gettext('Privileges')">
<n-dynamic-input
v-model:value="createModel.privileges"
:placeholder="$gettext('Enter database name')"
/>
</n-form-item>
<n-form-item path="remark" :label="$gettext('Comment')">
<n-input
v-model:value="createModel.remark"
type="textarea"
@keydown.enter.prevent
:placeholder="$gettext('Enter database user comment')"
/>
</n-form-item>
</n-form>
<n-button type="info" block @click="handleCreate">{{ $gettext('Submit') }}</n-button>
</n-flex>
</n-modal>
</template>
+1 -1
View File
@@ -27,7 +27,7 @@ watch(
() => show.value,
(value) => {
if (value && id.value) {
useRequest(database.serverGet(id.value)).onSuccess(({ data }) => {
useRequest(database.serverGet(id.value)).onSuccess(({ data }: { data: any }) => {
updateModel.value.name = data.name
updateModel.value.host = data.host
updateModel.value.port = data.port
+34 -27
View File
@@ -24,7 +24,7 @@ watch(
() => show.value,
(value) => {
if (value && id.value) {
useRequest(database.userGet(id.value)).onSuccess(({ data }) => {
useRequest(database.userGet(id.value)).onSuccess(({ data }: { data: any }) => {
updateModel.value.password = data.password
updateModel.value.privileges = data.privileges
updateModel.value.remark = data.remark
@@ -45,32 +45,39 @@ watch(
:segmented="false"
@close="show = false"
>
<n-form :model="updateModel">
<n-form-item path="password" :label="$gettext('Password')">
<n-input
v-model:value="updateModel.password"
type="password"
show-password-on="click"
@keydown.enter.prevent
:placeholder="$gettext('Enter password')"
/>
</n-form-item>
<n-form-item path="privileges" :label="$gettext('Privileges')">
<n-dynamic-input
v-model:value="updateModel.privileges"
:placeholder="$gettext('Enter database name')"
/>
</n-form-item>
<n-form-item path="remark" :label="$gettext('Comment')">
<n-input
v-model:value="updateModel.remark"
type="textarea"
@keydown.enter.prevent
:placeholder="$gettext('Enter database user comment')"
/>
</n-form-item>
</n-form>
<n-button type="info" block @click="handleUpdate">{{ $gettext('Submit') }}</n-button>
<n-flex vertical>
<n-alert type="info">
{{
$gettext('If the privilege databases does not exist, it will be created automatically.')
}}
</n-alert>
<n-form :model="updateModel">
<n-form-item path="password" :label="$gettext('Password')">
<n-input
v-model:value="updateModel.password"
type="password"
show-password-on="click"
@keydown.enter.prevent
:placeholder="$gettext('Enter password')"
/>
</n-form-item>
<n-form-item path="privileges" :label="$gettext('Privileges')">
<n-dynamic-input
v-model:value="updateModel.privileges"
:placeholder="$gettext('Enter database name')"
/>
</n-form-item>
<n-form-item path="remark" :label="$gettext('Comment')">
<n-input
v-model:value="updateModel.remark"
type="textarea"
@keydown.enter.prevent
:placeholder="$gettext('Enter database user comment')"
/>
</n-form-item>
</n-form>
<n-button type="info" block @click="handleUpdate">{{ $gettext('Submit') }}</n-button>
</n-flex>
</n-modal>
</template>
+1 -5
View File
@@ -104,11 +104,7 @@ const handleCreate = async () => {
<n-dynamic-input
v-model:value="createModel.address"
show-sort-button
:placeholder="
$gettext(
'Optional IP or IP range: 127.0.0.1 or 172.16.0.0/24 (multiple separated by commas)'
)
"
:placeholder="$gettext('IP or IP range: 172.16.0.1 or 172.16.0.0/16')"
/>
</n-form-item>
<n-form-item path="strategy" :label="$gettext('Strategy')">
+15 -20
View File
@@ -64,25 +64,23 @@ const createModel = ref({
protocol: 'tcp',
port_start: 80,
port_end: 80,
address: '',
address: [],
strategy: 'accept',
direction: 'in'
})
const handleCreate = async () => {
useRequest(firewall.createRule(createModel.value)).onSuccess(() => {
show.value = false
createModel.value = {
family: 'ipv4',
protocol: 'tcp',
port_start: 80,
port_end: 80,
address: '',
strategy: 'accept',
direction: 'in'
}
window.$message.success($gettext('Created successfully'))
})
for (const address of createModel.value.address) {
useRequest(
firewall.createRule({
...createModel.value,
address
})
).onSuccess(() => {
window.$message.success($gettext('%{ address } created successfully', { address: address }))
show.value = false
})
}
}
</script>
@@ -127,13 +125,10 @@ const handleCreate = async () => {
</n-col>
</n-row>
<n-form-item path="address" :label="$gettext('Target')">
<n-input
<n-dynamic-input
v-model:value="createModel.address"
:placeholder="
$gettext(
'Optional IP or IP range: 127.0.0.1 or 172.16.0.0/24 (multiple separated by commas)'
)
"
show-sort-button
:placeholder="$gettext('IP or IP range: 172.16.0.1 or 172.16.0.0/16')"
/>
</n-form-item>
<n-form-item path="strategy" :label="$gettext('Strategy')">
+1 -1
View File
@@ -23,7 +23,7 @@ const model = defineModel<any>('model', { type: Object, required: true })
</n-input-number>
</n-form-item>
<n-form-item :label="$gettext('Access Entrance')">
<n-input v-model:value="model.entrance" :placeholder="$gettext('admin')" />
<n-input v-model:value="model.entrance" :placeholder="$gettext('/admin')" />
</n-form-item>
<n-form-item :label="$gettext('Bind Domain')">
<n-dynamic-input
+17 -1
View File
@@ -20,7 +20,17 @@ const columns: any = [
key: 'username',
minWidth: 100,
resizable: true,
ellipsis: { tooltip: true }
ellipsis: { tooltip: true },
render(row: any) {
return h(NInput, {
size: 'small',
value: row.username,
onBlur: () => handleUsername(row),
onUpdateValue(v) {
row.username = v
}
})
}
},
{
title: $gettext('Email'),
@@ -151,6 +161,12 @@ const { loading, data, page, total, pageSize, pageCount, refresh } = usePaginati
}
)
const handleUsername = (row: any) => {
useRequest(user.updateUsername(row.id, row.username)).onSuccess(() => {
window.$message.success($gettext('Modified successfully'))
})
}
const handleEmail = (row: any) => {
useRequest(user.updateEmail(row.id, row.email)).onSuccess(() => {
window.$message.success($gettext('Modified successfully'))
+33 -1
View File
@@ -73,6 +73,38 @@ const columns: any = [
})
}
},
{
title: $gettext('Certificate expiration'),
key: 'cert_expire',
width: 200,
render(row: any) {
return h(
NTag,
{
type: row.cert_expire == 0 ? 'default' : row.cert_expire > 0 ? 'success' : 'error',
class: 'cursor-pointer hover:opacity-60',
onClick: () => handleEdit(row)
},
{
default: () => {
if (row.cert_expire == 0) {
return $gettext('Not configured')
}
if (row.cert_expire < 0) {
return $gettext('Expired %{ days } days ago', {
days: Math.abs(row.cert_expire)
})
}
if (row.cert_expire > 0) {
return $gettext('Expires in %{ days } days', {
days: row.cert_expire
})
}
}
}
)
}
},
{
title: $gettext('Remark'),
key: 'remark',
@@ -378,7 +410,7 @@ onMounted(() => {
striped
remote
:loading="loading"
:scroll-x="1200"
:scroll-x="1400"
:columns="columns"
:data="data"
:row-key="(row: any) => row.id"