@appxdigital/appx-core 0.1.102 → 0.1.103

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.
Files changed (34) hide show
  1. package/dist/backoffice/appx-core-admin.module.d.ts +7 -0
  2. package/dist/backoffice/appx-core-admin.module.d.ts.map +1 -0
  3. package/dist/backoffice/appx-core-admin.module.js +238 -0
  4. package/dist/backoffice/utils.d.ts +21 -0
  5. package/dist/backoffice/utils.d.ts.map +1 -0
  6. package/dist/backoffice/utils.js +82 -0
  7. package/dist/common/config/adminConfigType.d.ts +26 -0
  8. package/dist/common/config/adminConfigType.d.ts.map +1 -0
  9. package/dist/common/config/adminConfigType.js +2 -0
  10. package/dist/index.d.ts +2 -0
  11. package/dist/index.d.ts.map +1 -1
  12. package/dist/index.js +2 -0
  13. package/dist/prisma/prisma.service.d.ts +2 -2
  14. package/dist/prisma/prisma.service.d.ts.map +1 -1
  15. package/dist/prisma/prisma.service.js +7 -6
  16. package/package.json +15 -3
  17. package/dist/config/admin/create.d.ts +0 -2
  18. package/dist/config/admin/create.d.ts.map +0 -1
  19. package/dist/config/admin/create.js +0 -25
  20. package/dist/config/admin/generate-admin.d.ts +0 -2
  21. package/dist/config/admin/generate-admin.d.ts.map +0 -1
  22. package/dist/config/admin/generate-admin.js +0 -75
  23. package/dist/config/admin/templates/admin.template.d.ts +0 -2
  24. package/dist/config/admin/templates/admin.template.d.ts.map +0 -1
  25. package/dist/config/admin/templates/admin.template.js +0 -131
  26. package/dist/config/admin/templates/component-loader.template.d.ts +0 -2
  27. package/dist/config/admin/templates/component-loader.template.d.ts.map +0 -1
  28. package/dist/config/admin/templates/component-loader.template.js +0 -17
  29. package/dist/config/admin/templates/dashboard.template.d.ts +0 -2
  30. package/dist/config/admin/templates/dashboard.template.d.ts.map +0 -1
  31. package/dist/config/admin/templates/dashboard.template.js +0 -40
  32. package/dist/config/admin/templates/utils.template.d.ts +0 -2
  33. package/dist/config/admin/templates/utils.template.d.ts.map +0 -1
  34. package/dist/config/admin/templates/utils.template.js +0 -135
