@drax/audit-back 0.38.0 → 0.39.0
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/dist/models/AuditModel.js +8 -3
- package/dist/schemas/AuditSchema.js +7 -2
- package/dist/utils/RegisterCrudEvent.js +47 -9
- package/package.json +4 -4
- package/src/models/AuditModel.ts +8 -3
- package/src/schemas/AuditSchema.ts +7 -2
- package/src/utils/RegisterCrudEvent.ts +56 -9
- package/tsconfig.tsbuildinfo +1 -1
- package/types/models/AuditModel.d.ts.map +1 -1
- package/types/schemas/AuditSchema.d.ts +62 -20
- package/types/schemas/AuditSchema.d.ts.map +1 -1
- package/types/utils/RegisterCrudEvent.d.ts.map +1 -1
|
@@ -3,6 +3,7 @@ import uniqueValidator from 'mongoose-unique-validator';
|
|
|
3
3
|
import mongoosePaginate from 'mongoose-paginate-v2';
|
|
4
4
|
const AuditSchema = new mongoose.Schema({
|
|
5
5
|
entity: { type: String, required: true, index: true, unique: false },
|
|
6
|
+
resourceId: { type: String, required: false, index: true, unique: false },
|
|
6
7
|
user: {
|
|
7
8
|
id: { type: String, required: true, index: true, unique: false },
|
|
8
9
|
username: { type: String, required: true, index: false, unique: false },
|
|
@@ -13,15 +14,19 @@ const AuditSchema = new mongoose.Schema({
|
|
|
13
14
|
userAgent: { type: String, required: false, index: false, unique: false },
|
|
14
15
|
changes: [{
|
|
15
16
|
field: { type: String, required: true, index: false, unique: false },
|
|
16
|
-
old: { type:
|
|
17
|
-
new: { type:
|
|
17
|
+
old: { type: mongoose.Schema.Types.Mixed, required: false, index: false, unique: false },
|
|
18
|
+
new: { type: mongoose.Schema.Types.Mixed, required: false, index: false, unique: false }
|
|
18
19
|
}],
|
|
19
20
|
sessionId: { type: String, required: false, index: true, unique: false },
|
|
20
21
|
requestId: { type: String, required: false, index: true, unique: false },
|
|
21
22
|
detail: { type: String, required: false, index: false, unique: false },
|
|
22
23
|
tenant: {
|
|
23
24
|
id: { type: String, required: false, index: true, unique: false },
|
|
24
|
-
name: { type: String, required: false, index:
|
|
25
|
+
name: { type: String, required: false, index: true, unique: false }
|
|
26
|
+
},
|
|
27
|
+
apiKey: {
|
|
28
|
+
id: { type: String, required: false, index: true, unique: false },
|
|
29
|
+
name: { type: String, required: false, index: true, unique: false }
|
|
25
30
|
}
|
|
26
31
|
}, { timestamps: true });
|
|
27
32
|
AuditSchema.plugin(uniqueValidator, { message: 'validation.unique' });
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { z } from 'zod';
|
|
2
2
|
const AuditBaseSchema = z.object({
|
|
3
3
|
entity: z.string().min(1, 'validation.required'),
|
|
4
|
+
resourceId: z.string().optional().nullable(),
|
|
4
5
|
user: z.object({
|
|
5
6
|
id: z.string().min(1, 'validation.required'),
|
|
6
7
|
username: z.string().min(1, 'validation.required'),
|
|
@@ -11,8 +12,8 @@ const AuditBaseSchema = z.object({
|
|
|
11
12
|
userAgent: z.string().optional().nullable(),
|
|
12
13
|
changes: z.array(z.object({
|
|
13
14
|
field: z.string().min(1, 'validation.required'),
|
|
14
|
-
old: z.
|
|
15
|
-
new: z.
|
|
15
|
+
old: z.any().optional().nullable(),
|
|
16
|
+
new: z.any().optional().nullable()
|
|
16
17
|
})).optional(),
|
|
17
18
|
sessionId: z.string().optional().nullable(),
|
|
18
19
|
requestId: z.string().optional().nullable(),
|
|
@@ -20,6 +21,10 @@ const AuditBaseSchema = z.object({
|
|
|
20
21
|
tenant: z.object({
|
|
21
22
|
id: z.string().optional().nullable(),
|
|
22
23
|
name: z.string().optional().nullable()
|
|
24
|
+
}).optional().nullable(),
|
|
25
|
+
apiKey: z.object({
|
|
26
|
+
id: z.string().optional().nullable(),
|
|
27
|
+
name: z.string().optional().nullable()
|
|
23
28
|
}).optional().nullable()
|
|
24
29
|
});
|
|
25
30
|
const AuditSchema = AuditBaseSchema
|
|
@@ -6,11 +6,12 @@ async function RegisterCrudEvent(crudEventData) {
|
|
|
6
6
|
if (!preItem) {
|
|
7
7
|
return changes;
|
|
8
8
|
}
|
|
9
|
+
const ignoredFields = ['_id', 'createdAt', 'updatedAt', 'createdBy', '$__', '$isNew'];
|
|
9
10
|
// Si no hay postItem (eliminación), registrar todos los campos como eliminados
|
|
10
11
|
if (!postItem) {
|
|
11
12
|
Object.keys(preItem).forEach(key => {
|
|
12
13
|
// Ignorar campos internos de MongoDB y timestamps
|
|
13
|
-
if (!key.startsWith('_') && key
|
|
14
|
+
if (!key.startsWith('_') && !ignoredFields.includes(key)) {
|
|
14
15
|
changes.push({
|
|
15
16
|
field: key,
|
|
16
17
|
old: preItem[key],
|
|
@@ -20,17 +21,49 @@ async function RegisterCrudEvent(crudEventData) {
|
|
|
20
21
|
});
|
|
21
22
|
return changes;
|
|
22
23
|
}
|
|
24
|
+
// Función para comparar valores teniendo en cuenta ObjectId y populated
|
|
25
|
+
function areValuesEqual(oldValue, newValue) {
|
|
26
|
+
// Si son exactamente iguales
|
|
27
|
+
if (JSON.stringify(oldValue) === JSON.stringify(newValue)) {
|
|
28
|
+
return true;
|
|
29
|
+
}
|
|
30
|
+
// Comparar referencias (ObjectId vs objeto poblado)
|
|
31
|
+
const oldId = extractId(oldValue);
|
|
32
|
+
const newId = extractId(newValue);
|
|
33
|
+
if (oldId && newId) {
|
|
34
|
+
return oldId.toString() === newId.toString();
|
|
35
|
+
}
|
|
36
|
+
// Si uno es array y el otro también, comparar elementos
|
|
37
|
+
if (Array.isArray(oldValue) && Array.isArray(newValue)) {
|
|
38
|
+
if (oldValue.length !== newValue.length) {
|
|
39
|
+
return false;
|
|
40
|
+
}
|
|
41
|
+
return oldValue.every((item, index) => areValuesEqual(item, newValue[index]));
|
|
42
|
+
}
|
|
43
|
+
return false;
|
|
44
|
+
}
|
|
45
|
+
function extractId(value) {
|
|
46
|
+
// Si es un ObjectId directo
|
|
47
|
+
if (value && typeof value === 'object' && value._id) {
|
|
48
|
+
return value._id;
|
|
49
|
+
}
|
|
50
|
+
// Si es directamente un ObjectId
|
|
51
|
+
if (value && typeof value === 'object' && value.toString && value.constructor.name === 'ObjectId') {
|
|
52
|
+
return value;
|
|
53
|
+
}
|
|
54
|
+
return null;
|
|
55
|
+
}
|
|
23
56
|
// Obtener todas las claves únicas de ambos objetos
|
|
24
57
|
const allKeys = new Set([...Object.keys(preItem), ...Object.keys(postItem)]);
|
|
25
58
|
allKeys.forEach(key => {
|
|
26
59
|
// Ignorar campos internos de MongoDB y timestamps
|
|
27
|
-
if (key.startsWith('_') || key
|
|
60
|
+
if (key.startsWith('_') || ignoredFields.includes(key)) {
|
|
28
61
|
return;
|
|
29
62
|
}
|
|
30
63
|
const oldValue = preItem[key];
|
|
31
64
|
const newValue = postItem[key];
|
|
32
|
-
// Comparar valores
|
|
33
|
-
if (
|
|
65
|
+
// Comparar valores usando la nueva función
|
|
66
|
+
if (!areValuesEqual(oldValue, newValue)) {
|
|
34
67
|
changes.push({
|
|
35
68
|
field: key,
|
|
36
69
|
old: oldValue,
|
|
@@ -43,23 +76,28 @@ async function RegisterCrudEvent(crudEventData) {
|
|
|
43
76
|
let changes = diff(crudEventData.preItem, crudEventData.postItem);
|
|
44
77
|
let data = {
|
|
45
78
|
action: crudEventData.action,
|
|
79
|
+
resourceId: crudEventData.resourceId || crudEventData.postItem?._id?.toString() || crudEventData.preItem?._id?.toString(),
|
|
46
80
|
changes: changes,
|
|
47
81
|
createdAt: crudEventData.timestamp,
|
|
48
|
-
detail:
|
|
82
|
+
detail: crudEventData.detail,
|
|
49
83
|
entity: crudEventData.entity,
|
|
50
84
|
tenant: {
|
|
51
|
-
id: crudEventData.user
|
|
52
|
-
name: crudEventData.user
|
|
85
|
+
id: crudEventData.user?.tenant?.id,
|
|
86
|
+
name: crudEventData.user?.tenant?.name
|
|
53
87
|
},
|
|
54
88
|
user: {
|
|
55
89
|
id: crudEventData.user.id,
|
|
56
90
|
username: crudEventData.user.username,
|
|
57
|
-
rolName: crudEventData.user.role
|
|
91
|
+
rolName: crudEventData.user.role?.name,
|
|
92
|
+
},
|
|
93
|
+
apiKey: {
|
|
94
|
+
id: crudEventData.user?.apiKey?.id,
|
|
95
|
+
name: crudEventData.user?.apiKey?.name
|
|
58
96
|
},
|
|
59
97
|
ip: crudEventData.ip,
|
|
60
98
|
userAgent: crudEventData.userAgent,
|
|
61
99
|
sessionId: crudEventData.user.session,
|
|
62
|
-
requestId: crudEventData.requestId
|
|
100
|
+
requestId: crudEventData.requestId,
|
|
63
101
|
};
|
|
64
102
|
return await AuditServiceFactory.instance.create(data);
|
|
65
103
|
}
|
package/package.json
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
"publishConfig": {
|
|
4
4
|
"access": "public"
|
|
5
5
|
},
|
|
6
|
-
"version": "0.
|
|
6
|
+
"version": "0.39.0",
|
|
7
7
|
"description": "Audit backend",
|
|
8
8
|
"main": "dist/index.js",
|
|
9
9
|
"types": "types/index.d.ts",
|
|
@@ -22,8 +22,8 @@
|
|
|
22
22
|
"author": "Cristian Incarnato & Drax Team",
|
|
23
23
|
"license": "ISC",
|
|
24
24
|
"dependencies": {
|
|
25
|
-
"@drax/crud-back": "^0.
|
|
26
|
-
"@drax/crud-share": "^0.
|
|
25
|
+
"@drax/crud-back": "^0.39.0",
|
|
26
|
+
"@drax/crud-share": "^0.39.0",
|
|
27
27
|
"mongoose": "^8.6.3",
|
|
28
28
|
"mongoose-paginate-v2": "^1.8.3"
|
|
29
29
|
},
|
|
@@ -39,5 +39,5 @@
|
|
|
39
39
|
"tsc-alias": "^1.8.10",
|
|
40
40
|
"typescript": "^5.6.2"
|
|
41
41
|
},
|
|
42
|
-
"gitHead": "
|
|
42
|
+
"gitHead": "b019c40f954cf60e4ff61c53e27d5bafaea6f16c"
|
|
43
43
|
}
|
package/src/models/AuditModel.ts
CHANGED
|
@@ -6,6 +6,7 @@ import type {IAudit} from '@drax/audit-share'
|
|
|
6
6
|
|
|
7
7
|
const AuditSchema = new mongoose.Schema<IAudit>({
|
|
8
8
|
entity: {type: String, required: true, index: true, unique: false},
|
|
9
|
+
resourceId: {type: String, required: false, index: true, unique: false},
|
|
9
10
|
user: {
|
|
10
11
|
id: {type: String, required: true, index: true, unique: false},
|
|
11
12
|
username: {type: String, required: true, index: false, unique: false},
|
|
@@ -16,15 +17,19 @@ const AuditSchema = new mongoose.Schema<IAudit>({
|
|
|
16
17
|
userAgent: {type: String, required: false, index: false, unique: false},
|
|
17
18
|
changes: [{
|
|
18
19
|
field: {type: String, required: true, index: false, unique: false},
|
|
19
|
-
old: {type:
|
|
20
|
-
new: {type:
|
|
20
|
+
old: {type: mongoose.Schema.Types.Mixed, required: false, index: false, unique: false},
|
|
21
|
+
new: {type: mongoose.Schema.Types.Mixed, required: false, index: false, unique: false}
|
|
21
22
|
}],
|
|
22
23
|
sessionId: {type: String, required: false, index: true, unique: false},
|
|
23
24
|
requestId: {type: String, required: false, index: true, unique: false},
|
|
24
25
|
detail: {type: String, required: false, index: false, unique: false},
|
|
25
26
|
tenant: {
|
|
26
27
|
id: {type: String, required: false, index: true, unique: false},
|
|
27
|
-
name: {type: String, required: false, index:
|
|
28
|
+
name: {type: String, required: false, index: true, unique: false}
|
|
29
|
+
},
|
|
30
|
+
apiKey: {
|
|
31
|
+
id: {type: String, required: false, index: true, unique: false},
|
|
32
|
+
name: {type: String, required: false, index: true, unique: false}
|
|
28
33
|
}
|
|
29
34
|
}, {timestamps: true});
|
|
30
35
|
|
|
@@ -3,6 +3,7 @@ import {z} from 'zod';
|
|
|
3
3
|
|
|
4
4
|
const AuditBaseSchema = z.object({
|
|
5
5
|
entity: z.string().min(1, 'validation.required'),
|
|
6
|
+
resourceId: z.string().optional().nullable(),
|
|
6
7
|
user: z.object({
|
|
7
8
|
id: z.string().min(1, 'validation.required'),
|
|
8
9
|
username: z.string().min(1, 'validation.required'),
|
|
@@ -14,8 +15,8 @@ const AuditBaseSchema = z.object({
|
|
|
14
15
|
changes: z.array(
|
|
15
16
|
z.object({
|
|
16
17
|
field: z.string().min(1, 'validation.required'),
|
|
17
|
-
old: z.
|
|
18
|
-
new: z.
|
|
18
|
+
old: z.any().optional().nullable(),
|
|
19
|
+
new: z.any().optional().nullable()
|
|
19
20
|
})
|
|
20
21
|
).optional(),
|
|
21
22
|
sessionId: z.string().optional().nullable(),
|
|
@@ -24,6 +25,10 @@ const AuditBaseSchema = z.object({
|
|
|
24
25
|
tenant: z.object({
|
|
25
26
|
id: z.string().optional().nullable(),
|
|
26
27
|
name: z.string().optional().nullable()
|
|
28
|
+
}).optional().nullable(),
|
|
29
|
+
apiKey: z.object({
|
|
30
|
+
id: z.string().optional().nullable(),
|
|
31
|
+
name: z.string().optional().nullable()
|
|
27
32
|
}).optional().nullable()
|
|
28
33
|
});
|
|
29
34
|
|
|
@@ -18,11 +18,13 @@ async function RegisterCrudEvent(crudEventData: IDraxCrudEvent){
|
|
|
18
18
|
return changes;
|
|
19
19
|
}
|
|
20
20
|
|
|
21
|
+
const ignoredFields = ['_id', 'createdAt', 'updatedAt', 'createdBy','$__','$isNew'];
|
|
22
|
+
|
|
21
23
|
// Si no hay postItem (eliminación), registrar todos los campos como eliminados
|
|
22
24
|
if (!postItem) {
|
|
23
25
|
Object.keys(preItem).forEach(key => {
|
|
24
26
|
// Ignorar campos internos de MongoDB y timestamps
|
|
25
|
-
if (!key.startsWith('_') && key
|
|
27
|
+
if (!key.startsWith('_') && !ignoredFields.includes(key)) {
|
|
26
28
|
changes.push({
|
|
27
29
|
field: key,
|
|
28
30
|
old: preItem[key],
|
|
@@ -33,20 +35,60 @@ async function RegisterCrudEvent(crudEventData: IDraxCrudEvent){
|
|
|
33
35
|
return changes;
|
|
34
36
|
}
|
|
35
37
|
|
|
38
|
+
// Función para comparar valores teniendo en cuenta ObjectId y populated
|
|
39
|
+
function areValuesEqual(oldValue: any, newValue: any): boolean {
|
|
40
|
+
// Si son exactamente iguales
|
|
41
|
+
if (JSON.stringify(oldValue) === JSON.stringify(newValue)) {
|
|
42
|
+
return true;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
// Comparar referencias (ObjectId vs objeto poblado)
|
|
46
|
+
const oldId = extractId(oldValue);
|
|
47
|
+
const newId = extractId(newValue);
|
|
48
|
+
|
|
49
|
+
if (oldId && newId) {
|
|
50
|
+
return oldId.toString() === newId.toString();
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
// Si uno es array y el otro también, comparar elementos
|
|
54
|
+
if (Array.isArray(oldValue) && Array.isArray(newValue)) {
|
|
55
|
+
if (oldValue.length !== newValue.length) {
|
|
56
|
+
return false;
|
|
57
|
+
}
|
|
58
|
+
return oldValue.every((item, index) =>
|
|
59
|
+
areValuesEqual(item, newValue[index])
|
|
60
|
+
);
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
return false;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
function extractId(value: any): any {
|
|
67
|
+
// Si es un ObjectId directo
|
|
68
|
+
if (value && typeof value === 'object' && value._id) {
|
|
69
|
+
return value._id;
|
|
70
|
+
}
|
|
71
|
+
// Si es directamente un ObjectId
|
|
72
|
+
if (value && typeof value === 'object' && value.toString && value.constructor.name === 'ObjectId') {
|
|
73
|
+
return value;
|
|
74
|
+
}
|
|
75
|
+
return null;
|
|
76
|
+
}
|
|
77
|
+
|
|
36
78
|
// Obtener todas las claves únicas de ambos objetos
|
|
37
79
|
const allKeys = new Set([...Object.keys(preItem), ...Object.keys(postItem)]);
|
|
38
80
|
|
|
39
81
|
allKeys.forEach(key => {
|
|
40
82
|
// Ignorar campos internos de MongoDB y timestamps
|
|
41
|
-
if (key.startsWith('_') || key
|
|
83
|
+
if (key.startsWith('_') || ignoredFields.includes(key)) {
|
|
42
84
|
return;
|
|
43
85
|
}
|
|
44
86
|
|
|
45
87
|
const oldValue = preItem[key];
|
|
46
88
|
const newValue = postItem[key];
|
|
47
89
|
|
|
48
|
-
// Comparar valores
|
|
49
|
-
if (
|
|
90
|
+
// Comparar valores usando la nueva función
|
|
91
|
+
if (!areValuesEqual(oldValue, newValue)) {
|
|
50
92
|
changes.push({
|
|
51
93
|
field: key,
|
|
52
94
|
old: oldValue,
|
|
@@ -62,23 +104,28 @@ async function RegisterCrudEvent(crudEventData: IDraxCrudEvent){
|
|
|
62
104
|
|
|
63
105
|
let data: IAuditBase = {
|
|
64
106
|
action: crudEventData.action,
|
|
107
|
+
resourceId: crudEventData.resourceId || crudEventData.postItem?._id?.toString() || crudEventData.preItem?._id?.toString(),
|
|
65
108
|
changes: changes,
|
|
66
109
|
createdAt: crudEventData.timestamp,
|
|
67
|
-
detail:
|
|
110
|
+
detail: crudEventData.detail,
|
|
68
111
|
entity: crudEventData.entity,
|
|
69
112
|
tenant: {
|
|
70
|
-
id: crudEventData.user
|
|
71
|
-
name: crudEventData.user
|
|
113
|
+
id: crudEventData.user?.tenant?.id,
|
|
114
|
+
name: crudEventData.user?.tenant?.name
|
|
72
115
|
},
|
|
73
116
|
user: {
|
|
74
117
|
id: crudEventData.user.id,
|
|
75
118
|
username: crudEventData.user.username,
|
|
76
|
-
rolName: crudEventData.user.role
|
|
119
|
+
rolName: crudEventData.user.role?.name,
|
|
120
|
+
},
|
|
121
|
+
apiKey: {
|
|
122
|
+
id: crudEventData.user?.apiKey?.id,
|
|
123
|
+
name: crudEventData.user?.apiKey?.name
|
|
77
124
|
},
|
|
78
125
|
ip: crudEventData.ip,
|
|
79
126
|
userAgent: crudEventData.userAgent,
|
|
80
127
|
sessionId: crudEventData.user.session,
|
|
81
|
-
requestId: crudEventData.requestId
|
|
128
|
+
requestId: crudEventData.requestId,
|
|
82
129
|
}
|
|
83
130
|
|
|
84
131
|
return await AuditServiceFactory.instance.create(data)
|