Skip to content

Commit 4aa94d1

Browse files
authored
Feature/custom permission helper (#49)
* feature: Custom Permission Helper package Salesforce har en fungerende metode for å sjekke en custom permission, men det er en del scenarioer den ikke dekker. Denne pakken forsøker å løse dette.
1 parent 53b8d1b commit 4aa94d1

12 files changed

+940
-0
lines changed

sfdx-project.json

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,13 @@
2222
"default": false,
2323
"package": "custom-metadata-dao",
2424
"versionDescription": "Custom Metadata Data Access Object class used to get access to Custom Metadata objects, and at the same time make it easier to test the various paths the code can take based on the values in the Custom Metadata."
25+
},
26+
{
27+
"versionNumber": "0.1.0.NEXT",
28+
"path": "src/platform-utility/custom-permission-helper",
29+
"default": false,
30+
"package": "custom-permission-helper",
31+
"versionDescription": "Custom Permission Helper class used to get access to Custom Permissions, and at the same time make it easier to test the various paths the code can take based on the values in the Custom Permissions."
2532
}
2633
],
2734
"packageAliases": {
Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
# custom-permission-helper
2+
3+
Denne pakken inneholder en hjelpeklasse for å håndtere custom permissions.
4+
5+
Salesforce har fra før metoden `FeatureManagement.checkPermission` som kan sjekke dette, men den er begrenset til å kun kjøre for running user og kan heller ikke mockes/stubbes. Denne har også muligheten til å verifisere om en custom setting eksisterer (eller om du skriver inn feil navn).
6+
7+
Hjelpeklassen her er tiltenkt å brukes når:
8+
9+
- Sjekke flere custom permissions.
10+
- Sjekke custom permissions i en test kontekts
11+
- Sjelle custom permissions for andre enn kjørende bruker.
12+
13+
## Hvordan ta i bruk
14+
15+
I utgangspunktet så er det bare å kalle på klassen og starte å bruke public metodene. En ting å være klar over er at man må kalle på `setCustomPermissionsMaps()` dersom man skal benytte seg av en del av metodene. Om ikke vil det kastes en exception.
16+
17+
### Eksempler
18+
19+
#### Sjekke en custom permissison
20+
21+
```java
22+
// Check if running user has the custom permission
23+
new CustomPermissionHelper().hasCustomPermission('MyPermission');
24+
```
25+
26+
#### Sjekke en custom permissison for en annen bruker
27+
28+
```java
29+
new CustomPermissionHelper()
30+
.setCustomPermissionMaps() // Load all custom permissions
31+
.validateCustomPermission('MyPermission') // Validate that the custom permission exists
32+
.hasCustomPermission(userId, 'MyPermission'); // Check if the user has the custom permission
33+
```
34+
35+
#### Få liste over _mine_ custom permissions
36+
37+
```java
38+
CustomPermissionHelper().setCustomPermissionMaps().;
39+
```
40+
41+
### Bruke stub klassen i testing
42+
43+
Stub klassen implementerer `System.StubProvider` og kan brukes til å mocke responsen fra `CustomPermissionHelper`.
44+
45+
I stub klassen kan man på forhånd sette verdiene sånn at man enkelt kan kjøre testene.
46+
47+
Resultatene legges inn i en liste, noe som muliggjør at man kan lage en mock som returnerer ulike verdier iløpet av en kjøring.
48+
49+
```java
50+
CustomPermissionHelperStub stub = new CustomPermissionHelperStub();
51+
stub.addHasCustomPermission(true);
52+
CustomPermissionHelper customPermissionHelper = stub.getMock();
53+
54+
System.Assert.isTrue(customPermissionHelper.hasCustomPermission('MyPermission'));
55+
```
56+
57+
Alternativt hvor man ønsker flere ulike responser etter hverandre:
58+
59+
```java
60+
CustomPermissionHelper customPermissionHelper = new CustomPermissionHelperStub()
61+
.addHasCustomPermission(true)
62+
.addHasCustomPermission(false)
63+
.addHasCustomPermission(true)
64+
.getMock();
65+
66+
System.Assert.isTrue(customPermissionHelper.hasCustomPermission('MyPermission'));
67+
System.Assert.isFalse(customPermissionHelper.hasCustomPermission('MyPermission'));
68+
System.Assert.isTrue(customPermissionHelper.hasCustomPermission('MyPermission'));
69+
```
Lines changed: 210 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,210 @@
1+
/**
2+
* @description Helper class for checking custom permissions.
3+
* The easiest way to check if the running user has permsissions is to use the `FeatureManagement.checkPermission` method.
4+
* This class is intended to be used when you need to check:
5+
* - Multiple custom permissions.
6+
* - Custom permissions in a test context.
7+
* - Custom permissions for a different user than the running user.
8+
*
9+
* @author Tor Håkon Sigurdsen
10+
* @since 0.1.0, March 2025
11+
* @group Custom Permission Helper
12+
* @example
13+
* Eksempel på bruk:
14+
* ```
15+
* Set<String> myCustomPermissionsSet = new CustomPermissionHelper().setCustomPermissionMaps().getAssignedCustomPermissions();
16+
* ```
17+
*/
18+
public inherited sharing class CustomPermissionHelper {
19+
@TestVisible
20+
private Map<Id, Set<String>> usersCustomPermissionsMap;
21+
@TestVisible
22+
private Map<Id, CustomPermission> customPermissionMapById;
23+
@TestVisible
24+
private Map<String, CustomPermission> customPermissionMapByDeveloperName;
25+
26+
/**
27+
* @description Load all custom permissions into maps.
28+
*
29+
* @author Tor Håkon Sigurdsen
30+
* @since 0.1.0, March 2025
31+
* @return `CustomPermissionHelper` instance
32+
*/
33+
public CustomPermissionHelper setCustomPermissionMaps() {
34+
return this.setCustomPermissionMaps(
35+
[SELECT Id, DeveloperName FROM CustomPermission LIMIT 1000]
36+
);
37+
}
38+
39+
/**
40+
* @description Load all custom permissions into maps.
41+
*
42+
* @author Tor Håkon Sigurdsen
43+
* @since 0.1.0, March 2025
44+
* @param customPermissions List of custom permissions to load into the maps
45+
* @return `CustomPermissionHelper` instance
46+
*/
47+
public CustomPermissionHelper setCustomPermissionMaps(
48+
List<CustomPermission> customPermissions
49+
) {
50+
customPermissionMapById = new Map<Id, CustomPermission>();
51+
customPermissionMapByDeveloperName = new Map<String, CustomPermission>();
52+
for (CustomPermission customPermission : customPermissions) {
53+
customPermissionMapById.put(customPermission.Id, customPermission);
54+
customPermissionMapByDeveloperName.put(
55+
customPermission.DeveloperName,
56+
customPermission
57+
);
58+
}
59+
return this;
60+
}
61+
62+
/**
63+
* @description Validate that the custom permission exists. If not, throw an exception.
64+
*
65+
* @author Tor Håkon Sigurdsen
66+
* @since 0.1.0, March 2025
67+
* @param customPermissionDeveloperName Developer name of the custom permission to validate
68+
* @return self for chaining
69+
* @exception Throws `CustomPermissionHelperException` if custom permission with developer name is not found
70+
*/
71+
public CustomPermissionHelper validateCustomPermission(
72+
String customPermissionDeveloperName
73+
) {
74+
if (
75+
!customPermissionMapByDeveloperName.containsKey(
76+
customPermissionDeveloperName
77+
)
78+
) {
79+
throw new CustomPermissionHelperException(
80+
'Custom Permission with Developer Name ' +
81+
customPermissionDeveloperName +
82+
' not found'
83+
);
84+
}
85+
return this;
86+
}
87+
88+
/**
89+
* @description Get the running users assigned custom permissions
90+
*
91+
* @author Tor Håkon Sigurdsen
92+
* @since 0.1.0, March 2025
93+
* @return `Set<String>` containing the developer name of the assigned custom permissions
94+
*/
95+
public Set<String> getAssignedCustomPermissions() {
96+
return getAssignedCustomPermissions(UserInfo.getUserId());
97+
}
98+
99+
/**
100+
* @description get the assigned custom permissions for a user
101+
*
102+
* @author Tor Håkon Sigurdsen
103+
* @since 0.1.0, March 2025
104+
* @param userId of the user to get the assigned custom permissions for
105+
* @return `Set<String>` containing the developer name of the assigned custom permissions
106+
*/
107+
public Set<String> getAssignedCustomPermissions(Id userId) {
108+
if (!this.usersCustomPermissionsMap.containsKey(userId)) {
109+
setAssignedCustomPermissionsByUser(
110+
userId,
111+
this.getSetupEntityAccesses(userId)
112+
);
113+
}
114+
return this.usersCustomPermissionsMap.get(userId);
115+
}
116+
117+
/**
118+
* @description Check if the running user has a custom permission
119+
*
120+
* @author Tor Håkon Sigurdsen
121+
* @since 0.1.0, March 2025
122+
* @param customPermissionDeveloperName Developer name of the custom permission to check
123+
* @return `Boolean` indicating if the running user has the custom permission
124+
*/
125+
public Boolean hasCustomPermission(String customPermissionDeveloperName) {
126+
return FeatureManagement.checkPermission(customPermissionDeveloperName);
127+
}
128+
129+
/**
130+
* @description Check if a user has a custom permission
131+
*
132+
* @author Tor Håkon Sigurdsen
133+
* @since 0.1.0, March 2025
134+
* @param userId of the user to check the custom permission for
135+
* @param customPermissionDeveloperName Developer name of the custom permission to check
136+
* @return `Boolean` indicating if the user has the custom permission
137+
*/
138+
public Boolean hasCustomPermission(
139+
Id userId,
140+
String customPermissionDeveloperName
141+
) {
142+
return getAssignedCustomPermissions(userId)
143+
.contains(customPermissionDeveloperName);
144+
}
145+
146+
/**
147+
* @description Load the assigned custom permissions for users
148+
*
149+
* @author Tor Håkon Sigurdsen
150+
* @since 0.1.0, March 2025
151+
* @param userId of the user to load the assigned custom permissions for
152+
* @param setupEntityAccessesList List of SetupEntityAccess objects for the users
153+
* @return `CustomPermissionHelper` instance
154+
*/
155+
@TestVisible
156+
private CustomPermissionHelper setAssignedCustomPermissionsByUser(
157+
Id userId,
158+
List<SetupEntityAccess> setupEntityAccessesList
159+
) {
160+
if (usersCustomPermissionsMap == null) {
161+
usersCustomPermissionsMap = new Map<Id, Set<String>>();
162+
}
163+
164+
usersCustomPermissionsMap.put(userId, new Set<String>());
165+
for (SetupEntityAccess setupEntityAccess : setupEntityAccessesList) {
166+
if (
167+
customPermissionMapById == null ||
168+
!customPermissionMapById.containsKey(
169+
setupEntityAccess.SetupEntityId
170+
)
171+
) {
172+
throw new CustomPermissionHelperException(
173+
'Could not map Custom Permissions to user. Custom Permission with Id ' +
174+
setupEntityAccess.SetupEntityId +
175+
' not found. Try calling setCustomPermissionMaps() first.'
176+
);
177+
}
178+
usersCustomPermissionsMap.get(userId)
179+
.add(
180+
customPermissionMapById.get(setupEntityAccess.SetupEntityId)
181+
.DeveloperName
182+
);
183+
}
184+
return this;
185+
}
186+
187+
/**
188+
* @description Get the SetupEntityAccess objects for the provided user
189+
*
190+
* @author Tor Håkon Sigurdsen
191+
* @since 0.1.0, March 2025
192+
* @param userId of the user to get the SetupEntityAccess objects for
193+
* @return `List<SetupEntityAccess>` containing the SetupEntityAccess objects for the provided users
194+
*/
195+
@TestVisible
196+
private List<SetupEntityAccess> getSetupEntityAccesses(Id userId) {
197+
return [
198+
SELECT SetupEntityId
199+
FROM SetupEntityAccess
200+
WHERE
201+
SetupEntityId IN :customPermissionMapById.keySet()
202+
AND ParentId IN (
203+
SELECT PermissionSetId
204+
FROM PermissionSetAssignment
205+
WHERE AssigneeId = :userId
206+
)
207+
WITH SECURITY_ENFORCED
208+
];
209+
}
210+
}
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<ApexClass xmlns="http://soap.sforce.com/2006/04/metadata">
3+
<apiVersion>63.0</apiVersion>
4+
<status>Active</status>
5+
</ApexClass>
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
/**
2+
* @description Exception related to the package custom permission helper.
3+
*
4+
* @author Tor Håkon Sigurdsen
5+
* @since 0.1.0, March 2025
6+
*/
7+
public inherited sharing class CustomPermissionHelperException extends Exception {
8+
// Added in order to avoid no test coverage even if the exception class is used.
9+
// This is probably a bug in the Salesforce platform.
10+
private Boolean isCustomPermissionHelperException = true;
11+
}
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<ApexClass xmlns="http://soap.sforce.com/2006/04/metadata">
3+
<apiVersion>63.0</apiVersion>
4+
<status>Active</status>
5+
</ApexClass>

0 commit comments

Comments
 (0)