@@ -0,0 +1,7 @@
1
+ import { DynamicModule } from '@nestjs/common';
2
+ import { AdminConfigType } from "../common/config/adminConfigType";
3
+ import { PermissionsConfigType } from "../common/config/permissionsConfigTypes";
4
+ export declare class AppxCoreAdminModule {
5
+ static forRoot(config: AdminConfigType, permissionConfig: PermissionsConfigType): Promise<DynamicModule>;
6
+ }
7
+ //# sourceMappingURL=appx-core-admin.module.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"appx-core-admin.module.d.ts","sourceRoot":"","sources":["../../src/backoffice/appx-core-admin.module.ts"],"names":[],"mappings":"AAAA,OAAO,EAAC,aAAa,EAAiB,MAAM,gBAAgB,CAAC;AAQ7D,OAAO,EAAC,eAAe,EAAC,MAAM,kCAAkC,CAAC;AAIjE,OAAO,EAAC,qBAAqB,EAAC,MAAM,yCAAyC,CAAC;AAE9E,qBAEa,mBAAmB;IAC5B,MAAM,CAAC,OAAO,CAAC,MAAM,EAAE,eAAe,EAAE,gBAAgB,EAAE,qBAAqB,GAAG,OAAO,CAAC,aAAa,CAAC;CAG3G"}
@@ -0,0 +1,238 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
19
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
20
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
21
+ else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
22
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
23
+ };
24
+ var __importStar = (this && this.__importStar) || (function () {
25
+ var ownKeys = function(o) {
26
+ ownKeys = Object.getOwnPropertyNames || function (o) {
27
+ var ar = [];
28
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
29
+ return ar;
30
+ };
31
+ return ownKeys(o);
32
+ };
33
+ return function (mod) {
34
+ if (mod && mod.__esModule) return mod;
35
+ var result = {};
36
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
37
+ __setModuleDefault(result, mod);
38
+ return result;
39
+ };
40
+ })();
41
+ Object.defineProperty(exports, "__esModule", { value: true });
42
+ exports.AppxCoreAdminModule = void 0;
43
+ const common_1 = require("@nestjs/common");
44
+ const utils_1 = require("./utils");
45
+ const fs_1 = require("fs");
46
+ const sdk_1 = require("@prisma/sdk");
47
+ const nestjs_request_context_1 = require("nestjs-request-context");
48
+ const adminjs_1 = require("adminjs");
49
+ const argon2 = __importStar(require("argon2"));
50
+ const prisma_service_1 = require("../prisma/prisma.service");
51
+ let AppxCoreAdminModule = class AppxCoreAdminModule {
52
+ static forRoot(config, permissionConfig) {
53
+ return createAdminJsModule(config, permissionConfig);
54
+ }
55
+ };
56
+ exports.AppxCoreAdminModule = AppxCoreAdminModule;
57
+ exports.AppxCoreAdminModule = AppxCoreAdminModule = __decorate([
58
+ (0, common_1.Global)(),
59
+ (0, common_1.Module)({})
60
+ ], AppxCoreAdminModule);
61
+ async function createAdminJsModule(adminConfig, permissionConfig) {
62
+ // Due to AdminJS only allowing ESM now, we need to use dynamic imports to load the modules, this function can be found within src/backoffice/utils.ts
63
+ const { default: AdminJS } = await (0, utils_1.dynamicImport)('adminjs');
64
+ const { Database, Resource, convertParam } = await (0, utils_1.dynamicImport)('@adminjs/prisma');
65
+ const { AdminModule } = await (0, utils_1.dynamicImport)('@adminjs/nestjs');
66
+ const { default: importExportFeature } = await (0, utils_1.dynamicImport)('@adminjs/import-export');
67
+ const { default: passwordFeature } = await (0, utils_1.dynamicImport)('@adminjs/passwords');
68
+ // This gets the models from the Prisma schema, and then creates the AdminJS resources
69
+ const schemaPath = './prisma/schema.prisma';
70
+ const schema = (0, fs_1.readFileSync)(schemaPath, 'utf-8');
71
+ const dmmf = await (0, sdk_1.getDMMF)({ datamodel: schema });
72
+ const models = [];
73
+ for (const resource of adminConfig.resources) {
74
+ const model = dmmf.datamodel.models.find((model) => model.name === resource.name);
75
+ if (!model)
76
+ continue;
77
+ models.push({
78
+ model: model,
79
+ options: {
80
+ navigation: {
81
+ name: null,
82
+ ...(resource.options?.navigation || {}),
83
+ },
84
+ ...resource.options,
85
+ },
86
+ features: model.name === 'User'
87
+ ? [
88
+ passwordFeature({
89
+ properties: {
90
+ encryptedPassword: 'password',
91
+ password: 'plainPassword',
92
+ },
93
+ hash: argon2.hash,
94
+ componentLoader: adminConfig.componentLoader,
95
+ }),
96
+ ]
97
+ : [],
98
+ });
99
+ }
100
+ AdminJS.registerAdapter({
101
+ Database,
102
+ Resource: class ExtendedResource extends Resource {
103
+ async findOne(id) {
104
+ const idProperty = this.properties().find((property) => property.isId());
105
+ if (!idProperty)
106
+ return null;
107
+ const result = await this.manager.findFirst({
108
+ where: {
109
+ [idProperty.path()]: convertParam(idProperty, this.model.fields, id),
110
+ },
111
+ });
112
+ if (!result)
113
+ return null;
114
+ return new adminjs_1.BaseRecord(this.prepareReturnValues(result), this);
115
+ }
116
+ async update(pk, params = {}) {
117
+ const idProperty = this.properties().find((property) => property.isId());
118
+ if (!idProperty)
119
+ return {};
120
+ const preparedParams = this.prepareParams(params);
121
+ await this.manager.updateMany({
122
+ where: {
123
+ [idProperty.path()]: convertParam(idProperty, this.model.fields, pk),
124
+ },
125
+ data: preparedParams,
126
+ });
127
+ const result = (await this.manager.findFirst({
128
+ where: {
129
+ [idProperty.path()]: convertParam(idProperty, this.model.fields, pk),
130
+ },
131
+ }));
132
+ return this.prepareReturnValues(result);
133
+ }
134
+ },
135
+ });
136
+ const Module = await AdminModule.createAdminAsync({
137
+ inject: [prisma_service_1.PrismaService],
138
+ useFactory: async (prisma) => {
139
+ const authenticate = async (email, password) => {
140
+ return new Promise((resolve) => {
141
+ prisma.withExposedModels(['User'], async () => {
142
+ const user = await prisma.user.findFirst({
143
+ where: {
144
+ email,
145
+ },
146
+ },
147
+ //@ts-ignore
148
+ {
149
+ BYPASS_OMISSION: true,
150
+ });
151
+ if (!user) {
152
+ return resolve(null);
153
+ }
154
+ const isPasswordValid = await argon2.verify(user.password, password);
155
+ if (!isPasswordValid) {
156
+ return resolve(null);
157
+ }
158
+ return resolve({ email: user.email, role: user.role, id: user.id });
159
+ });
160
+ });
161
+ };
162
+ return {
163
+ adminJsOptions: {
164
+ rootPath: adminConfig.rootPath,
165
+ dashboard: adminConfig.dashboard,
166
+ branding: {
167
+ withMadeWithLove: false,
168
+ ...adminConfig.branding,
169
+ },
170
+ resources: models.map((m) => {
171
+ return {
172
+ // Proxy client with global getter that reads client.model.X
173
+ resource: {
174
+ model: m.model,
175
+ client: new Proxy(prisma, {
176
+ get(target, prop) {
177
+ return (target[prop] ||
178
+ target.model[m.model.name.toLowerCase()]);
179
+ },
180
+ }),
181
+ },
182
+ options: {
183
+ ...m.options,
184
+ actions: (0, utils_1.createActions)(permissionConfig),
185
+ },
186
+ features: [
187
+ ...(m.features || []),
188
+ importExportFeature({ componentLoader: adminConfig.componentLoader }),
189
+ ],
190
+ };
191
+ }),
192
+ componentLoader: adminConfig.componentLoader,
193
+ },
194
+ auth: {
195
+ authenticate,
196
+ cookieName: process.env.SESSION_COOKIE_NAME,
197
+ cookiePassword: process.env.SESSION_SECRET,
198
+ },
199
+ sessionOptions: {
200
+ resave: false,
201
+ saveUninitialized: true,
202
+ secret: process.env.SESSION_SECRET,
203
+ cookie: {
204
+ httpOnly: process.env.NODE_ENV === 'production',
205
+ //secure: process.env.NODE_ENV === 'production',
206
+ secure: false,
207
+ },
208
+ name: process.env.SESSION_COOKIE_NAME,
209
+ },
210
+ };
211
+ },
212
+ });
213
+ return {
214
+ ...Module,
215
+ module: class AdminJsModule extends Module.module {
216
+ async onModuleInit() {
217
+ if (super.onModuleInit) {
218
+ await super.onModuleInit();
219
+ }
220
+ const options = this.adminModuleOptions.adminJsOptions;
221
+ const httpAdapter = this.httpAdapterHost.httpAdapter.getInstance();
222
+ // Add to stack, right before admin router
223
+ const adminIdx = httpAdapter.router.stack.findIndex((l) => l.name === 'admin');
224
+ const middleware = new nestjs_request_context_1.RequestContextMiddleware();
225
+ //httpAdapter.use(options.rootPath, );
226
+ httpAdapter.use(options.rootPath, (req, res, next) => {
227
+ middleware.use(req, res, () => {
228
+ // @ts-ignore
229
+ req.user = req.session?.adminUser;
230
+ next();
231
+ });
232
+ });
233
+ const requestContextLayer = httpAdapter.router.stack.splice(httpAdapter.router.stack.length - 1, 1)[0];
234
+ httpAdapter.router.stack.splice(adminIdx, 0, requestContextLayer);
235
+ }
236
+ },
237
+ };
238
+ }
@@ -0,0 +1,21 @@
1
+ import { PermissionsConfigType } from "../common/config/permissionsConfigTypes";
2
+ export declare const dynamicImport: (packageName: string) => Promise<any>;
3
+ export declare function createPermissionHandler(role: string, resource: string, action: string, permissionConfig: PermissionsConfigType): (requestContext: any) => any;
4
+ export declare const createActions: (permissionConfig: PermissionsConfigType) => {
5
+ list: {
6
+ isAccessible: (context: any) => any;
7
+ };
8
+ show: {
9
+ isAccessible: (context: any) => any;
10
+ };
11
+ edit: {
12
+ isAccessible: (context: any) => any;
13
+ };
14
+ delete: {
15
+ isAccessible: (context: any) => any;
16
+ };
17
+ new: {
18
+ isAccessible: (context: any) => any;
19
+ };
20
+ };
21
+ //# sourceMappingURL=utils.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../../src/backoffice/utils.ts"],"names":[],"mappings":"AACA,OAAO,EAAC,qBAAqB,EAAC,MAAM,yCAAyC,CAAC;AAE9E,eAAO,MAAM,aAAa,GAAU,aAAa,MAAM,iBACF,CAAC;AAEtD,wBAAgB,uBAAuB,CACnC,IAAI,EAAE,MAAM,EACZ,QAAQ,EAAE,MAAM,EAChB,MAAM,EAAE,MAAM,EACd,gBAAgB,EAAE,qBAAqB,oBAkCP,GAAG,SAwBtC;AAED,eAAO,MAAM,aAAa,GAAI,kBAAkB,qBAAqB;;gCAqBhD,GAAG;;;gCAAH,GAAG;;;gCAAH,GAAG;;;gCAAH,GAAG;;;gCAAH,GAAG;;CAHvB,CAAC"}
@@ -0,0 +1,82 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.createActions = exports.dynamicImport = void 0;
4
+ exports.createPermissionHandler = createPermissionHandler;
5
+ const prisma_service_1 = require("../prisma/prisma.service");
6
+ const dynamicImport = async (packageName) => new Function(`return import('${packageName}')`)();
7
+ exports.dynamicImport = dynamicImport;
8
+ function createPermissionHandler(role, resource, action, permissionConfig) {
9
+ const rolePermissions = permissionConfig[resource]?.[role];
10
+ if (!rolePermissions) {
11
+ return () => false;
12
+ }
13
+ const actionMapping = {
14
+ list: ['findMany', 'findFirst'],
15
+ show: ['findFirst', 'findMany'],
16
+ edit: 'updateMany',
17
+ delete: 'delete',
18
+ new: 'create',
19
+ };
20
+ const mappedAction = Array.isArray(actionMapping[action])
21
+ ? actionMapping[action]
22
+ : [actionMapping[action]];
23
+ for (const act of mappedAction) {
24
+ if (!rolePermissions[act]) {
25
+ continue;
26
+ }
27
+ if (rolePermissions[act] === 'ALL') {
28
+ return () => true;
29
+ }
30
+ if (typeof rolePermissions[act] === 'object') {
31
+ return () => true;
32
+ // TODO granular permissions with db query (cached)
33
+ return (requestContext) => {
34
+ // @ts-ignore
35
+ let conditions = rolePermissions[act]?.conditions;
36
+ if (!conditions)
37
+ return () => false;
38
+ conditions = prisma_service_1.PrismaService._buildConditions(conditions, requestContext.currentAdmin);
39
+ const record = requestContext.record;
40
+ // Overlay conditions with record values if available
41
+ // Todo validation is shallow
42
+ if (record) {
43
+ for (const key in conditions) {
44
+ if (record.params[key] !== conditions[key]) {
45
+ return false;
46
+ }
47
+ }
48
+ }
49
+ return conditions;
50
+ };
51
+ }
52
+ }
53
+ return () => false;
54
+ }
55
+ const createActions = (permissionConfig) => {
56
+ return {
57
+ list: {
58
+ isAccessible: createIsAccessible('list', permissionConfig),
59
+ },
60
+ show: {
61
+ isAccessible: createIsAccessible('show', permissionConfig),
62
+ },
63
+ edit: {
64
+ isAccessible: createIsAccessible('edit', permissionConfig),
65
+ },
66
+ delete: {
67
+ isAccessible: createIsAccessible('delete', permissionConfig),
68
+ },
69
+ new: {
70
+ isAccessible: createIsAccessible('new', permissionConfig),
71
+ },
72
+ };
73
+ };
74
+ exports.createActions = createActions;
75
+ const createIsAccessible = (action, permissionConfig) => {
76
+ return (context) => {
77
+ if (!context.currentAdmin)
78
+ return false;
79
+ const { role } = context.currentAdmin;
80
+ return createPermissionHandler(role, context.resource.model.name, action, permissionConfig)(context);
81
+ };
82
+ };
@@ -0,0 +1,26 @@
1
+ export interface AdminConfigType {
2
+ resources: {
3
+ name: string;
4
+ options?: {
5
+ navigation?: {
6
+ name?: string | null;
7
+ icon?: string;
8
+ };
9
+ [key: string]: any;
10
+ };
11
+ }[];
12
+ rootPath: string;
13
+ branding: {
14
+ companyName?: string;
15
+ withMadeWithLove?: boolean;
16
+ logo?: string;
17
+ };
18
+ dashboard?: {
19
+ component: string;
20
+ handler?: (request: any, response: any) => Promise<{
21
+ [key: string]: any;
22
+ }>;
23
+ };
24
+ componentLoader: any;
25
+ }
26
+ //# sourceMappingURL=adminConfigType.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"adminConfigType.d.ts","sourceRoot":"","sources":["../../../src/common/config/adminConfigType.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,eAAe;IAC5B,SAAS,EAAE;QACP,IAAI,EAAE,MAAM,CAAC;QACb,OAAO,CAAC,EAAE;YACN,UAAU,CAAC,EAAE;gBACT,IAAI,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;gBACrB,IAAI,CAAC,EAAE,MAAM,CAAC;aACjB,CAAC;YACF,CAAC,GAAG,EAAE,MAAM,GAAG,GAAG,CAAC;SACtB,CAAC;KACL,EAAE,CAAC;IACJ,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE;QACN,WAAW,CAAC,EAAE,MAAM,CAAC;QACrB,gBAAgB,CAAC,EAAE,OAAO,CAAC;QAC3B,IAAI,CAAC,EAAE,MAAM,CAAC;KACjB,CAAC;IACF,SAAS,CAAC,EAAE;QACR,SAAS,EAAE,MAAM,CAAC;QAClB,OAAO,CAAC,EAAE,CAAC,OAAO,EAAE,GAAG,EAAE,QAAQ,EAAE,GAAG,KAAK,OAAO,CAAC;YAAE,CAAC,GAAG,EAAE,MAAM,GAAG,GAAG,CAAA;SAAE,CAAC,CAAC;KAC9E,CAAC;IACF,eAAe,EAAE,GAAG,CAAC;CACxB"}
@@ -0,0 +1,2 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
package/dist/index.d.ts CHANGED
@@ -12,6 +12,7 @@ export * from './common/guards/user-population.guard';
12
12
  export * from './modules/common.module';
