@memberjunction/core-entities 5.28.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/MCPEngine.d.ts +20 -1
- package/dist/engines/MCPEngine.d.ts.map +1 -1
- package/dist/engines/MCPEngine.js +31 -0
- package/dist/engines/MCPEngine.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 +1593 -78
- package/dist/generated/entity_subclasses.d.ts.map +1 -1
- package/dist/generated/entity_subclasses.js +2440 -352
- 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,101 @@
|
|
|
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, EntityPermissionType, RunView } from '@memberjunction/core';
|
|
8
|
+
import { RegisterClass, UUIDsEqual } from '@memberjunction/global';
|
|
9
|
+
import { MJCollectionPermissionEntity } from '../../generated/entity_subclasses.js';
|
|
10
|
+
import { assertCallerMayCreateShare, buildActionsSummary, checkShareManagePermission, dispatchShareNotificationAfterSave, } from './BaseShareEntityExtended.js';
|
|
11
|
+
/**
|
|
12
|
+
* Extended Collection Permission entity — same dual-purpose pattern as
|
|
13
|
+
* {@link MJDashboardPermissionEntityExtended}. See that class for rationale.
|
|
14
|
+
*
|
|
15
|
+
* Note: Collections have no entry in the `MJ: Resource Type` catalog, so
|
|
16
|
+
* `ResourceTypeName` is omitted and the notification's `ResourceTypeID` is
|
|
17
|
+
* left null. The bell icon still shows the title/message; click-through
|
|
18
|
+
* deep-linking can be added later if a Collection ResourceType is seeded.
|
|
19
|
+
*/
|
|
20
|
+
let MJCollectionPermissionEntityExtended = class MJCollectionPermissionEntityExtended extends MJCollectionPermissionEntity {
|
|
21
|
+
CheckPermissions(type, throwError) {
|
|
22
|
+
if (type === EntityPermissionType.Update || type === EntityPermissionType.Delete) {
|
|
23
|
+
const user = this.ActiveUser;
|
|
24
|
+
if (user && checkShareManagePermission(user, this.SharedByUserID))
|
|
25
|
+
return true;
|
|
26
|
+
}
|
|
27
|
+
return super.CheckPermissions(type, throwError);
|
|
28
|
+
}
|
|
29
|
+
async Save(options) {
|
|
30
|
+
const isNewShare = !this.IsSaved;
|
|
31
|
+
const allowed = await assertCallerMayCreateShare(this, isNewShare, () => this.callerMayShareCollection(), 'Only the collection owner or someone with Share permission on this collection can create a new share.');
|
|
32
|
+
if (!allowed)
|
|
33
|
+
return false;
|
|
34
|
+
const saved = await super.Save(options);
|
|
35
|
+
if (saved) {
|
|
36
|
+
await dispatchShareNotificationAfterSave(this, isNewShare, this.SharedByUserID, (provider, grantorId) => ({
|
|
37
|
+
Provider: provider,
|
|
38
|
+
ContextUser: this.ContextCurrentUser,
|
|
39
|
+
GrantorUserID: grantorId,
|
|
40
|
+
GranteeUserID: this.UserID,
|
|
41
|
+
ResourceTypeLabel: 'Collection',
|
|
42
|
+
// No ResourceTypeName — Collections aren't in the Resource Type catalog
|
|
43
|
+
ResourceName: this.Collection ?? null,
|
|
44
|
+
ResourceRecordID: this.CollectionID,
|
|
45
|
+
ActionsSummary: this.actionsSummary(),
|
|
46
|
+
ExtraConfiguration: { PermissionID: this.ID },
|
|
47
|
+
}));
|
|
48
|
+
}
|
|
49
|
+
return saved;
|
|
50
|
+
}
|
|
51
|
+
actionsSummary() {
|
|
52
|
+
return buildActionsSummary({
|
|
53
|
+
view: this.CanRead,
|
|
54
|
+
edit: this.CanEdit,
|
|
55
|
+
delete: this.CanDelete,
|
|
56
|
+
share: this.CanShare,
|
|
57
|
+
});
|
|
58
|
+
}
|
|
59
|
+
/**
|
|
60
|
+
* Authorization for CREATING a new CollectionPermission row. Caller must
|
|
61
|
+
* be the collection owner or hold an existing Share-capable grant. Same
|
|
62
|
+
* two-query pattern as {@link MJArtifactPermissionEntityExtended.callerMayShareArtifact}.
|
|
63
|
+
*/
|
|
64
|
+
async callerMayShareCollection() {
|
|
65
|
+
const user = this.ContextCurrentUser;
|
|
66
|
+
if (!user)
|
|
67
|
+
return false;
|
|
68
|
+
const rv = new RunView();
|
|
69
|
+
const [ownerResult, grantResult] = await rv.RunViews([
|
|
70
|
+
{
|
|
71
|
+
EntityName: 'MJ: Collections',
|
|
72
|
+
ExtraFilter: `ID='${this.CollectionID}'`,
|
|
73
|
+
Fields: ['ID', 'OwnerID'],
|
|
74
|
+
MaxRows: 1,
|
|
75
|
+
ResultType: 'simple',
|
|
76
|
+
},
|
|
77
|
+
{
|
|
78
|
+
EntityName: 'MJ: Collection Permissions',
|
|
79
|
+
ExtraFilter: `CollectionID='${this.CollectionID}' AND UserID='${user.ID}' AND CanShare=1`,
|
|
80
|
+
Fields: ['ID'],
|
|
81
|
+
MaxRows: 1,
|
|
82
|
+
ResultType: 'simple',
|
|
83
|
+
},
|
|
84
|
+
]);
|
|
85
|
+
const ownerId = ownerResult.Success
|
|
86
|
+
? ownerResult.Results?.[0]?.OwnerID
|
|
87
|
+
: undefined;
|
|
88
|
+
if (ownerId && UUIDsEqual(ownerId, user.ID))
|
|
89
|
+
return true;
|
|
90
|
+
return grantResult.Success && (grantResult.Results?.length ?? 0) > 0;
|
|
91
|
+
}
|
|
92
|
+
};
|
|
93
|
+
MJCollectionPermissionEntityExtended = __decorate([
|
|
94
|
+
RegisterClass(BaseEntity, 'MJ: Collection Permissions')
|
|
95
|
+
], MJCollectionPermissionEntityExtended);
|
|
96
|
+
export { MJCollectionPermissionEntityExtended };
|
|
97
|
+
/** Tree-shaking prevention — referenced from the custom/Permissions barrel. */
|
|
98
|
+
export function LoadMJCollectionPermissionEntityExtended() {
|
|
99
|
+
// intentionally empty
|
|
100
|
+
}
|
|
101
|
+
//# sourceMappingURL=MJCollectionPermissionEntityExtended.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"MJCollectionPermissionEntityExtended.js","sourceRoot":"","sources":["../../../src/custom/Permissions/MJCollectionPermissionEntityExtended.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { EntityPermissionType, EntitySaveOptions } from '@memberjunction/core';
|
|
2
|
+
import { MJDashboardPermissionEntity } from '../../generated/entity_subclasses.js';
|
|
3
|
+
/**
|
|
4
|
+
* Extended Dashboard Permission entity. Adds two behaviors on top of the
|
|
5
|
+
* generated base:
|
|
6
|
+
*
|
|
7
|
+
* 1. **CheckPermissions override** — grantor and dashboard owner can always
|
|
8
|
+
* Update/Delete their own grant. Without this, UI/Developer users can't
|
|
9
|
+
* revoke their own shares because neither role has `CanDelete` on
|
|
10
|
+
* `MJ: Dashboard Permissions`. The owner fallback also covers the
|
|
11
|
+
* `SharedByUserID IS NULL` legacy case.
|
|
12
|
+
*
|
|
13
|
+
* 2. **Save override** — notifies the grantee via the shared `CreateShareNotification`
|
|
14
|
+
* pipeline so `NotificationEngine` honors their in-app / email / SMS
|
|
15
|
+
* preferences uniformly.
|
|
16
|
+
*/
|
|
17
|
+
export declare class MJDashboardPermissionEntityExtended extends MJDashboardPermissionEntity {
|
|
18
|
+
CheckPermissions(type: EntityPermissionType, throwError: boolean): boolean;
|
|
19
|
+
Save(options?: EntitySaveOptions): Promise<boolean>;
|
|
20
|
+
private isDashboardOwner;
|
|
21
|
+
/**
|
|
22
|
+
* Authorization for CREATING a new DashboardPermission row. Matches the
|
|
23
|
+
* `MJResourcePermissionEntityExtended.callerMayGrantShare` pattern:
|
|
24
|
+
* caller is either the dashboard owner, or holds an existing DashboardPermission
|
|
25
|
+
* on the same dashboard with `CanShare=true`.
|
|
26
|
+
*/
|
|
27
|
+
private callerMayShareDashboard;
|
|
28
|
+
private actionsSummary;
|
|
29
|
+
}
|
|
30
|
+
/** Tree-shaking prevention — referenced from the custom/Permissions barrel. */
|
|
31
|
+
export declare function LoadMJDashboardPermissionEntityExtended(): void;
|
|
32
|
+
//# sourceMappingURL=MJDashboardPermissionEntityExtended.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"MJDashboardPermissionEntityExtended.d.ts","sourceRoot":"","sources":["../../../src/custom/Permissions/MJDashboardPermissionEntityExtended.ts"],"names":[],"mappings":"AAAA,OAAO,EAAc,oBAAoB,EAAE,iBAAiB,EAAE,MAAM,sBAAsB,CAAC;AAI3F,OAAO,EAAE,2BAA2B,EAAE,MAAM,mCAAmC,CAAC;AAQhF;;;;;;;;;;;;;GAaG;AACH,qBACa,mCAAoC,SAAQ,2BAA2B;IACvE,gBAAgB,CAAC,IAAI,EAAE,oBAAoB,EAAE,UAAU,EAAE,OAAO,GAAG,OAAO;IAUpE,IAAI,CAAC,OAAO,CAAC,EAAE,iBAAiB,GAAG,OAAO,CAAC,OAAO,CAAC;IA4BlE,OAAO,CAAC,gBAAgB;IAKxB;;;;;OAKG;IACH,OAAO,CAAC,uBAAuB;IAY/B,OAAO,CAAC,cAAc;CAQzB;AAED,+EAA+E;AAC/E,wBAAgB,uCAAuC,IAAI,IAAI,CAE9D"}
|
|
@@ -0,0 +1,95 @@
|
|
|
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, EntityPermissionType } from '@memberjunction/core';
|
|
8
|
+
import { RegisterClass, UUIDsEqual } from '@memberjunction/global';
|
|
9
|
+
import { DashboardEngine } from '../../engines/dashboards.js';
|
|
10
|
+
import { MJDashboardPermissionEntity } from '../../generated/entity_subclasses.js';
|
|
11
|
+
import { assertCallerMayCreateShare, buildActionsSummary, checkShareManagePermission, dispatchShareNotificationAfterSave, } from './BaseShareEntityExtended.js';
|
|
12
|
+
/**
|
|
13
|
+
* Extended Dashboard Permission entity. Adds two behaviors on top of the
|
|
14
|
+
* generated base:
|
|
15
|
+
*
|
|
16
|
+
* 1. **CheckPermissions override** — grantor and dashboard owner can always
|
|
17
|
+
* Update/Delete their own grant. Without this, UI/Developer users can't
|
|
18
|
+
* revoke their own shares because neither role has `CanDelete` on
|
|
19
|
+
* `MJ: Dashboard Permissions`. The owner fallback also covers the
|
|
20
|
+
* `SharedByUserID IS NULL` legacy case.
|
|
21
|
+
*
|
|
22
|
+
* 2. **Save override** — notifies the grantee via the shared `CreateShareNotification`
|
|
23
|
+
* pipeline so `NotificationEngine` honors their in-app / email / SMS
|
|
24
|
+
* preferences uniformly.
|
|
25
|
+
*/
|
|
26
|
+
let MJDashboardPermissionEntityExtended = class MJDashboardPermissionEntityExtended extends MJDashboardPermissionEntity {
|
|
27
|
+
CheckPermissions(type, throwError) {
|
|
28
|
+
if (type === EntityPermissionType.Update || type === EntityPermissionType.Delete) {
|
|
29
|
+
const user = this.ActiveUser;
|
|
30
|
+
if (user && checkShareManagePermission(user, this.SharedByUserID, (userId) => this.isDashboardOwner(userId))) {
|
|
31
|
+
return true;
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
return super.CheckPermissions(type, throwError);
|
|
35
|
+
}
|
|
36
|
+
async Save(options) {
|
|
37
|
+
const isNewShare = !this.IsSaved;
|
|
38
|
+
const allowed = await assertCallerMayCreateShare(this, isNewShare, () => this.callerMayShareDashboard(), 'Only the dashboard owner or someone with Share permission on this dashboard can create a new share.');
|
|
39
|
+
if (!allowed)
|
|
40
|
+
return false;
|
|
41
|
+
const saved = await super.Save(options);
|
|
42
|
+
if (saved) {
|
|
43
|
+
await dispatchShareNotificationAfterSave(this, isNewShare, this.SharedByUserID, (provider, grantorId) => ({
|
|
44
|
+
Provider: provider,
|
|
45
|
+
ContextUser: this.ContextCurrentUser,
|
|
46
|
+
GrantorUserID: grantorId,
|
|
47
|
+
GranteeUserID: this.UserID,
|
|
48
|
+
ResourceTypeLabel: 'Dashboard',
|
|
49
|
+
ResourceTypeName: 'Dashboards',
|
|
50
|
+
ResourceName: this.Dashboard ?? null,
|
|
51
|
+
ResourceRecordID: this.DashboardID,
|
|
52
|
+
ActionsSummary: this.actionsSummary(),
|
|
53
|
+
ExtraConfiguration: { PermissionID: this.ID },
|
|
54
|
+
}));
|
|
55
|
+
}
|
|
56
|
+
return saved;
|
|
57
|
+
}
|
|
58
|
+
isDashboardOwner(userId) {
|
|
59
|
+
const dashboard = DashboardEngine.Instance.Dashboards.find((d) => UUIDsEqual(d.ID, this.DashboardID));
|
|
60
|
+
return !!dashboard?.UserID && UUIDsEqual(dashboard.UserID, userId);
|
|
61
|
+
}
|
|
62
|
+
/**
|
|
63
|
+
* Authorization for CREATING a new DashboardPermission row. Matches the
|
|
64
|
+
* `MJResourcePermissionEntityExtended.callerMayGrantShare` pattern:
|
|
65
|
+
* caller is either the dashboard owner, or holds an existing DashboardPermission
|
|
66
|
+
* on the same dashboard with `CanShare=true`.
|
|
67
|
+
*/
|
|
68
|
+
callerMayShareDashboard() {
|
|
69
|
+
const user = this.ContextCurrentUser;
|
|
70
|
+
if (!user)
|
|
71
|
+
return false;
|
|
72
|
+
if (this.isDashboardOwner(user.ID))
|
|
73
|
+
return true;
|
|
74
|
+
return DashboardEngine.Instance.DashboardPermissions.some((p) => UUIDsEqual(p.DashboardID, this.DashboardID) &&
|
|
75
|
+
UUIDsEqual(p.UserID, user.ID) &&
|
|
76
|
+
p.CanShare === true);
|
|
77
|
+
}
|
|
78
|
+
actionsSummary() {
|
|
79
|
+
return buildActionsSummary({
|
|
80
|
+
view: this.CanRead,
|
|
81
|
+
edit: this.CanEdit,
|
|
82
|
+
delete: this.CanDelete,
|
|
83
|
+
share: this.CanShare,
|
|
84
|
+
});
|
|
85
|
+
}
|
|
86
|
+
};
|
|
87
|
+
MJDashboardPermissionEntityExtended = __decorate([
|
|
88
|
+
RegisterClass(BaseEntity, 'MJ: Dashboard Permissions')
|
|
89
|
+
], MJDashboardPermissionEntityExtended);
|
|
90
|
+
export { MJDashboardPermissionEntityExtended };
|
|
91
|
+
/** Tree-shaking prevention — referenced from the custom/Permissions barrel. */
|
|
92
|
+
export function LoadMJDashboardPermissionEntityExtended() {
|
|
93
|
+
// intentionally empty
|
|
94
|
+
}
|
|
95
|
+
//# sourceMappingURL=MJDashboardPermissionEntityExtended.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"MJDashboardPermissionEntityExtended.js","sourceRoot":"","sources":["../../../src/custom/Permissions/MJDashboardPermissionEntityExtended.ts"],"names":[],"mappings":";;;;;;AAAA,OAAO,EAAE,UAAU,EAAE,oBAAoB,EAAqB,MAAM,sBAAsB,CAAC;AAC3F,OAAO,EAAE,aAAa,EAAE,UAAU,EAAE,MAAM,wBAAwB,CAAC;AAEnE,OAAO,EAAE,eAAe,EAAE,MAAM,0BAA0B,CAAC;AAC3D,OAAO,EAAE,2BAA2B,EAAE,MAAM,mCAAmC,CAAC;AAChF,OAAO,EACH,0BAA0B,EAC1B,mBAAmB,EACnB,0BAA0B,EAC1B,kCAAkC,GACrC,MAAM,2BAA2B,CAAC;AAEnC;;;;;;;;;;;;;GAaG;AAEI,IAAM,mCAAmC,GAAzC,MAAM,mCAAoC,SAAQ,2BAA2B;IACvE,gBAAgB,CAAC,IAA0B,EAAE,UAAmB;QACrE,IAAI,IAAI,KAAK,oBAAoB,CAAC,MAAM,IAAI,IAAI,KAAK,oBAAoB,CAAC,MAAM,EAAE,CAAC;YAC/E,MAAM,IAAI,GAAG,IAAI,CAAC,UAAU,CAAC;YAC7B,IAAI,IAAI,IAAI,0BAA0B,CAAC,IAAI,EAAE,IAAI,CAAC,cAAc,EAAE,CAAC,MAAM,EAAE,EAAE,CAAC,IAAI,CAAC,gBAAgB,CAAC,MAAM,CAAC,CAAC,EAAE,CAAC;gBAC3G,OAAO,IAAI,CAAC;YAChB,CAAC;QACL,CAAC;QACD,OAAO,KAAK,CAAC,gBAAgB,CAAC,IAAI,EAAE,UAAU,CAAC,CAAC;IACpD,CAAC;IAEQ,KAAK,CAAC,IAAI,CAAC,OAA2B;QAC3C,MAAM,UAAU,GAAG,CAAC,IAAI,CAAC,OAAO,CAAC;QACjC,MAAM,OAAO,GAAG,MAAM,0BAA0B,CAC5C,IAAI,EACJ,UAAU,EACV,GAAG,EAAE,CAAC,IAAI,CAAC,uBAAuB,EAAE,EACpC,qGAAqG,CACxG,CAAC;QACF,IAAI,CAAC,OAAO;YAAE,OAAO,KAAK,CAAC;QAE3B,MAAM,KAAK,GAAG,MAAM,KAAK,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;QACxC,IAAI,KAAK,EAAE,CAAC;YACR,MAAM,kCAAkC,CAAC,IAAI,EAAE,UAAU,EAAE,IAAI,CAAC,cAAc,EAAE,CAAC,QAAQ,EAAE,SAAS,EAAE,EAAE,CAAC,CAAC;gBACtG,QAAQ,EAAE,QAAQ;gBAClB,WAAW,EAAE,IAAI,CAAC,kBAAkB;gBACpC,aAAa,EAAE,SAAS;gBACxB,aAAa,EAAE,IAAI,CAAC,MAAM;gBAC1B,iBAAiB,EAAE,WAAW;gBAC9B,gBAAgB,EAAE,YAAY;gBAC9B,YAAY,EAAE,IAAI,CAAC,SAAS,IAAI,IAAI;gBACpC,gBAAgB,EAAE,IAAI,CAAC,WAAW;gBAClC,cAAc,EAAE,IAAI,CAAC,cAAc,EAAE;gBACrC,kBAAkB,EAAE,EAAE,YAAY,EAAE,IAAI,CAAC,EAAE,EAAE;aAChD,CAAC,CAAC,CAAC;QACR,CAAC;QACD,OAAO,KAAK,CAAC;IACjB,CAAC;IAEO,gBAAgB,CAAC,MAAc;QACnC,MAAM,SAAS,GAAG,eAAe,CAAC,QAAQ,CAAC,UAAU,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,UAAU,CAAC,CAAC,CAAC,EAAE,EAAE,IAAI,CAAC,WAAW,CAAC,CAAC,CAAC;QACtG,OAAO,CAAC,CAAC,SAAS,EAAE,MAAM,IAAI,UAAU,CAAC,SAAS,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACvE,CAAC;IAED;;;;;OAKG;IACK,uBAAuB;QAC3B,MAAM,IAAI,GAAG,IAAI,CAAC,kBAAkB,CAAC;QACrC,IAAI,CAAC,IAAI;YAAE,OAAO,KAAK,CAAC;QACxB,IAAI,IAAI,CAAC,gBAAgB,CAAC,IAAI,CAAC,EAAE,CAAC;YAAE,OAAO,IAAI,CAAC;QAChD,OAAO,eAAe,CAAC,QAAQ,CAAC,oBAAoB,CAAC,IAAI,CACrD,CAAC,CAAC,EAAE,EAAE,CACF,UAAU,CAAC,CAAC,CAAC,WAAW,EAAE,IAAI,CAAC,WAAW,CAAC;YAC3C,UAAU,CAAC,CAAC,CAAC,MAAM,EAAE,IAAI,CAAC,EAAE,CAAC;YAC7B,CAAC,CAAC,QAAQ,KAAK,IAAI,CAC1B,CAAC;IACN,CAAC;IAEO,cAAc;QAClB,OAAO,mBAAmB,CAAC;YACvB,IAAI,EAAE,IAAI,CAAC,OAAO;YAClB,IAAI,EAAE,IAAI,CAAC,OAAO;YAClB,MAAM,EAAE,IAAI,CAAC,SAAS;YACtB,KAAK,EAAE,IAAI,CAAC,QAAQ;SACvB,CAAC,CAAC;IACP,CAAC;CACJ,CAAA;AAtEY,mCAAmC;IAD/C,aAAa,CAAC,UAAU,EAAE,2BAA2B,CAAC;GAC1C,mCAAmC,CAsE/C;;AAED,+EAA+E;AAC/E,MAAM,UAAU,uCAAuC;IACnD,sBAAsB;AAC1B,CAAC"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
export * from './MJDashboardPermissionEntityExtended.js';
|
|
2
|
+
export * from './MJCollectionPermissionEntityExtended.js';
|
|
3
|
+
export * from './MJArtifactPermissionEntityExtended.js';
|
|
4
|
+
export * from './MJAccessControlRuleEntityExtended.js';
|
|
5
|
+
export * from './shareNotification.js';
|
|
6
|
+
export * from './BaseShareEntityExtended.js';
|
|
7
|
+
/**
|
|
8
|
+
* Forces all extended permission entity classes to load so their @RegisterClass
|
|
9
|
+
* decorators fire and override the generated entity classes in the ClassFactory.
|
|
10
|
+
* Called from `@memberjunction/core-entities` barrel on package import.
|
|
11
|
+
*/
|
|
12
|
+
export declare function LoadPermissionEntityExtensions(): void;
|
|
13
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/custom/Permissions/index.ts"],"names":[],"mappings":"AAAA,cAAc,uCAAuC,CAAC;AACtD,cAAc,wCAAwC,CAAC;AACvD,cAAc,sCAAsC,CAAC;AACrD,cAAc,qCAAqC,CAAC;AACpD,cAAc,qBAAqB,CAAC;AACpC,cAAc,2BAA2B,CAAC;AAO1C;;;;GAIG;AACH,wBAAgB,8BAA8B,IAAI,IAAI,CAKrD"}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
export * from './MJDashboardPermissionEntityExtended.js';
|
|
2
|
+
export * from './MJCollectionPermissionEntityExtended.js';
|
|
3
|
+
export * from './MJArtifactPermissionEntityExtended.js';
|
|
4
|
+
export * from './MJAccessControlRuleEntityExtended.js';
|
|
5
|
+
export * from './shareNotification.js';
|
|
6
|
+
export * from './BaseShareEntityExtended.js';
|
|
7
|
+
import { LoadMJDashboardPermissionEntityExtended } from './MJDashboardPermissionEntityExtended.js';
|
|
8
|
+
import { LoadMJCollectionPermissionEntityExtended } from './MJCollectionPermissionEntityExtended.js';
|
|
9
|
+
import { LoadMJArtifactPermissionEntityExtended } from './MJArtifactPermissionEntityExtended.js';
|
|
10
|
+
import { LoadMJAccessControlRuleEntityExtended } from './MJAccessControlRuleEntityExtended.js';
|
|
11
|
+
/**
|
|
12
|
+
* Forces all extended permission entity classes to load so their @RegisterClass
|
|
13
|
+
* decorators fire and override the generated entity classes in the ClassFactory.
|
|
14
|
+
* Called from `@memberjunction/core-entities` barrel on package import.
|
|
15
|
+
*/
|
|
16
|
+
export function LoadPermissionEntityExtensions() {
|
|
17
|
+
LoadMJDashboardPermissionEntityExtended();
|
|
18
|
+
LoadMJCollectionPermissionEntityExtended();
|
|
19
|
+
LoadMJArtifactPermissionEntityExtended();
|
|
20
|
+
LoadMJAccessControlRuleEntityExtended();
|
|
21
|
+
}
|
|
22
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/custom/Permissions/index.ts"],"names":[],"mappings":"AAAA,cAAc,uCAAuC,CAAC;AACtD,cAAc,wCAAwC,CAAC;AACvD,cAAc,sCAAsC,CAAC;AACrD,cAAc,qCAAqC,CAAC;AACpD,cAAc,qBAAqB,CAAC;AACpC,cAAc,2BAA2B,CAAC;AAE1C,OAAO,EAAE,uCAAuC,EAAE,MAAM,uCAAuC,CAAC;AAChG,OAAO,EAAE,wCAAwC,EAAE,MAAM,wCAAwC,CAAC;AAClG,OAAO,EAAE,sCAAsC,EAAE,MAAM,sCAAsC,CAAC;AAC9F,OAAO,EAAE,qCAAqC,EAAE,MAAM,qCAAqC,CAAC;AAE5F;;;;GAIG;AACH,MAAM,UAAU,8BAA8B;IAC1C,uCAAuC,EAAE,CAAC;IAC1C,wCAAwC,EAAE,CAAC;IAC3C,sCAAsC,EAAE,CAAC;IACzC,qCAAqC,EAAE,CAAC;AAC5C,CAAC"}
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
import { IMetadataProvider } from '@memberjunction/core';
|
|
2
|
+
/**
|
|
3
|
+
* Input to {@link CreateShareNotification} — everything needed to deliver a
|
|
4
|
+
* share notification to the grantee of a newly-created permission record.
|
|
5
|
+
*/
|
|
6
|
+
export interface ShareNotificationInput {
|
|
7
|
+
/** Metadata provider — must be the Database provider (server-side). */
|
|
8
|
+
Provider: IMetadataProvider;
|
|
9
|
+
/** Context user to authorize the save. */
|
|
10
|
+
ContextUser: import('@memberjunction/core').UserInfo;
|
|
11
|
+
/** ID of the user who granted the share — the `from`. */
|
|
12
|
+
GrantorUserID: string;
|
|
13
|
+
/** ID of the user receiving the share — the `to` and the notification recipient. */
|
|
14
|
+
GranteeUserID: string;
|
|
15
|
+
/**
|
|
16
|
+
* Human-readable resource type label used in notification text (e.g., "Dashboard",
|
|
17
|
+
* "Collection"). Distinct from `ResourceTypeName` below — this is purely cosmetic.
|
|
18
|
+
*/
|
|
19
|
+
ResourceTypeLabel: string;
|
|
20
|
+
/**
|
|
21
|
+
* Optional name from the {@link MJResourceTypeEntity} catalog (e.g., `"Dashboards"`,
|
|
22
|
+
* `"Artifacts"`, `"Records"`). When provided AND found in the catalog, the resolved
|
|
23
|
+
* ResourceType.ID is written to `MJUserNotification.ResourceTypeID` so the bell icon
|
|
24
|
+
* can deep-link via the matching `DriverClass`.
|
|
25
|
+
*/
|
|
26
|
+
ResourceTypeName?: string;
|
|
27
|
+
/** Optional display name for the shared resource. */
|
|
28
|
+
ResourceName?: string | null;
|
|
29
|
+
/** Primary key of the shared resource. */
|
|
30
|
+
ResourceRecordID: string;
|
|
31
|
+
/** Short sentence describing what was granted. Goes in the notification body. */
|
|
32
|
+
ActionsSummary?: string;
|
|
33
|
+
/** Extra JSON payload for the notification (e.g., PermissionID, DomainName). */
|
|
34
|
+
ExtraConfiguration?: Record<string, unknown>;
|
|
35
|
+
/**
|
|
36
|
+
* Optional override for the notification title. When omitted, the dispatcher
|
|
37
|
+
* auto-generates `"<grantor> shared <resource> with you"`. Used by
|
|
38
|
+
* access-request workflow notifications (e.g., "New request for access to …")
|
|
39
|
+
* that don't match the default share-event phrasing.
|
|
40
|
+
*/
|
|
41
|
+
Title?: string;
|
|
42
|
+
/**
|
|
43
|
+
* Optional override for the notification message body. When omitted, the
|
|
44
|
+
* dispatcher auto-generates a short sentence from `ActionsSummary`.
|
|
45
|
+
*/
|
|
46
|
+
Message?: string;
|
|
47
|
+
}
|
|
48
|
+
/**
|
|
49
|
+
* Registerable handler that actually delivers a share notification. Declared
|
|
50
|
+
* here so server-side code (e.g., `@memberjunction/notifications`) can plug in
|
|
51
|
+
* richer delivery (in-app + email + SMS via `NotificationEngine`) without
|
|
52
|
+
* `@memberjunction/core-entities` having to import the notifications package —
|
|
53
|
+
* that direction would create a circular dependency.
|
|
54
|
+
*/
|
|
55
|
+
export type ShareNotificationHandler = (input: ShareNotificationInput) => Promise<boolean>;
|
|
56
|
+
/**
|
|
57
|
+
* Register a custom dispatcher (e.g., one backed by `NotificationEngine.SendNotification`).
|
|
58
|
+
* Typically called once at server startup. Subsequent calls replace the handler.
|
|
59
|
+
* Passing `null` restores the default in-app-only behavior.
|
|
60
|
+
*/
|
|
61
|
+
export declare function RegisterShareNotificationHandler(handler: ShareNotificationHandler | null): void;
|
|
62
|
+
/**
|
|
63
|
+
* Create and deliver a share notification. If a custom handler has been
|
|
64
|
+
* registered via {@link RegisterShareNotificationHandler}, it's called first;
|
|
65
|
+
* otherwise (and as a fallback on handler error) we write an in-app
|
|
66
|
+
* `MJ: User Notifications` row directly.
|
|
67
|
+
*
|
|
68
|
+
* Returns `true` when the notification was delivered successfully. Never
|
|
69
|
+
* throws — sharing succeeds even if notification delivery fails.
|
|
70
|
+
*/
|
|
71
|
+
export declare function CreateShareNotification(input: ShareNotificationInput): Promise<boolean>;
|
|
72
|
+
//# sourceMappingURL=shareNotification.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"shareNotification.d.ts","sourceRoot":"","sources":["../../../src/custom/Permissions/shareNotification.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,iBAAiB,EAAY,MAAM,sBAAsB,CAAC;AAKnE;;;GAGG;AACH,MAAM,WAAW,sBAAsB;IACnC,uEAAuE;IACvE,QAAQ,EAAE,iBAAiB,CAAC;IAC5B,0CAA0C;IAC1C,WAAW,EAAE,OAAO,sBAAsB,EAAE,QAAQ,CAAC;IACrD,yDAAyD;IACzD,aAAa,EAAE,MAAM,CAAC;IACtB,oFAAoF;IACpF,aAAa,EAAE,MAAM,CAAC;IACtB;;;OAGG;IACH,iBAAiB,EAAE,MAAM,CAAC;IAC1B;;;;;OAKG;IACH,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,qDAAqD;IACrD,YAAY,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC7B,0CAA0C;IAC1C,gBAAgB,EAAE,MAAM,CAAC;IACzB,iFAAiF;IACjF,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,gFAAgF;IAChF,kBAAkB,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAC7C;;;;;OAKG;IACH,KAAK,CAAC,EAAE,MAAM,CAAC;IACf;;;OAGG;IACH,OAAO,CAAC,EAAE,MAAM,CAAC;CACpB;AAED;;;;;;GAMG;AACH,MAAM,MAAM,wBAAwB,GAAG,CAAC,KAAK,EAAE,sBAAsB,KAAK,OAAO,CAAC,OAAO,CAAC,CAAC;AAI3F;;;;GAIG;AACH,wBAAgB,gCAAgC,CAAC,OAAO,EAAE,wBAAwB,GAAG,IAAI,GAAG,IAAI,CAE/F;AAED;;;;;;;;GAQG;AACH,wBAAsB,uBAAuB,CAAC,KAAK,EAAE,sBAAsB,GAAG,OAAO,CAAC,OAAO,CAAC,CAmB7F"}
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
import { LogError } from '@memberjunction/core';
|
|
2
|
+
import { ResourcePermissionEngine } from '../ResourcePermissions/ResourcePermissionEngine.js';
|
|
3
|
+
let registeredHandler = null;
|
|
4
|
+
/**
|
|
5
|
+
* Register a custom dispatcher (e.g., one backed by `NotificationEngine.SendNotification`).
|
|
6
|
+
* Typically called once at server startup. Subsequent calls replace the handler.
|
|
7
|
+
* Passing `null` restores the default in-app-only behavior.
|
|
8
|
+
*/
|
|
9
|
+
export function RegisterShareNotificationHandler(handler) {
|
|
10
|
+
registeredHandler = handler;
|
|
11
|
+
}
|
|
12
|
+
/**
|
|
13
|
+
* Create and deliver a share notification. If a custom handler has been
|
|
14
|
+
* registered via {@link RegisterShareNotificationHandler}, it's called first;
|
|
15
|
+
* otherwise (and as a fallback on handler error) we write an in-app
|
|
16
|
+
* `MJ: User Notifications` row directly.
|
|
17
|
+
*
|
|
18
|
+
* Returns `true` when the notification was delivered successfully. Never
|
|
19
|
+
* throws — sharing succeeds even if notification delivery fails.
|
|
20
|
+
*/
|
|
21
|
+
export async function CreateShareNotification(input) {
|
|
22
|
+
// Self-shares are a no-op (guards against duplicate-notification loops on seeded data).
|
|
23
|
+
if (input.GrantorUserID === input.GranteeUserID)
|
|
24
|
+
return true;
|
|
25
|
+
if (!input.GranteeUserID || !input.ResourceRecordID)
|
|
26
|
+
return true;
|
|
27
|
+
if (registeredHandler) {
|
|
28
|
+
try {
|
|
29
|
+
return await registeredHandler(input);
|
|
30
|
+
}
|
|
31
|
+
catch (err) {
|
|
32
|
+
LogError(`Share notification handler threw; falling back to in-app only delivery: ${err instanceof Error ? err.message : String(err)}`);
|
|
33
|
+
// Fall through to default implementation below
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
return defaultInAppDispatch(input);
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* Default dispatcher: saves a single `MJ: User Notifications` row. No email /
|
|
40
|
+
* SMS delivery. Used when no custom handler is registered (e.g., on the client,
|
|
41
|
+
* or before the server startup wires up the NotificationEngine handler).
|
|
42
|
+
*/
|
|
43
|
+
async function defaultInAppDispatch(input) {
|
|
44
|
+
try {
|
|
45
|
+
const grantor = await input.Provider.GetEntityObject('MJ: Users', input.ContextUser);
|
|
46
|
+
await grantor.Load(input.GrantorUserID);
|
|
47
|
+
const grantorName = grantor.Name || grantor.Email || 'Another user';
|
|
48
|
+
const notification = await input.Provider.GetEntityObject('MJ: User Notifications', input.ContextUser);
|
|
49
|
+
const resourceLabel = input.ResourceName
|
|
50
|
+
? `"${input.ResourceName}"`
|
|
51
|
+
: `a ${input.ResourceTypeLabel.toLowerCase()}`;
|
|
52
|
+
notification.UserID = input.GranteeUserID;
|
|
53
|
+
notification.Title = input.Title ?? `${grantorName} shared ${resourceLabel} with you`;
|
|
54
|
+
notification.Message =
|
|
55
|
+
input.Message ??
|
|
56
|
+
(input.ActionsSummary
|
|
57
|
+
? `${grantorName} shared ${resourceLabel} with you (${input.ActionsSummary}).`
|
|
58
|
+
: `${grantorName} shared ${resourceLabel} with you.`);
|
|
59
|
+
notification.Unread = true;
|
|
60
|
+
const resolvedTypeId = await resolveResourceTypeId(input.ResourceTypeName, input.ContextUser);
|
|
61
|
+
if (resolvedTypeId)
|
|
62
|
+
notification.ResourceTypeID = resolvedTypeId;
|
|
63
|
+
notification.ResourceRecordID = input.ResourceRecordID;
|
|
64
|
+
notification.ResourceConfiguration = JSON.stringify({
|
|
65
|
+
DomainName: input.ResourceTypeLabel,
|
|
66
|
+
...input.ExtraConfiguration,
|
|
67
|
+
});
|
|
68
|
+
const saved = await notification.Save();
|
|
69
|
+
if (!saved) {
|
|
70
|
+
LogError(`CreateShareNotification (default): save failed — ${notification.LatestResult?.CompleteMessage ?? 'unknown error'}`);
|
|
71
|
+
return false;
|
|
72
|
+
}
|
|
73
|
+
return true;
|
|
74
|
+
}
|
|
75
|
+
catch (err) {
|
|
76
|
+
LogError(`CreateShareNotification (default): ${err instanceof Error ? err.message : String(err)}`);
|
|
77
|
+
return false;
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
/**
|
|
81
|
+
* Ensure the `ResourcePermissionEngine` is configured, then resolve
|
|
82
|
+
* `MJ: Resource Type.Name → ID`. Returns null when the engine fails to load or
|
|
83
|
+
* the type isn't in the catalog.
|
|
84
|
+
*/
|
|
85
|
+
async function resolveResourceTypeId(name, contextUser) {
|
|
86
|
+
if (!name)
|
|
87
|
+
return null;
|
|
88
|
+
try {
|
|
89
|
+
const engine = ResourcePermissionEngine.Instance;
|
|
90
|
+
await engine.Config(false, contextUser);
|
|
91
|
+
return engine.ResourceTypeIdByName(name);
|
|
92
|
+
}
|
|
93
|
+
catch (err) {
|
|
94
|
+
LogError(`resolveResourceTypeId('${name}'): ${err instanceof Error ? err.message : String(err)}`);
|
|
95
|
+
return null;
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
//# sourceMappingURL=shareNotification.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"shareNotification.js","sourceRoot":"","sources":["../../../src/custom/Permissions/shareNotification.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,9 +1,64 @@
|
|
|
1
|
-
import { EntitySaveOptions } from "@memberjunction/core";
|
|
1
|
+
import { EntityDeleteOptions, EntityPermissionType, EntitySaveOptions } from "@memberjunction/core";
|
|
2
2
|
import { MJResourcePermissionEntity } from "../../generated/entity_subclasses.js";
|
|
3
3
|
/**
|
|
4
4
|
* Subclass for the Resource Permissiosn entity that implements some workflow logic
|
|
5
5
|
*/
|
|
6
6
|
export declare class MJResourcePermissionEntityExtended extends MJResourcePermissionEntity {
|
|
7
|
+
/**
|
|
8
|
+
* Set by the async `Delete`/`Save` overrides after they confirm the
|
|
9
|
+
* context user is authorized via resource ownership or Owner-level grant.
|
|
10
|
+
* Read by the (sync) `CheckPermissions` override to bypass the role-based
|
|
11
|
+
* gate that would otherwise block non-admin users from revoking shares.
|
|
12
|
+
*/
|
|
13
|
+
private _authorizedByOwnerOverride;
|
|
14
|
+
/**
|
|
15
|
+
* Relaxes the default role-based Update/Delete gate for three parties
|
|
16
|
+
* who legitimately need to manage a share:
|
|
17
|
+
*
|
|
18
|
+
* 1. **Grantor** — whoever created the grant (`SharedByUserID`).
|
|
19
|
+
* 2. **Resource owner** — the user who owns the underlying resource.
|
|
20
|
+
* Checked synchronously via in-memory engine caches (currently
|
|
21
|
+
* `ConversationEngine` for Conversations; add other engines as
|
|
22
|
+
* resource types adopt this pattern).
|
|
23
|
+
* 3. **Owner-level grantee** — anyone else holding an `Owner` permission
|
|
24
|
+
* on the same resource, consulted via the cached
|
|
25
|
+
* `ResourcePermissionEngine.Permissions`.
|
|
26
|
+
*
|
|
27
|
+
* Without this, resource owners can't revoke shares other users created —
|
|
28
|
+
* the UI/Developer roles don't have `CanDelete` on `MJ: Resource Permissions`.
|
|
29
|
+
*/
|
|
30
|
+
CheckPermissions(type: EntityPermissionType, throwError: boolean): boolean;
|
|
31
|
+
/**
|
|
32
|
+
* Async owner lookup that loads the target resource and returns `true`
|
|
33
|
+
* if the context user owns it. Generic — uses the resource type catalog
|
|
34
|
+
* to find the owner field name, so any resource type seeded in
|
|
35
|
+
* `MJ: Resource Types` works without per-type code here.
|
|
36
|
+
*/
|
|
37
|
+
private currentUserOwnsResourceAsync;
|
|
38
|
+
/**
|
|
39
|
+
* Compute whether the context user may Update/Delete this permission row.
|
|
40
|
+
* Combines the sync checks (fast path, uses engine caches) with the async
|
|
41
|
+
* resource-owner lookup (works on the server where caches aren't populated).
|
|
42
|
+
*/
|
|
43
|
+
private callerMayManageShare;
|
|
44
|
+
/**
|
|
45
|
+
* Async wrapper that runs the full authorization check (including the
|
|
46
|
+
* async resource-owner lookup) before delegating to the base delete. Sets
|
|
47
|
+
* `_authorizedByOwnerOverride` so the sync `CheckPermissions` called by
|
|
48
|
+
* the base class will bypass the role-based gate.
|
|
49
|
+
*/
|
|
50
|
+
Delete(options?: EntityDeleteOptions): Promise<boolean>;
|
|
51
|
+
/**
|
|
52
|
+
* Checks resource-type-specific engine caches synchronously to decide
|
|
53
|
+
* whether `userId` owns the record this permission row points at.
|
|
54
|
+
*/
|
|
55
|
+
private currentUserOwnsResource;
|
|
56
|
+
/**
|
|
57
|
+
* Owner-level grantees (direct or via role) can manage shares on the
|
|
58
|
+
* resource. Reads from `ResourcePermissionEngine`'s cached permissions —
|
|
59
|
+
* must already be configured; on the server this happens at startup.
|
|
60
|
+
*/
|
|
61
|
+
private currentUserHasOwnerGrant;
|
|
7
62
|
/**
|
|
8
63
|
* This override encapsulates some busienss logic for the Resource Permissions entity as follows:
|
|
9
64
|
* 1) Whenever a new permission record is created that has a status of "Requested", we generate a new Notifications record for the owner of the resource being requested
|
|
@@ -12,5 +67,12 @@ export declare class MJResourcePermissionEntityExtended extends MJResourcePermis
|
|
|
12
67
|
* @param options
|
|
13
68
|
*/
|
|
14
69
|
Save(options?: EntitySaveOptions): Promise<boolean>;
|
|
70
|
+
/**
|
|
71
|
+
* `true` when the context user may create an Approved grant on this resource:
|
|
72
|
+
* they are either the resource's owner, or they already hold an Owner-level
|
|
73
|
+
* `MJ: Resource Permissions` row on it (direct or via role). Returns `false`
|
|
74
|
+
* when there is no context user.
|
|
75
|
+
*/
|
|
76
|
+
private callerMayGrantShare;
|
|
15
77
|
}
|
|
16
78
|
//# sourceMappingURL=MJResourcePermissionEntityExtended.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"MJResourcePermissionEntityExtended.d.ts","sourceRoot":"","sources":["../../../src/custom/ResourcePermissions/MJResourcePermissionEntityExtended.ts"],"names":[],"mappings":"AAAA,OAAO,EAA4B,iBAAiB,
|
|
1
|
+
{"version":3,"file":"MJResourcePermissionEntityExtended.d.ts","sourceRoot":"","sources":["../../../src/custom/ResourcePermissions/MJResourcePermissionEntityExtended.ts"],"names":[],"mappings":"AAAA,OAAO,EAA4B,mBAAmB,EAAE,oBAAoB,EAAE,iBAAiB,EAA+B,MAAM,sBAAsB,CAAC;AAE3J,OAAO,EAAE,0BAA0B,EAAgB,MAAM,mCAAmC,CAAC;AAS7F;;GAEG;AACH,qBACa,kCAAmC,SAAQ,0BAA0B;IAC9E;;;;;OAKG;IACH,OAAO,CAAC,0BAA0B,CAAS;IAC3C;;;;;;;;;;;;;;;OAeG;IACM,gBAAgB,CAAC,IAAI,EAAE,oBAAoB,EAAE,UAAU,EAAE,OAAO,GAAG,OAAO;IAanF;;;;;OAKG;YACW,4BAA4B;IAqC1C;;;;OAIG;YACW,oBAAoB;IASlC;;;;;OAKG;IACY,MAAM,CAAC,OAAO,CAAC,EAAE,mBAAmB,GAAG,OAAO,CAAC,OAAO,CAAC;IAetE;;;OAGG;IACH,OAAO,CAAC,uBAAuB;IAW/B;;;;OAIG;IACH,OAAO,CAAC,wBAAwB;IAehC;;;;;;OAMG;IACY,IAAI,CAAC,OAAO,CAAC,EAAE,iBAAiB,GAAG,OAAO,CAAC,OAAO,CAAC;IA+IlE;;;;;OAKG;IACH,OAAO,CAAC,mBAAmB;CAa9B"}
|