@hedhog/admin 0.48.1 → 0.48.3

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.
@@ -1 +1 @@
1
- {"version":3,"file":"admin.module.d.ts","sourceRoot":"","sources":["../src/admin.module.ts"],"names":[],"mappings":"AAaA,qBAyBa,WAAW;CAAG"}
1
+ {"version":3,"file":"admin.module.d.ts","sourceRoot":"","sources":["../src/admin.module.ts"],"names":[],"mappings":"AAcA,qBA0Ba,WAAW;CAAG"}
@@ -14,6 +14,7 @@ const prisma_1 = require("@hedhog/prisma");
14
14
  const common_1 = require("@nestjs/common");
15
15
  const config_1 = require("@nestjs/config");
16
16
  const auth_module_1 = require("./auth/auth.module");
17
+ const core_module_1 = require("./core/core.module");
17
18
  const menu_module_1 = require("./menu/menu.module");
18
19
  const role_module_1 = require("./role/role.module");
19
20
  const route_module_1 = require("./route/route.module");
@@ -36,6 +37,7 @@ exports.AdminModule = AdminModule = __decorate([
36
37
  (0, common_1.forwardRef)(() => screen_module_1.ScreenModule),
37
38
  (0, common_1.forwardRef)(() => locale_1.LocaleModule),
38
39
  (0, common_1.forwardRef)(() => user_module_1.UserModule),
40
+ (0, common_1.forwardRef)(() => core_module_1.CoreModule),
39
41
  ],
40
42
  exports: [
41
43
  user_module_1.UserModule,
@@ -1 +1 @@
1
- {"version":3,"file":"admin.module.js","sourceRoot":"","sources":["../src/admin.module.ts"],"names":[],"mappings":";;;;;;;;;AAAA,2CAA8C;AAC9C,uCAA0C;AAC1C,mDAAsD;AACtD,2CAA8C;AAC9C,2CAAoD;AACpD,2CAA8C;AAC9C,oDAAgD;AAChD,oDAAgD;AAChD,oDAAgD;AAChD,uDAAmD;AACnD,0DAAsD;AACtD,oDAAgD;AA2BzC,IAAM,WAAW,GAAjB,MAAM,WAAW;CAAG,CAAA;AAAd,kCAAW;sBAAX,WAAW;IAzBvB,IAAA,eAAM,EAAC;QACN,OAAO,EAAE;YACP,qBAAY,CAAC,OAAO,EAAE;YACtB,IAAA,mBAAU,EAAC,GAAG,EAAE,CAAC,wBAAU,CAAC;YAC5B,IAAA,mBAAU,EAAC,GAAG,EAAE,CAAC,iBAAU,CAAC;YAC5B,IAAA,mBAAU,EAAC,GAAG,EAAE,CAAC,wBAAU,CAAC;YAC5B,IAAA,mBAAU,EAAC,GAAG,EAAE,CAAC,6BAAgB,CAAC;YAClC,IAAA,mBAAU,EAAC,GAAG,EAAE,CAAC,wBAAU,CAAC;YAC5B,IAAA,mBAAU,EAAC,GAAG,EAAE,CAAC,0BAAW,CAAC;YAC7B,IAAA,mBAAU,EAAC,GAAG,EAAE,CAAC,qBAAY,CAAC;YAC9B,IAAA,mBAAU,EAAC,GAAG,EAAE,CAAC,4BAAY,CAAC;YAC9B,IAAA,mBAAU,EAAC,GAAG,EAAE,CAAC,qBAAY,CAAC;YAC9B,IAAA,mBAAU,EAAC,GAAG,EAAE,CAAC,wBAAU,CAAC;SAC7B;QACD,OAAO,EAAE;YACP,wBAAU;YACV,wBAAU;YACV,iBAAU;YACV,0BAAW;YACX,wBAAU;YACV,wBAAU;YACV,4BAAY;YACZ,qBAAY;SACb;KACF,CAAC;GACW,WAAW,CAAG"}
1
+ {"version":3,"file":"admin.module.js","sourceRoot":"","sources":["../src/admin.module.ts"],"names":[],"mappings":";;;;;;;;;AAAA,2CAA8C;AAC9C,uCAA0C;AAC1C,mDAAsD;AACtD,2CAA8C;AAC9C,2CAAoD;AACpD,2CAA8C;AAC9C,oDAAgD;AAChD,oDAAgD;AAChD,oDAAgD;AAChD,oDAAgD;AAChD,uDAAmD;AACnD,0DAAsD;AACtD,oDAAgD;AA4BzC,IAAM,WAAW,GAAjB,MAAM,WAAW;CAAG,CAAA;AAAd,kCAAW;sBAAX,WAAW;IA1BvB,IAAA,eAAM,EAAC;QACN,OAAO,EAAE;YACP,qBAAY,CAAC,OAAO,EAAE;YACtB,IAAA,mBAAU,EAAC,GAAG,EAAE,CAAC,wBAAU,CAAC;YAC5B,IAAA,mBAAU,EAAC,GAAG,EAAE,CAAC,iBAAU,CAAC;YAC5B,IAAA,mBAAU,EAAC,GAAG,EAAE,CAAC,wBAAU,CAAC;YAC5B,IAAA,mBAAU,EAAC,GAAG,EAAE,CAAC,6BAAgB,CAAC;YAClC,IAAA,mBAAU,EAAC,GAAG,EAAE,CAAC,wBAAU,CAAC;YAC5B,IAAA,mBAAU,EAAC,GAAG,EAAE,CAAC,0BAAW,CAAC;YAC7B,IAAA,mBAAU,EAAC,GAAG,EAAE,CAAC,qBAAY,CAAC;YAC9B,IAAA,mBAAU,EAAC,GAAG,EAAE,CAAC,4BAAY,CAAC;YAC9B,IAAA,mBAAU,EAAC,GAAG,EAAE,CAAC,qBAAY,CAAC;YAC9B,IAAA,mBAAU,EAAC,GAAG,EAAE,CAAC,wBAAU,CAAC;YAC5B,IAAA,mBAAU,EAAC,GAAG,EAAE,CAAC,wBAAU,CAAC;SAC7B;QACD,OAAO,EAAE;YACP,wBAAU;YACV,wBAAU;YACV,iBAAU;YACV,0BAAW;YACX,wBAAU;YACV,wBAAU;YACV,4BAAY;YACZ,qBAAY;SACb;KACF,CAAC;GACW,WAAW,CAAG"}
@@ -0,0 +1,32 @@
1
+ import { CoreService } from './core.service';
2
+ export declare class CoreController {
3
+ private readonly service;
4
+ constructor(service: CoreService);
5
+ index(): Promise<{
6
+ os: {
7
+ platform: NodeJS.Platform;
8
+ version: string;
9
+ architecture: string;
10
+ uptime: number;
11
+ cpu: {
12
+ model: string;
13
+ speed: number;
14
+ physicalCores: number;
15
+ virtualCores: number;
16
+ };
17
+ memory: {
18
+ total: number;
19
+ free: number;
20
+ };
21
+ disk: unknown;
22
+ };
23
+ modules: unknown;
24
+ users: {
25
+ total: number;
26
+ admin: number;
27
+ active: number;
28
+ activities: any[];
29
+ };
30
+ }>;
31
+ }
32
+ //# sourceMappingURL=core.controller.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"core.controller.d.ts","sourceRoot":"","sources":["../../src/core/core.controller.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,WAAW,EAAE,MAAM,gBAAgB,CAAC;AAE7C,qBACa,cAAc;IAGvB,OAAO,CAAC,QAAQ,CAAC,OAAO;gBAAP,OAAO,EAAE,WAAW;IAIjC,KAAK;;;;;;;;;;;;;;;;;;;;;;;;;;CAGZ"}
@@ -0,0 +1,38 @@
1
+ "use strict";
2
+ var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
3
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
4
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
5
+ 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;
6
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
7
+ };
8
+ var __metadata = (this && this.__metadata) || function (k, v) {
9
+ if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
10
+ };
11
+ var __param = (this && this.__param) || function (paramIndex, decorator) {
12
+ return function (target, key) { decorator(target, key, paramIndex); }
13
+ };
14
+ Object.defineProperty(exports, "__esModule", { value: true });
15
+ exports.CoreController = void 0;
16
+ const common_1 = require("@nestjs/common");
17
+ const core_service_1 = require("./core.service");
18
+ let CoreController = class CoreController {
19
+ constructor(service) {
20
+ this.service = service;
21
+ }
22
+ async index() {
23
+ return this.service.index();
24
+ }
25
+ };
26
+ exports.CoreController = CoreController;
27
+ __decorate([
28
+ (0, common_1.Get)(),
29
+ __metadata("design:type", Function),
30
+ __metadata("design:paramtypes", []),
31
+ __metadata("design:returntype", Promise)
32
+ ], CoreController.prototype, "index", null);
33
+ exports.CoreController = CoreController = __decorate([
34
+ (0, common_1.Controller)('core'),
35
+ __param(0, (0, common_1.Inject)((0, common_1.forwardRef)(() => core_service_1.CoreService))),
36
+ __metadata("design:paramtypes", [core_service_1.CoreService])
37
+ ], CoreController);
38
+ //# sourceMappingURL=core.controller.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"core.controller.js","sourceRoot":"","sources":["../../src/core/core.controller.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;AAAA,2CAAqE;AACrE,iDAA6C;AAGtC,IAAM,cAAc,GAApB,MAAM,cAAc;IACzB,YAEmB,OAAoB;QAApB,YAAO,GAAP,OAAO,CAAa;IACpC,CAAC;IAGE,AAAN,KAAK,CAAC,KAAK;QACT,OAAO,IAAI,CAAC,OAAO,CAAC,KAAK,EAAE,CAAC;IAC9B,CAAC;CACF,CAAA;AAVY,wCAAc;AAOnB;IADL,IAAA,YAAG,GAAE;;;;2CAGL;yBATU,cAAc;IAD1B,IAAA,mBAAU,EAAC,MAAM,CAAC;IAGd,WAAA,IAAA,eAAM,EAAC,IAAA,mBAAU,EAAC,GAAG,EAAE,CAAC,0BAAW,CAAC,CAAC,CAAA;qCACZ,0BAAW;GAH5B,cAAc,CAU1B"}
@@ -0,0 +1,3 @@
1
+ export declare class CoreModule {
2
+ }
3
+ //# sourceMappingURL=core.module.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"core.module.d.ts","sourceRoot":"","sources":["../../src/core/core.module.ts"],"names":[],"mappings":"AAMA,qBAqBa,UAAU;CAAG"}
@@ -0,0 +1,39 @@
1
+ "use strict";
2
+ var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
3
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
4
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
5
+ 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;
6
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
7
+ };
8
+ Object.defineProperty(exports, "__esModule", { value: true });
9
+ exports.CoreModule = void 0;
10
+ const prisma_1 = require("@hedhog/prisma");
11
+ const common_1 = require("@nestjs/common");
12
+ const jwt_1 = require("@nestjs/jwt");
13
+ const core_controller_1 = require("./core.controller");
14
+ const core_service_1 = require("./core.service");
15
+ let CoreModule = class CoreModule {
16
+ };
17
+ exports.CoreModule = CoreModule;
18
+ exports.CoreModule = CoreModule = __decorate([
19
+ (0, common_1.Module)({
20
+ imports: [
21
+ (0, common_1.forwardRef)(() => jwt_1.JwtModule.registerAsync({
22
+ global: true,
23
+ useFactory: () => {
24
+ return {
25
+ secret: String(process.env.JWT_SECRET),
26
+ global: true,
27
+ signOptions: {
28
+ expiresIn: process.env.JWT_EXPIRES_IN || '30d',
29
+ },
30
+ };
31
+ },
32
+ })),
33
+ (0, common_1.forwardRef)(() => prisma_1.PrismaModule),
34
+ ],
35
+ controllers: [core_controller_1.CoreController],
36
+ providers: [core_service_1.CoreService],
37
+ })
38
+ ], CoreModule);
39
+ //# sourceMappingURL=core.module.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"core.module.js","sourceRoot":"","sources":["../../src/core/core.module.ts"],"names":[],"mappings":";;;;;;;;;AAAA,2CAA8C;AAC9C,2CAAoD;AACpD,qCAAwC;AACxC,uDAAmD;AACnD,iDAA6C;AAuBtC,IAAM,UAAU,GAAhB,MAAM,UAAU;CAAG,CAAA;AAAb,gCAAU;qBAAV,UAAU;IArBtB,IAAA,eAAM,EAAC;QACN,OAAO,EAAE;YACP,IAAA,mBAAU,EAAC,GAAG,EAAE,CACd,eAAS,CAAC,aAAa,CAAC;gBACtB,MAAM,EAAE,IAAI;gBACZ,UAAU,EAAE,GAAG,EAAE;oBACf,OAAO;wBACL,MAAM,EAAE,MAAM,CAAC,OAAO,CAAC,GAAG,CAAC,UAAU,CAAC;wBACtC,MAAM,EAAE,IAAI;wBACZ,WAAW,EAAE;4BACX,SAAS,EAAE,OAAO,CAAC,GAAG,CAAC,cAAc,IAAI,KAAK;yBAC/C;qBACF,CAAC;gBACJ,CAAC;aACF,CAAC,CACH;YACD,IAAA,mBAAU,EAAC,GAAG,EAAE,CAAC,qBAAY,CAAC;SAC/B;QACD,WAAW,EAAE,CAAC,gCAAc,CAAC;QAC7B,SAAS,EAAE,CAAC,0BAAW,CAAC;KACzB,CAAC;GACW,UAAU,CAAG"}
@@ -0,0 +1,41 @@
1
+ import { PrismaService } from '@hedhog/prisma';
2
+ export declare class CoreService {
3
+ private prismaService;
4
+ constructor(prismaService: PrismaService);
5
+ index(): Promise<{
6
+ os: {
7
+ platform: NodeJS.Platform;
8
+ version: string;
9
+ architecture: string;
10
+ uptime: number;
11
+ cpu: {
12
+ model: string;
13
+ speed: number;
14
+ physicalCores: number;
15
+ virtualCores: number;
16
+ };
17
+ memory: {
18
+ total: number;
19
+ free: number;
20
+ };
21
+ disk: unknown;
22
+ };
23
+ modules: unknown;
24
+ users: {
25
+ total: number;
26
+ admin: number;
27
+ active: number;
28
+ activities: any[];
29
+ };
30
+ }>;
31
+ private getUsersInfo;
32
+ private getModulesInfo;
33
+ private getLatestVersion;
34
+ private getCpuInfo;
35
+ private getMemoryInfo;
36
+ private getDiskInfo;
37
+ private getDiskCommand;
38
+ private parseWindowsDiskInfo;
39
+ private parseUnixDiskInfo;
40
+ }
41
+ //# sourceMappingURL=core.service.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"core.service.d.ts","sourceRoot":"","sources":["../../src/core/core.service.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,gBAAgB,CAAC;AAO/C,qBACa,WAAW;IACV,OAAO,CAAC,aAAa;gBAAb,aAAa,EAAE,aAAa;IAE1C,KAAK;;;;;;;;;;;;;;;;;;;;;;;;;;YAoBG,YAAY;YAsBZ,cAAc;YAoCd,gBAAgB;IAkB9B,OAAO,CAAC,UAAU;IASlB,OAAO,CAAC,aAAa;YAOP,WAAW;IA2BzB,OAAO,CAAC,cAAc;IAYtB,OAAO,CAAC,oBAAoB;IAgB5B,OAAO,CAAC,iBAAiB;CAkB1B"}
@@ -0,0 +1,227 @@
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
+ var __metadata = (this && this.__metadata) || function (k, v) {
42
+ if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
43
+ };
44
+ Object.defineProperty(exports, "__esModule", { value: true });
45
+ exports.CoreService = void 0;
46
+ const prisma_1 = require("@hedhog/prisma");
47
+ const common_1 = require("@nestjs/common");
48
+ const child_process_1 = require("child_process");
49
+ const fs = __importStar(require("fs"));
50
+ const os = __importStar(require("os"));
51
+ const path = __importStar(require("path"));
52
+ let CoreService = class CoreService {
53
+ constructor(prismaService) {
54
+ this.prismaService = prismaService;
55
+ }
56
+ async index() {
57
+ const cpus = os.cpus();
58
+ const totalSpeed = cpus.reduce((acc, cpu) => acc + cpu.speed, 0);
59
+ const averageSpeed = totalSpeed / cpus.length;
60
+ return {
61
+ os: {
62
+ platform: os.platform(),
63
+ version: os.release(),
64
+ architecture: os.arch(),
65
+ uptime: os.uptime(),
66
+ cpu: this.getCpuInfo(cpus, averageSpeed),
67
+ memory: this.getMemoryInfo(),
68
+ disk: await this.getDiskInfo(),
69
+ },
70
+ modules: await this.getModulesInfo(),
71
+ users: await this.getUsersInfo(),
72
+ };
73
+ }
74
+ async getUsersInfo() {
75
+ const users = await this.prismaService.user.findMany({
76
+ include: {
77
+ role_user: {
78
+ where: {
79
+ role_id: 1,
80
+ },
81
+ select: {
82
+ role_id: true,
83
+ },
84
+ },
85
+ },
86
+ });
87
+ return {
88
+ total: users.length,
89
+ admin: users.filter((user) => user.role_user.length > 0).length,
90
+ active: 0,
91
+ activities: [],
92
+ };
93
+ }
94
+ async getModulesInfo() {
95
+ const packageJsonPath = path.resolve(process.cwd(), 'package.json');
96
+ return new Promise((resolve, reject) => {
97
+ fs.readFile(packageJsonPath, 'utf8', async (err, data) => {
98
+ if (err) {
99
+ reject(`Error reading package.json: ${err.message}`);
100
+ return;
101
+ }
102
+ try {
103
+ const packageJson = JSON.parse(data);
104
+ const dependencies = packageJson.dependencies || {};
105
+ const hedgehogModules = await Promise.all(Object.keys(dependencies)
106
+ .filter((key) => key.startsWith('@hedhog'))
107
+ .map(async (key) => {
108
+ const currentVersion = dependencies[key].replace(/^[\^~]/, '');
109
+ const latestVersion = await this.getLatestVersion(key);
110
+ return {
111
+ name: key,
112
+ version: dependencies[key],
113
+ latestVersion,
114
+ upToDate: currentVersion === latestVersion,
115
+ };
116
+ }));
117
+ resolve(hedgehogModules);
118
+ }
119
+ catch (parseError) {
120
+ reject(`Error parsing package.json: ${parseError === null || parseError === void 0 ? void 0 : parseError.message}`);
121
+ }
122
+ });
123
+ });
124
+ }
125
+ async getLatestVersion(moduleName) {
126
+ return new Promise((resolve, reject) => {
127
+ (0, child_process_1.exec)(`npm show ${moduleName} version`, (error, stdout, stderr) => {
128
+ if (error) {
129
+ reject(`Error fetching latest version for ${moduleName}: ${error.message}`);
130
+ return;
131
+ }
132
+ if (stderr) {
133
+ reject(`stderr: ${stderr}`);
134
+ return;
135
+ }
136
+ resolve(stdout.trim());
137
+ });
138
+ });
139
+ }
140
+ getCpuInfo(cpus, averageSpeed) {
141
+ return {
142
+ model: cpus[0].model,
143
+ speed: averageSpeed,
144
+ physicalCores: cpus.length / 2, // Assuming hyper-threading, this gives physical cores
145
+ virtualCores: cpus.length,
146
+ };
147
+ }
148
+ getMemoryInfo() {
149
+ return {
150
+ total: os.totalmem(),
151
+ free: os.freemem(),
152
+ };
153
+ }
154
+ async getDiskInfo() {
155
+ return new Promise((resolve, reject) => {
156
+ const command = this.getDiskCommand();
157
+ if (!command) {
158
+ reject('Unsupported OS');
159
+ return;
160
+ }
161
+ (0, child_process_1.exec)(command, (error, stdout, stderr) => {
162
+ if (error) {
163
+ reject(`error: ${error.message}`);
164
+ return;
165
+ }
166
+ if (stderr) {
167
+ reject(`stderr: ${stderr}`);
168
+ return;
169
+ }
170
+ const diskInfo = os.platform() === 'win32'
171
+ ? this.parseWindowsDiskInfo(stdout)
172
+ : this.parseUnixDiskInfo(stdout);
173
+ resolve(diskInfo);
174
+ });
175
+ });
176
+ }
177
+ getDiskCommand() {
178
+ switch (os.platform()) {
179
+ case 'win32':
180
+ return 'wmic logicaldisk get size,freespace,caption';
181
+ case 'darwin':
182
+ case 'linux':
183
+ return 'df -h';
184
+ default:
185
+ return null;
186
+ }
187
+ }
188
+ parseWindowsDiskInfo(output) {
189
+ const lines = output.trim().split('\n');
190
+ const result = [];
191
+ for (let i = 1; i < lines.length; i++) {
192
+ const parts = lines[i].trim().split(/\s+/);
193
+ if (parts.length === 3) {
194
+ result.push({
195
+ filesystem: parts[0],
196
+ size: parseInt(parts[1], 10),
197
+ free: parseInt(parts[2], 10),
198
+ });
199
+ }
200
+ }
201
+ return result;
202
+ }
203
+ parseUnixDiskInfo(output) {
204
+ const lines = output.trim().split('\n');
205
+ const result = [];
206
+ for (let i = 1; i < lines.length; i++) {
207
+ const parts = lines[i].split(/\s+/);
208
+ if (parts.length >= 6) {
209
+ result.push({
210
+ filesystem: parts[0],
211
+ size: parts[1],
212
+ used: parts[2],
213
+ available: parts[3],
214
+ capacity: parts[4],
215
+ mountpoint: parts[5],
216
+ });
217
+ }
218
+ }
219
+ return result;
220
+ }
221
+ };
222
+ exports.CoreService = CoreService;
223
+ exports.CoreService = CoreService = __decorate([
224
+ (0, common_1.Injectable)(),
225
+ __metadata("design:paramtypes", [prisma_1.PrismaService])
226
+ ], CoreService);
227
+ //# sourceMappingURL=core.service.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"core.service.js","sourceRoot":"","sources":["../../src/core/core.service.ts"],"names":[],"mappings":"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"}
package/hedhog.yaml CHANGED
@@ -529,6 +529,21 @@ tables:
529
529
  - type: created_at
