@memberjunction/core-entities 5.29.0 → 5.30.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/custom/MJConversationDetailEntityExtended.d.ts +31 -0
- package/dist/custom/MJConversationDetailEntityExtended.d.ts.map +1 -0
- package/dist/custom/MJConversationDetailEntityExtended.js +106 -0
- package/dist/custom/MJConversationDetailEntityExtended.js.map +1 -0
- package/dist/custom/PermissionProviders/AIAgentPermissionProvider.d.ts +31 -0
- package/dist/custom/PermissionProviders/AIAgentPermissionProvider.d.ts.map +1 -0
- package/dist/custom/PermissionProviders/AIAgentPermissionProvider.js +151 -0
- package/dist/custom/PermissionProviders/AIAgentPermissionProvider.js.map +1 -0
- package/dist/custom/PermissionProviders/AccessControlRuleProvider.d.ts +45 -0
- package/dist/custom/PermissionProviders/AccessControlRuleProvider.d.ts.map +1 -0
- package/dist/custom/PermissionProviders/AccessControlRuleProvider.js +253 -0
- package/dist/custom/PermissionProviders/AccessControlRuleProvider.js.map +1 -0
- package/dist/custom/PermissionProviders/ApplicationRolePermissionProvider.d.ts +28 -0
- package/dist/custom/PermissionProviders/ApplicationRolePermissionProvider.d.ts.map +1 -0
- package/dist/custom/PermissionProviders/ApplicationRolePermissionProvider.js +144 -0
- package/dist/custom/PermissionProviders/ApplicationRolePermissionProvider.js.map +1 -0
- package/dist/custom/PermissionProviders/ArtifactPermissionProvider.d.ts +45 -0
- package/dist/custom/PermissionProviders/ArtifactPermissionProvider.d.ts.map +1 -0
- package/dist/custom/PermissionProviders/ArtifactPermissionProvider.js +169 -0
- package/dist/custom/PermissionProviders/ArtifactPermissionProvider.js.map +1 -0
- package/dist/custom/PermissionProviders/CollectionPermissionProvider.d.ts +40 -0
- package/dist/custom/PermissionProviders/CollectionPermissionProvider.d.ts.map +1 -0
- package/dist/custom/PermissionProviders/CollectionPermissionProvider.js +220 -0
- package/dist/custom/PermissionProviders/CollectionPermissionProvider.js.map +1 -0
- package/dist/custom/PermissionProviders/DashboardPermissionProvider.d.ts +47 -0
- package/dist/custom/PermissionProviders/DashboardPermissionProvider.d.ts.map +1 -0
- package/dist/custom/PermissionProviders/DashboardPermissionProvider.js +218 -0
- package/dist/custom/PermissionProviders/DashboardPermissionProvider.js.map +1 -0
- package/dist/custom/PermissionProviders/EntityPermissionProvider.d.ts +25 -0
- package/dist/custom/PermissionProviders/EntityPermissionProvider.d.ts.map +1 -0
- package/dist/custom/PermissionProviders/EntityPermissionProvider.js +129 -0
- package/dist/custom/PermissionProviders/EntityPermissionProvider.js.map +1 -0
- package/dist/custom/PermissionProviders/QueryPermissionProvider.d.ts +24 -0
- package/dist/custom/PermissionProviders/QueryPermissionProvider.d.ts.map +1 -0
- package/dist/custom/PermissionProviders/QueryPermissionProvider.js +123 -0
- package/dist/custom/PermissionProviders/QueryPermissionProvider.js.map +1 -0
- package/dist/custom/PermissionProviders/ResourcePermissionProvider.d.ts +39 -0
- package/dist/custom/PermissionProviders/ResourcePermissionProvider.d.ts.map +1 -0
- package/dist/custom/PermissionProviders/ResourcePermissionProvider.js +193 -0
- package/dist/custom/PermissionProviders/ResourcePermissionProvider.js.map +1 -0
- package/dist/custom/PermissionProviders/index.d.ts +16 -0
- package/dist/custom/PermissionProviders/index.d.ts.map +1 -0
- package/dist/custom/PermissionProviders/index.js +41 -0
- package/dist/custom/PermissionProviders/index.js.map +1 -0
- package/dist/custom/Permissions/BaseShareEntityExtended.d.ts +105 -0
- package/dist/custom/Permissions/BaseShareEntityExtended.d.ts.map +1 -0
- package/dist/custom/Permissions/BaseShareEntityExtended.js +162 -0
- package/dist/custom/Permissions/BaseShareEntityExtended.js.map +1 -0
- package/dist/custom/Permissions/MJAccessControlRuleEntityExtended.d.ts +22 -0
- package/dist/custom/Permissions/MJAccessControlRuleEntityExtended.d.ts.map +1 -0
- package/dist/custom/Permissions/MJAccessControlRuleEntityExtended.js +75 -0
- package/dist/custom/Permissions/MJAccessControlRuleEntityExtended.js.map +1 -0
- package/dist/custom/Permissions/MJArtifactPermissionEntityExtended.d.ts +22 -0
- package/dist/custom/Permissions/MJArtifactPermissionEntityExtended.d.ts.map +1 -0
- package/dist/custom/Permissions/MJArtifactPermissionEntityExtended.js +114 -0
- package/dist/custom/Permissions/MJArtifactPermissionEntityExtended.js.map +1 -0
- package/dist/custom/Permissions/MJCollectionPermissionEntityExtended.d.ts +25 -0
- package/dist/custom/Permissions/MJCollectionPermissionEntityExtended.d.ts.map +1 -0
- package/dist/custom/Permissions/MJCollectionPermissionEntityExtended.js +101 -0
- package/dist/custom/Permissions/MJCollectionPermissionEntityExtended.js.map +1 -0
- package/dist/custom/Permissions/MJDashboardPermissionEntityExtended.d.ts +32 -0
- package/dist/custom/Permissions/MJDashboardPermissionEntityExtended.d.ts.map +1 -0
- package/dist/custom/Permissions/MJDashboardPermissionEntityExtended.js +95 -0
- package/dist/custom/Permissions/MJDashboardPermissionEntityExtended.js.map +1 -0
- package/dist/custom/Permissions/index.d.ts +13 -0
- package/dist/custom/Permissions/index.d.ts.map +1 -0
- package/dist/custom/Permissions/index.js +22 -0
- package/dist/custom/Permissions/index.js.map +1 -0
- package/dist/custom/Permissions/shareNotification.d.ts +72 -0
- package/dist/custom/Permissions/shareNotification.d.ts.map +1 -0
- package/dist/custom/Permissions/shareNotification.js +98 -0
- package/dist/custom/Permissions/shareNotification.js.map +1 -0
- package/dist/custom/ResourcePermissions/MJResourcePermissionEntityExtended.d.ts +63 -1
- package/dist/custom/ResourcePermissions/MJResourcePermissionEntityExtended.d.ts.map +1 -1
- package/dist/custom/ResourcePermissions/MJResourcePermissionEntityExtended.js +244 -27
- package/dist/custom/ResourcePermissions/MJResourcePermissionEntityExtended.js.map +1 -1
- package/dist/custom/ResourcePermissions/ResourcePermissionEngine.d.ts +7 -0
- package/dist/custom/ResourcePermissions/ResourcePermissionEngine.d.ts.map +1 -1
- package/dist/custom/ResourcePermissions/ResourcePermissionEngine.js +13 -0
- package/dist/custom/ResourcePermissions/ResourcePermissionEngine.js.map +1 -1
- package/dist/engines/GeoDataEngine.d.ts +42 -8
- package/dist/engines/GeoDataEngine.d.ts.map +1 -1
- package/dist/engines/GeoDataEngine.js +191 -36
- package/dist/engines/GeoDataEngine.js.map +1 -1
- package/dist/engines/PermissionEngine.d.ts +142 -0
- package/dist/engines/PermissionEngine.d.ts.map +1 -0
- package/dist/engines/PermissionEngine.js +343 -0
- package/dist/engines/PermissionEngine.js.map +1 -0
- package/dist/engines/UserInfoEngine.d.ts +6 -1
- package/dist/engines/UserInfoEngine.d.ts.map +1 -1
- package/dist/engines/UserInfoEngine.js +21 -5
- package/dist/engines/UserInfoEngine.js.map +1 -1
- package/dist/engines/conversations.d.ts +35 -0
- package/dist/engines/conversations.d.ts.map +1 -1
- package/dist/engines/conversations.js +103 -16
- package/dist/engines/conversations.js.map +1 -1
- package/dist/generated/entity_subclasses.d.ts +579 -52
- package/dist/generated/entity_subclasses.d.ts.map +1 -1
- package/dist/generated/entity_subclasses.js +697 -66
- package/dist/generated/entity_subclasses.js.map +1 -1
- package/dist/index.d.ts +4 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +8 -0
- package/dist/index.js.map +1 -1
- package/package.json +5 -5
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { EntityDeleteOptions, EntitySaveOptions } from '@memberjunction/core';
|
|
2
|
+
import { MJConversationDetailEntity } from '../generated/entity_subclasses.js';
|
|
3
|
+
/**
|
|
4
|
+
* Server-side defense-in-depth for conversation sharing. The Angular chat UI
|
|
5
|
+
* disables the message input when the current user only holds `View` access,
|
|
6
|
+
* but that's a cosmetic gate — a determined caller could still hit the API
|
|
7
|
+
* directly. This override blocks Create/Update/Delete of conversation
|
|
8
|
+
* messages unless the context user is either:
|
|
9
|
+
*
|
|
10
|
+
* 1. The conversation's owner (`MJ: Conversations.UserID`), or
|
|
11
|
+
* 2. A grantee on `MJ: Resource Permissions` with `PermissionLevel` of
|
|
12
|
+
* `Edit` or `Owner` (directly or via role) and `Status='Approved'`.
|
|
13
|
+
*
|
|
14
|
+
* Runs on the server only (`ProviderType === 'Database'`) — client-side
|
|
15
|
+
* executions pass straight through to `super` so offline/optimistic paths
|
|
16
|
+
* still work. `ResourcePermissionEngine`'s cache is used to avoid per-save
|
|
17
|
+
* round trips for permission lookups.
|
|
18
|
+
*/
|
|
19
|
+
export declare class MJConversationDetailEntityExtended extends MJConversationDetailEntity {
|
|
20
|
+
Save(options?: EntitySaveOptions): Promise<boolean>;
|
|
21
|
+
Delete(options?: EntityDeleteOptions): Promise<boolean>;
|
|
22
|
+
private currentUserMayWrite;
|
|
23
|
+
/**
|
|
24
|
+
* Populate `LatestResult.Message` so callers that inspect the save result
|
|
25
|
+
* see why the write was refused rather than a generic failure.
|
|
26
|
+
*/
|
|
27
|
+
private RecordDenied;
|
|
28
|
+
}
|
|
29
|
+
/** Tree-shaking guard — referenced from the MJCoreEntities barrel so the decorator fires. */
|
|
30
|
+
export declare function LoadMJConversationDetailEntityExtended(): void;
|
|
31
|
+
//# sourceMappingURL=MJConversationDetailEntityExtended.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"MJConversationDetailEntityExtended.d.ts","sourceRoot":"","sources":["../../src/custom/MJConversationDetailEntityExtended.ts"],"names":[],"mappings":"AAAA,OAAO,EAEH,mBAAmB,EACnB,iBAAiB,EAGpB,MAAM,sBAAsB,CAAC;AAE9B,OAAO,EACH,0BAA0B,EAG7B,MAAM,gCAAgC,CAAC;AAMxC;;;;;;;;;;;;;;;GAeG;AACH,qBACa,kCAAmC,SAAQ,0BAA0B;IAC/D,IAAI,CAAC,OAAO,CAAC,EAAE,iBAAiB,GAAG,OAAO,CAAC,OAAO,CAAC;IAOnD,MAAM,CAAC,OAAO,CAAC,EAAE,mBAAmB,GAAG,OAAO,CAAC,OAAO,CAAC;YAOxD,mBAAmB;IA6DjC;;;OAGG;IACH,OAAO,CAAC,YAAY;CAOvB;AAED,6FAA6F;AAC7F,wBAAgB,sCAAsC,IAAI,IAAI,CAE7D"}
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
|
|
2
|
+
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
3
|
+
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
4
|
+
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;
|
|
5
|
+
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
6
|
+
};
|
|
7
|
+
import { BaseEntity, LogError } from '@memberjunction/core';
|
|
8
|
+
import { RegisterClass, UUIDsEqual } from '@memberjunction/global';
|
|
9
|
+
import { MJConversationDetailEntity } from '../generated/entity_subclasses.js';
|
|
10
|
+
import { ResourcePermissionEngine } from './ResourcePermissions/ResourcePermissionEngine.js';
|
|
11
|
+
/** `MJ: Resource Types.ID` for Conversations — seeded in the resource type catalog. */
|
|
12
|
+
const CONVERSATIONS_RESOURCE_TYPE_ID = '81D4BC3D-9FEB-EF11-B01A-286B35C04427';
|
|
13
|
+
/**
|
|
14
|
+
* Server-side defense-in-depth for conversation sharing. The Angular chat UI
|
|
15
|
+
* disables the message input when the current user only holds `View` access,
|
|
16
|
+
* but that's a cosmetic gate — a determined caller could still hit the API
|
|
17
|
+
* directly. This override blocks Create/Update/Delete of conversation
|
|
18
|
+
* messages unless the context user is either:
|
|
19
|
+
*
|
|
20
|
+
* 1. The conversation's owner (`MJ: Conversations.UserID`), or
|
|
21
|
+
* 2. A grantee on `MJ: Resource Permissions` with `PermissionLevel` of
|
|
22
|
+
* `Edit` or `Owner` (directly or via role) and `Status='Approved'`.
|
|
23
|
+
*
|
|
24
|
+
* Runs on the server only (`ProviderType === 'Database'`) — client-side
|
|
25
|
+
* executions pass straight through to `super` so offline/optimistic paths
|
|
26
|
+
* still work. `ResourcePermissionEngine`'s cache is used to avoid per-save
|
|
27
|
+
* round trips for permission lookups.
|
|
28
|
+
*/
|
|
29
|
+
let MJConversationDetailEntityExtended = class MJConversationDetailEntityExtended extends MJConversationDetailEntity {
|
|
30
|
+
async Save(options) {
|
|
31
|
+
if (!(await this.currentUserMayWrite())) {
|
|
32
|
+
return false;
|
|
33
|
+
}
|
|
34
|
+
return super.Save(options);
|
|
35
|
+
}
|
|
36
|
+
async Delete(options) {
|
|
37
|
+
if (!(await this.currentUserMayWrite())) {
|
|
38
|
+
return false;
|
|
39
|
+
}
|
|
40
|
+
return super.Delete(options);
|
|
41
|
+
}
|
|
42
|
+
async currentUserMayWrite() {
|
|
43
|
+
const provider = this.ProviderToUse;
|
|
44
|
+
if (provider?.ProviderType !== 'Database') {
|
|
45
|
+
// Client-side path — trust the enforcement that already ran upstream.
|
|
46
|
+
return true;
|
|
47
|
+
}
|
|
48
|
+
const user = this.ContextCurrentUser;
|
|
49
|
+
if (!user) {
|
|
50
|
+
// No user context on a server save = system operation; allow.
|
|
51
|
+
return true;
|
|
52
|
+
}
|
|
53
|
+
try {
|
|
54
|
+
const conversation = await provider.GetEntityObject('MJ: Conversations', user);
|
|
55
|
+
const loaded = await conversation.Load(this.ConversationID);
|
|
56
|
+
if (!loaded) {
|
|
57
|
+
// Parent conversation missing — let the FK/base save handle it.
|
|
58
|
+
return true;
|
|
59
|
+
}
|
|
60
|
+
if (conversation.UserID && UUIDsEqual(conversation.UserID, user.ID)) {
|
|
61
|
+
return true;
|
|
62
|
+
}
|
|
63
|
+
const engine = ResourcePermissionEngine.GetProviderInstance(provider, ResourcePermissionEngine);
|
|
64
|
+
await engine.Config(false, user);
|
|
65
|
+
const grant = engine
|
|
66
|
+
.GetUserAvailableResources(user, CONVERSATIONS_RESOURCE_TYPE_ID)
|
|
67
|
+
.find((p) => UUIDsEqual(p.ResourceRecordID, this.ConversationID));
|
|
68
|
+
if (!grant) {
|
|
69
|
+
this.RecordDenied('You do not have access to this conversation.');
|
|
70
|
+
return false;
|
|
71
|
+
}
|
|
72
|
+
if (grant.PermissionLevel === 'Edit' || grant.PermissionLevel === 'Owner') {
|
|
73
|
+
return true;
|
|
74
|
+
}
|
|
75
|
+
// Only View — block writes.
|
|
76
|
+
this.RecordDenied('You have view-only access to this conversation.');
|
|
77
|
+
return false;
|
|
78
|
+
}
|
|
79
|
+
catch (error) {
|
|
80
|
+
LogError(`MJConversationDetailEntityExtended.currentUserMayWrite failed: ${error instanceof Error ? error.message : String(error)}`);
|
|
81
|
+
// Fail closed — safer to deny than silently allow a compromised write.
|
|
82
|
+
this.RecordDenied('Unable to verify conversation permissions.');
|
|
83
|
+
return false;
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
/**
|
|
87
|
+
* Populate `LatestResult.Message` so callers that inspect the save result
|
|
88
|
+
* see why the write was refused rather than a generic failure.
|
|
89
|
+
*/
|
|
90
|
+
RecordDenied(message) {
|
|
91
|
+
const result = this.LatestResult;
|
|
92
|
+
if (result) {
|
|
93
|
+
result.Success = false;
|
|
94
|
+
result.Message = message;
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
};
|
|
98
|
+
MJConversationDetailEntityExtended = __decorate([
|
|
99
|
+
RegisterClass(BaseEntity, 'MJ: Conversation Details')
|
|
100
|
+
], MJConversationDetailEntityExtended);
|
|
101
|
+
export { MJConversationDetailEntityExtended };
|
|
102
|
+
/** Tree-shaking guard — referenced from the MJCoreEntities barrel so the decorator fires. */
|
|
103
|
+
export function LoadMJConversationDetailEntityExtended() {
|
|
104
|
+
// intentionally empty
|
|
105
|
+
}
|
|
106
|
+
//# sourceMappingURL=MJConversationDetailEntityExtended.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"MJConversationDetailEntityExtended.js","sourceRoot":"","sources":["../../src/custom/MJConversationDetailEntityExtended.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { GranteeType, NormalizedPermission, PermissionAction, PermissionCheckResult, PermissionProviderBase, UserInfo } from '@memberjunction/core';
|
|
2
|
+
/**
|
|
3
|
+
* Wraps `MJ: AI Agent Permissions` behind the unified {@link PermissionProviderBase} contract.
|
|
4
|
+
*
|
|
5
|
+
* AIAgentPermission rows grant either a User (via UserID) or a Role (via RoleID) — never both;
|
|
6
|
+
* the underlying entity enforces this via a table-level validator. Action mapping:
|
|
7
|
+
* - CanView → `Read`
|
|
8
|
+
* - CanRun → `Execute`
|
|
9
|
+
* - CanEdit → `Update`
|
|
10
|
+
* - CanDelete → `Delete`
|
|
11
|
+
*
|
|
12
|
+
* User+Role grants for the same user are OR-aggregated (any grant of an action suffices).
|
|
13
|
+
*
|
|
14
|
+
* `resourceType` is `"AI Agents"`. `resourceId` is the agent ID.
|
|
15
|
+
*/
|
|
16
|
+
export declare class AIAgentPermissionProvider extends PermissionProviderBase {
|
|
17
|
+
readonly DomainName = "AI Agent Permissions";
|
|
18
|
+
readonly Description = "User- or role-level permissions on AI agents. Actions: View (Read), Run (Execute), Edit (Update), Delete.";
|
|
19
|
+
readonly SupportedGranteeTypes: GranteeType[];
|
|
20
|
+
readonly SupportedActions: PermissionAction[];
|
|
21
|
+
readonly SupportsDeny = false;
|
|
22
|
+
GetResourceTypes(): string[];
|
|
23
|
+
CheckPermission(user: UserInfo, _resourceType: string, resourceId: string | null, action: PermissionAction): Promise<PermissionCheckResult>;
|
|
24
|
+
GetEffectivePermissions(user: UserInfo, _resourceType: string, resourceId: string): Promise<NormalizedPermission[]>;
|
|
25
|
+
GetUserResources(user: UserInfo, resourceType?: string): Promise<NormalizedPermission[]>;
|
|
26
|
+
GetResourcePermissions(resourceType: string, resourceId: string): Promise<NormalizedPermission[]>;
|
|
27
|
+
private fetchPermissionsForAgent;
|
|
28
|
+
private actionsForUser;
|
|
29
|
+
private rowActions;
|
|
30
|
+
}
|
|
31
|
+
//# sourceMappingURL=AIAgentPermissionProvider.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"AIAgentPermissionProvider.d.ts","sourceRoot":"","sources":["../../../src/custom/PermissionProviders/AIAgentPermissionProvider.ts"],"names":[],"mappings":"AAAA,OAAO,EACH,WAAW,EACX,oBAAoB,EACpB,gBAAgB,EAChB,qBAAqB,EACrB,sBAAsB,EACtB,QAAQ,EACX,MAAM,sBAAsB,CAAC;AAgB9B;;;;;;;;;;;;;GAaG;AACH,qBACa,yBAA0B,SAAQ,sBAAsB;IACjE,QAAQ,CAAC,UAAU,0BAA0B;IAC7C,QAAQ,CAAC,WAAW,+GAC4F;IAChH,QAAQ,CAAC,qBAAqB,EAAE,WAAW,EAAE,CAAoB;IACjE,QAAQ,CAAC,gBAAgB,EAAE,gBAAgB,EAAE,CAA2C;IACxF,QAAQ,CAAC,YAAY,SAAS;IAErB,gBAAgB,IAAI,MAAM,EAAE;IAI/B,eAAe,CACjB,IAAI,EAAE,QAAQ,EACd,aAAa,EAAE,MAAM,EACrB,UAAU,EAAE,MAAM,GAAG,IAAI,EACzB,MAAM,EAAE,gBAAgB,GACzB,OAAO,CAAC,qBAAqB,CAAC;IAqB3B,uBAAuB,CAAC,IAAI,EAAE,QAAQ,EAAE,aAAa,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,oBAAoB,EAAE,CAAC;IAYnH,gBAAgB,CAAC,IAAI,EAAE,QAAQ,EAAE,YAAY,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,oBAAoB,EAAE,CAAC;IAuCxF,sBAAsB,CAAC,YAAY,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,oBAAoB,EAAE,CAAC;YA8BzF,wBAAwB;IAStC,OAAO,CAAC,cAAc;IAYtB,OAAO,CAAC,UAAU;CAQrB"}
|
|
@@ -0,0 +1,151 @@
|
|
|
1
|
+
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
|
|
2
|
+
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
3
|
+
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
4
|
+
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;
|
|
5
|
+
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
6
|
+
};
|
|
7
|
+
import { PermissionProviderBase, } from '@memberjunction/core';
|
|
8
|
+
import { RegisterClass, UUIDsEqual } from '@memberjunction/global';
|
|
9
|
+
/**
|
|
10
|
+
* Wraps `MJ: AI Agent Permissions` behind the unified {@link PermissionProviderBase} contract.
|
|
11
|
+
*
|
|
12
|
+
* AIAgentPermission rows grant either a User (via UserID) or a Role (via RoleID) — never both;
|
|
13
|
+
* the underlying entity enforces this via a table-level validator. Action mapping:
|
|
14
|
+
* - CanView → `Read`
|
|
15
|
+
* - CanRun → `Execute`
|
|
16
|
+
* - CanEdit → `Update`
|
|
17
|
+
* - CanDelete → `Delete`
|
|
18
|
+
*
|
|
19
|
+
* User+Role grants for the same user are OR-aggregated (any grant of an action suffices).
|
|
20
|
+
*
|
|
21
|
+
* `resourceType` is `"AI Agents"`. `resourceId` is the agent ID.
|
|
22
|
+
*/
|
|
23
|
+
let AIAgentPermissionProvider = class AIAgentPermissionProvider extends PermissionProviderBase {
|
|
24
|
+
constructor() {
|
|
25
|
+
super(...arguments);
|
|
26
|
+
this.DomainName = 'AI Agent Permissions';
|
|
27
|
+
this.Description = 'User- or role-level permissions on AI agents. Actions: View (Read), Run (Execute), Edit (Update), Delete.';
|
|
28
|
+
this.SupportedGranteeTypes = ['User', 'Role'];
|
|
29
|
+
this.SupportedActions = ['Read', 'Execute', 'Update', 'Delete'];
|
|
30
|
+
this.SupportsDeny = false;
|
|
31
|
+
}
|
|
32
|
+
GetResourceTypes() {
|
|
33
|
+
return ['AI Agents'];
|
|
34
|
+
}
|
|
35
|
+
async CheckPermission(user, _resourceType, resourceId, action) {
|
|
36
|
+
if (!resourceId) {
|
|
37
|
+
return {
|
|
38
|
+
Allowed: false,
|
|
39
|
+
DomainName: this.DomainName,
|
|
40
|
+
Reason: 'AI Agent permissions require a specific agent ID',
|
|
41
|
+
};
|
|
42
|
+
}
|
|
43
|
+
const rows = await this.fetchPermissionsForAgent(resourceId);
|
|
44
|
+
const actions = this.actionsForUser(user, rows);
|
|
45
|
+
const allowed = actions.includes(action);
|
|
46
|
+
return {
|
|
47
|
+
Allowed: allowed,
|
|
48
|
+
DomainName: this.DomainName,
|
|
49
|
+
Reason: allowed
|
|
50
|
+
? `User has ${action} via user or role grant on agent '${resourceId}'`
|
|
51
|
+
: `User has no ${action} permission on agent '${resourceId}'`,
|
|
52
|
+
};
|
|
53
|
+
}
|
|
54
|
+
async GetEffectivePermissions(user, _resourceType, resourceId) {
|
|
55
|
+
const rows = await this.fetchPermissionsForAgent(resourceId);
|
|
56
|
+
const actions = this.actionsForUser(user, rows);
|
|
57
|
+
if (actions.length === 0)
|
|
58
|
+
return [];
|
|
59
|
+
const nameMap = await this.bulkLookupNames('MJ: AI Agents', [resourceId]);
|
|
60
|
+
return [this.buildNormalizedPermission({
|
|
61
|
+
resourceType: 'AI Agents', resourceId, resourceName: nameMap.get(resourceId),
|
|
62
|
+
granteeType: 'User', granteeId: user.ID, granteeName: user.Name, actions,
|
|
63
|
+
})];
|
|
64
|
+
}
|
|
65
|
+
async GetUserResources(user, resourceType) {
|
|
66
|
+
if (resourceType && resourceType !== 'AI Agents')
|
|
67
|
+
return [];
|
|
68
|
+
const userRoleIds = (user.UserRoles ?? []).map((ur) => ur.RoleID);
|
|
69
|
+
const userFilter = `UserID='${user.ID}'`;
|
|
70
|
+
const roleFilter = userRoleIds.length ? `RoleID IN (${userRoleIds.map((r) => `'${r}'`).join(',')})` : null;
|
|
71
|
+
const combinedFilter = roleFilter ? `(${userFilter}) OR (${roleFilter})` : userFilter;
|
|
72
|
+
const rows = await this.fetchRows('MJ: AI Agent Permissions', combinedFilter, ['ID', 'AgentID', 'RoleID', 'UserID', 'CanView', 'CanRun', 'CanEdit', 'CanDelete'], 'GetUserResources');
|
|
73
|
+
// Group by agent and aggregate actions
|
|
74
|
+
const byAgent = new Map();
|
|
75
|
+
for (const row of rows) {
|
|
76
|
+
const bucket = byAgent.get(row.AgentID) ?? { actions: new Set(), sourceIds: [] };
|
|
77
|
+
for (const a of this.rowActions(row))
|
|
78
|
+
bucket.actions.add(a);
|
|
79
|
+
bucket.sourceIds.push(row.ID);
|
|
80
|
+
byAgent.set(row.AgentID, bucket);
|
|
81
|
+
}
|
|
82
|
+
if (byAgent.size === 0)
|
|
83
|
+
return [];
|
|
84
|
+
const nameMap = await this.bulkLookupNames('MJ: AI Agents', Array.from(byAgent.keys()));
|
|
85
|
+
const results = [];
|
|
86
|
+
for (const [agentId, { actions, sourceIds }] of byAgent) {
|
|
87
|
+
if (actions.size === 0)
|
|
88
|
+
continue;
|
|
89
|
+
results.push(this.buildNormalizedPermission({
|
|
90
|
+
resourceType: 'AI Agents', resourceId: agentId, resourceName: nameMap.get(agentId),
|
|
91
|
+
granteeType: 'User', granteeId: user.ID, granteeName: user.Name,
|
|
92
|
+
actions: Array.from(actions),
|
|
93
|
+
sourceRecordId: sourceIds.length === 1 ? sourceIds[0] : undefined,
|
|
94
|
+
}));
|
|
95
|
+
}
|
|
96
|
+
return results;
|
|
97
|
+
}
|
|
98
|
+
async GetResourcePermissions(resourceType, resourceId) {
|
|
99
|
+
if (resourceType !== 'AI Agents')
|
|
100
|
+
return [];
|
|
101
|
+
const rows = await this.fetchRows('MJ: AI Agent Permissions', `AgentID='${resourceId}'`, ['ID', 'AgentID', 'RoleID', 'UserID', 'Role', 'User', 'CanView', 'CanRun', 'CanEdit', 'CanDelete'], 'GetResourcePermissions');
|
|
102
|
+
if (rows.length === 0)
|
|
103
|
+
return [];
|
|
104
|
+
const nameMap = await this.bulkLookupNames('MJ: AI Agents', [resourceId]);
|
|
105
|
+
const resourceName = nameMap.get(resourceId);
|
|
106
|
+
const results = [];
|
|
107
|
+
for (const row of rows) {
|
|
108
|
+
const actions = this.rowActions(row);
|
|
109
|
+
if (actions.length === 0)
|
|
110
|
+
continue;
|
|
111
|
+
const isUser = row.UserID != null;
|
|
112
|
+
results.push(this.buildNormalizedPermission({
|
|
113
|
+
resourceType: 'AI Agents', resourceId, resourceName,
|
|
114
|
+
granteeType: isUser ? 'User' : 'Role',
|
|
115
|
+
granteeId: isUser ? row.UserID : row.RoleID,
|
|
116
|
+
granteeName: isUser ? row.User ?? undefined : row.Role ?? undefined,
|
|
117
|
+
actions,
|
|
118
|
+
sourceRecordId: row.ID,
|
|
119
|
+
}));
|
|
120
|
+
}
|
|
121
|
+
return results;
|
|
122
|
+
}
|
|
123
|
+
async fetchPermissionsForAgent(agentId) {
|
|
124
|
+
return this.fetchRows('MJ: AI Agent Permissions', `AgentID='${agentId}'`, ['ID', 'AgentID', 'RoleID', 'UserID', 'CanView', 'CanRun', 'CanEdit', 'CanDelete'], 'fetchPermissionsForAgent');
|
|
125
|
+
}
|
|
126
|
+
actionsForUser(user, rows) {
|
|
127
|
+
const set = new Set();
|
|
128
|
+
for (const row of rows) {
|
|
129
|
+
const matches = (row.UserID && UUIDsEqual(row.UserID, user.ID)) ||
|
|
130
|
+
(row.RoleID && user.UserRoles?.some((ur) => UUIDsEqual(ur.RoleID, row.RoleID)));
|
|
131
|
+
if (!matches)
|
|
132
|
+
continue;
|
|
133
|
+
for (const a of this.rowActions(row))
|
|
134
|
+
set.add(a);
|
|
135
|
+
}
|
|
136
|
+
return Array.from(set);
|
|
137
|
+
}
|
|
138
|
+
rowActions(row) {
|
|
139
|
+
return this.boolsToActions({
|
|
140
|
+
Read: row.CanView,
|
|
141
|
+
Execute: row.CanRun,
|
|
142
|
+
Update: row.CanEdit,
|
|
143
|
+
Delete: row.CanDelete,
|
|
144
|
+
});
|
|
145
|
+
}
|
|
146
|
+
};
|
|
147
|
+
AIAgentPermissionProvider = __decorate([
|
|
148
|
+
RegisterClass(PermissionProviderBase, 'MJAIAgentPermissionProvider')
|
|
149
|
+
], AIAgentPermissionProvider);
|
|
150
|
+
export { AIAgentPermissionProvider };
|
|
151
|
+
//# sourceMappingURL=AIAgentPermissionProvider.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"AIAgentPermissionProvider.js","sourceRoot":"","sources":["../../../src/custom/PermissionProviders/AIAgentPermissionProvider.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import { GranteeType, NormalizedPermission, PermissionAction, PermissionCheckResult, PermissionProviderBase, UserInfo } from '@memberjunction/core';
|
|
2
|
+
/**
|
|
3
|
+
* Wraps `MJ: Access Control Rules` behind the unified {@link PermissionProviderBase} contract.
|
|
4
|
+
*
|
|
5
|
+
* ACRs are record-scoped permissions on any entity, using a single polymorphic
|
|
6
|
+
* `(GranteeType, GranteeID)` column pair. They support the broadest grantee set
|
|
7
|
+
* (User, Role, Everyone, Public), the full CRUD+Share action set, and optional
|
|
8
|
+
* time-bound expiration via `ExpiresAt`.
|
|
9
|
+
*
|
|
10
|
+
* `resourceType` is the entity name the ACR targets (e.g., `"Accounts"`); the provider
|
|
11
|
+
* resolves it to the EntityID before querying. `resourceId` is the `RecordID` value
|
|
12
|
+
* (typically a UUID but stored as nvarchar(500) to accommodate composite keys).
|
|
13
|
+
*/
|
|
14
|
+
export declare class AccessControlRuleProvider extends PermissionProviderBase {
|
|
15
|
+
readonly DomainName = "Access Control Rules";
|
|
16
|
+
readonly Description = "Record-level permissions with User/Role/Everyone/Public grantees, full CRUD+Share, and optional expiration.";
|
|
17
|
+
readonly SupportedGranteeTypes: GranteeType[];
|
|
18
|
+
readonly SupportedActions: PermissionAction[];
|
|
19
|
+
readonly SupportsDeny = false;
|
|
20
|
+
readonly SupportsExpiration = true;
|
|
21
|
+
GetResourceTypes(): string[];
|
|
22
|
+
CheckPermission(user: UserInfo, resourceType: string, resourceId: string | null, action: PermissionAction): Promise<PermissionCheckResult>;
|
|
23
|
+
GetEffectivePermissions(user: UserInfo, resourceType: string, resourceId: string): Promise<NormalizedPermission[]>;
|
|
24
|
+
GetUserResources(user: UserInfo, resourceType?: string): Promise<NormalizedPermission[]>;
|
|
25
|
+
GetResourcePermissions(resourceType: string, resourceId: string): Promise<NormalizedPermission[]>;
|
|
26
|
+
/**
|
|
27
|
+
* ACRs where this user is the User-type grantee AND someone else issued the grant.
|
|
28
|
+
* Excludes rules the user created for themselves. Role/Everyone/Public grants don't
|
|
29
|
+
* belong in the personal "Shared with me" view — they're always aggregated, and there's
|
|
30
|
+
* no single recipient they were shared *with*. Only unexpired rules are returned.
|
|
31
|
+
*/
|
|
32
|
+
GetPermissionsSharedWithUser(grantee: UserInfo): Promise<NormalizedPermission[]>;
|
|
33
|
+
/**
|
|
34
|
+
* Every ACR where this user is the grantor. Only unexpired rules are returned — an
|
|
35
|
+
* expired ACR can't be acted on, so surfacing it in "Shared by me" would be noise.
|
|
36
|
+
*/
|
|
37
|
+
GetPermissionsGrantedByUser(grantor: UserInfo): Promise<NormalizedPermission[]>;
|
|
38
|
+
private resolveEntityId;
|
|
39
|
+
private fetchActiveRules;
|
|
40
|
+
private resolveGranteeName;
|
|
41
|
+
private actionsForUser;
|
|
42
|
+
private granteeMatchesUser;
|
|
43
|
+
private rowActions;
|
|
44
|
+
}
|
|
45
|
+
//# sourceMappingURL=AccessControlRuleProvider.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"AccessControlRuleProvider.d.ts","sourceRoot":"","sources":["../../../src/custom/PermissionProviders/AccessControlRuleProvider.ts"],"names":[],"mappings":"AAAA,OAAO,EACH,WAAW,EAEX,oBAAoB,EACpB,gBAAgB,EAChB,qBAAqB,EACrB,sBAAsB,EACtB,QAAQ,EACX,MAAM,sBAAsB,CAAC;AAyB9B;;;;;;;;;;;GAWG;AACH,qBACa,yBAA0B,SAAQ,sBAAsB;IACjE,QAAQ,CAAC,UAAU,0BAA0B;IAC7C,QAAQ,CAAC,WAAW,iHAC8F;IAClH,QAAQ,CAAC,qBAAqB,EAAE,WAAW,EAAE,CAA0C;IACvF,QAAQ,CAAC,gBAAgB,EAAE,gBAAgB,EAAE,CAAmD;IAChG,QAAQ,CAAC,YAAY,SAAS;IAC9B,QAAQ,CAAC,kBAAkB,QAAQ;IAE1B,gBAAgB,IAAI,MAAM,EAAE;IAI/B,eAAe,CACjB,IAAI,EAAE,QAAQ,EACd,YAAY,EAAE,MAAM,EACpB,UAAU,EAAE,MAAM,GAAG,IAAI,EACzB,MAAM,EAAE,gBAAgB,GACzB,OAAO,CAAC,qBAAqB,CAAC;IA6B3B,uBAAuB,CAAC,IAAI,EAAE,QAAQ,EAAE,YAAY,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,oBAAoB,EAAE,CAAC;IAclH,gBAAgB,CAAC,IAAI,EAAE,QAAQ,EAAE,YAAY,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,oBAAoB,EAAE,CAAC;IAqDxF,sBAAsB,CAAC,YAAY,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,oBAAoB,EAAE,CAAC;IAsBvG;;;;;OAKG;IACY,4BAA4B,CAAC,OAAO,EAAE,QAAQ,GAAG,OAAO,CAAC,oBAAoB,EAAE,CAAC;IAyB/F;;;OAGG;IACY,2BAA2B,CAAC,OAAO,EAAE,QAAQ,GAAG,OAAO,CAAC,oBAAoB,EAAE,CAAC;IA0B9F,OAAO,CAAC,eAAe;YAMT,gBAAgB;IAS9B,OAAO,CAAC,kBAAkB;IAc1B,OAAO,CAAC,cAAc;IAStB,OAAO,CAAC,kBAAkB;IAc1B,OAAO,CAAC,UAAU;CASrB"}
|
|
@@ -0,0 +1,253 @@
|
|
|
1
|
+
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
|
|
2
|
+
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
3
|
+
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
4
|
+
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;
|
|
5
|
+
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
6
|
+
};
|
|
7
|
+
import { Metadata, PermissionProviderBase, } from '@memberjunction/core';
|
|
8
|
+
import { RegisterClass, UUIDsEqual } from '@memberjunction/global';
|
|
9
|
+
/** Fields pulled for every `GetPermissionsGrantedByUser` / `GetPermissionsSharedWithUser` query. */
|
|
10
|
+
const ACR_GRANT_FIELDS = [
|
|
11
|
+
'ID', 'EntityID', 'Entity', 'RecordID', 'GranteeType', 'GranteeID', 'GrantedByUserID',
|
|
12
|
+
'CanRead', 'CanCreate', 'CanUpdate', 'CanDelete', 'CanShare', 'ExpiresAt',
|
|
13
|
+
];
|
|
14
|
+
/**
|
|
15
|
+
* Wraps `MJ: Access Control Rules` behind the unified {@link PermissionProviderBase} contract.
|
|
16
|
+
*
|
|
17
|
+
* ACRs are record-scoped permissions on any entity, using a single polymorphic
|
|
18
|
+
* `(GranteeType, GranteeID)` column pair. They support the broadest grantee set
|
|
19
|
+
* (User, Role, Everyone, Public), the full CRUD+Share action set, and optional
|
|
20
|
+
* time-bound expiration via `ExpiresAt`.
|
|
21
|
+
*
|
|
22
|
+
* `resourceType` is the entity name the ACR targets (e.g., `"Accounts"`); the provider
|
|
23
|
+
* resolves it to the EntityID before querying. `resourceId` is the `RecordID` value
|
|
24
|
+
* (typically a UUID but stored as nvarchar(500) to accommodate composite keys).
|
|
25
|
+
*/
|
|
26
|
+
let AccessControlRuleProvider = class AccessControlRuleProvider extends PermissionProviderBase {
|
|
27
|
+
constructor() {
|
|
28
|
+
super(...arguments);
|
|
29
|
+
this.DomainName = 'Access Control Rules';
|
|
30
|
+
this.Description = 'Record-level permissions with User/Role/Everyone/Public grantees, full CRUD+Share, and optional expiration.';
|
|
31
|
+
this.SupportedGranteeTypes = ['User', 'Role', 'Everyone', 'Public'];
|
|
32
|
+
this.SupportedActions = ['Read', 'Create', 'Update', 'Delete', 'Share'];
|
|
33
|
+
this.SupportsDeny = false;
|
|
34
|
+
this.SupportsExpiration = true;
|
|
35
|
+
}
|
|
36
|
+
GetResourceTypes() {
|
|
37
|
+
return new Metadata().Entities.map((e) => e.Name).sort((a, b) => a.localeCompare(b));
|
|
38
|
+
}
|
|
39
|
+
async CheckPermission(user, resourceType, resourceId, action) {
|
|
40
|
+
if (!resourceId) {
|
|
41
|
+
return {
|
|
42
|
+
Allowed: false,
|
|
43
|
+
DomainName: this.DomainName,
|
|
44
|
+
Reason: 'ACRs require a specific record ID',
|
|
45
|
+
};
|
|
46
|
+
}
|
|
47
|
+
const entityId = this.resolveEntityId(resourceType);
|
|
48
|
+
if (!entityId) {
|
|
49
|
+
return {
|
|
50
|
+
Allowed: false,
|
|
51
|
+
DomainName: this.DomainName,
|
|
52
|
+
Reason: `Unknown entity '${resourceType}'`,
|
|
53
|
+
};
|
|
54
|
+
}
|
|
55
|
+
const rows = await this.fetchActiveRules(entityId, resourceId);
|
|
56
|
+
const actions = this.actionsForUser(user, rows);
|
|
57
|
+
const allowed = actions.includes(action);
|
|
58
|
+
return {
|
|
59
|
+
Allowed: allowed,
|
|
60
|
+
DomainName: this.DomainName,
|
|
61
|
+
Reason: allowed
|
|
62
|
+
? `User has ${action} via an active ACR`
|
|
63
|
+
: `No active ACR grants ${action} on ${resourceType}/${resourceId}`,
|
|
64
|
+
};
|
|
65
|
+
}
|
|
66
|
+
async GetEffectivePermissions(user, resourceType, resourceId) {
|
|
67
|
+
const entityId = this.resolveEntityId(resourceType);
|
|
68
|
+
if (!entityId)
|
|
69
|
+
return [];
|
|
70
|
+
const rows = await this.fetchActiveRules(entityId, resourceId);
|
|
71
|
+
const actions = this.actionsForUser(user, rows);
|
|
72
|
+
if (actions.length === 0)
|
|
73
|
+
return [];
|
|
74
|
+
return [this.buildNormalizedPermission({
|
|
75
|
+
resourceType, resourceId,
|
|
76
|
+
granteeType: 'User', granteeId: user.ID, granteeName: user.Name, actions,
|
|
77
|
+
})];
|
|
78
|
+
}
|
|
79
|
+
async GetUserResources(user, resourceType) {
|
|
80
|
+
const userRoleIds = (user.UserRoles ?? []).map((ur) => `'${ur.RoleID}'`);
|
|
81
|
+
const granteeClauses = [
|
|
82
|
+
`(GranteeType='User' AND GranteeID='${user.ID}')`,
|
|
83
|
+
`(GranteeType IN ('Everyone','Public'))`,
|
|
84
|
+
];
|
|
85
|
+
if (userRoleIds.length > 0) {
|
|
86
|
+
granteeClauses.push(`(GranteeType='Role' AND GranteeID IN (${userRoleIds.join(',')}))`);
|
|
87
|
+
}
|
|
88
|
+
const granteeFilter = granteeClauses.join(' OR ');
|
|
89
|
+
let filter = `(${granteeFilter}) AND (ExpiresAt IS NULL OR ExpiresAt > GETUTCDATE())`;
|
|
90
|
+
if (resourceType) {
|
|
91
|
+
const entityId = this.resolveEntityId(resourceType);
|
|
92
|
+
if (!entityId)
|
|
93
|
+
return [];
|
|
94
|
+
filter = `(${filter}) AND EntityID='${entityId}'`;
|
|
95
|
+
}
|
|
96
|
+
const rows = await this.fetchRows('MJ: Access Control Rules', filter, ACR_GRANT_FIELDS.filter((f) => f !== 'GrantedByUserID'), 'GetUserResources');
|
|
97
|
+
const buckets = new Map();
|
|
98
|
+
for (const row of rows) {
|
|
99
|
+
const key = `${row.EntityID}|${row.RecordID}`;
|
|
100
|
+
const bucket = buckets.get(key) ?? { actions: new Set(), sourceIds: [], entityName: row.Entity ?? null };
|
|
101
|
+
for (const a of this.rowActions(row))
|
|
102
|
+
bucket.actions.add(a);
|
|
103
|
+
bucket.sourceIds.push(row.ID);
|
|
104
|
+
if (!bucket.entityName && row.Entity)
|
|
105
|
+
bucket.entityName = row.Entity;
|
|
106
|
+
buckets.set(key, bucket);
|
|
107
|
+
}
|
|
108
|
+
const results = [];
|
|
109
|
+
for (const [key, bucket] of buckets) {
|
|
110
|
+
const [, recordId] = key.split('|');
|
|
111
|
+
if (bucket.actions.size === 0)
|
|
112
|
+
continue;
|
|
113
|
+
results.push(this.buildNormalizedPermission({
|
|
114
|
+
resourceType: bucket.entityName ?? 'Unknown',
|
|
115
|
+
resourceId: recordId,
|
|
116
|
+
granteeType: 'User', granteeId: user.ID, granteeName: user.Name,
|
|
117
|
+
actions: Array.from(bucket.actions),
|
|
118
|
+
sourceRecordId: bucket.sourceIds.length === 1 ? bucket.sourceIds[0] : undefined,
|
|
119
|
+
}));
|
|
120
|
+
}
|
|
121
|
+
return results;
|
|
122
|
+
}
|
|
123
|
+
async GetResourcePermissions(resourceType, resourceId) {
|
|
124
|
+
const entityId = this.resolveEntityId(resourceType);
|
|
125
|
+
if (!entityId)
|
|
126
|
+
return [];
|
|
127
|
+
const rows = await this.fetchActiveRules(entityId, resourceId);
|
|
128
|
+
const results = [];
|
|
129
|
+
for (const row of rows) {
|
|
130
|
+
const actions = this.rowActions(row);
|
|
131
|
+
if (actions.length === 0)
|
|
132
|
+
continue;
|
|
133
|
+
results.push(this.buildNormalizedPermission({
|
|
134
|
+
resourceType, resourceId,
|
|
135
|
+
granteeType: row.GranteeType,
|
|
136
|
+
granteeId: row.GranteeID,
|
|
137
|
+
granteeName: this.resolveGranteeName(row),
|
|
138
|
+
actions,
|
|
139
|
+
sourceRecordId: row.ID,
|
|
140
|
+
expiresAt: row.ExpiresAt ? new Date(row.ExpiresAt) : undefined,
|
|
141
|
+
}));
|
|
142
|
+
}
|
|
143
|
+
return results;
|
|
144
|
+
}
|
|
145
|
+
/**
|
|
146
|
+
* ACRs where this user is the User-type grantee AND someone else issued the grant.
|
|
147
|
+
* Excludes rules the user created for themselves. Role/Everyone/Public grants don't
|
|
148
|
+
* belong in the personal "Shared with me" view — they're always aggregated, and there's
|
|
149
|
+
* no single recipient they were shared *with*. Only unexpired rules are returned.
|
|
150
|
+
*/
|
|
151
|
+
async GetPermissionsSharedWithUser(grantee) {
|
|
152
|
+
const rows = await this.fetchRows('MJ: Access Control Rules', `GranteeType='User' AND GranteeID='${grantee.ID}' ` +
|
|
153
|
+
`AND GrantedByUserID <> '${grantee.ID}' ` +
|
|
154
|
+
`AND (ExpiresAt IS NULL OR ExpiresAt > GETUTCDATE())`, ACR_GRANT_FIELDS, 'GetPermissionsSharedWithUser');
|
|
155
|
+
const results = [];
|
|
156
|
+
for (const row of rows) {
|
|
157
|
+
const actions = this.rowActions(row);
|
|
158
|
+
if (actions.length === 0)
|
|
159
|
+
continue;
|
|
160
|
+
results.push(this.buildNormalizedPermission({
|
|
161
|
+
resourceType: row.Entity ?? 'Unknown',
|
|
162
|
+
resourceId: row.RecordID,
|
|
163
|
+
granteeType: 'User', granteeId: grantee.ID, granteeName: grantee.Name, actions,
|
|
164
|
+
sourceRecordId: row.ID,
|
|
165
|
+
expiresAt: row.ExpiresAt ? new Date(row.ExpiresAt) : undefined,
|
|
166
|
+
}));
|
|
167
|
+
}
|
|
168
|
+
return results;
|
|
169
|
+
}
|
|
170
|
+
/**
|
|
171
|
+
* Every ACR where this user is the grantor. Only unexpired rules are returned — an
|
|
172
|
+
* expired ACR can't be acted on, so surfacing it in "Shared by me" would be noise.
|
|
173
|
+
*/
|
|
174
|
+
async GetPermissionsGrantedByUser(grantor) {
|
|
175
|
+
const rows = await this.fetchRows('MJ: Access Control Rules', `GrantedByUserID='${grantor.ID}' AND (ExpiresAt IS NULL OR ExpiresAt > GETUTCDATE())`, ACR_GRANT_FIELDS, 'GetPermissionsGrantedByUser');
|
|
176
|
+
const results = [];
|
|
177
|
+
for (const row of rows) {
|
|
178
|
+
const actions = this.rowActions(row);
|
|
179
|
+
if (actions.length === 0)
|
|
180
|
+
continue;
|
|
181
|
+
results.push(this.buildNormalizedPermission({
|
|
182
|
+
resourceType: row.Entity ?? 'Unknown',
|
|
183
|
+
resourceId: row.RecordID,
|
|
184
|
+
granteeType: row.GranteeType,
|
|
185
|
+
granteeId: row.GranteeID,
|
|
186
|
+
granteeName: this.resolveGranteeName(row),
|
|
187
|
+
actions,
|
|
188
|
+
sourceRecordId: row.ID,
|
|
189
|
+
expiresAt: row.ExpiresAt ? new Date(row.ExpiresAt) : undefined,
|
|
190
|
+
}));
|
|
191
|
+
}
|
|
192
|
+
return results;
|
|
193
|
+
}
|
|
194
|
+
resolveEntityId(entityName) {
|
|
195
|
+
const md = new Metadata();
|
|
196
|
+
const entity = md.EntityByName(entityName);
|
|
197
|
+
return entity?.ID ?? null;
|
|
198
|
+
}
|
|
199
|
+
async fetchActiveRules(entityId, recordId) {
|
|
200
|
+
return this.fetchRows('MJ: Access Control Rules', `EntityID='${entityId}' AND RecordID='${recordId}' AND (ExpiresAt IS NULL OR ExpiresAt > GETUTCDATE())`, ACR_GRANT_FIELDS.filter((f) => f !== 'GrantedByUserID' && f !== 'Entity'), 'fetchActiveRules');
|
|
201
|
+
}
|
|
202
|
+
resolveGranteeName(row) {
|
|
203
|
+
switch (row.GranteeType) {
|
|
204
|
+
case 'Role':
|
|
205
|
+
if (!row.GranteeID)
|
|
206
|
+
return undefined;
|
|
207
|
+
return new Metadata().Roles.find((r) => UUIDsEqual(r.ID, row.GranteeID))?.Name;
|
|
208
|
+
case 'Everyone':
|
|
209
|
+
return 'All authenticated users';
|
|
210
|
+
case 'Public':
|
|
211
|
+
return 'Unauthenticated public';
|
|
212
|
+
default:
|
|
213
|
+
return undefined;
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
actionsForUser(user, rows) {
|
|
217
|
+
const set = new Set();
|
|
218
|
+
for (const row of rows) {
|
|
219
|
+
if (!this.granteeMatchesUser(user, row))
|
|
220
|
+
continue;
|
|
221
|
+
for (const a of this.rowActions(row))
|
|
222
|
+
set.add(a);
|
|
223
|
+
}
|
|
224
|
+
return Array.from(set);
|
|
225
|
+
}
|
|
226
|
+
granteeMatchesUser(user, row) {
|
|
227
|
+
switch (row.GranteeType) {
|
|
228
|
+
case 'Everyone':
|
|
229
|
+
case 'Public':
|
|
230
|
+
return true;
|
|
231
|
+
case 'User':
|
|
232
|
+
return !!row.GranteeID && UUIDsEqual(row.GranteeID, user.ID);
|
|
233
|
+
case 'Role':
|
|
234
|
+
return !!row.GranteeID && (user.UserRoles ?? []).some((ur) => UUIDsEqual(ur.RoleID, row.GranteeID));
|
|
235
|
+
default:
|
|
236
|
+
return false;
|
|
237
|
+
}
|
|
238
|
+
}
|
|
239
|
+
rowActions(row) {
|
|
240
|
+
return this.boolsToActions({
|
|
241
|
+
Read: row.CanRead,
|
|
242
|
+
Create: row.CanCreate,
|
|
243
|
+
Update: row.CanUpdate,
|
|
244
|
+
Delete: row.CanDelete,
|
|
245
|
+
Share: row.CanShare,
|
|
246
|
+
});
|
|
247
|
+
}
|
|
248
|
+
};
|
|
249
|
+
AccessControlRuleProvider = __decorate([
|
|
250
|
+
RegisterClass(PermissionProviderBase, 'MJAccessControlRuleProvider')
|
|
251
|
+
], AccessControlRuleProvider);
|
|
252
|
+
export { AccessControlRuleProvider };
|
|
253
|
+
//# sourceMappingURL=AccessControlRuleProvider.js.map
|