@open-mercato/core 0.6.6-develop.5751.1.39143f001b → 0.6.6-develop.5754.1.c908b2af3f
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.
|
@@ -24,45 +24,40 @@ async function resolveAllowedWidgetIds(em, ctx, widgets) {
|
|
|
24
24
|
allowedByUser = null;
|
|
25
25
|
}
|
|
26
26
|
}
|
|
27
|
-
if (allowedByUser && allowedByUser.size === 0) {
|
|
28
|
-
return Array.from(allowedByUser);
|
|
29
|
-
}
|
|
30
|
-
const userRoles = await findWithDecryption(
|
|
31
|
-
em,
|
|
32
|
-
UserRole,
|
|
33
|
-
{ user: ctx.userId, deletedAt: null },
|
|
34
|
-
{ populate: ["role"] },
|
|
35
|
-
{ tenantId: ctx.tenantId, organizationId: ctx.organizationId }
|
|
36
|
-
);
|
|
37
|
-
const roleRecords = await em.find(DashboardRoleWidgets, {
|
|
38
|
-
roleId: { $in: userRoles.map((ur) => String(ur.role?.id || ur.role)) },
|
|
39
|
-
deletedAt: null
|
|
40
|
-
});
|
|
41
|
-
const byRole = /* @__PURE__ */ new Map();
|
|
42
|
-
for (const record of roleRecords) {
|
|
43
|
-
const role = String(record.roleId);
|
|
44
|
-
if (record.tenantId && ctx.tenantId && record.tenantId !== ctx.tenantId) continue;
|
|
45
|
-
if (record.tenantId && !ctx.tenantId) continue;
|
|
46
|
-
if (record.organizationId && ctx.organizationId && record.organizationId !== ctx.organizationId) continue;
|
|
47
|
-
if (record.organizationId && !ctx.organizationId) continue;
|
|
48
|
-
const current = byRole.get(role);
|
|
49
|
-
if (!current || specificity(record) > specificity(current)) {
|
|
50
|
-
byRole.set(role, record);
|
|
51
|
-
}
|
|
52
|
-
}
|
|
53
|
-
const allowedByRole = /* @__PURE__ */ new Set();
|
|
54
|
-
for (const record of byRole.values()) {
|
|
55
|
-
for (const id of record.widgetIdsJson) {
|
|
56
|
-
if (allWidgetIds.includes(id)) allowedByRole.add(id);
|
|
57
|
-
}
|
|
58
|
-
}
|
|
59
27
|
let baseSet;
|
|
60
28
|
if (allowedByUser) {
|
|
61
29
|
baseSet = allowedByUser;
|
|
62
|
-
} else if (allowedByRole.size > 0) {
|
|
63
|
-
baseSet = allowedByRole;
|
|
64
30
|
} else {
|
|
65
|
-
|
|
31
|
+
const userRoles = await findWithDecryption(
|
|
32
|
+
em,
|
|
33
|
+
UserRole,
|
|
34
|
+
{ user: ctx.userId, deletedAt: null },
|
|
35
|
+
{ populate: ["role"] },
|
|
36
|
+
{ tenantId: ctx.tenantId, organizationId: ctx.organizationId }
|
|
37
|
+
);
|
|
38
|
+
const roleRecords = await em.find(DashboardRoleWidgets, {
|
|
39
|
+
roleId: { $in: userRoles.map((ur) => String(ur.role?.id || ur.role)) },
|
|
40
|
+
deletedAt: null
|
|
41
|
+
});
|
|
42
|
+
const byRole = /* @__PURE__ */ new Map();
|
|
43
|
+
for (const record of roleRecords) {
|
|
44
|
+
const role = String(record.roleId);
|
|
45
|
+
if (record.tenantId && ctx.tenantId && record.tenantId !== ctx.tenantId) continue;
|
|
46
|
+
if (record.tenantId && !ctx.tenantId) continue;
|
|
47
|
+
if (record.organizationId && ctx.organizationId && record.organizationId !== ctx.organizationId) continue;
|
|
48
|
+
if (record.organizationId && !ctx.organizationId) continue;
|
|
49
|
+
const current = byRole.get(role);
|
|
50
|
+
if (!current || specificity(record) > specificity(current)) {
|
|
51
|
+
byRole.set(role, record);
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
const allowedByRole = /* @__PURE__ */ new Set();
|
|
55
|
+
for (const record of byRole.values()) {
|
|
56
|
+
for (const id of record.widgetIdsJson) {
|
|
57
|
+
if (allWidgetIds.includes(id)) allowedByRole.add(id);
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
baseSet = allowedByRole.size > 0 ? allowedByRole : new Set(allWidgetIds);
|
|
66
61
|
}
|
|
67
62
|
if (baseSet.size === 0) return [];
|
|
68
63
|
const filtered = widgets.filter((widget) => {
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../../src/modules/dashboards/lib/access.ts"],
|
|
4
|
-
"sourcesContent": ["import type { EntityManager } from '@mikro-orm/postgresql'\nimport { DashboardRoleWidgets, DashboardUserWidgets } from '../data/entities'\nimport { UserRole } from '@open-mercato/core/modules/auth/data/entities'\nimport { hasAllFeatures as userHasAllFeatures } from '@open-mercato/shared/security/features'\nimport { findWithDecryption } from '@open-mercato/shared/lib/encryption/find'\n\ntype LoadedWidget = {\n metadata: {\n id: string\n features?: string[]\n }\n}\n\ntype AccessContext = {\n userId: string\n tenantId: string | null\n organizationId: string | null\n features: string[]\n isSuperAdmin: boolean\n}\n\nfunction specificity(record: DashboardRoleWidgets): number {\n let score = 0\n if (record.tenantId) score += 1\n if (record.organizationId) score += 2\n return score\n}\n\nexport async function resolveAllowedWidgetIds(\n em: EntityManager,\n ctx: AccessContext,\n widgets: LoadedWidget[],\n): Promise<string[]> {\n const allWidgetIds = widgets.map((w) => w.metadata.id)\n\n // Load user override (if any)\n const userRecord = await em.findOne(DashboardUserWidgets, {\n userId: ctx.userId,\n tenantId: ctx.tenantId,\n organizationId: ctx.organizationId,\n deletedAt: null,\n })\n\n let allowedByUser: Set<string> | null = null\n if (userRecord) {\n if (userRecord.mode === 'override') {\n allowedByUser = new Set(userRecord.widgetIdsJson.filter((id) => allWidgetIds.includes(id)))\n } else {\n allowedByUser = null\n }\n }\n\n if (allowedByUser
|
|
5
|
-
"mappings": "AACA,SAAS,sBAAsB,4BAA4B;AAC3D,SAAS,gBAAgB;AACzB,SAAS,kBAAkB,0BAA0B;AACrD,SAAS,0BAA0B;AAiBnC,SAAS,YAAY,QAAsC;AACzD,MAAI,QAAQ;AACZ,MAAI,OAAO,SAAU,UAAS;AAC9B,MAAI,OAAO,eAAgB,UAAS;AACpC,SAAO;AACT;AAEA,eAAsB,wBACpB,IACA,KACA,SACmB;AACnB,QAAM,eAAe,QAAQ,IAAI,CAAC,MAAM,EAAE,SAAS,EAAE;AAGrD,QAAM,aAAa,MAAM,GAAG,QAAQ,sBAAsB;AAAA,IACxD,QAAQ,IAAI;AAAA,IACZ,UAAU,IAAI;AAAA,IACd,gBAAgB,IAAI;AAAA,IACpB,WAAW;AAAA,EACb,CAAC;AAED,MAAI,gBAAoC;AACxC,MAAI,YAAY;AACd,QAAI,WAAW,SAAS,YAAY;AAClC,sBAAgB,IAAI,IAAI,WAAW,cAAc,OAAO,CAAC,OAAO,aAAa,SAAS,EAAE,CAAC,CAAC;AAAA,IAC5F,OAAO;AACL,sBAAgB;AAAA,IAClB;AAAA,EACF;AAEA,MAAI,
|
|
4
|
+
"sourcesContent": ["import type { EntityManager } from '@mikro-orm/postgresql'\nimport { DashboardRoleWidgets, DashboardUserWidgets } from '../data/entities'\nimport { UserRole } from '@open-mercato/core/modules/auth/data/entities'\nimport { hasAllFeatures as userHasAllFeatures } from '@open-mercato/shared/security/features'\nimport { findWithDecryption } from '@open-mercato/shared/lib/encryption/find'\n\ntype LoadedWidget = {\n metadata: {\n id: string\n features?: string[]\n }\n}\n\ntype AccessContext = {\n userId: string\n tenantId: string | null\n organizationId: string | null\n features: string[]\n isSuperAdmin: boolean\n}\n\nfunction specificity(record: DashboardRoleWidgets): number {\n let score = 0\n if (record.tenantId) score += 1\n if (record.organizationId) score += 2\n return score\n}\n\nexport async function resolveAllowedWidgetIds(\n em: EntityManager,\n ctx: AccessContext,\n widgets: LoadedWidget[],\n): Promise<string[]> {\n const allWidgetIds = widgets.map((w) => w.metadata.id)\n\n // Load user override (if any)\n const userRecord = await em.findOne(DashboardUserWidgets, {\n userId: ctx.userId,\n tenantId: ctx.tenantId,\n organizationId: ctx.organizationId,\n deletedAt: null,\n })\n\n let allowedByUser: Set<string> | null = null\n if (userRecord) {\n if (userRecord.mode === 'override') {\n allowedByUser = new Set(userRecord.widgetIdsJson.filter((id) => allWidgetIds.includes(id)))\n } else {\n allowedByUser = null\n }\n }\n\n let baseSet: Set<string>\n if (allowedByUser) {\n // A user override fully determines visibility, so role-level lookups would\n // be discarded \u2014 skip them entirely. An empty override is handled by the\n // shared `baseSet.size === 0` guard below.\n baseSet = allowedByUser\n } else {\n // No user override: aggregate role-level settings.\n const userRoles = await findWithDecryption(\n em,\n UserRole,\n { user: ctx.userId as any, deletedAt: null },\n { populate: ['role'] },\n { tenantId: ctx.tenantId, organizationId: ctx.organizationId },\n )\n const roleRecords = await em.find(DashboardRoleWidgets, {\n roleId: { $in: userRoles.map((ur) => String(ur.role?.id || ur.role)) },\n deletedAt: null,\n })\n\n const byRole = new Map<string, DashboardRoleWidgets>()\n for (const record of roleRecords) {\n const role = String(record.roleId)\n if (record.tenantId && ctx.tenantId && record.tenantId !== ctx.tenantId) continue\n if (record.tenantId && !ctx.tenantId) continue\n if (record.organizationId && ctx.organizationId && record.organizationId !== ctx.organizationId) continue\n if (record.organizationId && !ctx.organizationId) continue\n const current = byRole.get(role)\n if (!current || specificity(record) > specificity(current)) {\n byRole.set(role, record)\n }\n }\n\n const allowedByRole = new Set<string>()\n for (const record of byRole.values()) {\n for (const id of record.widgetIdsJson) {\n if (allWidgetIds.includes(id)) allowedByRole.add(id)\n }\n }\n\n baseSet = allowedByRole.size > 0 ? allowedByRole : new Set(allWidgetIds)\n }\n\n if (baseSet.size === 0) return []\n\n const filtered = widgets.filter((widget) => {\n if (!baseSet.has(widget.metadata.id)) return false\n if (ctx.isSuperAdmin) return true\n return userHasAllFeatures(ctx.features, widget.metadata.features ?? [])\n })\n\n return filtered.map((widget) => widget.metadata.id)\n}\n"],
|
|
5
|
+
"mappings": "AACA,SAAS,sBAAsB,4BAA4B;AAC3D,SAAS,gBAAgB;AACzB,SAAS,kBAAkB,0BAA0B;AACrD,SAAS,0BAA0B;AAiBnC,SAAS,YAAY,QAAsC;AACzD,MAAI,QAAQ;AACZ,MAAI,OAAO,SAAU,UAAS;AAC9B,MAAI,OAAO,eAAgB,UAAS;AACpC,SAAO;AACT;AAEA,eAAsB,wBACpB,IACA,KACA,SACmB;AACnB,QAAM,eAAe,QAAQ,IAAI,CAAC,MAAM,EAAE,SAAS,EAAE;AAGrD,QAAM,aAAa,MAAM,GAAG,QAAQ,sBAAsB;AAAA,IACxD,QAAQ,IAAI;AAAA,IACZ,UAAU,IAAI;AAAA,IACd,gBAAgB,IAAI;AAAA,IACpB,WAAW;AAAA,EACb,CAAC;AAED,MAAI,gBAAoC;AACxC,MAAI,YAAY;AACd,QAAI,WAAW,SAAS,YAAY;AAClC,sBAAgB,IAAI,IAAI,WAAW,cAAc,OAAO,CAAC,OAAO,aAAa,SAAS,EAAE,CAAC,CAAC;AAAA,IAC5F,OAAO;AACL,sBAAgB;AAAA,IAClB;AAAA,EACF;AAEA,MAAI;AACJ,MAAI,eAAe;AAIjB,cAAU;AAAA,EACZ,OAAO;AAEL,UAAM,YAAY,MAAM;AAAA,MACtB;AAAA,MACA;AAAA,MACA,EAAE,MAAM,IAAI,QAAe,WAAW,KAAK;AAAA,MAC3C,EAAE,UAAU,CAAC,MAAM,EAAE;AAAA,MACrB,EAAE,UAAU,IAAI,UAAU,gBAAgB,IAAI,eAAe;AAAA,IAC/D;AACA,UAAM,cAAc,MAAM,GAAG,KAAK,sBAAsB;AAAA,MACtD,QAAQ,EAAE,KAAK,UAAU,IAAI,CAAC,OAAO,OAAO,GAAG,MAAM,MAAM,GAAG,IAAI,CAAC,EAAE;AAAA,MACrE,WAAW;AAAA,IACb,CAAC;AAED,UAAM,SAAS,oBAAI,IAAkC;AACrD,eAAW,UAAU,aAAa;AAChC,YAAM,OAAO,OAAO,OAAO,MAAM;AACjC,UAAI,OAAO,YAAY,IAAI,YAAY,OAAO,aAAa,IAAI,SAAU;AACzE,UAAI,OAAO,YAAY,CAAC,IAAI,SAAU;AACtC,UAAI,OAAO,kBAAkB,IAAI,kBAAkB,OAAO,mBAAmB,IAAI,eAAgB;AACjG,UAAI,OAAO,kBAAkB,CAAC,IAAI,eAAgB;AAClD,YAAM,UAAU,OAAO,IAAI,IAAI;AAC/B,UAAI,CAAC,WAAW,YAAY,MAAM,IAAI,YAAY,OAAO,GAAG;AAC1D,eAAO,IAAI,MAAM,MAAM;AAAA,MACzB;AAAA,IACF;AAEA,UAAM,gBAAgB,oBAAI,IAAY;AACtC,eAAW,UAAU,OAAO,OAAO,GAAG;AACpC,iBAAW,MAAM,OAAO,eAAe;AACrC,YAAI,aAAa,SAAS,EAAE,EAAG,eAAc,IAAI,EAAE;AAAA,MACrD;AAAA,IACF;AAEA,cAAU,cAAc,OAAO,IAAI,gBAAgB,IAAI,IAAI,YAAY;AAAA,EACzE;AAEA,MAAI,QAAQ,SAAS,EAAG,QAAO,CAAC;AAEhC,QAAM,WAAW,QAAQ,OAAO,CAAC,WAAW;AAC1C,QAAI,CAAC,QAAQ,IAAI,OAAO,SAAS,EAAE,EAAG,QAAO;AAC7C,QAAI,IAAI,aAAc,QAAO;AAC7B,WAAO,mBAAmB,IAAI,UAAU,OAAO,SAAS,YAAY,CAAC,CAAC;AAAA,EACxE,CAAC;AAED,SAAO,SAAS,IAAI,CAAC,WAAW,OAAO,SAAS,EAAE;AACpD;",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@open-mercato/core",
|
|
3
|
-
"version": "0.6.6-develop.
|
|
3
|
+
"version": "0.6.6-develop.5754.1.c908b2af3f",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"main": "./dist/index.js",
|
|
6
6
|
"scripts": {
|
|
@@ -245,16 +245,16 @@
|
|
|
245
245
|
"zod": "^4.4.3"
|
|
246
246
|
},
|
|
247
247
|
"peerDependencies": {
|
|
248
|
-
"@open-mercato/ai-assistant": "0.6.6-develop.
|
|
249
|
-
"@open-mercato/shared": "0.6.6-develop.
|
|
250
|
-
"@open-mercato/ui": "0.6.6-develop.
|
|
248
|
+
"@open-mercato/ai-assistant": "0.6.6-develop.5754.1.c908b2af3f",
|
|
249
|
+
"@open-mercato/shared": "0.6.6-develop.5754.1.c908b2af3f",
|
|
250
|
+
"@open-mercato/ui": "0.6.6-develop.5754.1.c908b2af3f",
|
|
251
251
|
"react": "^19.0.0",
|
|
252
252
|
"react-dom": "^19.0.0"
|
|
253
253
|
},
|
|
254
254
|
"devDependencies": {
|
|
255
|
-
"@open-mercato/ai-assistant": "0.6.6-develop.
|
|
256
|
-
"@open-mercato/shared": "0.6.6-develop.
|
|
257
|
-
"@open-mercato/ui": "0.6.6-develop.
|
|
255
|
+
"@open-mercato/ai-assistant": "0.6.6-develop.5754.1.c908b2af3f",
|
|
256
|
+
"@open-mercato/shared": "0.6.6-develop.5754.1.c908b2af3f",
|
|
257
|
+
"@open-mercato/ui": "0.6.6-develop.5754.1.c908b2af3f",
|
|
258
258
|
"@testing-library/dom": "^10.4.1",
|
|
259
259
|
"@testing-library/jest-dom": "^6.9.1",
|
|
260
260
|
"@testing-library/react": "^16.3.1",
|
|
@@ -50,50 +50,47 @@ export async function resolveAllowedWidgetIds(
|
|
|
50
50
|
}
|
|
51
51
|
}
|
|
52
52
|
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
53
|
+
let baseSet: Set<string>
|
|
54
|
+
if (allowedByUser) {
|
|
55
|
+
// A user override fully determines visibility, so role-level lookups would
|
|
56
|
+
// be discarded — skip them entirely. An empty override is handled by the
|
|
57
|
+
// shared `baseSet.size === 0` guard below.
|
|
58
|
+
baseSet = allowedByUser
|
|
59
|
+
} else {
|
|
60
|
+
// No user override: aggregate role-level settings.
|
|
61
|
+
const userRoles = await findWithDecryption(
|
|
62
|
+
em,
|
|
63
|
+
UserRole,
|
|
64
|
+
{ user: ctx.userId as any, deletedAt: null },
|
|
65
|
+
{ populate: ['role'] },
|
|
66
|
+
{ tenantId: ctx.tenantId, organizationId: ctx.organizationId },
|
|
67
|
+
)
|
|
68
|
+
const roleRecords = await em.find(DashboardRoleWidgets, {
|
|
69
|
+
roleId: { $in: userRoles.map((ur) => String(ur.role?.id || ur.role)) },
|
|
70
|
+
deletedAt: null,
|
|
71
|
+
})
|
|
69
72
|
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
73
|
+
const byRole = new Map<string, DashboardRoleWidgets>()
|
|
74
|
+
for (const record of roleRecords) {
|
|
75
|
+
const role = String(record.roleId)
|
|
76
|
+
if (record.tenantId && ctx.tenantId && record.tenantId !== ctx.tenantId) continue
|
|
77
|
+
if (record.tenantId && !ctx.tenantId) continue
|
|
78
|
+
if (record.organizationId && ctx.organizationId && record.organizationId !== ctx.organizationId) continue
|
|
79
|
+
if (record.organizationId && !ctx.organizationId) continue
|
|
80
|
+
const current = byRole.get(role)
|
|
81
|
+
if (!current || specificity(record) > specificity(current)) {
|
|
82
|
+
byRole.set(role, record)
|
|
83
|
+
}
|
|
80
84
|
}
|
|
81
|
-
}
|
|
82
85
|
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
86
|
+
const allowedByRole = new Set<string>()
|
|
87
|
+
for (const record of byRole.values()) {
|
|
88
|
+
for (const id of record.widgetIdsJson) {
|
|
89
|
+
if (allWidgetIds.includes(id)) allowedByRole.add(id)
|
|
90
|
+
}
|
|
87
91
|
}
|
|
88
|
-
}
|
|
89
92
|
|
|
90
|
-
|
|
91
|
-
if (allowedByUser) {
|
|
92
|
-
baseSet = allowedByUser
|
|
93
|
-
} else if (allowedByRole.size > 0) {
|
|
94
|
-
baseSet = allowedByRole
|
|
95
|
-
} else {
|
|
96
|
-
baseSet = new Set(allWidgetIds)
|
|
93
|
+
baseSet = allowedByRole.size > 0 ? allowedByRole : new Set(allWidgetIds)
|
|
97
94
|
}
|
|
98
95
|
|
|
99
96
|
if (baseSet.size === 0) return []
|