13
13
  export * from './common/interceptors/prisma.interceptor';
14
14
  export * from './common/config/permissionsConfigTypes';
15
+ export * from './common/config/adminConfigType';
15
16
  export * from './common/config/permissions.config.provider';
16
17
  export * from './appx-core.module';
17
18
  export * from './modules/file/file-upload.module';
@@ -24,4 +25,5 @@ export * from './common/decorators/permission.decorator';
24
25
  export * from './common/interceptors/file.interceptor';
25
26
  export * from './modules/auth/authenticated.guard';
26
27
  export * from './modules/auth/jwt-auth.guard';
28
+ export * from './backoffice/appx-core-admin.module';
27
29
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,4BAA4B,CAAC;AAC3C,cAAc,6BAA6B,CAAC;AAC5C,cAAc,gCAAgC,CAAC;AAC/C,cAAc,yBAAyB,CAAC;AACxC,cAAc,0BAA0B,CAAC;AACzC,cAAc,4BAA4B,CAAC;AAC3C,cAAc,iCAAiC,CAAC;AAChD,cAAc,4BAA4B,CAAC;AAC3C,cAAc,sCAAsC,CAAC;AACrD,cAAc,4BAA4B,CAAC;AAC3C,cAAc,uCAAuC,CAAC;AACtD,cAAc,yBAAyB,CAAC;AACxC,cAAc,0CAA0C,CAAC;AACzD,cAAc,wCAAwC,CAAC;AACvD,cAAc,6CAA6C,CAAC;AAC5D,cAAc,oBAAoB,CAAC;AACnC,cAAc,mCAAmC,CAAC;AAClD,cAAc,2CAA2C,CAAC;AAC1D,cAAc,wCAAwC,CAAC;AACvD,cAAc,+CAA+C,CAAC;AAC9D,cAAc,uCAAuC,CAAC;AACtD,cAAc,oCAAoC,CAAC;AACnD,cAAc,0CAA0C,CAAC;AACzD,cAAc,wCAAwC,CAAC;AACvD,cAAc,oCAAoC,CAAC;AACnD,cAAc,+BAA+B,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,4BAA4B,CAAC;AAC3C,cAAc,6BAA6B,CAAC;AAC5C,cAAc,gCAAgC,CAAC;AAC/C,cAAc,yBAAyB,CAAC;AACxC,cAAc,0BAA0B,CAAC;AACzC,cAAc,4BAA4B,CAAC;AAC3C,cAAc,iCAAiC,CAAC;AAChD,cAAc,4BAA4B,CAAC;AAC3C,cAAc,sCAAsC,CAAC;AACrD,cAAc,4BAA4B,CAAC;AAC3C,cAAc,uCAAuC,CAAC;AACtD,cAAc,yBAAyB,CAAC;AACxC,cAAc,0CAA0C,CAAC;AACzD,cAAc,wCAAwC,CAAC;AACvD,cAAc,iCAAiC,CAAC;AAChD,cAAc,6CAA6C,CAAC;AAC5D,cAAc,oBAAoB,CAAC;AACnC,cAAc,mCAAmC,CAAC;AAClD,cAAc,2CAA2C,CAAC;AAC1D,cAAc,wCAAwC,CAAC;AACvD,cAAc,+CAA+C,CAAC;AAC9D,cAAc,uCAAuC,CAAC;AACtD,cAAc,oCAAoC,CAAC;AACnD,cAAc,0CAA0C,CAAC;AACzD,cAAc,wCAAwC,CAAC;AACvD,cAAc,oCAAoC,CAAC;AACnD,cAAc,+BAA+B,CAAC;AAC9C,cAAc,qCAAqC,CAAC"}
package/dist/index.js CHANGED
@@ -28,6 +28,7 @@ __exportStar(require("./common/guards/user-population.guard"), exports);
28
28
  __exportStar(require("./modules/common.module"), exports);
29
29
  __exportStar(require("./common/interceptors/prisma.interceptor"), exports);
30
30
  __exportStar(require("./common/config/permissionsConfigTypes"), exports);
31
+ __exportStar(require("./common/config/adminConfigType"), exports);
31
32
  __exportStar(require("./common/config/permissions.config.provider"), exports);
32
33
  __exportStar(require("./appx-core.module"), exports);
33
34
  __exportStar(require("./modules/file/file-upload.module"), exports);
@@ -40,3 +41,4 @@ __exportStar(require("./common/decorators/permission.decorator"), exports);
40
41
  __exportStar(require("./common/interceptors/file.interceptor"), exports);
41
42
  __exportStar(require("./modules/auth/authenticated.guard"), exports);
42
43
  __exportStar(require("./modules/auth/jwt-auth.guard"), exports);
