@memberjunction/core-entities 5.29.0 → 5.30.1
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,105 @@
|
|
|
1
|
+
import { BaseEntity, EntityPermissionType, EntitySaveOptions, IMetadataProvider, UserInfo } from '@memberjunction/core';
|
|
2
|
+
import { ShareNotificationInput } from './shareNotification.js';
|
|
3
|
+
/**
|
|
4
|
+
* Shared lifecycle for the four user-grantee sharing permission entities
|
|
5
|
+
* (Dashboard, Artifact, Collection, Access Control Rule). Each of those
|
|
6
|
+
* classes delegates three repetitive behaviors to the helpers in this module:
|
|
7
|
+
*
|
|
8
|
+
* 1. **Grantor Update/Delete relaxation** — {@link checkShareManagePermission}
|
|
9
|
+
* Lets the grantor (and, via the optional `additional` hook, resource owners
|
|
10
|
+
* or other privileged parties) revoke or edit their own grant without needing
|
|
11
|
+
* broader CRUD on the permission entity itself.
|
|
12
|
+
*
|
|
13
|
+
* 2. **Post-save share notification dispatch** — {@link dispatchShareNotificationAfterSave}
|
|
14
|
+
* After a successful server-side save of a new share, asks the caller for
|
|
15
|
+
* a notification payload and fires it off through `CreateShareNotification`.
|
|
16
|
+
* Returning `null` from the payload builder short-circuits (used by Access
|
|
17
|
+
* Control Rules for Role / Everyone grantees who have no single recipient).
|
|
18
|
+
*
|
|
19
|
+
* 3. **Action summary rendering** — {@link buildActionsSummary}
|
|
20
|
+
* Turns `{ view: this.CanRead, edit: this.CanEdit, … }` into `"view, edit"`.
|
|
21
|
+
*
|
|
22
|
+
* The original class inheritance shape is preserved (each extended class still
|
|
23
|
+
* extends its generated entity base) — these are plain functions the subclasses
|
|
24
|
+
* call from their `CheckPermissions` / `Save` overrides. We use functions rather
|
|
25
|
+
* than another class in the chain because each permission entity already has a
|
|
26
|
+
* fixed generated base, and multiple inheritance isn't available in TypeScript.
|
|
27
|
+
*/
|
|
28
|
+
/**
|
|
29
|
+
* Determine whether `user` may Update/Delete a share row they don't own via
|
|
30
|
+
* role permissions. Returns true when the user is the grantor, or when the
|
|
31
|
+
* optional `additional(userId)` predicate says they have some domain-specific
|
|
32
|
+
* management right (e.g., dashboard owner, Owner-level grantee).
|
|
33
|
+
*
|
|
34
|
+
* Use:
|
|
35
|
+
* ```typescript
|
|
36
|
+
* override CheckPermissions(type, throwError) {
|
|
37
|
+
* if ((type === Update || Delete) && this.ActiveUser &&
|
|
38
|
+
* checkShareManagePermission(this.ActiveUser, this.SharedByUserID, (u) => …)) {
|
|
39
|
+
* return true;
|
|
40
|
+
* }
|
|
41
|
+
* return super.CheckPermissions(type, throwError);
|
|
42
|
+
* }
|
|
43
|
+
* ```
|
|
44
|
+
*/
|
|
45
|
+
export declare function checkShareManagePermission(user: UserInfo, grantorUserId: string | null | undefined, additional?: (userId: string) => boolean): boolean;
|
|
46
|
+
/**
|
|
47
|
+
* Post-save share-notification dispatcher for extended permission entities.
|
|
48
|
+
* Call immediately after `super.Save(options)` returns `true`:
|
|
49
|
+
*
|
|
50
|
+
* ```typescript
|
|
51
|
+
* const saved = await super.Save(options);
|
|
52
|
+
* if (saved) {
|
|
53
|
+
* await dispatchShareNotificationAfterSave(this, isNewShare, async (provider, grantorId) => {
|
|
54
|
+
* return { Provider: provider, ContextUser: this.ContextCurrentUser, … };
|
|
55
|
+
* });
|
|
56
|
+
* }
|
|
57
|
+
* return saved;
|
|
58
|
+
* ```
|
|
59
|
+
*
|
|
60
|
+
* Handles the boilerplate each previous implementation repeated:
|
|
61
|
+
* - bail on client-side saves (`ProviderType !== 'Database'`)
|
|
62
|
+
* - bail on updates (`isNewShare === false`)
|
|
63
|
+
* - resolve the effective grantor ID (falls back to ContextCurrentUser.ID)
|
|
64
|
+
* - let `payloadBuilder` return `null` to skip (e.g., Role-grantee ACRs)
|
|
65
|
+
* - fire-and-forget via `void CreateShareNotification(...)` — notification
|
|
66
|
+
* failures never fail the save.
|
|
67
|
+
*/
|
|
68
|
+
export declare function dispatchShareNotificationAfterSave(entity: BaseEntity, isNewShare: boolean, grantorUserId: string | null | undefined, payloadBuilder: (provider: IMetadataProvider, grantorId: string) => Promise<ShareNotificationInput | null> | ShareNotificationInput | null): Promise<void>;
|
|
69
|
+
/**
|
|
70
|
+
* Turn `{ view: this.CanRead, edit: this.CanEdit, … }` into `"view, edit"`.
|
|
71
|
+
* Truthy verbs are emitted in declaration order. Replaces the hand-rolled
|
|
72
|
+
* `actionsSummary()` method each sharing entity used to carry.
|
|
73
|
+
*/
|
|
74
|
+
export declare function buildActionsSummary(flags: Record<string, boolean | null | undefined>): string;
|
|
75
|
+
/**
|
|
76
|
+
* Server-side gate for CREATING a new share. Blocks users who hold role-level
|
|
77
|
+
* `CanCreate` on a sharing entity but don't own the target resource and don't
|
|
78
|
+
* already hold a Share-capable grant on it.
|
|
79
|
+
*
|
|
80
|
+
* Separate from `checkShareManagePermission` (which handles Update/Delete) because
|
|
81
|
+
* Angular's default role-based check can't express "the caller owns the underlying
|
|
82
|
+
* resource" — that requires a resource-specific lookup.
|
|
83
|
+
*
|
|
84
|
+
* Usage in an extended entity's `Save()` override:
|
|
85
|
+
* ```typescript
|
|
86
|
+
* const isNewShare = !this.IsSaved;
|
|
87
|
+
* if (!assertCallerMayCreateShare(this, isNewShare, () => this.callerIsAuthorizedToShare())) {
|
|
88
|
+
* return false; // save is short-circuited; LatestResult carries the reason
|
|
89
|
+
* }
|
|
90
|
+
* const saved = await super.Save(options);
|
|
91
|
+
* ```
|
|
92
|
+
*
|
|
93
|
+
* Returns `true` when the save should proceed, `false` to short-circuit.
|
|
94
|
+
* On `false`, sets `entity.LatestResult` with `Success=false` and a user-visible
|
|
95
|
+
* `Message`, and emits a `LogError` for server logs.
|
|
96
|
+
*
|
|
97
|
+
* Short-circuits to `true` (allows the save) when:
|
|
98
|
+
* - `isNewShare` is false (not a create — Update/Delete handled by CheckPermissions)
|
|
99
|
+
* - provider is not the Database provider (client-side save, already trusted)
|
|
100
|
+
* - `entity.ContextCurrentUser` is missing (defer to downstream auth layers)
|
|
101
|
+
*/
|
|
102
|
+
export declare function assertCallerMayCreateShare(entity: BaseEntity, isNewShare: boolean, authorized: () => boolean | Promise<boolean>, reason?: string): Promise<boolean> | boolean;
|
|
103
|
+
/** Re-export for ergonomic `import { EntityPermissionType } from '...'` in subclasses. */
|
|
104
|
+
export { EntityPermissionType, EntitySaveOptions };
|
|
105
|
+
//# sourceMappingURL=BaseShareEntityExtended.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"BaseShareEntityExtended.d.ts","sourceRoot":"","sources":["../../../src/custom/Permissions/BaseShareEntityExtended.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,oBAAoB,EAAE,iBAAiB,EAAE,iBAAiB,EAAY,QAAQ,EAAE,MAAM,sBAAsB,CAAC;AAGlI,OAAO,EAA2B,sBAAsB,EAAE,MAAM,qBAAqB,CAAC;AAEtF;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AAEH;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAgB,0BAA0B,CACtC,IAAI,EAAE,QAAQ,EACd,aAAa,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,EACxC,UAAU,CAAC,EAAE,CAAC,MAAM,EAAE,MAAM,KAAK,OAAO,GACzC,OAAO,CAIT;AAED;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,wBAAsB,kCAAkC,CACpD,MAAM,EAAE,UAAU,EAClB,UAAU,EAAE,OAAO,EACnB,aAAa,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,EACxC,cAAc,EAAE,CAAC,QAAQ,EAAE,iBAAiB,EAAE,SAAS,EAAE,MAAM,KAAK,OAAO,CAAC,sBAAsB,GAAG,IAAI,CAAC,GAAG,sBAAsB,GAAG,IAAI,GAC3I,OAAO,CAAC,IAAI,CAAC,CAcf;AAED;;;;GAIG;AACH,wBAAgB,mBAAmB,CAAC,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,GAAG,IAAI,GAAG,SAAS,CAAC,GAAG,MAAM,CAM7F;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AACH,wBAAgB,0BAA0B,CACtC,MAAM,EAAE,UAAU,EAClB,UAAU,EAAE,OAAO,EACnB,UAAU,EAAE,MAAM,OAAO,GAAG,OAAO,CAAC,OAAO,CAAC,EAC5C,MAAM,GAAE,MAA0F,GACnG,OAAO,CAAC,OAAO,CAAC,GAAG,OAAO,CAY5B;AAgBD,0FAA0F;AAC1F,OAAO,EAAE,oBAAoB,EAAE,iBAAiB,EAAE,CAAC"}
|
|
@@ -0,0 +1,162 @@
|
|
|
1
|
+
import { EntityPermissionType, EntitySaveOptions, LogError } from '@memberjunction/core';
|
|
2
|
+
import { UUIDsEqual } from '@memberjunction/global';
|
|
3
|
+
import { CreateShareNotification } from './shareNotification.js';
|
|
4
|
+
/**
|
|
5
|
+
* Shared lifecycle for the four user-grantee sharing permission entities
|
|
6
|
+
* (Dashboard, Artifact, Collection, Access Control Rule). Each of those
|
|
7
|
+
* classes delegates three repetitive behaviors to the helpers in this module:
|
|
8
|
+
*
|
|
9
|
+
* 1. **Grantor Update/Delete relaxation** — {@link checkShareManagePermission}
|
|
10
|
+
* Lets the grantor (and, via the optional `additional` hook, resource owners
|
|
11
|
+
* or other privileged parties) revoke or edit their own grant without needing
|
|
12
|
+
* broader CRUD on the permission entity itself.
|
|
13
|
+
*
|
|
14
|
+
* 2. **Post-save share notification dispatch** — {@link dispatchShareNotificationAfterSave}
|
|
15
|
+
* After a successful server-side save of a new share, asks the caller for
|
|
16
|
+
* a notification payload and fires it off through `CreateShareNotification`.
|
|
17
|
+
* Returning `null` from the payload builder short-circuits (used by Access
|
|
18
|
+
* Control Rules for Role / Everyone grantees who have no single recipient).
|
|
19
|
+
*
|
|
20
|
+
* 3. **Action summary rendering** — {@link buildActionsSummary}
|
|
21
|
+
* Turns `{ view: this.CanRead, edit: this.CanEdit, … }` into `"view, edit"`.
|
|
22
|
+
*
|
|
23
|
+
* The original class inheritance shape is preserved (each extended class still
|
|
24
|
+
* extends its generated entity base) — these are plain functions the subclasses
|
|
25
|
+
* call from their `CheckPermissions` / `Save` overrides. We use functions rather
|
|
26
|
+
* than another class in the chain because each permission entity already has a
|
|
27
|
+
* fixed generated base, and multiple inheritance isn't available in TypeScript.
|
|
28
|
+
*/
|
|
29
|
+
/**
|
|
30
|
+
* Determine whether `user` may Update/Delete a share row they don't own via
|
|
31
|
+
* role permissions. Returns true when the user is the grantor, or when the
|
|
32
|
+
* optional `additional(userId)` predicate says they have some domain-specific
|
|
33
|
+
* management right (e.g., dashboard owner, Owner-level grantee).
|
|
34
|
+
*
|
|
35
|
+
* Use:
|
|
36
|
+
* ```typescript
|
|
37
|
+
* override CheckPermissions(type, throwError) {
|
|
38
|
+
* if ((type === Update || Delete) && this.ActiveUser &&
|
|
39
|
+
* checkShareManagePermission(this.ActiveUser, this.SharedByUserID, (u) => …)) {
|
|
40
|
+
* return true;
|
|
41
|
+
* }
|
|
42
|
+
* return super.CheckPermissions(type, throwError);
|
|
43
|
+
* }
|
|
44
|
+
* ```
|
|
45
|
+
*/
|
|
46
|
+
export function checkShareManagePermission(user, grantorUserId, additional) {
|
|
47
|
+
if (grantorUserId && UUIDsEqual(grantorUserId, user.ID))
|
|
48
|
+
return true;
|
|
49
|
+
if (additional && additional(user.ID))
|
|
50
|
+
return true;
|
|
51
|
+
return false;
|
|
52
|
+
}
|
|
53
|
+
/**
|
|
54
|
+
* Post-save share-notification dispatcher for extended permission entities.
|
|
55
|
+
* Call immediately after `super.Save(options)` returns `true`:
|
|
56
|
+
*
|
|
57
|
+
* ```typescript
|
|
58
|
+
* const saved = await super.Save(options);
|
|
59
|
+
* if (saved) {
|
|
60
|
+
* await dispatchShareNotificationAfterSave(this, isNewShare, async (provider, grantorId) => {
|
|
61
|
+
* return { Provider: provider, ContextUser: this.ContextCurrentUser, … };
|
|
62
|
+
* });
|
|
63
|
+
* }
|
|
64
|
+
* return saved;
|
|
65
|
+
* ```
|
|
66
|
+
*
|
|
67
|
+
* Handles the boilerplate each previous implementation repeated:
|
|
68
|
+
* - bail on client-side saves (`ProviderType !== 'Database'`)
|
|
69
|
+
* - bail on updates (`isNewShare === false`)
|
|
70
|
+
* - resolve the effective grantor ID (falls back to ContextCurrentUser.ID)
|
|
71
|
+
* - let `payloadBuilder` return `null` to skip (e.g., Role-grantee ACRs)
|
|
72
|
+
* - fire-and-forget via `void CreateShareNotification(...)` — notification
|
|
73
|
+
* failures never fail the save.
|
|
74
|
+
*/
|
|
75
|
+
export async function dispatchShareNotificationAfterSave(entity, isNewShare, grantorUserId, payloadBuilder) {
|
|
76
|
+
const provider = entity.ProviderToUse;
|
|
77
|
+
const isServerSide = provider?.ProviderType === 'Database';
|
|
78
|
+
if (!isServerSide || !isNewShare)
|
|
79
|
+
return;
|
|
80
|
+
const grantorId = grantorUserId ?? entity.ContextCurrentUser?.ID ?? null;
|
|
81
|
+
if (!grantorId)
|
|
82
|
+
return;
|
|
83
|
+
try {
|
|
84
|
+
const input = await payloadBuilder(provider, grantorId);
|
|
85
|
+
if (input)
|
|
86
|
+
void CreateShareNotification(input);
|
|
87
|
+
}
|
|
88
|
+
catch {
|
|
89
|
+
// Defensive: payload builder never fails the save.
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
/**
|
|
93
|
+
* Turn `{ view: this.CanRead, edit: this.CanEdit, … }` into `"view, edit"`.
|
|
94
|
+
* Truthy verbs are emitted in declaration order. Replaces the hand-rolled
|
|
95
|
+
* `actionsSummary()` method each sharing entity used to carry.
|
|
96
|
+
*/
|
|
97
|
+
export function buildActionsSummary(flags) {
|
|
98
|
+
const parts = [];
|
|
99
|
+
for (const [label, enabled] of Object.entries(flags)) {
|
|
100
|
+
if (enabled)
|
|
101
|
+
parts.push(label);
|
|
102
|
+
}
|
|
103
|
+
return parts.join(', ');
|
|
104
|
+
}
|
|
105
|
+
/**
|
|
106
|
+
* Server-side gate for CREATING a new share. Blocks users who hold role-level
|
|
107
|
+
* `CanCreate` on a sharing entity but don't own the target resource and don't
|
|
108
|
+
* already hold a Share-capable grant on it.
|
|
109
|
+
*
|
|
110
|
+
* Separate from `checkShareManagePermission` (which handles Update/Delete) because
|
|
111
|
+
* Angular's default role-based check can't express "the caller owns the underlying
|
|
112
|
+
* resource" — that requires a resource-specific lookup.
|
|
113
|
+
*
|
|
114
|
+
* Usage in an extended entity's `Save()` override:
|
|
115
|
+
* ```typescript
|
|
116
|
+
* const isNewShare = !this.IsSaved;
|
|
117
|
+
* if (!assertCallerMayCreateShare(this, isNewShare, () => this.callerIsAuthorizedToShare())) {
|
|
118
|
+
* return false; // save is short-circuited; LatestResult carries the reason
|
|
119
|
+
* }
|
|
120
|
+
* const saved = await super.Save(options);
|
|
121
|
+
* ```
|
|
122
|
+
*
|
|
123
|
+
* Returns `true` when the save should proceed, `false` to short-circuit.
|
|
124
|
+
* On `false`, sets `entity.LatestResult` with `Success=false` and a user-visible
|
|
125
|
+
* `Message`, and emits a `LogError` for server logs.
|
|
126
|
+
*
|
|
127
|
+
* Short-circuits to `true` (allows the save) when:
|
|
128
|
+
* - `isNewShare` is false (not a create — Update/Delete handled by CheckPermissions)
|
|
129
|
+
* - provider is not the Database provider (client-side save, already trusted)
|
|
130
|
+
* - `entity.ContextCurrentUser` is missing (defer to downstream auth layers)
|
|
131
|
+
*/
|
|
132
|
+
export function assertCallerMayCreateShare(entity, isNewShare, authorized, reason = 'Only the resource owner or someone with Share permission can create this share.') {
|
|
133
|
+
if (!isNewShare)
|
|
134
|
+
return true;
|
|
135
|
+
const provider = entity.ProviderToUse;
|
|
136
|
+
if (provider?.ProviderType !== 'Database')
|
|
137
|
+
return true;
|
|
138
|
+
const user = entity.ContextCurrentUser;
|
|
139
|
+
if (!user)
|
|
140
|
+
return true;
|
|
141
|
+
const result = authorized();
|
|
142
|
+
if (result instanceof Promise) {
|
|
143
|
+
return result.then((ok) => ok || failSave(entity, user, reason));
|
|
144
|
+
}
|
|
145
|
+
return result || failSave(entity, user, reason);
|
|
146
|
+
}
|
|
147
|
+
/**
|
|
148
|
+
* Fail-the-save helper: marks `LatestResult` so the UI sees the reason, logs
|
|
149
|
+
* server-side. Always returns `false` so callers can `return failSave(...)`.
|
|
150
|
+
*/
|
|
151
|
+
function failSave(entity, user, reason) {
|
|
152
|
+
LogError(`${entity.constructor.name}: user ${user.ID} (${user.Email ?? user.Name ?? 'unknown'}) blocked from creating share — ${reason}`);
|
|
153
|
+
const latest = entity.LatestResult;
|
|
154
|
+
if (latest) {
|
|
155
|
+
latest.Success = false;
|
|
156
|
+
latest.Message = reason;
|
|
157
|
+
}
|
|
158
|
+
return false;
|
|
159
|
+
}
|
|
160
|
+
/** Re-export for ergonomic `import { EntityPermissionType } from '...'` in subclasses. */
|
|
161
|
+
export { EntityPermissionType, EntitySaveOptions };
|
|
162
|
+
//# sourceMappingURL=BaseShareEntityExtended.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"BaseShareEntityExtended.js","sourceRoot":"","sources":["../../../src/custom/Permissions/BaseShareEntityExtended.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { EntityPermissionType, EntitySaveOptions } from '@memberjunction/core';
|
|
2
|
+
import { MJAccessControlRuleEntity } from '../../generated/entity_subclasses.js';
|
|
3
|
+
/**
|
|
4
|
+
* Extended Access Control Rule entity — same dual-purpose pattern as
|
|
5
|
+
* {@link MJDashboardPermissionEntityExtended}, with two differences:
|
|
6
|
+
*
|
|
7
|
+
* - Uses `GrantedByUserID` instead of `SharedByUserID` (ACR column naming).
|
|
8
|
+
* - Only notifies when `GranteeType === 'User'` and `GranteeID` is populated.
|
|
9
|
+
* Role / Everyone / Public grants don't have a single identifiable recipient,
|
|
10
|
+
* so the payload builder returns `null` to skip.
|
|
11
|
+
*
|
|
12
|
+
* Notifications use the generic `Records` Resource Type from the catalog because
|
|
13
|
+
* ACRs target arbitrary entities — there's no single ResourceType that fits.
|
|
14
|
+
*/
|
|
15
|
+
export declare class MJAccessControlRuleEntityExtended extends MJAccessControlRuleEntity {
|
|
16
|
+
CheckPermissions(type: EntityPermissionType, throwError: boolean): boolean;
|
|
17
|
+
Save(options?: EntitySaveOptions): Promise<boolean>;
|
|
18
|
+
private actionsSummary;
|
|
19
|
+
}
|
|
20
|
+
/** Tree-shaking prevention — referenced from the custom/Permissions barrel. */
|
|
21
|
+
export declare function LoadMJAccessControlRuleEntityExtended(): void;
|
|
22
|
+
//# sourceMappingURL=MJAccessControlRuleEntityExtended.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"MJAccessControlRuleEntityExtended.d.ts","sourceRoot":"","sources":["../../../src/custom/Permissions/MJAccessControlRuleEntityExtended.ts"],"names":[],"mappings":"AAAA,OAAO,EAAc,oBAAoB,EAAE,iBAAiB,EAAY,MAAM,sBAAsB,CAAC;AAGrG,OAAO,EAAE,yBAAyB,EAAE,MAAM,mCAAmC,CAAC;AAO9E;;;;;;;;;;;GAWG;AACH,qBACa,iCAAkC,SAAQ,yBAAyB;IACnE,gBAAgB,CAAC,IAAI,EAAE,oBAAoB,EAAE,UAAU,EAAE,OAAO,GAAG,OAAO;IAQpE,IAAI,CAAC,OAAO,CAAC,EAAE,iBAAiB,GAAG,OAAO,CAAC,OAAO,CAAC;IA0BlE,OAAO,CAAC,cAAc;CASzB;AAED,+EAA+E;AAC/E,wBAAgB,qCAAqC,IAAI,IAAI,CAE5D"}
|
|
@@ -0,0 +1,75 @@
|
|
|
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, Metadata } from '@memberjunction/core';
|
|
8
|
+
import { RegisterClass, UUIDsEqual } from '@memberjunction/global';
|
|
9
|
+
import { MJAccessControlRuleEntity } from '../../generated/entity_subclasses.js';
|
|
10
|
+
import { buildActionsSummary, checkShareManagePermission, dispatchShareNotificationAfterSave, } from './BaseShareEntityExtended.js';
|
|
11
|
+
/**
|
|
12
|
+
* Extended Access Control Rule entity — same dual-purpose pattern as
|
|
13
|
+
* {@link MJDashboardPermissionEntityExtended}, with two differences:
|
|
14
|
+
*
|
|
15
|
+
* - Uses `GrantedByUserID` instead of `SharedByUserID` (ACR column naming).
|
|
16
|
+
* - Only notifies when `GranteeType === 'User'` and `GranteeID` is populated.
|
|
17
|
+
* Role / Everyone / Public grants don't have a single identifiable recipient,
|
|
18
|
+
* so the payload builder returns `null` to skip.
|
|
19
|
+
*
|
|
20
|
+
* Notifications use the generic `Records` Resource Type from the catalog because
|
|
21
|
+
* ACRs target arbitrary entities — there's no single ResourceType that fits.
|
|
22
|
+
*/
|
|
23
|
+
let MJAccessControlRuleEntityExtended = class MJAccessControlRuleEntityExtended extends MJAccessControlRuleEntity {
|
|
24
|
+
CheckPermissions(type, throwError) {
|
|
25
|
+
if (type === EntityPermissionType.Update || type === EntityPermissionType.Delete) {
|
|
26
|
+
const user = this.ActiveUser;
|
|
27
|
+
if (user && checkShareManagePermission(user, this.GrantedByUserID))
|
|
28
|
+
return true;
|
|
29
|
+
}
|
|
30
|
+
return super.CheckPermissions(type, throwError);
|
|
31
|
+
}
|
|
32
|
+
async Save(options) {
|
|
33
|
+
const isNewShare = !this.IsSaved;
|
|
34
|
+
const saved = await super.Save(options);
|
|
35
|
+
if (saved) {
|
|
36
|
+
await dispatchShareNotificationAfterSave(this, isNewShare, this.GrantedByUserID, (provider, grantorId) => {
|
|
37
|
+
// Only user grantees get individual notifications.
|
|
38
|
+
if (this.GranteeType !== 'User' || !this.GranteeID)
|
|
39
|
+
return null;
|
|
40
|
+
const entityInfo = new Metadata().Entities.find((e) => UUIDsEqual(e.ID, this.EntityID));
|
|
41
|
+
return {
|
|
42
|
+
Provider: provider,
|
|
43
|
+
ContextUser: this.ContextCurrentUser,
|
|
44
|
+
GrantorUserID: grantorId,
|
|
45
|
+
GranteeUserID: this.GranteeID,
|
|
46
|
+
ResourceTypeLabel: entityInfo?.Name ?? 'Record',
|
|
47
|
+
ResourceTypeName: 'Records',
|
|
48
|
+
ResourceName: null,
|
|
49
|
+
ResourceRecordID: this.RecordID,
|
|
50
|
+
ActionsSummary: this.actionsSummary(),
|
|
51
|
+
ExtraConfiguration: { AccessControlRuleID: this.ID, EntityID: this.EntityID },
|
|
52
|
+
};
|
|
53
|
+
});
|
|
54
|
+
}
|
|
55
|
+
return saved;
|
|
56
|
+
}
|
|
57
|
+
actionsSummary() {
|
|
58
|
+
return buildActionsSummary({
|
|
59
|
+
view: this.CanRead,
|
|
60
|
+
create: this.CanCreate,
|
|
61
|
+
edit: this.CanUpdate,
|
|
62
|
+
delete: this.CanDelete,
|
|
63
|
+
share: this.CanShare,
|
|
64
|
+
});
|
|
65
|
+
}
|
|
66
|
+
};
|
|
67
|
+
MJAccessControlRuleEntityExtended = __decorate([
|
|
68
|
+
RegisterClass(BaseEntity, 'MJ: Access Control Rules')
|
|
69
|
+
], MJAccessControlRuleEntityExtended);
|
|
70
|
+
export { MJAccessControlRuleEntityExtended };
|
|
71
|
+
/** Tree-shaking prevention — referenced from the custom/Permissions barrel. */
|
|
72
|
+
export function LoadMJAccessControlRuleEntityExtended() {
|
|
73
|
+
// intentionally empty
|
|
74
|
+
}
|
|
75
|
+
//# sourceMappingURL=MJAccessControlRuleEntityExtended.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"MJAccessControlRuleEntityExtended.js","sourceRoot":"","sources":["../../../src/custom/Permissions/MJAccessControlRuleEntityExtended.ts"],"names":[],"mappings":";;;;;;AAAA,OAAO,EAAE,UAAU,EAAE,oBAAoB,EAAqB,QAAQ,EAAE,MAAM,sBAAsB,CAAC;AACrG,OAAO,EAAE,aAAa,EAAE,UAAU,EAAE,MAAM,wBAAwB,CAAC;AAEnE,OAAO,EAAE,yBAAyB,EAAE,MAAM,mCAAmC,CAAC;AAC9E,OAAO,EACH,mBAAmB,EACnB,0BAA0B,EAC1B,kCAAkC,GACrC,MAAM,2BAA2B,CAAC;AAEnC;;;;;;;;;;;GAWG;AAEI,IAAM,iCAAiC,GAAvC,MAAM,iCAAkC,SAAQ,yBAAyB;IACnE,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,eAAe,CAAC;gBAAE,OAAO,IAAI,CAAC;QACpF,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,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,eAAe,EAAE,CAAC,QAAQ,EAAE,SAAS,EAAE,EAAE;gBACrG,mDAAmD;gBACnD,IAAI,IAAI,CAAC,WAAW,KAAK,MAAM,IAAI,CAAC,IAAI,CAAC,SAAS;oBAAE,OAAO,IAAI,CAAC;gBAEhE,MAAM,UAAU,GAAG,IAAI,QAAQ,EAAE,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,UAAU,CAAC,CAAC,CAAC,EAAE,EAAE,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC;gBACxF,OAAO;oBACH,QAAQ,EAAE,QAAQ;oBAClB,WAAW,EAAE,IAAI,CAAC,kBAAkB;oBACpC,aAAa,EAAE,SAAS;oBACxB,aAAa,EAAE,IAAI,CAAC,SAAS;oBAC7B,iBAAiB,EAAE,UAAU,EAAE,IAAI,IAAI,QAAQ;oBAC/C,gBAAgB,EAAE,SAAS;oBAC3B,YAAY,EAAE,IAAI;oBAClB,gBAAgB,EAAE,IAAI,CAAC,QAAQ;oBAC/B,cAAc,EAAE,IAAI,CAAC,cAAc,EAAE;oBACrC,kBAAkB,EAAE,EAAE,mBAAmB,EAAE,IAAI,CAAC,EAAE,EAAE,QAAQ,EAAE,IAAI,CAAC,QAAQ,EAAE;iBAChF,CAAC;YACN,CAAC,CAAC,CAAC;QACP,CAAC;QACD,OAAO,KAAK,CAAC;IACjB,CAAC;IAEO,cAAc;QAClB,OAAO,mBAAmB,CAAC;YACvB,IAAI,EAAE,IAAI,CAAC,OAAO;YAClB,MAAM,EAAE,IAAI,CAAC,SAAS;YACtB,IAAI,EAAE,IAAI,CAAC,SAAS;YACpB,MAAM,EAAE,IAAI,CAAC,SAAS;YACtB,KAAK,EAAE,IAAI,CAAC,QAAQ;SACvB,CAAC,CAAC;IACP,CAAC;CACJ,CAAA;AA5CY,iCAAiC;IAD7C,aAAa,CAAC,UAAU,EAAE,0BAA0B,CAAC;GACzC,iCAAiC,CA4C7C;;AAED,+EAA+E;AAC/E,MAAM,UAAU,qCAAqC;IACjD,sBAAsB;AAC1B,CAAC"}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { EntityPermissionType, EntitySaveOptions } from '@memberjunction/core';
|
|
2
|
+
import { MJArtifactPermissionEntity } from '../../generated/entity_subclasses.js';
|
|
3
|
+
/**
|
|
4
|
+
* Extended Artifact Permission entity — same dual-purpose pattern as
|
|
5
|
+
* {@link MJDashboardPermissionEntityExtended}. See that class for rationale.
|
|
6
|
+
*/
|
|
7
|
+
export declare class MJArtifactPermissionEntityExtended extends MJArtifactPermissionEntity {
|
|
8
|
+
CheckPermissions(type: EntityPermissionType, throwError: boolean): boolean;
|
|
9
|
+
Save(options?: EntitySaveOptions): Promise<boolean>;
|
|
10
|
+
private actionsSummary;
|
|
11
|
+
/**
|
|
12
|
+
* Authorization for CREATING a new ArtifactPermission row.
|
|
13
|
+
* Same pattern as MJDashboardPermissionEntityExtended.callerMayShareDashboard
|
|
14
|
+
* but without an in-memory engine — we fetch the artifact and the caller's
|
|
15
|
+
* existing grant row directly.
|
|
16
|
+
*/
|
|
17
|
+
private callerMayShareArtifact;
|
|
18
|
+
private fetchArtifactName;
|
|
19
|
+
}
|
|
20
|
+
/** Tree-shaking prevention — referenced from the custom/Permissions barrel. */
|
|
21
|
+
export declare function LoadMJArtifactPermissionEntityExtended(): void;
|
|
22
|
+
//# sourceMappingURL=MJArtifactPermissionEntityExtended.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"MJArtifactPermissionEntityExtended.d.ts","sourceRoot":"","sources":["../../../src/custom/Permissions/MJArtifactPermissionEntityExtended.ts"],"names":[],"mappings":"AAAA,OAAO,EAAc,oBAAoB,EAAE,iBAAiB,EAAW,MAAM,sBAAsB,CAAC;AAGpG,OAAO,EAAE,0BAA0B,EAAE,MAAM,mCAAmC,CAAC;AAQ/E;;;GAGG;AACH,qBACa,kCAAmC,SAAQ,0BAA0B;IACrE,gBAAgB,CAAC,IAAI,EAAE,oBAAoB,EAAE,UAAU,EAAE,OAAO,GAAG,OAAO;IAQpE,IAAI,CAAC,OAAO,CAAC,EAAE,iBAAiB,GAAG,OAAO,CAAC,OAAO,CAAC;IAgClE,OAAO,CAAC,cAAc;IAStB;;;;;OAKG;YACW,sBAAsB;YA6BtB,iBAAiB;CAWlC;AAED,+EAA+E;AAC/E,wBAAgB,sCAAsC,IAAI,IAAI,CAE7D"}
|
|
@@ -0,0 +1,114 @@
|
|
|
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 { MJArtifactPermissionEntity } from '../../generated/entity_subclasses.js';
|
|
10
|
+
import { assertCallerMayCreateShare, buildActionsSummary, checkShareManagePermission, dispatchShareNotificationAfterSave, } from './BaseShareEntityExtended.js';
|
|
11
|
+
/**
|
|
12
|
+
* Extended Artifact Permission entity — same dual-purpose pattern as
|
|
13
|
+
* {@link MJDashboardPermissionEntityExtended}. See that class for rationale.
|
|
14
|
+
*/
|
|
15
|
+
let MJArtifactPermissionEntityExtended = class MJArtifactPermissionEntityExtended extends MJArtifactPermissionEntity {
|
|
16
|
+
CheckPermissions(type, throwError) {
|
|
17
|
+
if (type === EntityPermissionType.Update || type === EntityPermissionType.Delete) {
|
|
18
|
+
const user = this.ActiveUser;
|
|
19
|
+
if (user && checkShareManagePermission(user, this.SharedByUserID))
|
|
20
|
+
return true;
|
|
21
|
+
}
|
|
22
|
+
return super.CheckPermissions(type, throwError);
|
|
23
|
+
}
|
|
24
|
+
async Save(options) {
|
|
25
|
+
const isNewShare = !this.IsSaved;
|
|
26
|
+
const allowed = await assertCallerMayCreateShare(this, isNewShare, () => this.callerMayShareArtifact(), 'Only the artifact owner or someone with Share permission on this artifact can create a new share.');
|
|
27
|
+
if (!allowed)
|
|
28
|
+
return false;
|
|
29
|
+
const saved = await super.Save(options);
|
|
30
|
+
if (saved) {
|
|
31
|
+
await dispatchShareNotificationAfterSave(this, isNewShare, this.SharedByUserID, async (provider, grantorId) => {
|
|
32
|
+
// The Artifact view doesn't denormalize Name onto the permission row — look it up.
|
|
33
|
+
const artifactName = await this.fetchArtifactName();
|
|
34
|
+
return {
|
|
35
|
+
Provider: provider,
|
|
36
|
+
ContextUser: this.ContextCurrentUser,
|
|
37
|
+
GrantorUserID: grantorId,
|
|
38
|
+
GranteeUserID: this.UserID,
|
|
39
|
+
ResourceTypeLabel: 'Artifact',
|
|
40
|
+
ResourceTypeName: 'Artifacts',
|
|
41
|
+
ResourceName: artifactName,
|
|
42
|
+
ResourceRecordID: this.ArtifactID,
|
|
43
|
+
ActionsSummary: this.actionsSummary(),
|
|
44
|
+
ExtraConfiguration: { PermissionID: this.ID },
|
|
45
|
+
};
|
|
46
|
+
});
|
|
47
|
+
}
|
|
48
|
+
return saved;
|
|
49
|
+
}
|
|
50
|
+
actionsSummary() {
|
|
51
|
+
return buildActionsSummary({
|
|
52
|
+
view: this.CanRead,
|
|
53
|
+
edit: this.CanEdit,
|
|
54
|
+
delete: this.CanDelete,
|
|
55
|
+
share: this.CanShare,
|
|
56
|
+
});
|
|
57
|
+
}
|
|
58
|
+
/**
|
|
59
|
+
* Authorization for CREATING a new ArtifactPermission row.
|
|
60
|
+
* Same pattern as MJDashboardPermissionEntityExtended.callerMayShareDashboard
|
|
61
|
+
* but without an in-memory engine — we fetch the artifact and the caller's
|
|
62
|
+
* existing grant row directly.
|
|
63
|
+
*/
|
|
64
|
+
async callerMayShareArtifact() {
|
|
65
|
+
const user = this.ContextCurrentUser;
|
|
66
|
+
if (!user)
|
|
67
|
+
return false;
|
|
68
|
+
const rv = new RunView();
|
|
69
|
+
// One round-trip: fetch the artifact's owner AND any existing Share-capable
|
|
70
|
+
// permission row for this caller on this artifact.
|
|
71
|
+
const [ownerResult, grantResult] = await rv.RunViews([
|
|
72
|
+
{
|
|
73
|
+
EntityName: 'MJ: Artifacts',
|
|
74
|
+
ExtraFilter: `ID='${this.ArtifactID}'`,
|
|
75
|
+
Fields: ['ID', 'UserID'],
|
|
76
|
+
MaxRows: 1,
|
|
77
|
+
ResultType: 'simple',
|
|
78
|
+
},
|
|
79
|
+
{
|
|
80
|
+
EntityName: 'MJ: Artifact Permissions',
|
|
81
|
+
ExtraFilter: `ArtifactID='${this.ArtifactID}' AND UserID='${user.ID}' AND CanShare=1`,
|
|
82
|
+
Fields: ['ID'],
|
|
83
|
+
MaxRows: 1,
|
|
84
|
+
ResultType: 'simple',
|
|
85
|
+
},
|
|
86
|
+
]);
|
|
87
|
+
const ownerId = ownerResult.Success
|
|
88
|
+
? ownerResult.Results?.[0]?.UserID
|
|
89
|
+
: undefined;
|
|
90
|
+
if (ownerId && UUIDsEqual(ownerId, user.ID))
|
|
91
|
+
return true;
|
|
92
|
+
return grantResult.Success && (grantResult.Results?.length ?? 0) > 0;
|
|
93
|
+
}
|
|
94
|
+
async fetchArtifactName() {
|
|
95
|
+
const rv = new RunView();
|
|
96
|
+
const result = await rv.RunView({
|
|
97
|
+
EntityName: 'MJ: Artifacts',
|
|
98
|
+
ExtraFilter: `ID='${this.ArtifactID}'`,
|
|
99
|
+
Fields: ['ID', 'Name'],
|
|
100
|
+
MaxRows: 1,
|
|
101
|
+
ResultType: 'simple',
|
|
102
|
+
});
|
|
103
|
+
return result.Success ? result.Results?.[0]?.Name ?? null : null;
|
|
104
|
+
}
|
|
105
|
+
};
|
|
106
|
+
MJArtifactPermissionEntityExtended = __decorate([
|
|
107
|
+
RegisterClass(BaseEntity, 'MJ: Artifact Permissions')
|
|
108
|
+
], MJArtifactPermissionEntityExtended);
|
|
109
|
+
export { MJArtifactPermissionEntityExtended };
|
|
110
|
+
/** Tree-shaking prevention — referenced from the custom/Permissions barrel. */
|
|
111
|
+
export function LoadMJArtifactPermissionEntityExtended() {
|
|
112
|
+
// intentionally empty
|
|
113
|
+
}
|
|
114
|
+
//# sourceMappingURL=MJArtifactPermissionEntityExtended.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"MJArtifactPermissionEntityExtended.js","sourceRoot":"","sources":["../../../src/custom/Permissions/MJArtifactPermissionEntityExtended.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { EntityPermissionType, EntitySaveOptions } from '@memberjunction/core';
|
|
2
|
+
import { MJCollectionPermissionEntity } from '../../generated/entity_subclasses.js';
|
|
3
|
+
/**
|
|
4
|
+
* Extended Collection Permission entity — same dual-purpose pattern as
|
|
5
|
+
* {@link MJDashboardPermissionEntityExtended}. See that class for rationale.
|
|
6
|
+
*
|
|
7
|
+
* Note: Collections have no entry in the `MJ: Resource Type` catalog, so
|
|
8
|
+
* `ResourceTypeName` is omitted and the notification's `ResourceTypeID` is
|
|
9
|
+
* left null. The bell icon still shows the title/message; click-through
|
|
10
|
+
* deep-linking can be added later if a Collection ResourceType is seeded.
|
|
11
|
+
*/
|
|
12
|
+
export declare class MJCollectionPermissionEntityExtended extends MJCollectionPermissionEntity {
|
|
13
|
+
CheckPermissions(type: EntityPermissionType, throwError: boolean): boolean;
|
|
14
|
+
Save(options?: EntitySaveOptions): Promise<boolean>;
|
|
15
|
+
private actionsSummary;
|
|
16
|
+
/**
|
|
17
|
+
* Authorization for CREATING a new CollectionPermission row. Caller must
|
|
18
|
+
* be the collection owner or hold an existing Share-capable grant. Same
|
|
19
|
+
* two-query pattern as {@link MJArtifactPermissionEntityExtended.callerMayShareArtifact}.
|
|
20
|
+
*/
|
|
21
|
+
private callerMayShareCollection;
|
|
22
|
+
}
|
|
23
|
+
/** Tree-shaking prevention — referenced from the custom/Permissions barrel. */
|
|
24
|
+
export declare function LoadMJCollectionPermissionEntityExtended(): void;
|
|
25
|
+
//# sourceMappingURL=MJCollectionPermissionEntityExtended.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"MJCollectionPermissionEntityExtended.d.ts","sourceRoot":"","sources":["../../../src/custom/Permissions/MJCollectionPermissionEntityExtended.ts"],"names":[],"mappings":"AAAA,OAAO,EAAc,oBAAoB,EAAE,iBAAiB,EAAW,MAAM,sBAAsB,CAAC;AAGpG,OAAO,EAAE,4BAA4B,EAAE,MAAM,mCAAmC,CAAC;AAQjF;;;;;;;;GAQG;AACH,qBACa,oCAAqC,SAAQ,4BAA4B;IACzE,gBAAgB,CAAC,IAAI,EAAE,oBAAoB,EAAE,UAAU,EAAE,OAAO,GAAG,OAAO;IAQpE,IAAI,CAAC,OAAO,CAAC,EAAE,iBAAiB,GAAG,OAAO,CAAC,OAAO,CAAC;IA4BlE,OAAO,CAAC,cAAc;IAStB;;;;OAIG;YACW,wBAAwB;CA0BzC;AAED,+EAA+E;AAC/E,wBAAgB,wCAAwC,IAAI,IAAI,CAE/D"}
|