NotificationActionHandler Interface
Implement this interface to execute an action on a custom notification.
Namespace
NotificationActionHandler Methods
The following are methods for NotificationActionHandler.
executeAction(actionableNotification)
Executes the actionable notification.
Signature
public Messaging.ActionResult executeAction(Messaging.ActionableNotification actionableNotification)
Parameters
- actionableNotification
- Type: Messaging.ActionableNotification
- An actionable custom notification.
Return Value
Type: Messaging.ActionResult
NotificationActionHandler Example Implementation
This is an example implementation of the Messaging.NotificationActionHandler interface.
1global class CaseNotificationActionHandler implements Messaging.NotificationActionHandler {
2
3 private static final String ACTION_REASSIGN_TO_QUEUE = 'reassignToQueue';
4 private static final String DEFAULT_QUEUE_NAME = 'Queue_Exec'; // Default queue name, can be customized
5
6 global Messaging.ActionResult executeAction(Messaging.ActionableNotification actionableNotification) {
7 try {
8 String actionIdentifier = actionableNotification.getActionIdentifier();
9 String targetId = actionableNotification.getTargetId();
10
11 if (String.isBlank(actionIdentifier) || String.isBlank(targetId)) {
12 return new Messaging.ActionResult.Builder()
13 .withSuccess(false)
14 .withMessage('Action identifier and target ID are required')
15 .withErrorCode(Messaging.ActionError.INVALID_ACTION_PARAMETERS)
16 .build();
17 }
18
19 // Validate that targetId is a valid Case ID
20 if (!targetId.startsWith('500')) {
21 return new Messaging.ActionResult.Builder()
22 .withSuccess(false)
23 .withMessage('Target ID must be a valid Case ID')
24 .withErrorCode(Messaging.ActionError.INVALID_ACTION_PARAMETERS)
25 .build();
26 }
27
28 switch on actionIdentifier {
29 when 'reassignToQueue' {
30 return reassignCaseToQueue(targetId);
31 }
32 when else {
33 return new Messaging.ActionResult.Builder()
34 .withSuccess(false)
35 .withMessage('Unsupported action identifier: ' + actionIdentifier)
36 .withErrorCode(Messaging.ActionError.ACTION_NOT_IMPLEMENTED)
37 .build();
38 }
39 }
40 } catch (Exception e) {
41 return new Messaging.ActionResult.Builder()
42 .withSuccess(false)
43 .withMessage('An unexpected error occurred: ' + e.getMessage())
44 .withErrorCode(Messaging.ActionError.INTERNAL_ERROR)
45 .build();
46 }
47 }
48
49 private Messaging.ActionResult reassignCaseToQueue(String caseId) {
50 try {
51 // Query the case to ensure it exists
52 List<Case> cases = [SELECT Id, CaseNumber, OwnerId FROM Case WHERE Id = :caseId LIMIT 1];
53
54 if (cases.isEmpty()) {
55 return new Messaging.ActionResult.Builder()
56 .withSuccess(false)
57 .withMessage('Case not found with ID: ' + caseId)
58 .withErrorCode(Messaging.ActionError.INVALID_ACTION_PARAMETERS)
59 .build();
60 }
61
62 Case caseToUpdate = cases[0];
63
64 // Query for the queue to assign the case to
65 List<Group> queues = [SELECT Id, Name FROM Group WHERE Type = 'Queue' AND DeveloperName = :DEFAULT_QUEUE_NAME LIMIT 1];
66
67 if (queues.isEmpty()) {
68 return new Messaging.ActionResult.Builder()
69 .withSuccess(false)
70 .withMessage('Queue not found: ' + DEFAULT_QUEUE_NAME)
71 .withErrorCode(Messaging.ActionError.INVALID_STATE)
72 .build();
73 }
74
75 // Assign the case to the queue
76 caseToUpdate.OwnerId = queues[0].Id;
77 update caseToUpdate;
78
79 return new Messaging.ActionResult.Builder()
80 .withSuccess(true)
81 .withMessage('Case ' + caseToUpdate.CaseNumber + ' successfully assigned to queue: ' + DEFAULT_QUEUE_NAME)
82 .build();
83
84 } catch (DmlException e) {
85 return new Messaging.ActionResult.Builder()
86 .withSuccess(false)
87 .withMessage('Failed to update case: ' + e.getMessage())
88 .withErrorCode(Messaging.ActionError.ACCESS_DENIED)
89 .build();
90 } catch (Exception e) {
91 return new Messaging.ActionResult.Builder()
92 .withSuccess(false)
93 .withMessage('Error reassigning case to queue: ' + e.getMessage())
94 .withErrorCode(Messaging.ActionError.INTERNAL_ERROR)
95 .build();
96 }
97 }
98}The following example tests the implementation:
1@IsTest
2global class TestNotificationActionHandler {
3 @IsTest
4 static void testActionHandler() {
5
6 //Set up the data, for example creating a case
7 Case newCase = new Case(
8 Subject = 'Important Case',
9 Status = 'New',
10 Priority = 'High'
11 );
12 insert newCase;
13
14 //Set up Actionable Notification data
15 Messaging.ActionableNotification notification =
16 new Messaging.ActionableNotification.Builder()
17 .withNotificationTypeId('0MLXXXXXXXXXXXX4AC')
18 .withActionIdentifier('testAction')
19 .withRecipientId(UserInfo.getUserId())
20 .withSenderId(UserInfo.getUserId())
21 .withTargetId(newCase.Id)
22 .withTargetPageRef('/lightning/r/Case/' + newCase.Id + '/view')
23 .build();
24
25
26 Messaging.ActionResult result = Test.testNotificationActionHandler(new CaseNotificationActionHandler(), notification);
27
28 //Insert assert statements here to verify your action
29 }
30}