vona-cli-set-api 1.0.172 → 1.0.176
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/cli/templates/create/project/basic/boilerplate/_.gitignore +0 -1
- package/cli/templates/create/project/basic/boilerplate/env/.env +1 -1
- package/cli/templates/create/project/basic/boilerplate/package.original.json +3 -3
- package/cli/templates/create/project/basic/boilerplate/src/suite/a-home/modules/home-base/src/.metadata/index.ts +3 -0
- package/cli/templates/create/project/basic/boilerplate/src/suite/a-home/modules/home-base/src/main.ts +16 -0
- package/cli/templates/create/project/basic/boilerplate/src/suite/a-home/modules/home-user/src/.metadata/index.ts +135 -2
- package/cli/templates/create/project/basic/boilerplate/src/suite/a-home/modules/home-user/src/bean/eventListener.activate.ts +28 -0
- package/cli/templates/create/project/basic/boilerplate/src/suite/a-home/modules/home-user/src/bean/eventListener.emailConfirmCallback.ts +24 -0
- package/cli/templates/create/project/basic/boilerplate/src/suite/a-home/modules/home-user/src/bean/eventListener.passwordResetCallback.ts +22 -0
- package/cli/templates/create/project/basic/boilerplate/src/suite/a-home/modules/home-user/src/bean/eventListener.register.ts +23 -0
- package/cli/templates/create/project/basic/boilerplate/src/suite/a-home/modules/home-user/src/bean/meta.version.ts +9 -10
- package/cli/templates/create/project/basic/boilerplate/src/suite/a-home/modules/home-user/src/bean/zodRefine.emailUnique.ts +20 -0
- package/cli/templates/create/project/basic/boilerplate/src/suite/a-home/modules/home-user/src/bean/zodRefine.passwordConfirm.ts +20 -0
- package/cli/templates/create/project/basic/boilerplate/src/suite/a-home/modules/home-user/src/bean/zodRefine.usernameUnique.ts +20 -0
- package/cli/templates/create/project/basic/boilerplate/src/suite/a-home/modules/home-user/src/config/config.ts +3 -0
- package/cli/templates/create/project/basic/boilerplate/src/suite/a-home/modules/home-user/src/config/locale/en-us.ts +9 -0
- package/cli/templates/create/project/basic/boilerplate/src/suite/a-home/modules/home-user/src/config/locale/zh-cn.ts +9 -0
- package/cli/templates/create/project/basic/boilerplate/src/suite/a-home/modules/home-user/src/controller/passport.ts +19 -8
- package/cli/templates/create/project/basic/boilerplate/src/suite/a-home/modules/home-user/src/dto/auth.ts +1 -1
- package/cli/templates/create/project/basic/boilerplate/src/suite/a-home/modules/home-user/src/dto/login.ts +18 -0
- package/cli/templates/create/project/basic/boilerplate/src/suite/a-home/modules/home-user/src/dto/register.ts +26 -0
- package/cli/templates/create/project/basic/boilerplate/src/suite/a-home/modules/home-user/src/entity/roleUser.ts +2 -1
- package/cli/templates/create/project/basic/boilerplate/src/suite/a-home/modules/home-user/src/entity/user.ts +9 -0
- package/cli/templates/create/project/basic/boilerplate/src/suite/a-home/modules/home-user/src/lib/authAdapter.ts +1 -1
- package/cli/templates/create/project/basic/boilerplate/src/suite/a-home/modules/home-user/src/lib/roleAdapter.ts +1 -1
- package/cli/templates/create/project/basic/boilerplate/src/suite/a-home/modules/home-user/src/lib/userAdapter.ts +14 -2
- package/cli/templates/create/project/basic/boilerplate/src/suite/a-home/modules/home-user/src/service/userInnerAdapter.ts +16 -6
- package/cli/templates/create/project/basic/boilerplate/src/suite/a-home/modules/home-user/src/types/passport.ts +1 -1
- package/cli/templates/create/project/basic/boilerplate/src/suite/a-home/modules/home-user/src/types/user.ts +3 -0
- package/cli/templates/tools/crud/boilerplate/src/controller/{{resourceName}}.ts_ +2 -4
- package/cli/templates/tools/crud/boilerplate/src/dto/{{resourceName}}Query.ts_ +4 -2
- package/cli/templates/tools/crud/boilerplate/src/service/{{resourceName}}.ts_ +2 -1
- package/dist/lib/bean/cli.tools.metadata.js +1 -0
- package/dist/lib/bean/toolsBin/generateEntryFiles.js +3 -0
- package/dist/lib/bean/toolsBin/generateZod.d.ts +2 -0
- package/dist/lib/bean/toolsBin/generateZod.js +48 -0
- package/dist/lib/utils.d.ts +1 -0
- package/dist/lib/utils.js +5 -0
- package/package.json +2 -2
|
@@ -40,7 +40,7 @@ BUILD_COPY_RELEASE =
|
|
|
40
40
|
TEST_CONCURRENCY = true
|
|
41
41
|
TEST_ONLY = false
|
|
42
42
|
TEST_WHYISNODERUNNING = false
|
|
43
|
-
TEST_PATTERNS_IGNORE = '**/test-vona/test/cache/cacheMem.test.ts,**/test-vona/test/cache/cacheRedis.test.ts,**/test-vona/test/cache/summer.test.ts'
|
|
43
|
+
TEST_PATTERNS_IGNORE = '**/test-vona/test/cache/cacheMem.test.ts,**/test-vona/test/cache/cacheRedis.test.ts,**/test-vona/test/cache/summer.test.ts,**/test-vona/test/mail.test.ts'
|
|
44
44
|
|
|
45
45
|
# database
|
|
46
46
|
|
|
@@ -22,7 +22,7 @@
|
|
|
22
22
|
"node": ">=24.1.0"
|
|
23
23
|
},
|
|
24
24
|
"scripts": {
|
|
25
|
-
"init": "pnpm install --no-frozen-lockfile && npm run prerun && pnpm install --no-frozen-lockfile",
|
|
25
|
+
"init": "pnpm install --no-frozen-lockfile && npm run prerun && pnpm install --no-frozen-lockfile && pnpm dedupe",
|
|
26
26
|
"demo": "vona :bin:demo --flavor=normal",
|
|
27
27
|
"db:reset": "npm run prerun && vona :bin:dbReset --flavor=normal",
|
|
28
28
|
"dev": "npm run prerun && vona :bin:dev --workers=2 --flavor=normal",
|
|
@@ -45,10 +45,10 @@
|
|
|
45
45
|
}
|
|
46
46
|
},
|
|
47
47
|
"dependencies": {
|
|
48
|
-
"vona": "^5.0.
|
|
48
|
+
"vona": "^5.0.104"
|
|
49
49
|
},
|
|
50
50
|
"devDependencies": {
|
|
51
51
|
"@cabloy/lint": "^5.0.16",
|
|
52
|
-
"eslint": "^9.
|
|
52
|
+
"eslint": "^9.35.0"
|
|
53
53
|
}
|
|
54
54
|
}
|
|
@@ -81,6 +81,9 @@ declare module 'vona-module-a-web' {
|
|
|
81
81
|
|
|
82
82
|
}
|
|
83
83
|
/** controller: end */
|
|
84
|
+
/** main: begin */
|
|
85
|
+
export * from '../main.ts';
|
|
86
|
+
/** main: end */
|
|
84
87
|
/** scope: begin */
|
|
85
88
|
import { BeanScopeBase, type BeanScopeUtil } from 'vona';
|
|
86
89
|
import { Scope } from 'vona-module-a-bean';
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import type { IModuleMain } from 'vona';
|
|
2
|
+
import { BeanSimple } from 'vona';
|
|
3
|
+
import { en, zhCN } from 'zod/locales';
|
|
4
|
+
|
|
5
|
+
export class Main extends BeanSimple implements IModuleMain {
|
|
6
|
+
async moduleLoading() {}
|
|
7
|
+
async moduleLoaded() {
|
|
8
|
+
const localeErrors = {
|
|
9
|
+
'en-us': en,
|
|
10
|
+
'zh-cn': zhCN,
|
|
11
|
+
};
|
|
12
|
+
this.app.util.setLocaleErrors(localeErrors, this.bean.scope('a-i18n').config.i18n.defaultLocale);
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
async configLoaded(_config: any) {}
|
|
16
|
+
}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
/* eslint-disable */
|
|
2
2
|
import type { TypeEntityMeta,TypeModelsClassLikeGeneral,TypeSymbolKeyFieldsMore,IModelRelationBelongsToMany } from 'vona-module-a-orm';
|
|
3
3
|
import type { TypeEntityOptionsFields,TypeControllerOptionsActions } from 'vona-module-a-openapi';
|
|
4
|
+
import type { TableIdentity } from 'table-identity';
|
|
4
5
|
/** entity: begin */
|
|
5
6
|
export * from '../entity/role.ts';
|
|
6
7
|
export * from '../entity/roleUser.ts';
|
|
@@ -135,7 +136,7 @@ declare module 'vona' {
|
|
|
135
136
|
}
|
|
136
137
|
/** model: end */
|
|
137
138
|
/** model: begin */
|
|
138
|
-
import type { IModelGetOptions, IModelMethodOptions, IModelSelectParams,
|
|
139
|
+
import type { IModelGetOptions, IModelMethodOptions, IModelSelectParams, TypeModelSelectAndCount, TypeModelRelationResult, TypeModelWhere, IModelInsertOptions, TypeModelMutateRelationData, IModelDeleteOptions, IModelUpdateOptions, IModelMutateOptions, IModelSelectCountParams, IModelSelectAggrParams, TypeModelAggrRelationResult, IModelSelectGroupParams, TypeModelGroupRelationResult } from 'vona-module-a-orm';
|
|
139
140
|
import { SymbolKeyEntity, SymbolKeyEntityMeta, SymbolKeyModelOptions } from 'vona-module-a-orm';
|
|
140
141
|
declare module 'vona-module-home-user' {
|
|
141
142
|
export interface IModelOptionsUser {
|
|
@@ -149,6 +150,7 @@ declare module 'vona-module-home-user' {
|
|
|
149
150
|
[SymbolKeyModelOptions]: IModelOptionsRole;
|
|
150
151
|
get<T extends IModelGetOptions<EntityRole,ModelRole>>(where: TypeModelWhere<EntityRole>, options?: T): Promise<TypeModelRelationResult<EntityRole, ModelRole, T> | undefined>;
|
|
151
152
|
mget<T extends IModelGetOptions<EntityRole,ModelRole>>(ids: TableIdentity[], options?: T): Promise<TypeModelRelationResult<EntityRole, ModelRole, T>[]>;
|
|
153
|
+
selectAndCount<T extends IModelSelectParams<EntityRole,ModelRole,ModelJoins>, ModelJoins extends TypeModelsClassLikeGeneral | undefined = undefined>(params?: T, options?: IModelMethodOptions, modelJoins?: ModelJoins): Promise<TypeModelSelectAndCount<EntityRole, ModelRole, T>>;
|
|
152
154
|
select<T extends IModelSelectParams<EntityRole,ModelRole,ModelJoins>, ModelJoins extends TypeModelsClassLikeGeneral | undefined = undefined>(params?: T, options?: IModelMethodOptions, modelJoins?: ModelJoins): Promise<TypeModelRelationResult<EntityRole, ModelRole, T>[]>;
|
|
153
155
|
insert<T extends IModelInsertOptions<EntityRole,ModelRole>>(data?: TypeModelMutateRelationData<EntityRole,ModelRole, T>, options?: T): Promise<TypeModelMutateRelationData<EntityRole,ModelRole, T, true>>;
|
|
154
156
|
insertBulk<T extends IModelInsertOptions<EntityRole,ModelRole>>(items: TypeModelMutateRelationData<EntityRole,ModelRole, T>[], options?: T): Promise<TypeModelMutateRelationData<EntityRole,ModelRole, T, true>[]>;
|
|
@@ -168,6 +170,7 @@ export interface ModelRoleUser {
|
|
|
168
170
|
[SymbolKeyModelOptions]: IModelOptionsRoleUser;
|
|
169
171
|
get<T extends IModelGetOptions<EntityRoleUser,ModelRoleUser>>(where: TypeModelWhere<EntityRoleUser>, options?: T): Promise<TypeModelRelationResult<EntityRoleUser, ModelRoleUser, T> | undefined>;
|
|
170
172
|
mget<T extends IModelGetOptions<EntityRoleUser,ModelRoleUser>>(ids: TableIdentity[], options?: T): Promise<TypeModelRelationResult<EntityRoleUser, ModelRoleUser, T>[]>;
|
|
173
|
+
selectAndCount<T extends IModelSelectParams<EntityRoleUser,ModelRoleUser,ModelJoins>, ModelJoins extends TypeModelsClassLikeGeneral | undefined = undefined>(params?: T, options?: IModelMethodOptions, modelJoins?: ModelJoins): Promise<TypeModelSelectAndCount<EntityRoleUser, ModelRoleUser, T>>;
|
|
171
174
|
select<T extends IModelSelectParams<EntityRoleUser,ModelRoleUser,ModelJoins>, ModelJoins extends TypeModelsClassLikeGeneral | undefined = undefined>(params?: T, options?: IModelMethodOptions, modelJoins?: ModelJoins): Promise<TypeModelRelationResult<EntityRoleUser, ModelRoleUser, T>[]>;
|
|
172
175
|
insert<T extends IModelInsertOptions<EntityRoleUser,ModelRoleUser>>(data?: TypeModelMutateRelationData<EntityRoleUser,ModelRoleUser, T>, options?: T): Promise<TypeModelMutateRelationData<EntityRoleUser,ModelRoleUser, T, true>>;
|
|
173
176
|
insertBulk<T extends IModelInsertOptions<EntityRoleUser,ModelRoleUser>>(items: TypeModelMutateRelationData<EntityRoleUser,ModelRoleUser, T>[], options?: T): Promise<TypeModelMutateRelationData<EntityRoleUser,ModelRoleUser, T, true>[]>;
|
|
@@ -187,6 +190,7 @@ export interface ModelUser {
|
|
|
187
190
|
[SymbolKeyModelOptions]: IModelOptionsUser;
|
|
188
191
|
get<T extends IModelGetOptions<EntityUser,ModelUser>>(where: TypeModelWhere<EntityUser>, options?: T): Promise<TypeModelRelationResult<EntityUser, ModelUser, T> | undefined>;
|
|
189
192
|
mget<T extends IModelGetOptions<EntityUser,ModelUser>>(ids: TableIdentity[], options?: T): Promise<TypeModelRelationResult<EntityUser, ModelUser, T>[]>;
|
|
193
|
+
selectAndCount<T extends IModelSelectParams<EntityUser,ModelUser,ModelJoins>, ModelJoins extends TypeModelsClassLikeGeneral | undefined = undefined>(params?: T, options?: IModelMethodOptions, modelJoins?: ModelJoins): Promise<TypeModelSelectAndCount<EntityUser, ModelUser, T>>;
|
|
190
194
|
select<T extends IModelSelectParams<EntityUser,ModelUser,ModelJoins>, ModelJoins extends TypeModelsClassLikeGeneral | undefined = undefined>(params?: T, options?: IModelMethodOptions, modelJoins?: ModelJoins): Promise<TypeModelRelationResult<EntityUser, ModelUser, T>[]>;
|
|
191
195
|
insert<T extends IModelInsertOptions<EntityUser,ModelUser>>(data?: TypeModelMutateRelationData<EntityUser,ModelUser, T>, options?: T): Promise<TypeModelMutateRelationData<EntityUser,ModelUser, T, true>>;
|
|
192
196
|
insertBulk<T extends IModelInsertOptions<EntityUser,ModelUser>>(items: TypeModelMutateRelationData<EntityUser,ModelUser, T>[], options?: T): Promise<TypeModelMutateRelationData<EntityUser,ModelUser, T, true>[]>;
|
|
@@ -294,6 +298,67 @@ declare module 'vona' {
|
|
|
294
298
|
}
|
|
295
299
|
}
|
|
296
300
|
/** service: end */
|
|
301
|
+
/** eventListener: begin */
|
|
302
|
+
export * from '../bean/eventListener.activate.ts';
|
|
303
|
+
export * from '../bean/eventListener.emailConfirmCallback.ts';
|
|
304
|
+
export * from '../bean/eventListener.passwordResetCallback.ts';
|
|
305
|
+
export * from '../bean/eventListener.register.ts';
|
|
306
|
+
|
|
307
|
+
import { type IDecoratorEventListenerOptions } from 'vona-module-a-event';
|
|
308
|
+
declare module 'vona-module-a-event' {
|
|
309
|
+
|
|
310
|
+
export interface IEventListenerRecord {
|
|
311
|
+
'home-user:activate': IDecoratorEventListenerOptions;
|
|
312
|
+
'home-user:emailConfirmCallback': IDecoratorEventListenerOptions;
|
|
313
|
+
'home-user:passwordResetCallback': IDecoratorEventListenerOptions;
|
|
314
|
+
'home-user:register': IDecoratorEventListenerOptions;
|
|
315
|
+
}
|
|
316
|
+
|
|
317
|
+
|
|
318
|
+
}
|
|
319
|
+
declare module 'vona-module-home-user' {
|
|
320
|
+
|
|
321
|
+
export interface EventListenerActivate {
|
|
322
|
+
/** @internal */
|
|
323
|
+
get scope(): ScopeModuleHomeUser;
|
|
324
|
+
}
|
|
325
|
+
|
|
326
|
+
export interface EventListenerActivate {
|
|
327
|
+
get $beanFullName(): 'home-user.eventListener.activate';
|
|
328
|
+
get $onionName(): 'home-user:activate';
|
|
329
|
+
}
|
|
330
|
+
|
|
331
|
+
export interface EventListenerEmailConfirmCallback {
|
|
332
|
+
/** @internal */
|
|
333
|
+
get scope(): ScopeModuleHomeUser;
|
|
334
|
+
}
|
|
335
|
+
|
|
336
|
+
export interface EventListenerEmailConfirmCallback {
|
|
337
|
+
get $beanFullName(): 'home-user.eventListener.emailConfirmCallback';
|
|
338
|
+
get $onionName(): 'home-user:emailConfirmCallback';
|
|
339
|
+
}
|
|
340
|
+
|
|
341
|
+
export interface EventListenerPasswordResetCallback {
|
|
342
|
+
/** @internal */
|
|
343
|
+
get scope(): ScopeModuleHomeUser;
|
|
344
|
+
}
|
|
345
|
+
|
|
346
|
+
export interface EventListenerPasswordResetCallback {
|
|
347
|
+
get $beanFullName(): 'home-user.eventListener.passwordResetCallback';
|
|
348
|
+
get $onionName(): 'home-user:passwordResetCallback';
|
|
349
|
+
}
|
|
350
|
+
|
|
351
|
+
export interface EventListenerRegister {
|
|
352
|
+
/** @internal */
|
|
353
|
+
get scope(): ScopeModuleHomeUser;
|
|
354
|
+
}
|
|
355
|
+
|
|
356
|
+
export interface EventListenerRegister {
|
|
357
|
+
get $beanFullName(): 'home-user.eventListener.register';
|
|
358
|
+
get $onionName(): 'home-user:register';
|
|
359
|
+
}
|
|
360
|
+
}
|
|
361
|
+
/** eventListener: end */
|
|
297
362
|
/** meta: begin */
|
|
298
363
|
export * from '../bean/meta.index.ts';
|
|
299
364
|
export * from '../bean/meta.version.ts';
|
|
@@ -333,18 +398,24 @@ declare module 'vona-module-home-user' {
|
|
|
333
398
|
/** meta: end */
|
|
334
399
|
/** dto: begin */
|
|
335
400
|
export * from '../dto/auth.ts';
|
|
401
|
+
export * from '../dto/login.ts';
|
|
336
402
|
export * from '../dto/passport.ts';
|
|
337
403
|
export * from '../dto/passportJwt.ts';
|
|
404
|
+
export * from '../dto/register.ts';
|
|
338
405
|
import type { IDtoOptionsAuth } from '../dto/auth.ts';
|
|
406
|
+
import type { IDtoOptionsLogin } from '../dto/login.ts';
|
|
339
407
|
import type { IDtoOptionsPassport } from '../dto/passport.ts';
|
|
340
408
|
import type { IDtoOptionsPassportJwt } from '../dto/passportJwt.ts';
|
|
409
|
+
import type { IDtoOptionsRegister } from '../dto/register.ts';
|
|
341
410
|
import 'vona';
|
|
342
411
|
declare module 'vona-module-a-web' {
|
|
343
412
|
|
|
344
413
|
export interface IDtoRecord {
|
|
345
414
|
'home-user:auth': IDtoOptionsAuth;
|
|
415
|
+
'home-user:login': IDtoOptionsLogin;
|
|
346
416
|
'home-user:passport': IDtoOptionsPassport;
|
|
347
417
|
'home-user:passportJwt': IDtoOptionsPassportJwt;
|
|
418
|
+
'home-user:register': IDtoOptionsRegister;
|
|
348
419
|
}
|
|
349
420
|
|
|
350
421
|
|
|
@@ -355,14 +426,20 @@ declare module 'vona-module-home-user' {
|
|
|
355
426
|
/** dto: end */
|
|
356
427
|
/** dto: begin */
|
|
357
428
|
import type { DtoAuth } from '../dto/auth.ts';
|
|
429
|
+
import type { DtoLogin } from '../dto/login.ts';
|
|
358
430
|
import type { DtoPassport } from '../dto/passport.ts';
|
|
359
|
-
import type { DtoPassportJwt } from '../dto/passportJwt.ts';
|
|
431
|
+
import type { DtoPassportJwt } from '../dto/passportJwt.ts';
|
|
432
|
+
import type { DtoRegister } from '../dto/register.ts';
|
|
360
433
|
declare module 'vona-module-home-user' {
|
|
361
434
|
|
|
362
435
|
export interface IDtoOptionsAuth {
|
|
363
436
|
fields?: TypeEntityOptionsFields<DtoAuth, IDtoOptionsAuth[TypeSymbolKeyFieldsMore]>;
|
|
364
437
|
}
|
|
365
438
|
|
|
439
|
+
export interface IDtoOptionsLogin {
|
|
440
|
+
fields?: TypeEntityOptionsFields<DtoLogin, IDtoOptionsLogin[TypeSymbolKeyFieldsMore]>;
|
|
441
|
+
}
|
|
442
|
+
|
|
366
443
|
export interface IDtoOptionsPassport {
|
|
367
444
|
fields?: TypeEntityOptionsFields<DtoPassport, IDtoOptionsPassport[TypeSymbolKeyFieldsMore]>;
|
|
368
445
|
}
|
|
@@ -370,6 +447,10 @@ declare module 'vona-module-home-user' {
|
|
|
370
447
|
export interface IDtoOptionsPassportJwt {
|
|
371
448
|
fields?: TypeEntityOptionsFields<DtoPassportJwt, IDtoOptionsPassportJwt[TypeSymbolKeyFieldsMore]>;
|
|
372
449
|
}
|
|
450
|
+
|
|
451
|
+
export interface IDtoOptionsRegister {
|
|
452
|
+
fields?: TypeEntityOptionsFields<DtoRegister, IDtoOptionsRegister[TypeSymbolKeyFieldsMore]>;
|
|
453
|
+
}
|
|
373
454
|
}
|
|
374
455
|
/** dto: end */
|
|
375
456
|
/** controller: begin */
|
|
@@ -415,6 +496,7 @@ declare module 'vona-module-a-web' {
|
|
|
415
496
|
}
|
|
416
497
|
export interface IApiPathPostRecord{
|
|
417
498
|
'/home/user/passport/logout': undefined;
|
|
499
|
+
'/home/user/passport/register': undefined;
|
|
418
500
|
'/home/user/passport/login': undefined;
|
|
419
501
|
'/home/user/passport/refreshAuthToken': undefined;
|
|
420
502
|
'/home/user/passport/createPassportJwtFromOauthCode': undefined;
|
|
@@ -423,6 +505,57 @@ export interface IApiPathPostRecord{
|
|
|
423
505
|
|
|
424
506
|
}
|
|
425
507
|
/** controller: end */
|
|
508
|
+
/** zodRefine: begin */
|
|
509
|
+
export * from '../bean/zodRefine.emailUnique.ts';
|
|
510
|
+
export * from '../bean/zodRefine.passwordConfirm.ts';
|
|
511
|
+
export * from '../bean/zodRefine.usernameUnique.ts';
|
|
512
|
+
import type { IZodRefineOptionsEmailUnique } from '../bean/zodRefine.emailUnique.ts';
|
|
513
|
+
import type { IZodRefineOptionsPasswordConfirm } from '../bean/zodRefine.passwordConfirm.ts';
|
|
514
|
+
import type { IZodRefineOptionsUsernameUnique } from '../bean/zodRefine.usernameUnique.ts';
|
|
515
|
+
import 'vona';
|
|
516
|
+
declare module 'vona-module-a-zod' {
|
|
517
|
+
|
|
518
|
+
export interface IZodRefineRecord {
|
|
519
|
+
'home-user:emailUnique': IZodRefineOptionsEmailUnique;
|
|
520
|
+
'home-user:passwordConfirm': IZodRefineOptionsPasswordConfirm;
|
|
521
|
+
'home-user:usernameUnique': IZodRefineOptionsUsernameUnique;
|
|
522
|
+
}
|
|
523
|
+
|
|
524
|
+
|
|
525
|
+
}
|
|
526
|
+
declare module 'vona-module-home-user' {
|
|
527
|
+
|
|
528
|
+
export interface ZodRefineEmailUnique {
|
|
529
|
+
/** @internal */
|
|
530
|
+
get scope(): ScopeModuleHomeUser;
|
|
531
|
+
}
|
|
532
|
+
|
|
533
|
+
export interface ZodRefineEmailUnique {
|
|
534
|
+
get $beanFullName(): 'home-user.zodRefine.emailUnique';
|
|
535
|
+
get $onionName(): 'home-user:emailUnique';
|
|
536
|
+
}
|
|
537
|
+
|
|
538
|
+
export interface ZodRefinePasswordConfirm {
|
|
539
|
+
/** @internal */
|
|
540
|
+
get scope(): ScopeModuleHomeUser;
|
|
541
|
+
}
|
|
542
|
+
|
|
543
|
+
export interface ZodRefinePasswordConfirm {
|
|
544
|
+
get $beanFullName(): 'home-user.zodRefine.passwordConfirm';
|
|
545
|
+
get $onionName(): 'home-user:passwordConfirm';
|
|
546
|
+
}
|
|
547
|
+
|
|
548
|
+
export interface ZodRefineUsernameUnique {
|
|
549
|
+
/** @internal */
|
|
550
|
+
get scope(): ScopeModuleHomeUser;
|
|
551
|
+
}
|
|
552
|
+
|
|
553
|
+
export interface ZodRefineUsernameUnique {
|
|
554
|
+
get $beanFullName(): 'home-user.zodRefine.usernameUnique';
|
|
555
|
+
get $onionName(): 'home-user:usernameUnique';
|
|
556
|
+
}
|
|
557
|
+
}
|
|
558
|
+
/** zodRefine: end */
|
|
426
559
|
/** config: begin */
|
|
427
560
|
export * from '../config/config.ts';
|
|
428
561
|
import type { config } from '../config/config.ts';
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import type { IEventExecute, NextEvent } from 'vona-module-a-event';
|
|
2
|
+
import type { TypeEventActivateData, TypeEventActivateResult } from 'vona-module-a-user';
|
|
3
|
+
import type { IUser } from '../types/user.ts';
|
|
4
|
+
import { BeanBase } from 'vona';
|
|
5
|
+
import { EventListener } from 'vona-module-a-event';
|
|
6
|
+
|
|
7
|
+
type TypeEventData = TypeEventActivateData;
|
|
8
|
+
type TypeEventResult = TypeEventActivateResult;
|
|
9
|
+
|
|
10
|
+
@EventListener({ match: 'a-user:activate' })
|
|
11
|
+
export class EventListenerActivate
|
|
12
|
+
extends BeanBase
|
|
13
|
+
implements IEventExecute<TypeEventData, TypeEventResult> {
|
|
14
|
+
async execute(data: TypeEventData, next: NextEvent<TypeEventData, TypeEventResult>): Promise<TypeEventResult> {
|
|
15
|
+
const user = data as IUser;
|
|
16
|
+
if (user.name === 'admin') {
|
|
17
|
+
// role: admin
|
|
18
|
+
const roleAdmin = await this.scope.model.role.get({ name: 'admin' });
|
|
19
|
+
// userRole: admin
|
|
20
|
+
await this.scope.model.roleUser.insert({
|
|
21
|
+
userId: user.id,
|
|
22
|
+
roleId: roleAdmin!.id,
|
|
23
|
+
});
|
|
24
|
+
}
|
|
25
|
+
// next
|
|
26
|
+
return next();
|
|
27
|
+
}
|
|
28
|
+
}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import type { IEventExecute, NextEvent } from 'vona-module-a-event';
|
|
2
|
+
import type { TypeEventEmailConfirmCallbackData, TypeEventEmailConfirmCallbackResult } from 'vona-module-a-mailconfirm';
|
|
3
|
+
import { BeanBase } from 'vona';
|
|
4
|
+
import { EventListener } from 'vona-module-a-event';
|
|
5
|
+
|
|
6
|
+
type TypeEventData = TypeEventEmailConfirmCallbackData;
|
|
7
|
+
type TypeEventResult = TypeEventEmailConfirmCallbackResult;
|
|
8
|
+
|
|
9
|
+
@EventListener({ match: 'a-mailconfirm:emailConfirmCallback' })
|
|
10
|
+
export class EventListenerEmailConfirmCallback
|
|
11
|
+
extends BeanBase
|
|
12
|
+
implements IEventExecute<TypeEventData, TypeEventResult> {
|
|
13
|
+
async execute(data: TypeEventData, _next: NextEvent<TypeEventData, TypeEventResult>): Promise<TypeEventResult> {
|
|
14
|
+
// check cache
|
|
15
|
+
if (!data) {
|
|
16
|
+
return this.scope.locale.ConfirmationEmailExpired();
|
|
17
|
+
}
|
|
18
|
+
// activate
|
|
19
|
+
const user = await this.bean.userInner.findOne({ id: data.userId });
|
|
20
|
+
await this.bean.userInner.activate(user!);
|
|
21
|
+
// ok
|
|
22
|
+
return this.scope.locale.ConfirmationEmailSucceeded();
|
|
23
|
+
}
|
|
24
|
+
}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import type { IEventExecute, NextEvent } from 'vona-module-a-event';
|
|
2
|
+
import type { TypeEventPasswordResetCallbackData, TypeEventPasswordResetCallbackResult } from 'vona-module-a-mailconfirm';
|
|
3
|
+
import { BeanBase } from 'vona';
|
|
4
|
+
import { EventListener } from 'vona-module-a-event';
|
|
5
|
+
|
|
6
|
+
type TypeEventData = TypeEventPasswordResetCallbackData;
|
|
7
|
+
type TypeEventResult = TypeEventPasswordResetCallbackResult;
|
|
8
|
+
|
|
9
|
+
@EventListener({ match: 'a-mailconfirm:passwordResetCallback' })
|
|
10
|
+
export class EventListenerPasswordResetCallback
|
|
11
|
+
extends BeanBase
|
|
12
|
+
implements IEventExecute<TypeEventData, TypeEventResult> {
|
|
13
|
+
async execute(data: TypeEventData, _next: NextEvent<TypeEventData, TypeEventResult>): Promise<TypeEventResult> {
|
|
14
|
+
// check cache
|
|
15
|
+
if (!data) {
|
|
16
|
+
return this.scope.locale.PasswordResetEmailExpired();
|
|
17
|
+
}
|
|
18
|
+
// maybe mock captcha token2 to do secendary verify
|
|
19
|
+
// todo: redirect to frontend
|
|
20
|
+
throw new Error('Not Implemented');
|
|
21
|
+
}
|
|
22
|
+
}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import type { IEventExecute, NextEvent } from 'vona-module-a-event';
|
|
2
|
+
import type { TypeEventRegisterData, TypeEventRegisterResult } from 'vona-module-a-user';
|
|
3
|
+
import type { IUser } from '../types/user.ts';
|
|
4
|
+
import { BeanBase } from 'vona';
|
|
5
|
+
import { EventListener } from 'vona-module-a-event';
|
|
6
|
+
|
|
7
|
+
type TypeEventData = TypeEventRegisterData;
|
|
8
|
+
type TypeEventResult = TypeEventRegisterResult;
|
|
9
|
+
|
|
10
|
+
@EventListener({ match: 'a-user:register' })
|
|
11
|
+
export class EventListenerRegister
|
|
12
|
+
extends BeanBase
|
|
13
|
+
implements IEventExecute<TypeEventData, TypeEventResult> {
|
|
14
|
+
async execute(data: TypeEventData, next: NextEvent<TypeEventData, TypeEventResult>): Promise<TypeEventResult> {
|
|
15
|
+
// next: registered
|
|
16
|
+
const user = await next() as IUser;
|
|
17
|
+
// mail: activate
|
|
18
|
+
if (!data.autoActivate && user.email) {
|
|
19
|
+
await this.$scope.mailconfirm.service.mail.emailConfirm(user);
|
|
20
|
+
}
|
|
21
|
+
return user;
|
|
22
|
+
}
|
|
23
|
+
}
|
|
@@ -20,6 +20,9 @@ export class MetaVersion extends BeanBase implements IMetaVersionUpdate, IMetaVe
|
|
|
20
20
|
table.basicFields();
|
|
21
21
|
table.string(entityUser.name, 255).comment(entityUser.$comment.name);
|
|
22
22
|
table.string(entityUser.avatar, 255).comment(entityUser.$comment.avatar);
|
|
23
|
+
table.string(entityUser.email, 255).comment(entityUser.$comment.email);
|
|
24
|
+
table.string(entityUser.mobile, 255).comment(entityUser.$comment.mobile);
|
|
25
|
+
table.boolean(entityUser.activated).defaultTo(entityUser.$default.activated).comment(entityUser.$comment.activated);
|
|
23
26
|
table.string(entityUser.locale, 255).comment(entityUser.$comment.locale);
|
|
24
27
|
});
|
|
25
28
|
// homeRoleUser
|
|
@@ -35,20 +38,16 @@ export class MetaVersion extends BeanBase implements IMetaVersionUpdate, IMetaVe
|
|
|
35
38
|
async init(options: IMetaVersionInitOptions) {
|
|
36
39
|
if (options.version === 1) {
|
|
37
40
|
// role: admin
|
|
38
|
-
|
|
41
|
+
await this.scope.model.role.insert({
|
|
39
42
|
name: 'admin',
|
|
40
43
|
});
|
|
41
44
|
// user: admin
|
|
42
|
-
|
|
43
|
-
|
|
45
|
+
await this.bean.authSimple.authenticate({
|
|
46
|
+
username: 'admin',
|
|
47
|
+
password: options.password || this.scope.config.passwordDefault.admin,
|
|
44
48
|
avatar: ':emoji:flower',
|
|
45
|
-
|
|
46
|
-
});
|
|
47
|
-
// userRole: admin
|
|
48
|
-
await this.scope.model.roleUser.insert({
|
|
49
|
-
userId: userAdmin.id,
|
|
50
|
-
roleId: roleAdmin.id,
|
|
51
|
-
});
|
|
49
|
+
confirmed: true,
|
|
50
|
+
}, 'register', 'default');
|
|
52
51
|
}
|
|
53
52
|
}
|
|
54
53
|
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import type { IDecoratorZodRefineOptions, IZodRefineExecute, TypeRefinementCtx } from 'vona-module-a-zod';
|
|
2
|
+
import { BeanBase } from 'vona';
|
|
3
|
+
import { ZodRefine } from 'vona-module-a-zod';
|
|
4
|
+
|
|
5
|
+
export type TypeZodRefineEmailUniqueData = string;
|
|
6
|
+
|
|
7
|
+
export interface IZodRefineOptionsEmailUnique extends IDecoratorZodRefineOptions {}
|
|
8
|
+
|
|
9
|
+
@ZodRefine<IZodRefineOptionsEmailUnique>()
|
|
10
|
+
export class ZodRefineEmailUnique extends BeanBase implements IZodRefineExecute<TypeZodRefineEmailUniqueData> {
|
|
11
|
+
async execute(value: TypeZodRefineEmailUniqueData, refinementCtx: TypeRefinementCtx, _options: IZodRefineOptionsEmailUnique) {
|
|
12
|
+
const user = await this.scope.model.user.get({ email: { _eqI_: value } });
|
|
13
|
+
if (user) {
|
|
14
|
+
refinementCtx.addIssue({
|
|
15
|
+
code: 'custom',
|
|
16
|
+
message: this.scope.locale.EmailExists(),
|
|
17
|
+
});
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import type { IDecoratorZodRefineOptions, IZodRefineExecute, TypeRefinementCtx } from 'vona-module-a-zod';
|
|
2
|
+
import { BeanBase } from 'vona';
|
|
3
|
+
import { ZodRefine } from 'vona-module-a-zod';
|
|
4
|
+
|
|
5
|
+
export interface TypeZodRefinePasswordConfirmData { password: string; passwordConfirm: string }
|
|
6
|
+
|
|
7
|
+
export interface IZodRefineOptionsPasswordConfirm extends IDecoratorZodRefineOptions {}
|
|
8
|
+
|
|
9
|
+
@ZodRefine<IZodRefineOptionsPasswordConfirm>()
|
|
10
|
+
export class ZodRefinePasswordConfirm extends BeanBase implements IZodRefineExecute<TypeZodRefinePasswordConfirmData> {
|
|
11
|
+
async execute(value: TypeZodRefinePasswordConfirmData, refinementCtx: TypeRefinementCtx, _options: IZodRefineOptionsPasswordConfirm) {
|
|
12
|
+
if (value.password !== value.passwordConfirm) {
|
|
13
|
+
refinementCtx.addIssue({
|
|
14
|
+
code: 'custom',
|
|
15
|
+
message: this.scope.locale.PasswordsNotMatch(),
|
|
16
|
+
path: ['passwordConfirm'],
|
|
17
|
+
});
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import type { IDecoratorZodRefineOptions, IZodRefineExecute, TypeRefinementCtx } from 'vona-module-a-zod';
|
|
2
|
+
import { BeanBase } from 'vona';
|
|
3
|
+
import { ZodRefine } from 'vona-module-a-zod';
|
|
4
|
+
|
|
5
|
+
export type TypeZodRefineUsernameUniqueData = string;
|
|
6
|
+
|
|
7
|
+
export interface IZodRefineOptionsUsernameUnique extends IDecoratorZodRefineOptions {}
|
|
8
|
+
|
|
9
|
+
@ZodRefine<IZodRefineOptionsUsernameUnique>()
|
|
10
|
+
export class ZodRefineUsernameUnique extends BeanBase implements IZodRefineExecute<TypeZodRefineUsernameUniqueData> {
|
|
11
|
+
async execute(value: TypeZodRefineUsernameUniqueData, refinementCtx: TypeRefinementCtx, _options: IZodRefineOptionsUsernameUnique) {
|
|
12
|
+
const user = await this.bean.userInner.findOneByName(value);
|
|
13
|
+
if (user) {
|
|
14
|
+
refinementCtx.addIssue({
|
|
15
|
+
code: 'custom',
|
|
16
|
+
message: this.scope.locale.UsernameExists(),
|
|
17
|
+
});
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
}
|
|
@@ -1,8 +1,17 @@
|
|
|
1
1
|
export default {
|
|
2
|
+
ConfirmationEmailExpired: 'This email confirmation link has expired',
|
|
3
|
+
ConfirmationEmailSucceeded: 'Your email address has been confirmed',
|
|
4
|
+
PasswordResetEmailExpired: 'This password reset link has expired',
|
|
2
5
|
Role: 'Role',
|
|
3
6
|
RoleName: 'Role Name',
|
|
4
7
|
User: 'User',
|
|
5
8
|
UserName: 'User Name',
|
|
6
9
|
UserAvatar: 'Avatar',
|
|
10
|
+
UserEmail: 'Email',
|
|
11
|
+
UserMobile: 'Mobile',
|
|
12
|
+
UserActivated: 'Activated',
|
|
7
13
|
UserLocale: 'Language',
|
|
14
|
+
UsernameExists: 'Username Exists',
|
|
15
|
+
EmailExists: 'Email Exists',
|
|
16
|
+
PasswordsNotMatch: 'Passwords do not match',
|
|
8
17
|
};
|
|
@@ -1,8 +1,17 @@
|
|
|
1
1
|
export default {
|
|
2
|
+
ConfirmationEmailExpired: '确认邮件链接已经过期',
|
|
3
|
+
ConfirmationEmailSucceeded: '您的邮件地址已经确认',
|
|
4
|
+
PasswordResetEmailExpired: '重置密码链接已经过期',
|
|
2
5
|
Role: '角色',
|
|
3
6
|
RoleName: '角色名',
|
|
4
7
|
User: '用户',
|
|
5
8
|
UserName: '用户名',
|
|
6
9
|
UserAvatar: '头像',
|
|
10
|
+
UserEmail: '电子邮件',
|
|
11
|
+
UserMobile: '手机号',
|
|
12
|
+
UserActivated: '已激活',
|
|
7
13
|
UserLocale: '语言',
|
|
14
|
+
UsernameExists: '用户名已存在',
|
|
15
|
+
EmailExists: '电子邮件已存在',
|
|
16
|
+
PasswordsNotMatch: '密码不一致',
|
|
8
17
|
};
|
|
@@ -4,14 +4,16 @@ import type { IDecoratorControllerOptions } from 'vona-module-a-web';
|
|
|
4
4
|
import type { EntityRole } from '../entity/role.ts';
|
|
5
5
|
import type { EntityUser } from '../entity/user.ts';
|
|
6
6
|
import { BeanBase } from 'vona';
|
|
7
|
-
import {
|
|
7
|
+
import { Captcha } from 'vona-module-a-captcha';
|
|
8
8
|
import { DtoJwtToken } from 'vona-module-a-jwt';
|
|
9
9
|
import { Api, v } from 'vona-module-a-openapi';
|
|
10
10
|
import { Passport } from 'vona-module-a-user';
|
|
11
11
|
import { Arg, Controller, Web } from 'vona-module-a-web';
|
|
12
12
|
import { z } from 'zod';
|
|
13
|
+
import { DtoLogin } from '../dto/login.ts';
|
|
13
14
|
import { DtoPassport } from '../dto/passport.ts';
|
|
14
15
|
import { DtoPassportJwt } from '../dto/passportJwt.ts';
|
|
16
|
+
import { DtoRegister } from '../dto/register.ts';
|
|
15
17
|
|
|
16
18
|
export interface IControllerOptionsPassport extends IDecoratorControllerOptions {}
|
|
17
19
|
|
|
@@ -29,28 +31,37 @@ export class ControllerPassport extends BeanBase {
|
|
|
29
31
|
return await this.bean.passport.signout();
|
|
30
32
|
}
|
|
31
33
|
|
|
34
|
+
@Web.post('register')
|
|
35
|
+
@Passport.public()
|
|
36
|
+
@Captcha.verify({ scene: 'a-captchasimple:simple' })
|
|
37
|
+
@Api.body(v.object(DtoPassportJwt))
|
|
38
|
+
async register(@Arg.body() data: DtoRegister) {
|
|
39
|
+
const jwt = await this.bean.authSimple.authenticate(data, 'register', 'default');
|
|
40
|
+
return this._combineDtoPassportJwt(jwt);
|
|
41
|
+
}
|
|
42
|
+
|
|
32
43
|
@Web.post('login')
|
|
33
44
|
@Passport.public()
|
|
45
|
+
@Captcha.verify({ scene: 'a-captchasimple:simple' })
|
|
34
46
|
@Api.body(v.object(DtoPassportJwt))
|
|
35
|
-
async
|
|
36
|
-
const jwt = await this.bean.authSimple.authenticate(
|
|
47
|
+
async login(@Arg.body() data: DtoLogin): Promise<DtoPassportJwt> {
|
|
48
|
+
const jwt = await this.bean.authSimple.authenticate(data, 'login', 'default');
|
|
37
49
|
return this._combineDtoPassportJwt(jwt);
|
|
38
50
|
}
|
|
39
51
|
|
|
40
52
|
@Web.get('login/:module/:providerName/:clientName?')
|
|
41
53
|
@Passport.public()
|
|
42
|
-
|
|
43
|
-
async login<T extends keyof IAuthProviderRecord>(
|
|
54
|
+
async loginOauth<T extends keyof IAuthProviderRecord>(
|
|
44
55
|
@Arg.param('module') module: string,
|
|
45
56
|
@Arg.param('providerName') providerName: string,
|
|
46
57
|
@Arg.param('clientName', z.string().optional()) clientName?: IAuthenticateOptions<IAuthProviderRecord[T]>['clientName'],
|
|
47
58
|
@Arg.query('redirect', v.optional()) redirect?: string,
|
|
48
|
-
)
|
|
49
|
-
|
|
59
|
+
) {
|
|
60
|
+
// only support oauth, so not return jwt to client
|
|
61
|
+
await this.bean.auth.authenticate(`${module}:${providerName}` as T, {
|
|
50
62
|
state: { intention: 'login', redirect },
|
|
51
63
|
clientName,
|
|
52
64
|
});
|
|
53
|
-
return this._combineDtoPassportJwt(jwt);
|
|
54
65
|
}
|
|
55
66
|
|
|
56
67
|
@Web.get('associate/:module/:providerName/:clientName?')
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { TableIdentity } from '
|
|
1
|
+
import type { TableIdentity } from 'table-identity';
|
|
2
2
|
import type { IAuthBase } from 'vona-module-a-user';
|
|
3
3
|
import type { IDecoratorDtoOptions } from 'vona-module-a-web';
|
|
4
4
|
import { Api, v } from 'vona-module-a-openapi';
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import type { IDecoratorDtoOptions } from 'vona-module-a-web';
|
|
2
|
+
import { DtoCaptchaVerify } from 'vona-module-a-captcha';
|
|
3
|
+
import { Api, v } from 'vona-module-a-openapi';
|
|
4
|
+
import { Dto } from 'vona-module-a-web';
|
|
5
|
+
|
|
6
|
+
export interface IDtoOptionsLogin extends IDecoratorDtoOptions {}
|
|
7
|
+
|
|
8
|
+
@Dto<IDtoOptionsLogin>()
|
|
9
|
+
export class DtoLogin {
|
|
10
|
+
@Api.field(v.min(3), v.trim())
|
|
11
|
+
username: string;
|
|
12
|
+
|
|
13
|
+
@Api.field(v.min(6))
|
|
14
|
+
password: string;
|
|
15
|
+
|
|
16
|
+
@Api.field(v.captcha({ scene: 'a-captchasimple:simple' }))
|
|
17
|
+
captcha: DtoCaptchaVerify;
|
|
18
|
+
}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import type { IDecoratorDtoOptions } from 'vona-module-a-web';
|
|
2
|
+
import { DtoCaptchaVerify } from 'vona-module-a-captcha';
|
|
3
|
+
import { Api, v } from 'vona-module-a-openapi';
|
|
4
|
+
import { Dto } from 'vona-module-a-web';
|
|
5
|
+
|
|
6
|
+
export interface IDtoOptionsRegister extends IDecoratorDtoOptions {}
|
|
7
|
+
|
|
8
|
+
@Dto<IDtoOptionsRegister>({
|
|
9
|
+
pipes: v.refine('home-user:passwordConfirm'),
|
|
10
|
+
})
|
|
11
|
+
export class DtoRegister {
|
|
12
|
+
@Api.field(v.refine('home-user:usernameUnique'), v.min(3), v.trim())
|
|
13
|
+
username: string;
|
|
14
|
+
|
|
15
|
+
@Api.field(v.refine('home-user:emailUnique'), v.email(), v.trim())
|
|
16
|
+
email: string;
|
|
17
|
+
|
|
18
|
+
@Api.field(v.min(6), v.max(20))
|
|
19
|
+
password: string;
|
|
20
|
+
|
|
21
|
+
@Api.field(v.min(6), v.max(20))
|
|
22
|
+
passwordConfirm: string;
|
|
23
|
+
|
|
24
|
+
@Api.field(v.captcha({ scene: 'a-captchasimple:simple' }))
|
|
25
|
+
captcha: DtoCaptchaVerify;
|
|
26
|
+
}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import type {
|
|
1
|
+
import type { TableIdentity } from 'table-identity';
|
|
2
|
+
import type { IDecoratorEntityOptions } from 'vona-module-a-orm';
|
|
2
3
|
import { Api, v } from 'vona-module-a-openapi';
|
|
3
4
|
import { Entity, EntityBase } from 'vona-module-a-orm';
|
|
4
5
|
|
|
@@ -15,6 +15,15 @@ export class EntityUser extends EntityBase {
|
|
|
15
15
|
@Api.field(v.title($locale('UserAvatar')), v.optional())
|
|
16
16
|
avatar?: string;
|
|
17
17
|
|
|
18
|
+
@Api.field(v.title($locale('UserEmail')), v.optional())
|
|
19
|
+
email?: string;
|
|
20
|
+
|
|
21
|
+
@Api.field(v.title($locale('UserMobile')), v.optional())
|
|
22
|
+
mobile?: string;
|
|
23
|
+
|
|
24
|
+
@Api.field(v.title($locale('UserActivated')), v.default(false))
|
|
25
|
+
activated: boolean;
|
|
26
|
+
|
|
18
27
|
@Api.field(v.title($locale('UserLocale')), z.string().optional())
|
|
19
28
|
locale?: keyof ILocaleInfos | undefined;
|
|
20
29
|
}
|
|
@@ -1,11 +1,11 @@
|
|
|
1
|
+
import type { TableIdentity } from 'table-identity';
|
|
1
2
|
import type { ILocaleInfos } from 'vona';
|
|
2
|
-
import type { TableIdentity } from 'vona-module-a-orm';
|
|
3
3
|
import type { IUserBase } from 'vona-module-a-user';
|
|
4
4
|
import type { IUser } from '../types/user.ts';
|
|
5
5
|
import { cast } from 'vona';
|
|
6
6
|
import { setUserAdapter } from 'vona-module-a-user';
|
|
7
7
|
|
|
8
|
-
setUserAdapter({ getUserId, getUserName, getUserAvatar, getUserLocale, getUserAnonymous });
|
|
8
|
+
setUserAdapter({ getUserId, getUserName, getUserAvatar, getUserEmail, getUserMobile, getUserActivated, getUserLocale, getUserAnonymous });
|
|
9
9
|
|
|
10
10
|
function getUserId(user: IUserBase): TableIdentity {
|
|
11
11
|
return cast<IUser>(user).id;
|
|
@@ -19,6 +19,18 @@ function getUserAvatar(user: IUserBase): string | undefined {
|
|
|
19
19
|
return cast<IUser>(user).avatar;
|
|
20
20
|
}
|
|
21
21
|
|
|
22
|
+
function getUserEmail(user: IUserBase): string | undefined {
|
|
23
|
+
return cast<IUser>(user).email;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
function getUserMobile(user: IUserBase): string | undefined {
|
|
27
|
+
return cast<IUser>(user).mobile;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
function getUserActivated(user: IUserBase): boolean {
|
|
31
|
+
return cast<IUser>(user).activated;
|
|
32
|
+
}
|
|
33
|
+
|
|
22
34
|
function getUserLocale(user: IUserBase): keyof ILocaleInfos | undefined {
|
|
23
35
|
return cast<IUser>(user).locale;
|
|
24
36
|
}
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import type { TableIdentity } from 'table-identity';
|
|
1
2
|
import type { IAuthUserProfile, IUserBase, IUserInnerAdapter } from 'vona-module-a-user';
|
|
2
3
|
import type { IUser } from '../types/user.ts';
|
|
3
4
|
import { BeanBase } from 'vona';
|
|
@@ -5,20 +6,25 @@ import { Service } from 'vona-module-a-bean';
|
|
|
5
6
|
|
|
6
7
|
@Service()
|
|
7
8
|
export class ServiceUserInnerAdapter extends BeanBase implements IUserInnerAdapter {
|
|
8
|
-
async
|
|
9
|
-
return await this.scope.model.user.insert(
|
|
9
|
+
async create(user: Partial<IUser>): Promise<IUserBase> {
|
|
10
|
+
return await this.scope.model.user.insert(user);
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
async userOfProfile(profile: IAuthUserProfile): Promise<IUserBase> {
|
|
14
|
+
return {
|
|
10
15
|
name: profile.username!,
|
|
16
|
+
email: profile.emails?.[0].value,
|
|
11
17
|
avatar: profile.photos?.[0].value,
|
|
12
|
-
locale:
|
|
13
|
-
}
|
|
18
|
+
locale: profile.locale || this.ctx.locale,
|
|
19
|
+
} as IUser;
|
|
14
20
|
}
|
|
15
21
|
|
|
16
22
|
async createAnonymous(): Promise<IUserBase> {
|
|
17
|
-
return { id: -1, name: 'anonymous', avatar: undefined, locale: undefined } as
|
|
23
|
+
return { id: -1, name: 'anonymous', avatar: undefined, locale: undefined } as IUser;
|
|
18
24
|
}
|
|
19
25
|
|
|
20
26
|
async findOneByName(name: string): Promise<IUserBase | undefined> {
|
|
21
|
-
return await this.
|
|
27
|
+
return await this.scope.model.user.get({ name: { _eqI_: name } });
|
|
22
28
|
}
|
|
23
29
|
|
|
24
30
|
async findOne(user: Partial<IUser>): Promise<IUserBase | undefined> {
|
|
@@ -32,4 +38,8 @@ export class ServiceUserInnerAdapter extends BeanBase implements IUserInnerAdapt
|
|
|
32
38
|
async remove(user: Partial<IUser>): Promise<void> {
|
|
33
39
|
await this.scope.model.user.delete(user);
|
|
34
40
|
}
|
|
41
|
+
|
|
42
|
+
async setActivated(id: TableIdentity, activated: boolean): Promise<void> {
|
|
43
|
+
await this.scope.model.user.update({ id, activated });
|
|
44
|
+
}
|
|
35
45
|
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
+
import type { TableIdentity } from 'table-identity';
|
|
1
2
|
import type { IPayloadDataBase } from 'vona-module-a-jwt';
|
|
2
|
-
import type { TableIdentity } from 'vona-module-a-orm';
|
|
3
3
|
import type { IPassportBase } from 'vona-module-a-user';
|
|
4
4
|
import type { IAuth } from './auth.ts';
|
|
5
5
|
import type { IUser } from './user.ts';
|
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import type {
|
|
1
|
+
import type { TableIdentity } from 'table-identity';
|
|
2
|
+
import type { IQueryParams } from 'vona-module-a-orm';
|
|
2
3
|
import type { IDecoratorControllerOptions } from 'vona-module-a-web';
|
|
3
4
|
import type { Model<%=argv.resourceNameCapitalize%> } from '../model/<%=argv.resourceName%>.ts';
|
|
4
5
|
import { BeanBase } from 'vona';
|
|
@@ -23,9 +24,6 @@ export class Controller<%=argv.resourceNameCapitalize%> extends BeanBase {
|
|
|
23
24
|
@Web.get()
|
|
24
25
|
@Api.body(Dto<%=argv.resourceNameCapitalize%>QueryRes)
|
|
25
26
|
async findMany(@Arg.queryPro(Dto<%=argv.resourceNameCapitalize%>Query) params: IQueryParams<Model<%=argv.resourceNameCapitalize%>>): Promise<Dto<%=argv.resourceNameCapitalize%>QueryRes> {
|
|
26
|
-
if (!params.orders) {
|
|
27
|
-
params.orders = [['<%=argv.moduleResourceName%>.createdAt', 'desc']];
|
|
28
|
-
}
|
|
29
27
|
return await this.scope.service.<%=argv.resourceName%>.findMany(params);
|
|
30
28
|
}
|
|
31
29
|
|
|
@@ -1,9 +1,11 @@
|
|
|
1
1
|
import type { IDecoratorDtoOptions } from 'vona-module-a-web';
|
|
2
|
-
import { $Dto } from 'vona-module-a-orm';
|
|
2
|
+
import { $Dto, $tableName } from 'vona-module-a-orm';
|
|
3
3
|
import { Dto } from 'vona-module-a-web';
|
|
4
4
|
import { Entity<%=argv.resourceNameCapitalize%> } from '../entity/<%=argv.resourceName%>.ts';
|
|
5
5
|
|
|
6
6
|
export interface IDtoOptions<%=argv.resourceNameCapitalize%>Query extends IDecoratorDtoOptions {}
|
|
7
7
|
|
|
8
|
-
@Dto<IDtoOptions<%=argv.resourceNameCapitalize%>Query>(
|
|
8
|
+
@Dto<IDtoOptions<%=argv.resourceNameCapitalize%>Query>({
|
|
9
|
+
openapi: { query: { table: $tableName(Entity<%=argv.resourceNameCapitalize%>) } },
|
|
10
|
+
})
|
|
9
11
|
export class Dto<%=argv.resourceNameCapitalize%>Query extends $Dto.queryPage(Entity<%=argv.resourceNameCapitalize%>, ['name']) {}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import type {
|
|
1
|
+
import type { TableIdentity } from 'table-identity';
|
|
2
|
+
import type { IQueryParams } from 'vona-module-a-orm';
|
|
2
3
|
import type { Dto<%=argv.resourceNameCapitalize%>Create } from '../dto/<%=argv.resourceName%>Create.ts';
|
|
3
4
|
import type { Dto<%=argv.resourceNameCapitalize%>QueryRes } from '../dto/<%=argv.resourceName%>QueryRes.ts';
|
|
4
5
|
import type { Dto<%=argv.resourceNameCapitalize%>Update } from '../dto/<%=argv.resourceName%>Update.ts';
|
|
@@ -134,6 +134,7 @@ export class CliToolsMetadata extends BeanCliBase {
|
|
|
134
134
|
_generatePatch(content) {
|
|
135
135
|
if (!content)
|
|
136
136
|
return content;
|
|
137
|
+
content = this._generatePatch_resources(content, 'table-identity', ['TableIdentity'], true);
|
|
137
138
|
content = this._generatePatch_resources(content, 'vona-module-a-openapi', ['TypeEntityOptionsFields', 'TypeControllerOptionsActions'], true);
|
|
138
139
|
content = this._generatePatch_resources(content, 'vona-module-a-orm', [
|
|
139
140
|
'TypeEntityMeta',
|
|
@@ -3,6 +3,7 @@ import { getEnvFiles } from '@cabloy/dotenv';
|
|
|
3
3
|
import chalk from 'chalk';
|
|
4
4
|
import fse from 'fs-extra';
|
|
5
5
|
import { copyTemplateFile, getEnvMeta, resolveTemplatePath } from "../../utils.js";
|
|
6
|
+
import { generateZod } from "./generateZod.js";
|
|
6
7
|
export async function generateEntryFiles(configMeta, configOptions, modulesMeta, env) {
|
|
7
8
|
// config
|
|
8
9
|
await __generateConfig();
|
|
@@ -12,6 +13,8 @@ export async function generateEntryFiles(configMeta, configOptions, modulesMeta,
|
|
|
12
13
|
await __generateEnvJson();
|
|
13
14
|
// app
|
|
14
15
|
await __generateApp();
|
|
16
|
+
// zod
|
|
17
|
+
await generateZod(configOptions);
|
|
15
18
|
//////////////////////////////
|
|
16
19
|
async function __generateConfig() {
|
|
17
20
|
// check config
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import { createRequire } from 'node:module';
|
|
2
|
+
import path from 'node:path';
|
|
3
|
+
import fse from 'fs-extra';
|
|
4
|
+
import { copyTemplateIfNeed, pathToHref } from "../../utils.js";
|
|
5
|
+
const __ImportZodCore = 'zod/v4/core';
|
|
6
|
+
export async function generateZod(configOptions) {
|
|
7
|
+
await __generateZodCoreUtil(configOptions);
|
|
8
|
+
await __generateZodCoreSchemas(configOptions);
|
|
9
|
+
}
|
|
10
|
+
async function __generateZodCoreUtil(configOptions) {
|
|
11
|
+
const pathZodCore = parseZodCorePath(configOptions.appDir);
|
|
12
|
+
const fileSrc = path.join(pathZodCore, 'util.js');
|
|
13
|
+
const fileSrcBak = path.join(pathZodCore, 'util-origin.js');
|
|
14
|
+
copyTemplateIfNeed(fileSrc, fileSrcBak);
|
|
15
|
+
const content = fse.readFileSync(fileSrcBak).toString();
|
|
16
|
+
const contentNew = content
|
|
17
|
+
.replace('export function finalizeIssue', `let __localeAdapterFn;
|
|
18
|
+
export function setLocaleAdapter(localeAdapterFn) {
|
|
19
|
+
__localeAdapterFn=localeAdapterFn;
|
|
20
|
+
}
|
|
21
|
+
export function finalizeIssue`)
|
|
22
|
+
.replace('const message = unwrapMessage(iss.inst?._zod.def?.error?.(iss)) ??', `const msg = unwrapMessage(iss.inst?._zod.def?.error?.(iss));
|
|
23
|
+
const message = (__localeAdapterFn?__localeAdapterFn(msg):msg) ??`);
|
|
24
|
+
fse.writeFileSync(fileSrc, contentNew);
|
|
25
|
+
}
|
|
26
|
+
async function __generateZodCoreSchemas(configOptions) {
|
|
27
|
+
const pathZodCore = parseZodCorePath(configOptions.appDir);
|
|
28
|
+
const fileSrc = path.join(pathZodCore, 'schemas.js');
|
|
29
|
+
const fileSrcBak = path.join(pathZodCore, 'schemas-origin.js');
|
|
30
|
+
copyTemplateIfNeed(fileSrc, fileSrcBak);
|
|
31
|
+
const content = fse.readFileSync(fileSrcBak).toString();
|
|
32
|
+
const contentNew = content
|
|
33
|
+
.replace('export const $ZodType =', `let __parseAdapterFn;
|
|
34
|
+
export function setParseAdapter(parseAdapterFn) {
|
|
35
|
+
__parseAdapterFn = parseAdapterFn;
|
|
36
|
+
}
|
|
37
|
+
export const $ZodType =`)
|
|
38
|
+
.replace('inst._zod.run = inst._zod.parse;', 'inst._zod.run = __parseAdapterFn ? __parseAdapterFn(inst, inst._zod.parse) : inst._zod.parse;')
|
|
39
|
+
.replace(/inst._zod.run = (\(payload, ctx\) => \{[\s\S]*?return runChecks\(result, checks, ctx\);\s*\};)/, (_, $0) => {
|
|
40
|
+
return `const __run = ${$0}\ninst._zod.run = __parseAdapterFn ? __parseAdapterFn(inst, __run) : __run;`;
|
|
41
|
+
});
|
|
42
|
+
fse.writeFileSync(fileSrc, contentNew);
|
|
43
|
+
}
|
|
44
|
+
function parseZodCorePath(appDir) {
|
|
45
|
+
const require = createRequire(pathToHref(path.join(appDir, '/')));
|
|
46
|
+
const fileCoreIndex = require.resolve(__ImportZodCore);
|
|
47
|
+
return path.dirname(fileCoreIndex);
|
|
48
|
+
}
|
package/dist/lib/utils.d.ts
CHANGED
|
@@ -15,3 +15,4 @@ export declare function saveJSONFile(fileName: string, json: object): Promise<vo
|
|
|
15
15
|
export declare function pathToHref(fileName: string): string;
|
|
16
16
|
export declare function getOutDir(): string;
|
|
17
17
|
export declare function getOutReleasesDir(): string;
|
|
18
|
+
export declare function copyTemplateIfNeed(fileSrc: string, fileDest: string): void;
|
package/dist/lib/utils.js
CHANGED
|
@@ -69,3 +69,8 @@ export function getOutDir() {
|
|
|
69
69
|
export function getOutReleasesDir() {
|
|
70
70
|
return `dist-releases/${process.env.META_FLAVOR}-${process.env.APP_VERSION}`;
|
|
71
71
|
}
|
|
72
|
+
export function copyTemplateIfNeed(fileSrc, fileDest) {
|
|
73
|
+
if (!fse.existsSync(fileDest)) {
|
|
74
|
+
fse.copyFileSync(fileSrc, fileDest);
|
|
75
|
+
}
|
|
76
|
+
}
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "vona-cli-set-api",
|
|
3
3
|
"type": "module",
|
|
4
|
-
"version": "1.0.
|
|
4
|
+
"version": "1.0.176",
|
|
5
5
|
"description": "vona cli-set-api",
|
|
6
6
|
"publishConfig": {
|
|
7
7
|
"access": "public"
|
|
@@ -61,7 +61,7 @@
|
|
|
61
61
|
"ts-node": "^10.9.2",
|
|
62
62
|
"urllib": "^4.6.11",
|
|
63
63
|
"uuid": "^11.1.0",
|
|
64
|
-
"vona-core": "^5.0.
|
|
64
|
+
"vona-core": "^5.0.49",
|
|
65
65
|
"why-is-node-running": "^3.2.2",
|
|
66
66
|
"yargs-parser": "^21.1.1"
|
|
67
67
|
},
|