44
+ __exportStar(require("./backoffice/appx-core-admin.module"), exports);
@@ -69,7 +69,7 @@ export declare class PrismaService {
69
69
  * @param user - The user object used to replace placeholders.
70
70
  * @returns The constructed `where` clause object.
71
71
  */
72
- private buildConditions;
72
+ static _buildConditions(conditions: any[], user: any): any;
73
73
  /**
74
74
  * Replaces placeholders (like `$USER_ID`) in the condition with actual values from the user object.
75
75
  * Handles conditions in the form of strings, arrays, or objects.
@@ -78,7 +78,7 @@ export declare class PrismaService {
78
78
  * @param user - The user object containing values like `id`.
79
79
  * @returns The condition with placeholders replaced by actual values.
80
80
  */
81
- private replacePlaceholders;
81
+ private static replacePlaceholders;
82
82
  /**
83
83
  * Retrieves the list of fields to omit based on the user's role.
84
84
  * It checks the field configurations stored in `fieldConfigs` and compares them against the role.
@@ -1 +1 @@
1
- {"version":3,"file":"prisma.service.d.ts","sourceRoot":"","sources":["../../src/prisma/prisma.service.ts"],"names":[],"mappings":"AACA,OAAO,EAAC,MAAM,EAAE,YAAY,EAAC,MAAM,gBAAgB,CAAC;AACpD,OAAO,EAAC,qBAAqB,EAAC,MAAM,yCAAyC,CAAC;AAE9E,OAAO,KAAK,EAAC,YAAY,IAAI,aAAa,EAAC,MAAM,gBAAgB,CAAC;AAElE,OAAO,EAAC,iBAAiB,EAAC,MAAM,kBAAkB,CAAC;AAEnD,eAAO,MAAM,iBAAiB;mBACX,MAAM,EAAE;EACvB,CAAC;AAEL,KAAK,QAAQ,GAAG,MAAM,aAAa,CAAC;AAEpC,oDAAoD;AACpD,MAAM,MAAM,iBAAiB,GAAG;IAC5B,eAAe,CAAC,EAAE,OAAO,CAAC;IAC1B,gBAAgB,CAAC,EAAE,OAAO,CAAC;CAC9B,CAAC;AAGF,MAAM,MAAM,eAAe,CAAC,CAAC,SAAS,QAAQ,IAAI,OAAO,CAAC,aAAa,CAAC,CAAC,CAAC,EAAE,YAAY,GAAG,mBAAmB,GAAG,QAAQ,GAAG,QAAQ,CAAC,CAAC;AAEtI,qBACa,aAAa;IAMY,OAAO,CAAC,QAAQ,CAAC,iBAAiB;IALpE,OAAO,CAAC,YAAY,CAA2B;IAC/C,YAAY,EAAE,YAAY,CAAC;gBAGvB,YAAY,EAAE,YAAY,EACqB,iBAAiB,EAAE,qBAAqB;IAO3F,YAAY,CAAC,MAAM,EAAE,OAAO;IAO5B,iBAAiB,CAAC,MAAM,EAAE,MAAM,EAAE,EAAE,QAAQ,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC;IAWjE,OAAO,CAAC,KAAK;IAQb,YAAY,CAAC,CAAC,EAAE,EAAE,EAAE,CAAC,MAAM,EAAE,MAAM,CAAC,iBAAiB,KAAK,OAAO,CAAC,CAAC,CAAC;IAIpE,WAAW;IAuDX;;;;OAIG;IACH,gBAAgB,CAAC,CAAC,SAAS,QAAQ,EAAE,KAAK,EAAE,CAAC,GAAG,eAAe,CAAC,CAAC,CAAC;IAYlE,IAAI,KAAK,IAAI,aAAa,CAUzB;IAED,IAAI,IAAI,IAAI,eAAe,CAAC,MAAM,CAAC,CAElC;IAED,IAAI,OAAO,IAAI,eAAe,CAAC,SAAS,CAAC,CAExC;IAED,IAAI,gBAAgB,QAEnB;IAED;;;OAGG;IACH,WAAW;IAqDX;;;;;;;;OAQG;IACH,OAAO,CAAC,kBAAkB;IAqC1B,IAAI,2BAA2B,QAM9B;IAED;;;;;;;;;;;OAWG;IACH,OAAO,CAAC,oBAAoB;IA8K5B;;;;;;;OAOG;IACH,OAAO,CAAC,eAAe;IAgBvB;;;;;;;OAOG;IACH,OAAO,CAAC,mBAAmB;IA2B3B;;;;;;;OAOG;IACH,OAAO,CAAC,eAAe;IAUvB;;;;;;;;;;OAUG;IACH,OAAO,CAAC,iBAAiB;IA8EzB,WAAW,CAAC,WAAW,EAAE,MAAM,EAAE,YAAY,EAAE,MAAM,EAAE,eAAe,CAAC,EAAE,IAAI,GAAG;QAC5E,KAAK,EAAE,MAAM,CAAC;QACd,QAAQ,EAAE,MAAM,CAAC;QACjB,UAAU,CAAC,EAAE,MAAM,CAAC;QACpB,iBAAiB,CAAC,EAAE,MAAM,CAAC;QAC3B,UAAU,EAAE,OAAO,CAAA;KACtB;IAmBD,gBAAgB,CAAC,WAAW,EAAE,GAAG,EAAE,MAAM,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM;CAgBzF"}
1
+ {"version":3,"file":"prisma.service.d.ts","sourceRoot":"","sources":["../../src/prisma/prisma.service.ts"],"names":[],"mappings":"AACA,OAAO,EAAC,MAAM,EAAE,YAAY,EAAC,MAAM,gBAAgB,CAAC;AACpD,OAAO,EAAC,qBAAqB,EAAC,MAAM,yCAAyC,CAAC;AAE9E,OAAO,KAAK,EAAC,YAAY,IAAI,aAAa,EAAC,MAAM,gBAAgB,CAAC;AAElE,OAAO,EAAC,iBAAiB,EAAC,MAAM,kBAAkB,CAAC;AAEnD,eAAO,MAAM,iBAAiB;mBACX,MAAM,EAAE;EACvB,CAAC;AAEL,KAAK,QAAQ,GAAG,MAAM,aAAa,CAAC;AAEpC,oDAAoD;AACpD,MAAM,MAAM,iBAAiB,GAAG;IAC5B,eAAe,CAAC,EAAE,OAAO,CAAC;IAC1B,gBAAgB,CAAC,EAAE,OAAO,CAAC;CAC9B,CAAC;AAGF,MAAM,MAAM,eAAe,CAAC,CAAC,SAAS,QAAQ,IAAI,OAAO,CAAC,aAAa,CAAC,CAAC,CAAC,EAAE,YAAY,GAAG,mBAAmB,GAAG,QAAQ,GAAG,QAAQ,CAAC,CAAC;AAEtI,qBACa,aAAa;IAMY,OAAO,CAAC,QAAQ,CAAC,iBAAiB;IALpE,OAAO,CAAC,YAAY,CAA2B;IAC/C,YAAY,EAAE,YAAY,CAAC;gBAGvB,YAAY,EAAE,YAAY,EACqB,iBAAiB,EAAE,qBAAqB;IAO3F,YAAY,CAAC,MAAM,EAAE,OAAO;IAO5B,iBAAiB,CAAC,MAAM,EAAE,MAAM,EAAE,EAAE,QAAQ,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC;IAWjE,OAAO,CAAC,KAAK;IAQb,YAAY,CAAC,CAAC,EAAE,EAAE,EAAE,CAAC,MAAM,EAAE,MAAM,CAAC,iBAAiB,KAAK,OAAO,CAAC,CAAC,CAAC;IAIpE,WAAW;IAuDX;;;;OAIG;IACH,gBAAgB,CAAC,CAAC,SAAS,QAAQ,EAAE,KAAK,EAAE,CAAC,GAAG,eAAe,CAAC,CAAC,CAAC;IAYlE,IAAI,KAAK,IAAI,aAAa,CAUzB;IAED,IAAI,IAAI,IAAI,eAAe,CAAC,MAAM,CAAC,CAElC;IAED,IAAI,OAAO,IAAI,eAAe,CAAC,SAAS,CAAC,CAExC;IAED,IAAI,gBAAgB,QAEnB;IAED;;;OAGG;IACH,WAAW;IAqDX;;;;;;;;OAQG;IACH,OAAO,CAAC,kBAAkB;IAqC1B,IAAI,2BAA2B,QAM9B;IAED;;;;;;;;;;;OAWG;IACH,OAAO,CAAC,oBAAoB;IA8K5B;;;;;;;OAOG;WACW,gBAAgB,CAAC,UAAU,EAAE,GAAG,EAAE,EAAE,IAAI,EAAE,GAAG,GAAG,GAAG;IAgBjE;;;;;;;OAOG;IACH,OAAO,CAAC,MAAM,CAAC,mBAAmB;IA2BlC;;;;;;;OAOG;IACH,OAAO,CAAC,eAAe;IAUvB;;;;;;;;;;OAUG;IACH,OAAO,CAAC,iBAAiB;IA8EzB,WAAW,CAAC,WAAW,EAAE,MAAM,EAAE,YAAY,EAAE,MAAM,EAAE,eAAe,CAAC,EAAE,IAAI,GAAG;QAC5E,KAAK,EAAE,MAAM,CAAC;QACd,QAAQ,EAAE,MAAM,CAAC;QACjB,UAAU,CAAC,EAAE,MAAM,CAAC;QACpB,iBAAiB,CAAC,EAAE,MAAM,CAAC;QAC3B,UAAU,EAAE,OAAO,CAAA;KACtB;IAmBD,gBAAgB,CAAC,WAAW,EAAE,GAAG,EAAE,MAAM,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM;CAgBzF"}
@@ -11,6 +11,7 @@ var __metadata = (this && this.__metadata) || function (k, v) {
11
11
  var __param = (this && this.__param) || function (paramIndex, decorator) {
12
12
  return function (target, key) { decorator(target, key, paramIndex); }
13
13
  };
14
+ var PrismaService_1;
14
15
  Object.defineProperty(exports, "__esModule", { value: true });
15
16
  exports.PrismaService = exports.CorePrismaContext = void 0;
16
17
  const common_1 = require("@nestjs/common");
@@ -18,7 +19,7 @@ const client_1 = require("@prisma/client");
18
19
  const nestjs_request_context_1 = require("nestjs-request-context");
19
20
  const node_async_hooks_1 = require("node:async_hooks");
20
21
  exports.CorePrismaContext = new node_async_hooks_1.AsyncLocalStorage();
21
- let PrismaService = class PrismaService {
22
+ let PrismaService = PrismaService_1 = class PrismaService {
22
23
  constructor(prismaClient, permissionsConfig) {
23
24
  this.permissionsConfig = permissionsConfig;
24
25
  this.fieldConfigs = {};
@@ -325,7 +326,7 @@ let PrismaService = class PrismaService {
325
326
  for (const entry of belongsToQueue) {
326
327
  const { relatedPermissions, field, relation } = entry;
327
328
  this.debug(`Merging conditions for belongsTo relation field '${field}': ${JSON.stringify(relatedPermissions?.conditions)}`, 'info');
328
- let belongsToConditions = this.buildConditions(relatedPermissions?.conditions, user);
329
+ let belongsToConditions = PrismaService_1._buildConditions(relatedPermissions?.conditions, user);
329
330
  if (!args.where)
330
331
  args.where = {};
331
332
  // If relation is optional allow for non-matching records
@@ -369,7 +370,7 @@ let PrismaService = class PrismaService {
369
370
  this.debug(`No conditions to apply for '${modelName}.${String(action)}()' on role ${userRole}`);
370
371
  return args;
371
372
  }
372
- const whereClause = this.buildConditions(actionPermissions.conditions, user);
373
+ const whereClause = PrismaService_1._buildConditions(actionPermissions.conditions, user);
373
374
  this.debug(`Applying where conditions for '${modelName}.${String(action)}()' on role ${userRole}: ${JSON.stringify(whereClause)}`);
374
375
  if (!args.where) {
375
376
  args.where = whereClause;
@@ -387,7 +388,7 @@ let PrismaService = class PrismaService {
387
388
  * @param user - The user object used to replace placeholders.
388
389
  * @returns The constructed `where` clause object.
389
390
  */
390
- buildConditions(conditions, user) {
391
+ static _buildConditions(conditions, user) {
391
392
  const whereClause = {};
392
393
  if (!conditions) {
393
394
  return whereClause;
@@ -405,7 +406,7 @@ let PrismaService = class PrismaService {
405
406
  * @param user - The user object containing values like `id`.
406
407
  * @returns The condition with placeholders replaced by actual values.
407
408
  */
408
- replacePlaceholders(condition, user) {
409
+ static replacePlaceholders(condition, user) {
409
410
  if (condition === null) {
410
411
  return null;
411
412
  }
@@ -535,7 +536,7 @@ let PrismaService = class PrismaService {
535
536
  }
536
537
  };
537
538
  exports.PrismaService = PrismaService;
538
- exports.PrismaService = PrismaService = __decorate([
539
+ exports.PrismaService = PrismaService = PrismaService_1 = __decorate([
539
540
  (0, common_1.Injectable)(),
540
541
  __param(1, (0, common_1.Inject)('PERMISSIONS_CONFIG')),
541
542
  __metadata("design:paramtypes", [Object, Object])
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@appxdigital/appx-core",
3
- "version": "0.1.102",
3
+ "version": "0.1.103",
4
4
  "description": "Appx Core is a library that provides a set of tools to help you build your application faster.",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
@@ -44,7 +44,13 @@
44
44
  "@types/multer": "^1.4.12",
45
45
  "@types/passport-jwt": "^4.0.1",
46
46
  "@types/passport-local": "^1.0.38",
47
- "typescript": "^5.1.3"
47
+ "typescript": "^5.1.3",
48
+ "@adminjs/express": "^6.1.1",
49
+ "@adminjs/import-export": "^3.0.0",
50
+ "@adminjs/nestjs": "^7.0.0",
51
+ "@adminjs/passwords": "^4.0.0",
52
+ "@adminjs/prisma": "^5.0.4",
53
+ "@prisma/sdk": "^3.15.2"
48
54
  },
49
55
  "peerDependencies": {
50
56
  "@nestjs/apollo": "^13.0.0",
@@ -58,7 +64,13 @@
58
64
  "@prisma/client": "^6.5.0",
59
65
  "nestjs-request-context": "^4.0.0",
60
66
  "reflect-metadata": "^0.2.0",
61
- "rxjs": "^7.8.1"
67
+ "rxjs": "^7.8.1",
68
+ "@adminjs/express": "^6.1.1",
69
+ "@adminjs/import-export": "^3.0.0",
70
+ "@adminjs/nestjs": "^7.0.0",
71
+ "@adminjs/passwords": "^4.0.0",
72
+ "@adminjs/prisma": "^5.0.4",
73
+ "@prisma/sdk": "^3.15.2"
62
74
  },
63
75
  "overrides": {
64
76
  "rimraf": "^4.0.0",
@@ -1,2 +0,0 @@
1
- export {};
2
- //# sourceMappingURL=create.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"create.d.ts","sourceRoot":"","sources":["../../../src/config/admin/create.ts"],"names":[],"mappings":""}
@@ -1,25 +0,0 @@
1
- "use strict";
2
- var __importDefault = (this && this.__importDefault) || function (mod) {
3
- return (mod && mod.__esModule) ? mod : { "default": mod };
4
- };
5
- Object.defineProperty(exports, "__esModule", { value: true });
6
- const child_process_1 = require("child_process");
7
- const path_1 = __importDefault(require("path"));
8
- const currentProjectPath = process.cwd();
9
- try {
10
- const command = 'npm install adminjs @adminjs/express @adminjs/nestjs @adminjs/prisma @prisma/sdk react express-formidable @adminjs/passwords @adminjs/import-export';
11
- (0, child_process_1.execSync)(command, {
12
- stdio: 'inherit',
13
- cwd: currentProjectPath
14
- });
15
- console.log('Dependencies installed successfully!');
16
- const scriptsDir = path_1.default.join(__dirname);
17
- console.log('Generating Admin...');
18
- (0, child_process_1.execSync)(`node ${path_1.default.join(scriptsDir, 'generate-admin.js')}`, {
19
- stdio: 'inherit',
20
- });
21
- console.log('Admin generated successfully!');
22
- }
23
- catch (error) {
24
- console.error('Error installing dependencies:', error.message);
25
- }
@@ -1,2 +0,0 @@
1
- export {};
2
- //# sourceMappingURL=generate-admin.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"generate-admin.d.ts","sourceRoot":"","sources":["../../../src/config/admin/generate-admin.ts"],"names":[],"mappings":""}
@@ -1,75 +0,0 @@
1
- "use strict";
2
- var __importDefault = (this && this.__importDefault) || function (mod) {
3
- return (mod && mod.__esModule) ? mod : { "default": mod };
4
- };
5
- Object.defineProperty(exports, "__esModule", { value: true });
6
- const fs_1 = __importDefault(require("fs"));
7
- const path_1 = __importDefault(require("path"));
8
- const admin_template_1 = require("./templates/admin.template");
9
- const utils_template_1 = require("./templates/utils.template");
10
- const dashboard_template_1 = require("./templates/dashboard.template");
11
- const component_loader_template_1 = require("./templates/component-loader.template");
12
- const scriptsDir = path_1.default.join(__dirname, "/templates");
13
- function ensureDirSync(dirPath) {
14
- if (!fs_1.default.existsSync(dirPath)) {
15
- fs_1.default.mkdirSync(dirPath, { recursive: true });
16
- }
17
- }
18
- function getTemplateContent(templateFileName) {
19
- const templatePath = path_1.default.join(scriptsDir, templateFileName);
20
- return fs_1.default.readFileSync(templatePath, 'utf8');
21
- }
22
- function setupAdminJS() {
23
- const projectPath = process.cwd();
24
- const backofficePath = path_1.default.join(projectPath, 'src/backoffice');
25
- ensureDirSync(backofficePath);
26
- const backofficeComponentsPath = path_1.default.join(backofficePath, 'components');
27
- ensureDirSync(backofficeComponentsPath);
28
- fs_1.default.writeFileSync(path_1.default.join(backofficePath, 'component-loader.ts'), component_loader_template_1.componentLoaderTemplate);
29
- fs_1.default.writeFileSync(path_1.default.join(backofficeComponentsPath, 'dashboard.tsx'), dashboard_template_1.dashboardTemplate);
30
- fs_1.default.writeFileSync(path_1.default.join(backofficePath, 'utils.ts'), utils_template_1.permissionsUtilsContent);
31
- fs_1.default.writeFileSync(path_1.default.join(backofficePath, 'admin.ts'), admin_template_1.adminJsModuleCode);
32
- const tsConfigPath = path_1.default.join(projectPath, 'tsconfig.json');
33
- if (fs_1.default.existsSync(tsConfigPath)) {
34
- const tsConfigData = fs_1.default.readFileSync(tsConfigPath, 'utf8');
35
- const tsConfig = JSON.parse(tsConfigData);
36
- tsConfig.compilerOptions = tsConfig.compilerOptions || {};
37
- tsConfig.compilerOptions.jsx = 'react';
38
- fs_1.default.writeFileSync(tsConfigPath, JSON.stringify(tsConfig, null, 2));
39
- console.log('Updated tsconfig.json with JSX support.');
40
- }
41
- else {
42
- console.error('tsconfig.json not found. Please ensure your project has TypeScript configured.');
43
- }
44
- insertInAppModuleImports();
45
- console.log('Backoffice setup complete!');
46
- }
47
- function insertInAppModuleImports() {
48
- const projectRoot = process.cwd();
49
- const appModulePath = path_1.default.join(projectRoot, 'src', 'app.module.ts');
50
- if (!fs_1.default.existsSync(appModulePath)) {
51
- console.error(`Could not find app.module.ts at ${appModulePath}`);
52
- return;
53
- }
54
- let appModuleContent = fs_1.default.readFileSync(appModulePath, 'utf8');
55
- const importStatement = 'import {createAdminJsModule} from "./backoffice/admin";';
56
- if (!appModuleContent.includes(importStatement)) {
57
- appModuleContent = `${importStatement}\n${appModuleContent}`;
58
- }
59
- const importsRegex = /imports\s*:\s*\[\s*([\s\S]*?)\s*\]/;
60
- if (importsRegex.test(appModuleContent)) {
61
- appModuleContent = appModuleContent.replace(importsRegex, (match, importsContent) => {
62
- const trimmedImportsContent = importsContent.trim();
63
- if (!trimmedImportsContent.includes('createAdminJsModule')) {
64
- return `imports: [${trimmedImportsContent}${trimmedImportsContent.endsWith(',') ? '' : ','} \ncreateAdminJsModule().then((AdminJsModule: any) => AdminJsModule)]`;
65
- }
66
- return match;
67
- });
68
- fs_1.default.writeFileSync(appModulePath, appModuleContent, 'utf8');
69
- console.log('createAdminJsModule has been added to the imports array.');
70
- }
71
- else {
72
- console.error('Could not find the imports array in app.module.ts');
73
- }
74
- }
75
- setupAdminJS();
@@ -1,2 +0,0 @@
1
- export declare const adminJsModuleCode = "\nimport {DynamicModule} from '@nestjs/common';\nimport {addBasicFilters, createActions, createPermissionHandler, dynamicImport, getAdminJSResources} from './utils';\nimport {initializeComponents} from './component-loader';\nimport {readFileSync} from 'fs';\nimport {getDMMF} from '@prisma/sdk';\nimport {PrismaService} from '@appxdigital/appx-core';\nimport {PrismaModule} from \"../prisma/prisma.module\";\n\nconst DEFAULT_ADMIN = {\n email: 'joao.duvido@appx.pt',\n password: 'password',\n};\n\nconst authenticate = async (email: string, password: string) => {\n if (email === DEFAULT_ADMIN.email && password === DEFAULT_ADMIN.password) {\n return Promise.resolve(DEFAULT_ADMIN);\n }\n return null;\n};\n\nexport async function createAdminJsModule(): Promise<DynamicModule> {\n const {default: AdminJS} = await dynamicImport('adminjs');\n const {Database, Resource} = await dynamicImport('@adminjs/prisma');\n const {AdminModule} = await dynamicImport('@adminjs/nestjs');\n const {default: importExportFeature} = await dynamicImport('@adminjs/import-export');\n const {default: passwordFeature} = await dynamicImport('@adminjs/passwords');\n const argon2 = await dynamicImport('argon2');\n\n const resources = getAdminJSResources();\n const {componentLoader, Components} = await initializeComponents();\n const schemaPath = './prisma/schema.prisma';\n const schema = readFileSync(schemaPath, 'utf-8');\n const dmmf = await getDMMF({datamodel: schema});\n\n const models = [];\n\n for (const resource of resources) {\n const model = dmmf.datamodel.models.find(\n (model) => model.name === resource.name,\n );\n\n models.push({\n model,\n options: resource.options,\n features: model.name === 'User' ? [\n passwordFeature({\n properties: {\n encryptedPassword: 'password',\n password: 'plainPassword',\n },\n hash: argon2.hash,\n componentLoader,\n }),\n ] : [],\n });\n }\n\n AdminJS.registerAdapter({Database, Resource});\n\n return AdminModule.createAdminAsync({\n imports: [PrismaModule],\n inject: [PrismaService],\n useFactory: async (prisma: PrismaService) => {\n const authenticate = async (email: string, password: string) => {\n const user = await prisma.user.findFirst({\n where: {\n email\n }\n });\n\n if (!user || user.role !== 'ADMIN') {\n return null;\n }\n\n const isPasswordValid = await argon2.verify(user.password, password);\n\n return isPasswordValid ? Promise.resolve({email: user.email, role: user.role, id: user.id}) : null;\n }\n\n return {\n adminJsOptions: {\n rootPath: '/admin',\n dashboard: {\n component: Components.Dashboard,\n handler: async () => {\n return {some: 'output'};\n },\n },\n branding: {\n companyName: 'AppX Core Wizard',\n withMadeWithLove: false,\n logo: 'https://i.ibb.co/XZNRS5m/appxdigitalcom-logo.jpg',\n },\n resources: models.map((m) => {\n return {\n resource: {model: m.model, client: prisma},\n options: {\n ...m.options,\n actions: createActions(),\n },\n features: [...(m.features || []), importExportFeature({\n componentLoader\n })],\n };\n }),\n componentLoader,\n },\n auth: {\n authenticate,\n cookieName: process.env.SESSION_COOKIE_NAME,\n cookiePassword: process.env.SESSION_SECRET,\n },\n sessionOptions: {\n resave: false,\n saveUninitialized: true,\n secret: process.env.SESSION_SECRET,\n cookie: {\n httpOnly: process.env.NODE_ENV === 'production',\n secure: false,\n },\n name: process.env.SESSION_COOKIE_NAME,\n },\n };\n },\n });\n}\n";
2
- //# sourceMappingURL=admin.template.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"admin.template.d.ts","sourceRoot":"","sources":["../../../../src/config/admin/templates/admin.template.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,iBAAiB,+vJA+H7B,CAAC"}
@@ -1,131 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.adminJsModuleCode = void 0;
4
- exports.adminJsModuleCode = `
5
- import {DynamicModule} from '@nestjs/common';
6
- import {addBasicFilters, createActions, createPermissionHandler, dynamicImport, getAdminJSResources} from './utils';
7
- import {initializeComponents} from './component-loader';
8
- import {readFileSync} from 'fs';
9
- import {getDMMF} from '@prisma/sdk';
10
- import {PrismaService} from '@appxdigital/appx-core';
11
- import {PrismaModule} from "../prisma/prisma.module";
12
-
13
- const DEFAULT_ADMIN = {
14
- email: 'joao.duvido@appx.pt',
15
- password: 'password',
16
- };
17
-
18
- const authenticate = async (email: string, password: string) => {
19
- if (email === DEFAULT_ADMIN.email && password === DEFAULT_ADMIN.password) {
20
- return Promise.resolve(DEFAULT_ADMIN);
21
- }
22
- return null;
23
- };
24
-
25
- export async function createAdminJsModule(): Promise<DynamicModule> {
26
- const {default: AdminJS} = await dynamicImport('adminjs');
27
- const {Database, Resource} = await dynamicImport('@adminjs/prisma');
28
- const {AdminModule} = await dynamicImport('@adminjs/nestjs');
29
- const {default: importExportFeature} = await dynamicImport('@adminjs/import-export');
30
- const {default: passwordFeature} = await dynamicImport('@adminjs/passwords');
31
- const argon2 = await dynamicImport('argon2');
32
-
33
- const resources = getAdminJSResources();
34
- const {componentLoader, Components} = await initializeComponents();
35
- const schemaPath = './prisma/schema.prisma';
36
- const schema = readFileSync(schemaPath, 'utf-8');
37
- const dmmf = await getDMMF({datamodel: schema});
38
-
39
- const models = [];
40
-
41
- for (const resource of resources) {
42
- const model = dmmf.datamodel.models.find(
43
- (model) => model.name === resource.name,
44
- );
45
-
46
- models.push({
47
- model,
48
- options: resource.options,
49
- features: model.name === 'User' ? [
50
- passwordFeature({
51
- properties: {
52
- encryptedPassword: 'password',
53
- password: 'plainPassword',
54
- },
55
- hash: argon2.hash,
56
- componentLoader,
57
- }),
58
- ] : [],
59
- });
60
- }
61
-
62
- AdminJS.registerAdapter({Database, Resource});
63
-
64
- return AdminModule.createAdminAsync({
65
- imports: [PrismaModule],
66
- inject: [PrismaService],
67
- useFactory: async (prisma: PrismaService) => {
68
- const authenticate = async (email: string, password: string) => {
69
- const user = await prisma.user.findFirst({
70
- where: {
71
- email
72
- }
73
- });
74
-
75
- if (!user || user.role !== 'ADMIN') {
76
- return null;
77
- }
78
-
79
- const isPasswordValid = await argon2.verify(user.password, password);
80
-
81
- return isPasswordValid ? Promise.resolve({email: user.email, role: user.role, id: user.id}) : null;
82
- }
83
-
84
- return {
85
- adminJsOptions: {
86
- rootPath: '/admin',
87
- dashboard: {
88
- component: Components.Dashboard,
89
- handler: async () => {
90
- return {some: 'output'};
91
- },
92
- },
93
- branding: {
94
- companyName: 'AppX Core Wizard',
95
- withMadeWithLove: false,
96
- logo: 'https://i.ibb.co/XZNRS5m/appxdigitalcom-logo.jpg',
97
- },
98
- resources: models.map((m) => {
99
- return {
100
- resource: {model: m.model, client: prisma},
101
- options: {
102
- ...m.options,
103
- actions: createActions(),
104
- },
105
- features: [...(m.features || []), importExportFeature({
106
- componentLoader
107
- })],
108
- };
109
- }),
110
- componentLoader,
111
- },
112
- auth: {
113
- authenticate,
114
- cookieName: process.env.SESSION_COOKIE_NAME,
115
- cookiePassword: process.env.SESSION_SECRET,
116
- },
117
- sessionOptions: {
118
- resave: false,
119
- saveUninitialized: true,
120
- secret: process.env.SESSION_SECRET,
121
- cookie: {
122
- httpOnly: process.env.NODE_ENV === 'production',
123
- secure: false,
124
- },
125
- name: process.env.SESSION_COOKIE_NAME,
126
- },
127
- };
128
- },
129
- });
130
- }
131
- `;
@@ -1,2 +0,0 @@
1
- export declare const componentLoaderTemplate = "import { dynamicImport } from \"./utils\";\n\nasync function loadComponents() {\n const { ComponentLoader } = await dynamicImport('adminjs');\n const componentLoader = new ComponentLoader();\n\n const Components = {\n Dashboard: componentLoader.add('dashboard', './components/dashboard'),\n };\n\n return { componentLoader, Components };\n}\nexport const initializeComponents = loadComponents;\n";
2
- //# sourceMappingURL=component-loader.template.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"component-loader.template.d.ts","sourceRoot":"","sources":["../../../../src/config/admin/templates/component-loader.template.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,uBAAuB,saAanC,CAAA"}
@@ -1,17 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.componentLoaderTemplate = void 0;
4
- exports.componentLoaderTemplate = `import { dynamicImport } from "./utils";
5
-
6
- async function loadComponents() {
7
- const { ComponentLoader } = await dynamicImport('adminjs');
8
- const componentLoader = new ComponentLoader();
9
-
10
- const Components = {
11
- Dashboard: componentLoader.add('dashboard', './components/dashboard'),
12
- };
13
-
14
- return { componentLoader, Components };
15
- }
16
- export const initializeComponents = loadComponents;
17
- `;
@@ -1,2 +0,0 @@
1
- export declare const dashboardTemplate = "import React from 'react';\n\nexport const Dashboard = () => {\n\n return (\n <div style={{\n backgroundColor: 'white',\n borderRadius: '15px',\n height: '100%',\n padding: '1rem',\n margin: '1rem',\n }}>\n <h1 style={{fontSize: \"1.5rem\", textAlign: \"center\"}}>Dashboard</h1>\n <div style={{\n display: 'flex',\n gap: '1rem',\n flexDirection: 'column',\n textAlign: 'center',\n marginTop: '3rem',\n borderRadius: '15px',\n border: '2px solid gainsboro',\n maxWidth: '300px',\n margin: '3rem auto',\n padding: '1rem',\n }}>\n <h2>Customize it!</h2>\n <p>You can customize your dashboard however you want.</p>\n <p>Display any data you might find useful.</p>\n <p>See the number of users or check statistics on graphics</p>\n <p>Whatever you want to do! Edit it on components/dashboard.</p>\n </div>\n </div>\n\n );\n};\n\nexport default Dashboard;";
2
- //# sourceMappingURL=dashboard.template.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"dashboard.template.d.ts","sourceRoot":"","sources":["../../../../src/config/admin/templates/dashboard.template.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,iBAAiB,srCAoCJ,CAAA"}
@@ -1,40 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.dashboardTemplate = void 0;
4
- exports.dashboardTemplate = `import React from 'react';
5
-
6
- export const Dashboard = () => {
7
-
8
- return (
9
- <div style={{
10
- backgroundColor: 'white',
11
- borderRadius: '15px',
12
- height: '100%',
13
- padding: '1rem',
14
- margin: '1rem',
15
- }}>
16
- <h1 style={{fontSize: "1.5rem", textAlign: "center"}}>Dashboard</h1>
17
- <div style={{
18
- display: 'flex',
19
- gap: '1rem',
20
- flexDirection: 'column',
21
- textAlign: 'center',
22
- marginTop: '3rem',
23
- borderRadius: '15px',
24
- border: '2px solid gainsboro',
25
- maxWidth: '300px',
26
- margin: '3rem auto',
27
- padding: '1rem',
28
- }}>
29
- <h2>Customize it!</h2>
30
- <p>You can customize your dashboard however you want.</p>
31
- <p>Display any data you might find useful.</p>
32
- <p>See the number of users or check statistics on graphics</p>
33
- <p>Whatever you want to do! Edit it on components/dashboard.</p>
34
- </div>
35
- </div>
36
-
37
- );
38
- };
39
-
40
- export default Dashboard;`;
@@ -1,2 +0,0 @@
1
- export declare const permissionsUtilsContent = "\nimport {PermissionsConfig} from \"../config/permissions.config\";\n\nexport const dynamicImport = async (packageName: string) =>\n new Function(`return import('${packageName}')`)();\n\nexport const getAdminJSResources = (specific = null) => {\n const resources = [\n {\n name: 'User',\n options: {},\n },\n ];\n\n return specific ? resources.filter((r) => r.name === specific) : resources;\n};\n\nexport function createPermissionHandler(role: string, resource: string, action: string) {\n const rolePermissions = PermissionsConfig[resource]?.[role];\n\n if (!rolePermissions) {\n return () => false;\n }\n\n const actionMapping = {\n list : 'findMany',\n show : 'findUnique',\n edit : 'update',\n delete : 'delete',\n new : 'create',\n };\n\n const mappedAction = actionMapping[action];\n\n if (!mappedAction || !rolePermissions[mappedAction]) {\n return () => false;\n }\n\n if (rolePermissions[mappedAction] === 'ALL') {\n return () => true;\n }\n\n if (typeof rolePermissions[mappedAction] === 'object') {\n\n return (requestContext) => {\n // @ts-ignore\n const clauses = rolePermissions[mappedAction]?.clauses;\n if (!clauses) return () => false;\n return parseClauses(clauses)(requestContext);\n };\n }\n\n return () => false;\n}\n\nconst clauseMapping = {\n '$USER_ID': \"id\",\n '$USER_EMAIL': \"email\",\n};\n\nconst parseClauses = (clauses) => {\n return (requestContext) => {\n if (!clauses || !Array.isArray(clauses)) return true;\n\n for (const clause of clauses) {\n if (clause.type === 'field') {\n for (const [field, value] of Object.entries(clause.conditions)) {\n let actualValue = value;\n\n if (typeof value === 'string' && value.startsWith('$')) {\n actualValue = requestContext?.currentAdmin[clauseMapping[value]] ?? null;\n }\n\n if (requestContext.record?.param(field) !== actualValue) {\n return false;\n }\n }\n }\n }\n return true;\n };\n};\n\nexport const addBasicFilters = (filters) => {\n return async (request, context) => {\n for (const [field, value] of Object.entries(filters)) {\n request.query[`filters.${field}`] = value;\n }\n return request;\n };\n};\n\nexport const createActions = () => {\n return {\n list: {\n isAccessible: createIsAccessible('list'),\n },\n show: {\n isAccessible: createIsAccessible('show'),\n },\n edit: {\n isAccessible: createIsAccessible('edit'),\n },\n delete: {\n isAccessible: createIsAccessible('delete'),\n },\n new: {\n isAccessible: createIsAccessible('new'),\n },\n };\n};\n\nconst createIsAccessible = (action) => {\n return (context) => {\n if (!context.currentAdmin) return false;\n const { role } = context.currentAdmin;\n return createPermissionHandler(role, context.resource.model.name, action)(context);\n };\n};\n\nconst createBeforeHook = (filters) => {\n return (request, context) => {\n if (context.currentAdmin) {\n request.query.filters = {\n ...request.query.filters,\n ...filters,\n };\n }\n return request;\n };\n};\n";
2
- //# sourceMappingURL=utils.template.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"utils.template.d.ts","sourceRoot":"","sources":["../../../../src/config/admin/templates/utils.template.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,uBAAuB,uiHAmInC,CAAC"}
@@ -1,135 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.permissionsUtilsContent = void 0;
4
- exports.permissionsUtilsContent = `
5
- import {PermissionsConfig} from "../config/permissions.config";
6
-
7
- export const dynamicImport = async (packageName: string) =>
8
- new Function(\`return import('\${packageName}')\`)();
9
-
10
- export const getAdminJSResources = (specific = null) => {
11
- const resources = [
12
- {
13
- name: 'User',
14
- options: {},
15
- },
16
- ];
17
-
18
- return specific ? resources.filter((r) => r.name === specific) : resources;
19
- };
20
-
21
- export function createPermissionHandler(role: string, resource: string, action: string) {
22
- const rolePermissions = PermissionsConfig[resource]?.[role];
23
-
24
- if (!rolePermissions) {
25
- return () => false;
26
- }
27
-
28
- const actionMapping = {
29
- list : 'findMany',
30
- show : 'findUnique',
31
- edit : 'update',
32
- delete : 'delete',
33
- new : 'create',
34
- };
35
-
36
- const mappedAction = actionMapping[action];
37
-
38
- if (!mappedAction || !rolePermissions[mappedAction]) {
39
- return () => false;
40
- }
41
-
42
- if (rolePermissions[mappedAction] === 'ALL') {
43
- return () => true;
44
- }
45
-
46
- if (typeof rolePermissions[mappedAction] === 'object') {
47
-
48
- return (requestContext) => {
49
- // @ts-ignore
50
- const clauses = rolePermissions[mappedAction]?.clauses;
51
- if (!clauses) return () => false;
52
- return parseClauses(clauses)(requestContext);
53
- };
54
- }
55
-
56
- return () => false;
57
- }
58
-
59
- const clauseMapping = {
60
- '$USER_ID': "id",
61
- '$USER_EMAIL': "email",
62
- };
63
-
64
- const parseClauses = (clauses) => {
65
- return (requestContext) => {
66
- if (!clauses || !Array.isArray(clauses)) return true;
67
-
68
- for (const clause of clauses) {
69
- if (clause.type === 'field') {
70
- for (const [field, value] of Object.entries(clause.conditions)) {
71
- let actualValue = value;
72
-
73
- if (typeof value === 'string' && value.startsWith('$')) {
74
- actualValue = requestContext?.currentAdmin[clauseMapping[value]] ?? null;
75
- }
76
-
77
- if (requestContext.record?.param(field) !== actualValue) {
78
- return false;
79
- }
80
- }
81
- }
82
- }
83
- return true;
84
- };
85
- };
86
-
87
- export const addBasicFilters = (filters) => {
88
- return async (request, context) => {
89
- for (const [field, value] of Object.entries(filters)) {
90
- request.query[\`filters.\${field}\`] = value;
91
- }
92
- return request;
93
- };
94
- };
95
-
96
- export const createActions = () => {
97
- return {
98
- list: {
99
- isAccessible: createIsAccessible('list'),
100
- },
101
- show: {
102
- isAccessible: createIsAccessible('show'),
103
- },
104
- edit: {
105
- isAccessible: createIsAccessible('edit'),
106
- },
107
- delete: {
108
- isAccessible: createIsAccessible('delete'),
109
- },
110
- new: {
111
- isAccessible: createIsAccessible('new'),
112
- },
113
- };
114
- };
115
-
116
- const createIsAccessible = (action) => {
117
- return (context) => {
118
- if (!context.currentAdmin) return false;
119
- const { role } = context.currentAdmin;
120
- return createPermissionHandler(role, context.resource.model.name, action)(context);
121
- };
122
- };
123
-
124
- const createBeforeHook = (filters) => {
125
- return (request, context) => {
126
- if (context.currentAdmin) {
127
- request.query.filters = {
128
- ...request.query.filters,
129
- ...filters,
130
- };
131
- }
132
- return request;
133
- };
134
- };
135
- `;