530
530
  - type: updated_at
531
531
  ifNotExists: true
532
+ user_activity:
533
+ columns:
534
+ - type: pk
535
+ - name: user_id
536
+ type: fk
537
+ references:
538
+ table: user
539
+ column: id
540
+ onDelete: CASCADE
541
+ - name: ip
542
+ - name: user_agent
543
+ - name: message
544
+ - type: created_at
545
+ - type: updated_at
546
+ ifNotExists: true
532
547
  user:
533
548
  columns:
534
549
  - type: pk
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@hedhog/admin",
3
- "version": "0.48.1",
3
+ "version": "0.48.3",
4
4
  "private": false,
5
5
  "main": "dist/index.js",
6
6
  "scripts": {
@@ -24,11 +24,9 @@
24
24
  "author": "",
25
25
  "license": "MIT",
26
26
  "description": "",
27
- "dependencies": {
28
- "@hedhog/mail": "^0.46.3"
29
- },
30
27
  "devDependencies": {
31
28
  "@hedhog/locale": "^0.46.2",
29
+ "@hedhog/mail": "^0.48.1",
32
30
  "@hedhog/pagination": "^0.46.1",
33
31
  "@hedhog/prisma": "^0.46.1",
34
32
  "@hedhog/utils": "^0.0.28",
@@ -5,6 +5,7 @@ import { PrismaModule } from '@hedhog/prisma';
5
5
  import { forwardRef, Module } from '@nestjs/common';
6
6
  import { ConfigModule } from '@nestjs/config';
7
7
  import { AuthModule } from './auth/auth.module';
8
+ import { CoreModule } from './core/core.module';
8
9
  import { MenuModule } from './menu/menu.module';
9
10
  import { RoleModule } from './role/role.module';
10
11
  import { RouteModule } from './route/route.module';
@@ -24,6 +25,7 @@ import { UserModule } from './user/user.module';
24
25
  forwardRef(() => ScreenModule),
25
26
  forwardRef(() => LocaleModule),
26
27
  forwardRef(() => UserModule),
28
+ forwardRef(() => CoreModule),
27
29
  ],
28
30
  exports: [
29
31
  UserModule,
@@ -0,0 +1,15 @@
1
+ import { Controller, forwardRef, Get, Inject } from '@nestjs/common';
2
+ import { CoreService } from './core.service';
3
+
4
+ @Controller('core')
5
+ export class CoreController {
6
+ constructor(
7
+ @Inject(forwardRef(() => CoreService))
8
+ private readonly service: CoreService,
9
+ ) {}
10
+
11
+ @Get()
12
+ async index() {
13
+ return this.service.index();
14
+ }
15
+ }
@@ -0,0 +1,28 @@
1
+ import { PrismaModule } from '@hedhog/prisma';
2
+ import { forwardRef, Module } from '@nestjs/common';
3
+ import { JwtModule } from '@nestjs/jwt';
4
+ import { CoreController } from './core.controller';
5
+ import { CoreService } from './core.service';
6
+
7
+ @Module({
8
+ imports: [
9
+ forwardRef(() =>
10
+ JwtModule.registerAsync({
11
+ global: true,
12
+ useFactory: () => {
13
+ return {
14
+ secret: String(process.env.JWT_SECRET),
15
+ global: true,
16
+ signOptions: {
17
+ expiresIn: process.env.JWT_EXPIRES_IN || '30d',
18
+ },
19
+ };
20
+ },
21
+ }),
22
+ ),
23
+ forwardRef(() => PrismaModule),
24
+ ],
25
+ controllers: [CoreController],
26
+ providers: [CoreService],
27
+ })
28
+ export class CoreModule {}
@@ -0,0 +1,197 @@
1
+ import { PrismaService } from '@hedhog/prisma';
2
+ import { Injectable } from '@nestjs/common';
3
+ import { exec } from 'child_process';
4
+ import * as fs from 'fs';
5
+ import * as os from 'os';
6
+ import * as path from 'path';
7
+
8
+ @Injectable()
9
+ export class CoreService {
10
+ constructor(private prismaService: PrismaService) {}
11
+
12
+ async index() {
13
+ const cpus = os.cpus();
14
+ const totalSpeed = cpus.reduce((acc, cpu) => acc + cpu.speed, 0);
15
+ const averageSpeed = totalSpeed / cpus.length;
16
+
17
+ return {
18
+ os: {
19
+ platform: os.platform(),
20
+ version: os.release(),
21
+ architecture: os.arch(),
22
+ uptime: os.uptime(),
23
+ cpu: this.getCpuInfo(cpus, averageSpeed),
24
+ memory: this.getMemoryInfo(),
25
+ disk: await this.getDiskInfo(),
26
+ },
27
+ modules: await this.getModulesInfo(),
28
+ users: await this.getUsersInfo(),
29
+ };
30
+ }
31
+
32
+ private async getUsersInfo() {
33
+ const users = await this.prismaService.user.findMany({
34
+ include: {
35
+ role_user: {
36
+ where: {
37
+ role_id: 1,
38
+ },
39
+ select: {
40
+ role_id: true,
41
+ },
42
+ },
43
+ },
44
+ });
45
+
46
+ return {
47
+ total: users.length,
48
+ admin: users.filter((user) => user.role_user.length > 0).length,
49
+ active: 0,
50
+ activities: [],
51
+ };
52
+ }
53
+
54
+ private async getModulesInfo() {
55
+ const packageJsonPath = path.resolve(process.cwd(), 'package.json');
56
+
57
+ return new Promise((resolve, reject) => {
58
+ fs.readFile(packageJsonPath, 'utf8', async (err, data) => {
59
+ if (err) {
60
+ reject(`Error reading package.json: ${err.message}`);
61
+ return;
62
+ }
63
+
64
+ try {
65
+ const packageJson = JSON.parse(data);
66
+ const dependencies = packageJson.dependencies || {};
67
+ const hedgehogModules = await Promise.all(
68
+ Object.keys(dependencies)
69
+ .filter((key) => key.startsWith('@hedhog'))
70
+ .map(async (key) => {
71
+ const currentVersion = dependencies[key].replace(/^[\^~]/, '');
72
+ const latestVersion = await this.getLatestVersion(key);
73
+ return {
74
+ name: key,
75
+ version: dependencies[key],
76
+ latestVersion,
77
+ upToDate: currentVersion === latestVersion,
78
+ };
79
+ }),
80
+ );
81
+
82
+ resolve(hedgehogModules);
83
+ } catch (parseError: any) {
84
+ reject(`Error parsing package.json: ${parseError?.message}`);
85
+ }
86
+ });
87
+ });
88
+ }
89
+
90
+ private async getLatestVersion(moduleName: string): Promise<string> {
91
+ return new Promise((resolve, reject) => {
92
+ exec(`npm show ${moduleName} version`, (error, stdout, stderr) => {
93
+ if (error) {
94
+ reject(
95
+ `Error fetching latest version for ${moduleName}: ${error.message}`,
96
+ );
97
+ return;
98
+ }
99
+ if (stderr) {
100
+ reject(`stderr: ${stderr}`);
101
+ return;
102
+ }
103
+ resolve(stdout.trim());
104
+ });
105
+ });
106
+ }
107
+
108
+ private getCpuInfo(cpus: os.CpuInfo[], averageSpeed: number) {
109
+ return {
110
+ model: cpus[0].model,
111
+ speed: averageSpeed,
112
+ physicalCores: cpus.length / 2, // Assuming hyper-threading, this gives physical cores
113
+ virtualCores: cpus.length,
114
+ };
115
+ }
116
+
117
+ private getMemoryInfo() {
118
+ return {
119
+ total: os.totalmem(),
120
+ free: os.freemem(),
121
+ };
122
+ }
123
+
124
+ private async getDiskInfo() {
125
+ return new Promise((resolve, reject) => {
126
+ const command = this.getDiskCommand();
127
+ if (!command) {
128
+ reject('Unsupported OS');
129
+ return;
130
+ }
131
+
132
+ exec(command, (error, stdout, stderr) => {
133
+ if (error) {
134
+ reject(`error: ${error.message}`);
135
+ return;
136
+ }
137
+ if (stderr) {
138
+ reject(`stderr: ${stderr}`);
139
+ return;
140
+ }
141
+
142
+ const diskInfo =
143
+ os.platform() === 'win32'
144
+ ? this.parseWindowsDiskInfo(stdout)
145
+ : this.parseUnixDiskInfo(stdout);
146
+ resolve(diskInfo);
147
+ });
148
+ });
149
+ }
150
+
151
+ private getDiskCommand() {
152
+ switch (os.platform()) {
153
+ case 'win32':
154
+ return 'wmic logicaldisk get size,freespace,caption';
155
+ case 'darwin':
156
+ case 'linux':
157
+ return 'df -h';
158
+ default:
159
+ return null;
160
+ }
161
+ }
162
+
163
+ private parseWindowsDiskInfo(output: string) {
164
+ const lines = output.trim().split('\n');
165
+ const result = [];
166
+ for (let i = 1; i < lines.length; i++) {
167
+ const parts = lines[i].trim().split(/\s+/);
168
+ if (parts.length === 3) {
169
+ result.push({
170
+ filesystem: parts[0],
171
+ size: parseInt(parts[1], 10),
172
+ free: parseInt(parts[2], 10),
173
+ });
174
+ }
175
+ }
176
+ return result;
177
+ }
178
+
179
+ private parseUnixDiskInfo(output: string) {
180
+ const lines = output.trim().split('\n');
181
+ const result = [];
182
+ for (let i = 1; i < lines.length; i++) {
183
+ const parts = lines[i].split(/\s+/);
184
+ if (parts.length >= 6) {
185
+ result.push({
186
+ filesystem: parts[0],
187
+ size: parts[1],
188
+ used: parts[2],
189
+ available: parts[3],
190
+ capacity: parts[4],
191
+ mountpoint: parts[5],
192
+ });
193
+ }
194
+ }
195
+ return result;
196
+ }
197
+ }