cabloy 5.1.152 → 5.1.154
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.cabloy-version +1 -1
- package/.claude/skills/cabloy-module-removal/SKILL.md +1 -1
- package/.claude/skills/cabloy-resource-field-update/SKILL.md +1 -1
- package/.claude/skills/cabloy-spec-generation/SKILL.md +1 -1
- package/.claude/skills/cabloy-spec-generation/references/repo-aware-discovery.md +1 -1
- package/.claude/skills/cabloy-spec-generation/scripts/generate-implementation-charts.mjs +46 -11
- package/.claude/skills/cabloy-spec-generation/scripts/generate-implementation-charts.test.mjs +13 -0
- package/.claude/skills/cabloy-workflow/SKILL.md +13 -14
- package/.claude/skills/cabloy-workflow/evals/evals.json +4 -4
- package/CHANGELOG.md +27 -0
- package/CLAUDE.md +2 -3
- package/package.json +1 -1
- package/repo-docs/.vitepress/config.mjs +5 -0
- package/repo-docs/ai/cli-to-skill-map.md +19 -0
- package/repo-docs/ai/docs-skills-rules-mapping.md +21 -6
- package/repo-docs/ai/future-skill-roadmap.md +17 -72
- package/repo-docs/ai/introduction.md +15 -5
- package/repo-docs/ai/playbook-spec-execution.md +144 -0
- package/repo-docs/ai/playbook-spec-generation.md +155 -0
- package/repo-docs/ai/repo-guidance.md +9 -5
- package/repo-docs/ai/rules-and-config.md +2 -2
- package/repo-docs/ai/skills.md +4 -0
- package/repo-docs/ai/virtual-decorator-guidance.md +1 -1
- package/repo-docs/backend/introduction.md +1 -1
- package/repo-docs/backend/menu-guide.md +3 -2
- package/repo-docs/frontend/model-resource-cookbook.md +38 -7
- package/repo-docs/frontend/model-resource-usage-guide.md +2 -1
- package/repo-docs/frontend/router-tabs-introduction.md +1 -1
- package/repo-docs/frontend/use-state-data-best-practices.md +39 -6
- package/repo-docs/reference/package-map.md +4 -1
- package/repo-docs/reference/repo-scripts.md +25 -0
- package/repo-e2e/specs/cabloy-basic.spec.ts +69 -20
- package/test-results/.last-run.json +4 -2
- package/test-results/cabloy-basic-ATP-BASIC-SUM-58d8a-ry-states-and-Markdown-HTML/error-context.md +195 -0
- package/vona/env/.env +8 -0
- package/vona/packages-vona/vona/package.json +1 -1
- package/vona/pnpm-lock.yaml +81 -145
- package/vona/src/suite/a-commerce/modules/commerce-siteadmin/package.json +1 -2
- package/vona/src/suite/a-commerce/modules/commerce-siteadmin/src/.metadata/index.ts +40 -65
- package/vona/src/suite/a-home/modules/home-base/src/.metadata/index.ts +78 -72
- package/vona/src/suite/a-home/modules/home-base/src/.metadata/locales.ts +18 -0
- package/vona/src/suite/a-home/modules/home-base/src/config/locale/en-us.ts +3 -0
- package/vona/src/suite/a-home/modules/home-base/src/config/locale/zh-cn.ts +3 -0
- package/vona/src/suite/a-home/modules/home-base/src/index.ts +1 -0
- package/vona/src/suite/a-home/modules/home-base/src/service/siteCatalog.ts +17 -10
- package/vona/src/suite/a-home/modules/home-user/src/bean/meta.version.ts +5 -0
- package/vona/src/suite/a-home/modules/home-user/src/config/config.ts +36 -5
- package/vona/src/suite/a-home/modules/home-user/src/config/roles.ts +7 -2
- package/vona/src/suite/a-home/modules/home-user/src/entity/role.ts +3 -0
- package/vona/src/suite/a-home/modules/home-user/src/types/env.ts +11 -0
- package/vona/src/suite/a-home/modules/home-user/src/types/index.ts +1 -0
- package/vona/src/suite/a-home/modules/home-user/test/config.test.ts +65 -0
- package/vona/src/suite/a-home/modules/home-user/test/role.test.ts +14 -6
- package/vona/src/suite-vendor/a-cabloy/modules/a-rbac/package.json +1 -1
- package/vona/src/suite-vendor/a-cabloy/modules/a-ssr/package.json +1 -1
- package/vona/src/suite-vendor/a-cabloy/modules/a-ssr/src/.metadata/index.ts +17 -2
- package/vona/src/suite-vendor/a-cabloy/modules/a-ssr/src/bean/event.resolveMenuVisibility.ts +19 -0
- package/vona/src/suite-vendor/a-cabloy/modules/a-ssr/src/lib/beanSsrSiteBase.ts +32 -16
- package/vona/src/suite-vendor/a-cabloy/modules/a-ssr/src/lib/index.ts +2 -0
- package/vona/src/suite-vendor/a-cabloy/modules/a-ssr/src/lib/ssrMenuEligibility.ts +107 -0
- package/vona/src/suite-vendor/a-cabloy/modules/a-ssr/src/lib/ssrMenuVisibility.ts +91 -0
- package/vona/src/suite-vendor/a-cabloy/modules/a-ssr/src/service/ssr.ts +30 -0
- package/vona/src/suite-vendor/a-cabloy/modules/a-ssr/src/types/ssrMenu.ts +67 -0
- package/vona/src/suite-vendor/a-cabloy/modules/a-ssr/test/ssrMenuEligibility.test.ts +135 -0
- package/vona/src/suite-vendor/a-cabloy/modules/a-ssr/test/ssrMenuVisibility.test.ts +64 -0
- package/vona/src/suite-vendor/a-cabloy/package.json +2 -2
- package/vona/src/suite-vendor/a-vona/modules/a-openapiutils/package.json +1 -1
- package/vona/src/suite-vendor/a-vona/modules/a-openapiutils/src/lib/const/index.ts +1 -0
- package/vona/src/suite-vendor/a-vona/modules/a-openapiutils/src/lib/const/site.ts +1 -0
- package/vona/src/suite-vendor/a-vona/modules/a-permission/package.json +1 -1
- package/vona/src/suite-vendor/a-vona/modules/a-user/package.json +1 -1
- package/vona/src/suite-vendor/a-vona/modules/a-user/src/types/role.ts +1 -0
- package/vona/src/suite-vendor/a-vona/package.json +1 -1
- package/zova/pnpm-lock.yaml +1 -1
- package/zova/src/suite/a-commerce/modules/commerce-trade/src/page/payment/controller.tsx +3 -2
- package/zova/src/suite/a-home/modules/home-api/mock/passport.fake.ts +6 -6
- package/zova/src/suite/a-home/modules/home-base/src/lib/index.ts +1 -0
- package/zova/src/suite/a-home/modules/home-base/src/lib/roleSiteAdmission.ts +15 -0
- package/zova/src/suite/a-home/modules/home-base/src/service/routerGuards.ts +3 -3
- package/zova/src/suite/a-home/modules/home-layoutadmin/src/model/menu.ts +4 -3
- package/zova/src/suite/a-home/modules/home-layoutweb/src/model/menu.ts +4 -3
- package/zova/src/suite/a-home/modules/home-passport/package.json +2 -1
- package/zova/src/suite/a-home/modules/home-passport/src/model/passport.ts +2 -2
- package/zova/src/suite/a-home/modules/home-passport/test/lib/roleSiteAdmission.test.ts +23 -0
- package/zova/src/suite/a-training/modules/training-student/src/bean/tableCell.actionSummary.tsx +29 -6
- package/zova/src/suite/a-training/modules/training-student/src/config/locale/en-us.ts +1 -0
- package/zova/src/suite/a-training/modules/training-student/src/config/locale/zh-cn.ts +1 -0
- package/zova/src/suite/a-training/modules/training-student/src/model/student.ts +1 -1
- package/zova/src/suite-vendor/a-cabloy/modules/rest-resource/package.json +1 -1
- package/zova/src/suite-vendor/a-cabloy/modules/rest-resource/src/lib/mutationSuccess.ts +11 -0
- package/zova/src/suite-vendor/a-cabloy/modules/rest-resource/src/model/resource.ts +12 -7
- package/zova/src/suite-vendor/a-cabloy/modules/rest-resource/test/lib/mutationSuccess.test.ts +95 -0
- package/zova/src/suite-vendor/a-cabloy/package.json +2 -2
- package/vona/src/suite/a-commerce/modules/commerce-siteadmin/src/bean/meta.version.ts +0 -32
- package/vona/src/suite/a-commerce/modules/commerce-siteadmin/test/meta.version.test.ts +0 -44
|
@@ -1,76 +1,6 @@
|
|
|
1
1
|
// eslint-disable
|
|
2
2
|
import type { TypeSymbolKeyFieldsMore } from 'vona-module-a-orm';
|
|
3
3
|
import type { TypeEntityOptionsFields,TypeControllerOptionsActions } from 'vona-module-a-openapi';
|
|
4
|
-
/** service: begin */
|
|
5
|
-
export * from '../service/menu.ts';
|
|
6
|
-
export * from '../service/permission.ts';
|
|
7
|
-
export * from '../service/siteCatalog.ts';
|
|
8
|
-
|
|
9
|
-
import 'vona-module-a-bean';
|
|
10
|
-
declare module 'vona-module-a-bean' {
|
|
11
|
-
|
|
12
|
-
export interface IServiceRecord {
|
|
13
|
-
'home-base:menu': never;
|
|
14
|
-
'home-base:permission': never;
|
|
15
|
-
'home-base:siteCatalog': never;
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
}
|
|
20
|
-
declare module 'vona-module-home-base' {
|
|
21
|
-
|
|
22
|
-
export interface ServiceMenu {
|
|
23
|
-
/** @internal */
|
|
24
|
-
get scope(): ScopeModuleHomeBase;
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
export interface ServiceMenu {
|
|
28
|
-
get $beanFullName(): 'home-base.service.menu';
|
|
29
|
-
get $onionName(): 'home-base:menu';
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
export interface ServicePermission {
|
|
33
|
-
/** @internal */
|
|
34
|
-
get scope(): ScopeModuleHomeBase;
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
export interface ServicePermission {
|
|
38
|
-
get $beanFullName(): 'home-base.service.permission';
|
|
39
|
-
get $onionName(): 'home-base:permission';
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
export interface ServiceSiteCatalog {
|
|
43
|
-
/** @internal */
|
|
44
|
-
get scope(): ScopeModuleHomeBase;
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
export interface ServiceSiteCatalog {
|
|
48
|
-
get $beanFullName(): 'home-base.service.siteCatalog';
|
|
49
|
-
get $onionName(): 'home-base:siteCatalog';
|
|
50
|
-
}
|
|
51
|
-
}
|
|
52
|
-
/** service: end */
|
|
53
|
-
/** service: begin */
|
|
54
|
-
import type { ServiceMenu } from '../service/menu.ts';
|
|
55
|
-
import type { ServicePermission } from '../service/permission.ts';
|
|
56
|
-
import type { ServiceSiteCatalog } from '../service/siteCatalog.ts';
|
|
57
|
-
export interface IModuleService {
|
|
58
|
-
'menu': ServiceMenu;
|
|
59
|
-
'permission': ServicePermission;
|
|
60
|
-
'siteCatalog': ServiceSiteCatalog;
|
|
61
|
-
}
|
|
62
|
-
/** service: end */
|
|
63
|
-
/** service: begin */
|
|
64
|
-
|
|
65
|
-
import 'vona';
|
|
66
|
-
declare module 'vona' {
|
|
67
|
-
export interface IBeanRecordGeneral {
|
|
68
|
-
'home-base.service.menu': ServiceMenu;
|
|
69
|
-
'home-base.service.permission': ServicePermission;
|
|
70
|
-
'home-base.service.siteCatalog': ServiceSiteCatalog;
|
|
71
|
-
}
|
|
72
|
-
}
|
|
73
|
-
/** service: end */
|
|
74
4
|
/** dto: begin */
|
|
75
5
|
export * from '../dto/siteCatalogSelectRes.ts';
|
|
76
6
|
export * from '../dto/siteCatalogSelectResItem.ts';
|
|
@@ -195,11 +125,84 @@ import 'vona-module-a-openapi';
|
|
|
195
125
|
}
|
|
196
126
|
|
|
197
127
|
/** controller: end */
|
|
128
|
+
/** service: begin */
|
|
129
|
+
export * from '../service/menu.ts';
|
|
130
|
+
export * from '../service/permission.ts';
|
|
131
|
+
export * from '../service/siteCatalog.ts';
|
|
132
|
+
|
|
133
|
+
import 'vona-module-a-bean';
|
|
134
|
+
declare module 'vona-module-a-bean' {
|
|
135
|
+
|
|
136
|
+
export interface IServiceRecord {
|
|
137
|
+
'home-base:menu': never;
|
|
138
|
+
'home-base:permission': never;
|
|
139
|
+
'home-base:siteCatalog': never;
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
|
|
143
|
+
}
|
|
144
|
+
declare module 'vona-module-home-base' {
|
|
145
|
+
|
|
146
|
+
export interface ServiceMenu {
|
|
147
|
+
/** @internal */
|
|
148
|
+
get scope(): ScopeModuleHomeBase;
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
export interface ServiceMenu {
|
|
152
|
+
get $beanFullName(): 'home-base.service.menu';
|
|
153
|
+
get $onionName(): 'home-base:menu';
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
export interface ServicePermission {
|
|
157
|
+
/** @internal */
|
|
158
|
+
get scope(): ScopeModuleHomeBase;
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
export interface ServicePermission {
|
|
162
|
+
get $beanFullName(): 'home-base.service.permission';
|
|
163
|
+
get $onionName(): 'home-base:permission';
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
export interface ServiceSiteCatalog {
|
|
167
|
+
/** @internal */
|
|
168
|
+
get scope(): ScopeModuleHomeBase;
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
export interface ServiceSiteCatalog {
|
|
172
|
+
get $beanFullName(): 'home-base.service.siteCatalog';
|
|
173
|
+
get $onionName(): 'home-base:siteCatalog';
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
/** service: end */
|
|
177
|
+
/** service: begin */
|
|
178
|
+
import type { ServiceMenu } from '../service/menu.ts';
|
|
179
|
+
import type { ServicePermission } from '../service/permission.ts';
|
|
180
|
+
import type { ServiceSiteCatalog } from '../service/siteCatalog.ts';
|
|
181
|
+
export interface IModuleService {
|
|
182
|
+
'menu': ServiceMenu;
|
|
183
|
+
'permission': ServicePermission;
|
|
184
|
+
'siteCatalog': ServiceSiteCatalog;
|
|
185
|
+
}
|
|
186
|
+
/** service: end */
|
|
187
|
+
/** service: begin */
|
|
188
|
+
|
|
189
|
+
import 'vona';
|
|
190
|
+
declare module 'vona' {
|
|
191
|
+
export interface IBeanRecordGeneral {
|
|
192
|
+
'home-base.service.menu': ServiceMenu;
|
|
193
|
+
'home-base.service.permission': ServicePermission;
|
|
194
|
+
'home-base.service.siteCatalog': ServiceSiteCatalog;
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
/** service: end */
|
|
198
|
+
/** locale: begin */
|
|
199
|
+
import { locales } from './locales.ts';
|
|
200
|
+
/** locale: end */
|
|
198
201
|
/** main: begin */
|
|
199
202
|
export * from '../main.ts';
|
|
200
203
|
/** main: end */
|
|
201
204
|
/** scope: begin */
|
|
202
|
-
import { BeanScopeBase, type BeanScopeUtil } from 'vona';
|
|
205
|
+
import { BeanScopeBase, type BeanScopeUtil, type TypeModuleLocales, type TypeLocaleBase } from 'vona';
|
|
203
206
|
import { Scope } from 'vona-module-a-bean';
|
|
204
207
|
|
|
205
208
|
@Scope()
|
|
@@ -207,6 +210,7 @@ export class ScopeModuleHomeBase extends BeanScopeBase {}
|
|
|
207
210
|
|
|
208
211
|
export interface ScopeModuleHomeBase {
|
|
209
212
|
util: BeanScopeUtil;
|
|
213
|
+
locale: TypeModuleLocales<(typeof locales)[TypeLocaleBase]>;
|
|
210
214
|
service: IModuleService;
|
|
211
215
|
}
|
|
212
216
|
|
|
@@ -222,7 +226,9 @@ declare module 'vona' {
|
|
|
222
226
|
|
|
223
227
|
|
|
224
228
|
|
|
225
|
-
|
|
229
|
+
export interface IBeanScopeLocale {
|
|
230
|
+
'home-base': (typeof locales)[TypeLocaleBase];
|
|
231
|
+
}
|
|
226
232
|
|
|
227
233
|
|
|
228
234
|
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import type { TypeLocaleBase } from 'vona';
|
|
2
|
+
|
|
3
|
+
import { $makeLocaleMagic } from 'vona';
|
|
4
|
+
|
|
5
|
+
import locale_en_us from '../config/locale/en-us.ts';
|
|
6
|
+
import locale_zh_cn from '../config/locale/zh-cn.ts';
|
|
7
|
+
|
|
8
|
+
export const locales = {
|
|
9
|
+
'en-us': locale_en_us,
|
|
10
|
+
'zh-cn': locale_zh_cn,
|
|
11
|
+
};
|
|
12
|
+
|
|
13
|
+
export function $locale<K extends keyof (typeof locales)[TypeLocaleBase]>(
|
|
14
|
+
key: K,
|
|
15
|
+
...args: any[]
|
|
16
|
+
): any {
|
|
17
|
+
return $makeLocaleMagic(`home-base::${key}`, ...args);
|
|
18
|
+
}
|
|
@@ -2,22 +2,29 @@ import type { IDecoratorSsrSiteOptions } from 'vona-module-a-ssr';
|
|
|
2
2
|
|
|
3
3
|
import { BeanBase } from 'vona';
|
|
4
4
|
import { Service } from 'vona-module-a-bean';
|
|
5
|
+
import { roleSiteIdAll } from 'vona-module-a-openapiutils';
|
|
5
6
|
|
|
6
7
|
import type { DtoSiteCatalogSelectRes } from '../dto/siteCatalogSelectRes.ts';
|
|
7
8
|
|
|
8
9
|
@Service()
|
|
9
10
|
export class ServiceSiteCatalog extends BeanBase {
|
|
10
11
|
async select(): Promise<DtoSiteCatalogSelectRes> {
|
|
11
|
-
const list =
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
12
|
+
const list = [
|
|
13
|
+
{
|
|
14
|
+
siteId: roleSiteIdAll,
|
|
15
|
+
title: this.scope.locale.SiteAll(),
|
|
16
|
+
},
|
|
17
|
+
...this.app
|
|
18
|
+
.scope('a-ssr')
|
|
19
|
+
.service.ssr.getSitesEnabled()
|
|
20
|
+
.map(site => {
|
|
21
|
+
const options = site.beanOptions.options as IDecoratorSsrSiteOptions;
|
|
22
|
+
return {
|
|
23
|
+
siteId: String(options.siteId),
|
|
24
|
+
title: this.app.meta.text.locale(this.ctx.locale, options.title),
|
|
25
|
+
};
|
|
26
|
+
}),
|
|
27
|
+
];
|
|
21
28
|
return {
|
|
22
29
|
list,
|
|
23
30
|
total: String(list.length),
|
|
@@ -21,6 +21,10 @@ export class MetaVersion extends BeanBase implements IMetaVersionUpdate, IMetaVe
|
|
|
21
21
|
table.string(entityRole.title, 255).comment(entityRole.$comment.title);
|
|
22
22
|
table.json(entityRole.titleLocales).comment(entityRole.$comment.titleLocales);
|
|
23
23
|
table.json(entityRole.siteIds).comment(entityRole.$comment.siteIds);
|
|
24
|
+
table
|
|
25
|
+
.boolean(entityRole.builtin)
|
|
26
|
+
.defaultTo(entityRole.$default.builtin)
|
|
27
|
+
.comment(entityRole.$comment.builtin);
|
|
24
28
|
});
|
|
25
29
|
// homeUser
|
|
26
30
|
const entityUser = this.scope.entity.user;
|
|
@@ -62,6 +66,7 @@ export class MetaVersion extends BeanBase implements IMetaVersionUpdate, IMetaVe
|
|
|
62
66
|
title: role.title,
|
|
63
67
|
titleLocales: role.titleLocales ?? {},
|
|
64
68
|
siteIds: role.siteIds,
|
|
69
|
+
builtin: role.builtin,
|
|
65
70
|
});
|
|
66
71
|
}
|
|
67
72
|
// user: admin
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
import type { VonaApplication } from 'vona';
|
|
2
2
|
|
|
3
|
+
import { roleSiteIdAll } from 'vona-module-a-openapiutils';
|
|
4
|
+
|
|
3
5
|
import { builtinRoles } from './roles.ts';
|
|
4
6
|
|
|
5
7
|
export { builtinRoles } from './roles.ts';
|
|
@@ -14,13 +16,42 @@ export interface IHomeUserConfig {
|
|
|
14
16
|
builtinRoles: typeof builtinRoles;
|
|
15
17
|
}
|
|
16
18
|
|
|
17
|
-
export function config(
|
|
19
|
+
export function config(app: VonaApplication): IHomeUserConfig {
|
|
20
|
+
const { env } = app.meta;
|
|
18
21
|
return {
|
|
19
22
|
passwordDefault: {
|
|
20
|
-
admin: '123456',
|
|
23
|
+
admin: env.HOME_USER_PASSWORD_DEFAULT_ADMIN || '123456',
|
|
24
|
+
},
|
|
25
|
+
disableBootstrapSystemAdmin: env.HOME_USER_DISABLE_BOOTSTRAP_SYSTEM_ADMIN === 'true',
|
|
26
|
+
disableUserAdmin: env.HOME_USER_DISABLE_USER_ADMIN === 'true',
|
|
27
|
+
builtinRoles: {
|
|
28
|
+
...builtinRoles,
|
|
29
|
+
registeredUser: {
|
|
30
|
+
...builtinRoles.registeredUser,
|
|
31
|
+
siteIds: parseBuiltinRoleSiteIds(
|
|
32
|
+
env.HOME_USER_BUILTIN_ROLE_REGISTERED_USER_SITE_IDS,
|
|
33
|
+
'HOME_USER_BUILTIN_ROLE_REGISTERED_USER_SITE_IDS',
|
|
34
|
+
),
|
|
35
|
+
},
|
|
36
|
+
systemAdmin: {
|
|
37
|
+
...builtinRoles.systemAdmin,
|
|
38
|
+
siteIds: parseBuiltinRoleSiteIds(
|
|
39
|
+
env.HOME_USER_BUILTIN_ROLE_SYSTEM_ADMIN_SITE_IDS,
|
|
40
|
+
'HOME_USER_BUILTIN_ROLE_SYSTEM_ADMIN_SITE_IDS',
|
|
41
|
+
),
|
|
42
|
+
},
|
|
21
43
|
},
|
|
22
|
-
disableBootstrapSystemAdmin: false,
|
|
23
|
-
disableUserAdmin: false,
|
|
24
|
-
builtinRoles,
|
|
25
44
|
};
|
|
26
45
|
}
|
|
46
|
+
|
|
47
|
+
function parseBuiltinRoleSiteIds(value: string | undefined, variableName: string): string[] {
|
|
48
|
+
const siteIds = value
|
|
49
|
+
?.split(',')
|
|
50
|
+
.map(siteId => siteId.trim())
|
|
51
|
+
.filter(Boolean) ?? [roleSiteIdAll];
|
|
52
|
+
if (siteIds.length === 0) return [roleSiteIdAll];
|
|
53
|
+
if (siteIds.includes(roleSiteIdAll) && siteIds.length !== 1) {
|
|
54
|
+
throw new Error(`${variableName} must contain only "${roleSiteIdAll}" or concrete site IDs`);
|
|
55
|
+
}
|
|
56
|
+
return siteIds;
|
|
57
|
+
}
|
|
@@ -1,24 +1,29 @@
|
|
|
1
1
|
import type { LocalizedTextMap } from 'vona-module-a-user';
|
|
2
2
|
|
|
3
|
+
import { roleSiteIdAll } from 'vona-module-a-openapiutils';
|
|
4
|
+
|
|
3
5
|
export interface IRoleConfig {
|
|
4
6
|
title: string;
|
|
5
7
|
titleLocales?: LocalizedTextMap;
|
|
6
8
|
siteIds: string[];
|
|
9
|
+
builtin: boolean;
|
|
7
10
|
}
|
|
8
11
|
|
|
9
12
|
export const builtinRoles: Record<string, IRoleConfig> = {
|
|
10
13
|
registeredUser: {
|
|
11
14
|
title: 'Registered User',
|
|
15
|
+
builtin: true,
|
|
12
16
|
titleLocales: {
|
|
13
17
|
'zh-cn': '注册用户',
|
|
14
18
|
},
|
|
15
|
-
siteIds: [
|
|
19
|
+
siteIds: [roleSiteIdAll],
|
|
16
20
|
},
|
|
17
21
|
systemAdmin: {
|
|
18
22
|
title: 'System Administrator',
|
|
23
|
+
builtin: true,
|
|
19
24
|
titleLocales: {
|
|
20
25
|
'zh-cn': '系统管理员',
|
|
21
26
|
},
|
|
22
|
-
siteIds: [
|
|
27
|
+
siteIds: [roleSiteIdAll],
|
|
23
28
|
},
|
|
24
29
|
};
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
declare module 'vona' {
|
|
2
|
+
export interface VonaConfigEnv {
|
|
3
|
+
HOME_USER_PASSWORD_DEFAULT_ADMIN: string | undefined;
|
|
4
|
+
HOME_USER_DISABLE_BOOTSTRAP_SYSTEM_ADMIN: string | undefined;
|
|
5
|
+
HOME_USER_DISABLE_USER_ADMIN: string | undefined;
|
|
6
|
+
HOME_USER_BUILTIN_ROLE_REGISTERED_USER_SITE_IDS: string | undefined;
|
|
7
|
+
HOME_USER_BUILTIN_ROLE_SYSTEM_ADMIN_SITE_IDS: string | undefined;
|
|
8
|
+
}
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
export {};
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
import assert from 'node:assert';
|
|
2
|
+
import { describe, it } from 'node:test';
|
|
3
|
+
|
|
4
|
+
import { config } from '../src/config/config.ts';
|
|
5
|
+
import { builtinRoles } from '../src/config/roles.ts';
|
|
6
|
+
|
|
7
|
+
function createConfig(env: Record<string, string | undefined>) {
|
|
8
|
+
return config({ meta: { env } } as never);
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
describe('config.test.ts', () => {
|
|
12
|
+
it('uses environment overrides and defaults without mutating static role definitions', () => {
|
|
13
|
+
const configured = createConfig({
|
|
14
|
+
HOME_USER_PASSWORD_DEFAULT_ADMIN: 'strong-admin-password',
|
|
15
|
+
HOME_USER_DISABLE_BOOTSTRAP_SYSTEM_ADMIN: 'true',
|
|
16
|
+
HOME_USER_DISABLE_USER_ADMIN: 'true',
|
|
17
|
+
HOME_USER_BUILTIN_ROLE_REGISTERED_USER_SITE_IDS: 'web',
|
|
18
|
+
HOME_USER_BUILTIN_ROLE_SYSTEM_ADMIN_SITE_IDS: 'web,admin',
|
|
19
|
+
});
|
|
20
|
+
assert.equal(configured.passwordDefault.admin, 'strong-admin-password');
|
|
21
|
+
assert.equal(configured.disableBootstrapSystemAdmin, true);
|
|
22
|
+
assert.equal(configured.disableUserAdmin, true);
|
|
23
|
+
assert.deepEqual(configured.builtinRoles.registeredUser.siteIds, ['web']);
|
|
24
|
+
assert.deepEqual(configured.builtinRoles.systemAdmin.siteIds, ['web', 'admin']);
|
|
25
|
+
assert.deepEqual(builtinRoles.registeredUser.siteIds, ['*']);
|
|
26
|
+
assert.deepEqual(builtinRoles.systemAdmin.siteIds, ['*']);
|
|
27
|
+
|
|
28
|
+
const defaults = createConfig({
|
|
29
|
+
HOME_USER_PASSWORD_DEFAULT_ADMIN: '',
|
|
30
|
+
HOME_USER_DISABLE_BOOTSTRAP_SYSTEM_ADMIN: 'false',
|
|
31
|
+
HOME_USER_DISABLE_USER_ADMIN: 'invalid',
|
|
32
|
+
});
|
|
33
|
+
assert.equal(defaults.passwordDefault.admin, '123456');
|
|
34
|
+
assert.equal(defaults.disableBootstrapSystemAdmin, false);
|
|
35
|
+
assert.equal(defaults.disableUserAdmin, false);
|
|
36
|
+
assert.deepEqual(defaults.builtinRoles.registeredUser.siteIds, ['*']);
|
|
37
|
+
assert.deepEqual(defaults.builtinRoles.systemAdmin.siteIds, ['*']);
|
|
38
|
+
});
|
|
39
|
+
|
|
40
|
+
it('parses comma-delimited role site IDs and falls back for blank values', () => {
|
|
41
|
+
const configured = createConfig({
|
|
42
|
+
HOME_USER_BUILTIN_ROLE_REGISTERED_USER_SITE_IDS: ' web, admin, , store ',
|
|
43
|
+
HOME_USER_BUILTIN_ROLE_SYSTEM_ADMIN_SITE_IDS: ' , ',
|
|
44
|
+
});
|
|
45
|
+
assert.deepEqual(configured.builtinRoles.registeredUser.siteIds, ['web', 'admin', 'store']);
|
|
46
|
+
assert.deepEqual(configured.builtinRoles.systemAdmin.siteIds, ['*']);
|
|
47
|
+
});
|
|
48
|
+
|
|
49
|
+
it('rejects non-exclusive wildcard role site IDs', () => {
|
|
50
|
+
assert.throws(
|
|
51
|
+
() =>
|
|
52
|
+
createConfig({
|
|
53
|
+
HOME_USER_BUILTIN_ROLE_REGISTERED_USER_SITE_IDS: '*,web',
|
|
54
|
+
}),
|
|
55
|
+
/HOME_USER_BUILTIN_ROLE_REGISTERED_USER_SITE_IDS/,
|
|
56
|
+
);
|
|
57
|
+
assert.throws(
|
|
58
|
+
() =>
|
|
59
|
+
createConfig({
|
|
60
|
+
HOME_USER_BUILTIN_ROLE_SYSTEM_ADMIN_SITE_IDS: 'web,*',
|
|
61
|
+
}),
|
|
62
|
+
/HOME_USER_BUILTIN_ROLE_SYSTEM_ADMIN_SITE_IDS/,
|
|
63
|
+
);
|
|
64
|
+
});
|
|
65
|
+
});
|
|
@@ -9,13 +9,17 @@ describe('role.test.ts', () => {
|
|
|
9
9
|
const roleRegisteredUser = await scope.model.role.getByName('registeredUser');
|
|
10
10
|
assert.equal(roleRegisteredUser?.title, 'Registered User');
|
|
11
11
|
assert.deepEqual(roleRegisteredUser?.titleLocales, { 'zh-cn': '注册用户' });
|
|
12
|
-
assert.
|
|
12
|
+
assert.deepEqual(
|
|
13
|
+
roleRegisteredUser?.siteIds,
|
|
14
|
+
scope.config.builtinRoles.registeredUser.siteIds,
|
|
15
|
+
);
|
|
16
|
+
assert.equal(roleRegisteredUser?.builtin, true);
|
|
13
17
|
|
|
14
18
|
const roleSystemAdmin = await scope.model.role.getByName('systemAdmin');
|
|
15
19
|
assert.equal(roleSystemAdmin?.title, 'System Administrator');
|
|
16
20
|
assert.deepEqual(roleSystemAdmin?.titleLocales, { 'zh-cn': '系统管理员' });
|
|
17
|
-
assert.
|
|
18
|
-
assert.
|
|
21
|
+
assert.deepEqual(roleSystemAdmin?.siteIds, scope.config.builtinRoles.systemAdmin.siteIds);
|
|
22
|
+
assert.equal(roleSystemAdmin?.builtin, true);
|
|
19
23
|
|
|
20
24
|
await app.bean.passport.signinMock();
|
|
21
25
|
const passport = await app.bean.executor.performAction('get', '/home/user/passport/current');
|
|
@@ -24,13 +28,17 @@ describe('role.test.ts', () => {
|
|
|
24
28
|
);
|
|
25
29
|
assert.equal(passportRegisteredUser?.title, 'Registered User');
|
|
26
30
|
assert.deepEqual(passportRegisteredUser?.titleLocales, { 'zh-cn': '注册用户' });
|
|
27
|
-
assert.
|
|
31
|
+
assert.deepEqual(
|
|
32
|
+
passportRegisteredUser?.siteIds,
|
|
33
|
+
scope.config.builtinRoles.registeredUser.siteIds,
|
|
34
|
+
);
|
|
35
|
+
assert.equal(passportRegisteredUser?.builtin, true);
|
|
28
36
|
|
|
29
37
|
const passportSystemAdmin = passport.roles.find((role: any) => role.name === 'systemAdmin');
|
|
30
38
|
assert.equal(passportSystemAdmin?.title, 'System Administrator');
|
|
31
39
|
assert.deepEqual(passportSystemAdmin?.titleLocales, { 'zh-cn': '系统管理员' });
|
|
32
|
-
assert.
|
|
33
|
-
assert.
|
|
40
|
+
assert.deepEqual(passportSystemAdmin?.siteIds, scope.config.builtinRoles.systemAdmin.siteIds);
|
|
41
|
+
assert.equal(passportSystemAdmin?.builtin, true);
|
|
34
42
|
});
|
|
35
43
|
});
|
|
36
44
|
});
|
|
@@ -162,6 +162,7 @@ declare module 'vona' {
|
|
|
162
162
|
}
|
|
163
163
|
/** service: end */
|
|
164
164
|
/** event: begin */
|
|
165
|
+
export * from '../bean/event.resolveMenuVisibility.ts';
|
|
165
166
|
export * from '../bean/event.retrieveMenus.ts';
|
|
166
167
|
export * from '../bean/event.retrieveMenusSite.ts';
|
|
167
168
|
|
|
@@ -172,6 +173,16 @@ declare module 'vona' {
|
|
|
172
173
|
}
|
|
173
174
|
declare module 'vona-module-a-ssr' {
|
|
174
175
|
|
|
176
|
+
export interface EventResolveMenuVisibility {
|
|
177
|
+
/** @internal */
|
|
178
|
+
get scope(): ScopeModuleASsr;
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
export interface EventResolveMenuVisibility {
|
|
182
|
+
get $beanFullName(): 'a-ssr.event.resolveMenuVisibility';
|
|
183
|
+
get $onionName(): 'a-ssr:resolveMenuVisibility';
|
|
184
|
+
}
|
|
185
|
+
|
|
175
186
|
export interface EventRetrieveMenus {
|
|
176
187
|
/** @internal */
|
|
177
188
|
get scope(): ScopeModuleASsr;
|
|
@@ -194,20 +205,24 @@ declare module 'vona-module-a-ssr' {
|
|
|
194
205
|
}
|
|
195
206
|
/** event: end */
|
|
196
207
|
/** event: begin */
|
|
208
|
+
import type { EventResolveMenuVisibility } from '../bean/event.resolveMenuVisibility.ts';
|
|
197
209
|
import type { EventRetrieveMenus } from '../bean/event.retrieveMenus.ts';
|
|
198
210
|
import type { EventRetrieveMenusSite } from '../bean/event.retrieveMenusSite.ts';
|
|
199
211
|
export interface IModuleEvent {
|
|
200
|
-
'
|
|
212
|
+
'resolveMenuVisibility': EventResolveMenuVisibility;
|
|
213
|
+
'retrieveMenus': EventRetrieveMenus;
|
|
201
214
|
'retrieveMenusSite': EventRetrieveMenusSite;
|
|
202
215
|
}
|
|
203
216
|
/** event: end */
|
|
204
217
|
/** event: begin */
|
|
218
|
+
import type { TypeEventResolveMenuVisibilityData, TypeEventResolveMenuVisibilityResult } from '../bean/event.resolveMenuVisibility.ts';
|
|
205
219
|
import type { TypeEventRetrieveMenusData, TypeEventRetrieveMenusResult } from '../bean/event.retrieveMenus.ts';
|
|
206
220
|
import type { TypeEventRetrieveMenusSiteData, TypeEventRetrieveMenusSiteResult } from '../bean/event.retrieveMenusSite.ts';
|
|
207
221
|
import type { EventOn } from 'vona-module-a-event';
|
|
208
222
|
declare module 'vona-module-a-event' {
|
|
209
223
|
export interface IEventRecord {
|
|
210
|
-
'a-ssr:
|
|
224
|
+
'a-ssr:resolveMenuVisibility': EventOn<TypeEventResolveMenuVisibilityData, TypeEventResolveMenuVisibilityResult>;
|
|
225
|
+
'a-ssr:retrieveMenus': EventOn<TypeEventRetrieveMenusData, TypeEventRetrieveMenusResult>;
|
|
211
226
|
'a-ssr:retrieveMenusSite': EventOn<TypeEventRetrieveMenusSiteData, TypeEventRetrieveMenusSiteResult>;
|
|
212
227
|
}
|
|
213
228
|
}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import type { TableIdentity } from 'table-identity';
|
|
2
|
+
|
|
3
|
+
import { BeanEventBase, Event } from 'vona-module-a-event';
|
|
4
|
+
|
|
5
|
+
import type { ISsrMenuItemPrepared } from '../types/ssrMenu.ts';
|
|
6
|
+
|
|
7
|
+
export interface TypeEventResolveMenuVisibilityData {
|
|
8
|
+
ssrSiteName: string;
|
|
9
|
+
menus: ISsrMenuItemPrepared[];
|
|
10
|
+
currentRoleIds: TableIdentity[];
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
export type TypeEventResolveMenuVisibilityResult = ISsrMenuItemPrepared[];
|
|
14
|
+
|
|
15
|
+
@Event()
|
|
16
|
+
export class EventResolveMenuVisibility extends BeanEventBase<
|
|
17
|
+
TypeEventResolveMenuVisibilityData,
|
|
18
|
+
TypeEventResolveMenuVisibilityResult
|
|
19
|
+
> {}
|