Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -1,15 +1,32 @@
/**
* Mock HTTP Callout class for testing mc_SubscriptionData
*
* Implements HttpCalloutMock to provide mock responses for HTTP callouts
* during test execution. This allows testing of the subscription data
* retrieval without making actual API calls.
*
* @author Andy Haas
*/
@isTest
global with sharing class SubscriptionData_MockHTTP implements HttpCalloutMock {
// Implement this interface method
global with sharing class SubscriptionData_MockHTTP implements HttpCalloutMock {
// API version constant for REST API calls (matches main class)
private static final String API_VERSION = 'v65.0';

/**
* Implement this interface method to provide mock HTTP responses
*
* @param req HTTPRequest object from the callout
* @return HTTPResponse Mock response with subscription data
*/
global HTTPResponse respond(HTTPRequest req) {
// Optionally, only send a mock response for a specific endpoint
// and method.
// Optionally, only send a mock response for a specific endpoint and method.
String expectedEndpoint = 'https://salesforce.com/services/data/' + API_VERSION + '/analytics/notifications?source=lightningReportSubscribe';
req.setEndpoint('https://salesforce.com/' +
'services/data/v55.0/analytics/' +
'services/data/' + API_VERSION + '/analytics/' +
'notifications?source=lightningReportSubscribe');
req.setMethod('GET');
System.assertEquals('https://salesforce.com/services/data/v55.0/analytics/notifications?source=lightningReportSubscribe', req.getEndpoint());
System.assertEquals('GET', req.getMethod());
System.assertEquals(expectedEndpoint, req.getEndpoint(), 'Endpoint should match expected value');
System.assertEquals('GET', req.getMethod(), 'HTTP method should be GET');

// Create a fake response
HttpResponse res = new HttpResponse();
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?>
<ApexClass xmlns="http://soap.sforce.com/2006/04/metadata">
<apiVersion>55.0</apiVersion>
<apiVersion>65.0</apiVersion>
<status>Active</status>
</ApexClass>

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?>
<ApexClass xmlns="http://soap.sforce.com/2006/04/metadata">
<apiVersion>55.0</apiVersion>
<apiVersion>65.0</apiVersion>
<status>Active</status>
</ApexClass>

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?>
<ApexClass xmlns="http://soap.sforce.com/2006/04/metadata">
<apiVersion>56.0</apiVersion>
<apiVersion>65.0</apiVersion>
<status>Active</status>
</ApexClass>
Original file line number Diff line number Diff line change
@@ -1,50 +1,114 @@
/**
* Flow Action: Parse Recipient Data
*
* Parses subscription definition JSON string to extract recipient information.
* This invocable action takes a serialized subscription definition and extracts
* the recipients list for use in Flow screens or other actions.
*
* @author Andy Haas
* @see https://unofficialsf.com/from-andy-haas-use-analytics-management-actions-to-show-report-subscribers-and-assignments/
*/
public with sharing class mc_GetRecipients {
@InvocableMethod(label='Parse Recipient Data' description='Parses the Recipient Data into usuable class for the flow' category='Analytic Subscription')
/**
* Invocable method to parse recipient data from subscription definition string
*
* @param requests List of Request objects containing definition_string (JSON)
* @return List<Results> List of Results containing recipients and notification details
*/
@InvocableMethod(label='Parse Recipient Data' description='Parses the Recipient Data into usable class for the flow' category='Analytic Subscription')
public static List<Results> mc_GetRecipients(List<Request> requests) {
System.debug('mc_GetRecipients: ' + requests);
System.debug('mc_GetRecipients: Processing ' + requests.size() + ' request(s)');

// Set Response Wrapper
List<Results> responseWrapper = new List<Results>();
// From the list of requests, get the recipients
List<mc_SubscriptionListDefinition_Recipients> recipients = new List<mc_SubscriptionListDefinition_Recipients>();


// Loop through the requests
for (Request request : requests) {
// Fix definition_string to remove [ and ]]
// Remove the first character
String definition_string = request.definition_string.substring(1);
// Remove the last character
definition_string = definition_string.substring(0, definition_string.length() - 1);

// Deserialize the request with SubscriptionListDefinition
mc_SubscriptionListDefinition subscriptionListDefinition = (mc_SubscriptionListDefinition)JSON.deserialize(definition_string, mc_SubscriptionListDefinition.class);

System.debug('mc_GetRecipients: subscriptionListDefinition: ' + subscriptionListDefinition);

Results response = new Results();

// Check if subscriptionListDefinition is not null and then if not then add to the response wrapper
if (subscriptionListDefinition != null) {
response.recipients_string = JSON.serialize(subscriptionListDefinition.thresholds[0].actions[0].configuration.recipients != null ? subscriptionListDefinition.thresholds[0].actions[0].configuration.recipients : null);
response.recipients = subscriptionListDefinition.thresholds[0].actions[0].configuration.recipients != null ? subscriptionListDefinition.thresholds[0].actions[0].configuration.recipients : null;
response.notificationId = subscriptionListDefinition.id != null ? subscriptionListDefinition.id : null;
response.definition = subscriptionListDefinition != null ? subscriptionListDefinition : null;
responseWrapper.add(response);
System.debug('recipients_string: ' + response.recipients_string);
System.debug('recipients: ' + response.recipients);
}
try {
// Validate input
if (String.isBlank(request.definition_string)) {
System.debug('Warning: Empty definition_string provided');
continue;
}

// Fix definition_string to remove [ and ] brackets if present
String definition_string = request.definition_string.trim();

// Remove the first character if it's a bracket
if (definition_string.startsWith('[')) {
definition_string = definition_string.substring(1);
}

// Remove the last character if it's a bracket
if (definition_string.endsWith(']')) {
definition_string = definition_string.substring(0, definition_string.length() - 1);
}

// Deserialize the request with SubscriptionListDefinition
mc_SubscriptionListDefinition subscriptionListDefinition;
try {
subscriptionListDefinition = (mc_SubscriptionListDefinition)JSON.deserialize(definition_string, mc_SubscriptionListDefinition.class);
} catch (JSONException e) {
System.debug('Error deserializing definition_string: ' + e.getMessage());
continue;
}

System.debug('mc_GetRecipients: subscriptionListDefinition: ' + subscriptionListDefinition);

Results response = new Results();

// Check if subscriptionListDefinition is not null and has required data
if (subscriptionListDefinition != null) {
// Validate thresholds and actions exist before accessing
if (subscriptionListDefinition.thresholds != null &&
!subscriptionListDefinition.thresholds.isEmpty() &&
subscriptionListDefinition.thresholds[0].actions != null &&
!subscriptionListDefinition.thresholds[0].actions.isEmpty() &&
subscriptionListDefinition.thresholds[0].actions[0].configuration != null) {

// Extract recipients safely
List<mc_SubscriptionListDefinition_Recipients> recipients =
subscriptionListDefinition.thresholds[0].actions[0].configuration.recipients;

response.recipients_string = JSON.serialize(recipients != null ? recipients : new List<mc_SubscriptionListDefinition_Recipients>());
response.recipients = recipients != null ? recipients : new List<mc_SubscriptionListDefinition_Recipients>();
} else {
// Set empty recipients if structure is invalid
response.recipients_string = JSON.serialize(new List<mc_SubscriptionListDefinition_Recipients>());
response.recipients = new List<mc_SubscriptionListDefinition_Recipients>();
System.debug('Warning: Subscription definition missing thresholds or actions structure');
}

response.notificationId = subscriptionListDefinition.id;
response.definition = subscriptionListDefinition;
responseWrapper.add(response);

System.debug('recipients_string: ' + response.recipients_string);
System.debug('recipients count: ' + (response.recipients != null ? response.recipients.size() : 0));
} else {
System.debug('Warning: subscriptionListDefinition is null after deserialization');
}
} catch (Exception e) {
System.debug('Error processing request: ' + e.getMessage());
System.debug('Stack trace: ' + e.getStackTraceString());
// Continue to next request instead of failing entire batch
}
}

return responseWrapper;

}

/**
* Request wrapper class for invocable method input
*/
public class Request {
@InvocableVariable(required=true)
public string definition_string;
}

/**
* Results wrapper class for invocable method output
*/
public class Results {
@InvocableVariable
public List<mc_SubscriptionListDefinition_Recipients> recipients;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?>
<ApexClass xmlns="http://soap.sforce.com/2006/04/metadata">
<apiVersion>55.0</apiVersion>
<apiVersion>65.0</apiVersion>
<status>Active</status>
</ApexClass>
Original file line number Diff line number Diff line change
@@ -1,28 +1,170 @@
/**
* Test class for mc_GetRecipients
*
* Provides test coverage for the Parse Recipient Data invocable action.
* Tests parsing of subscription definition JSON strings to extract recipient information.
*
* @author Andy Haas
*/
@isTest
public with sharing class mc_GetRecipientsTest {
public mc_GetRecipientsTest() {

}
/**
* Test method for mc_GetRecipients - successful parsing
*
* Tests the recipient parsing functionality by deserializing
* a subscription definition string and extracting recipients.
*/
@isTest
public static void mc_GetRecipients_test(){
list<mc_GetRecipients.request> reqs = new list<mc_getRecipients.Request>();
mc_GetRecipients.request req = new mc_GetRecipients.request();
req.definition_string = '${"active": true,';
req.definition_string += '"thresholds":';
List<mc_SubscriptionListDefinition_Thresholds> thresholds =
new list<mc_SubscriptionListDefinition_Thresholds>();
mc_SubscriptionListDefinition_Thresholds threshold =
new mc_SubscriptionListDefinition_Thresholds();
List<mc_SubscriptionListDefinition_Actions> actions =
new List<mc_SubscriptionListDefinition_Actions>();
List<mc_GetRecipients.Request> reqs = new List<mc_GetRecipients.Request>();
mc_GetRecipients.Request req = new mc_GetRecipients.Request();

// Create a valid subscription definition with recipients
mc_SubscriptionListDefinition def = new mc_SubscriptionListDefinition();
def.active = true;
def.id = '0Au3C00000000kdSAA';

List<mc_SubscriptionListDefinition_Thresholds> thresholds = new List<mc_SubscriptionListDefinition_Thresholds>();
mc_SubscriptionListDefinition_Thresholds threshold = new mc_SubscriptionListDefinition_Thresholds();
threshold.type = 'always';

List<mc_SubscriptionListDefinition_Actions> actions = new List<mc_SubscriptionListDefinition_Actions>();
mc_SubscriptionListDefinition_Actions action = new mc_SubscriptionListDefinition_Actions();
action.type = 'sendEmail';

mc_SubscriptionListDef_Config config = new mc_SubscriptionListDef_Config();
config.excludeSnapshot = false;

List<mc_SubscriptionListDefinition_Recipients> recipients = new List<mc_SubscriptionListDefinition_Recipients>();
mc_SubscriptionListDefinition_Recipients recip = new mc_SubscriptionListDefinition_Recipients();
recip.id = '0055e000001mKpC';
recip.displayName = 'Test User';
recip.type = 'user';
recipients.add(recip);
config.recipients = recipients;

action.configuration = config;
actions.add(action);
threshold.actions = actions;
thresholds.add(threshold);
def.thresholds = thresholds;

// Serialize with brackets to test bracket removal
req.definition_string = '[' + JSON.serialize(def) + ']';
reqs.add(req);

Test.startTest();
List<mc_GetRecipients.Results> results = mc_GetRecipients.mc_GetRecipients(reqs);
Test.stopTest();

System.assertNotEquals(null, results, 'Results should not be null');
System.assertEquals(1, results.size(), 'Should return one result');
System.assertNotEquals(null, results[0].recipients, 'Recipients should not be null');
System.assertEquals(1, results[0].recipients.size(), 'Should have one recipient');
}

/**
* Test empty definition_string
*/
@isTest
public static void mc_GetRecipients_testEmptyString(){
List<mc_GetRecipients.Request> reqs = new List<mc_GetRecipients.Request>();
mc_GetRecipients.Request req = new mc_GetRecipients.Request();
req.definition_string = ''; // Empty string
reqs.add(req);

Test.startTest();
List<mc_GetRecipients.Results> results = mc_GetRecipients.mc_GetRecipients(reqs);
Test.stopTest();

System.assertNotEquals(null, results, 'Results should not be null');
System.assertEquals(0, results.size(), 'Should return empty list for invalid input');
}

/**
* Test invalid JSON
*/
@isTest
public static void mc_GetRecipients_testInvalidJSON(){
List<mc_GetRecipients.Request> reqs = new List<mc_GetRecipients.Request>();
mc_GetRecipients.Request req = new mc_GetRecipients.Request();
req.definition_string = '{invalid json}';
reqs.add(req);

Test.startTest();
List<mc_GetRecipients.Results> results = mc_GetRecipients.mc_GetRecipients(reqs);
Test.stopTest();

System.assertNotEquals(null, results, 'Results should not be null');
System.assertEquals(0, results.size(), 'Should return empty list for invalid JSON');
}

/**
* Test missing thresholds/actions structure
*/
@isTest
public static void mc_GetRecipients_testMissingStructure(){
List<mc_GetRecipients.Request> reqs = new List<mc_GetRecipients.Request>();
mc_GetRecipients.Request req = new mc_GetRecipients.Request();

// Create definition without thresholds
mc_SubscriptionListDefinition def = new mc_SubscriptionListDefinition();
def.active = true;
def.id = '0Au3C00000000kdSAA';
def.thresholds = null; // No thresholds

req.definition_string = JSON.serialize(def);
reqs.add(req);

Test.startTest();
List<mc_GetRecipients.Results> results = mc_GetRecipients.mc_GetRecipients(reqs);
Test.stopTest();

System.assertNotEquals(null, results, 'Results should not be null');
System.assertEquals(1, results.size(), 'Should return one result');
System.assertNotEquals(null, results[0].recipients, 'Recipients should not be null');
System.assertEquals(0, results[0].recipients.size(), 'Should have empty recipients list');
}

/**
* Test with null recipients
*/
@isTest
public static void mc_GetRecipients_testNullRecipients(){
List<mc_GetRecipients.Request> reqs = new List<mc_GetRecipients.Request>();
mc_GetRecipients.Request req = new mc_GetRecipients.Request();

mc_SubscriptionListDefinition def = new mc_SubscriptionListDefinition();
def.active = true;
def.id = '0Au3C00000000kdSAA';

List<mc_SubscriptionListDefinition_Thresholds> thresholds = new List<mc_SubscriptionListDefinition_Thresholds>();
mc_SubscriptionListDefinition_Thresholds threshold = new mc_SubscriptionListDefinition_Thresholds();
threshold.type = 'always';

List<mc_SubscriptionListDefinition_Actions> actions = new List<mc_SubscriptionListDefinition_Actions>();
mc_SubscriptionListDefinition_Actions action = new mc_SubscriptionListDefinition_Actions();
action.type = 'sendEmail';

mc_SubscriptionListDef_Config config = new mc_SubscriptionListDef_Config();
config.excludeSnapshot = false;
config.recipients = null; // Null recipients
action.configuration = config;
actions.add(action);
threshold.actions = actions;
thresholds.add(threshold);
req.definition_string += json.serialize(thresholds) + '}$';
def.thresholds = thresholds;

req.definition_string = JSON.serialize(def);
reqs.add(req);
mc_GetRecipients.mc_GetRecipients(reqs);

Test.startTest();
List<mc_GetRecipients.Results> results = mc_GetRecipients.mc_GetRecipients(reqs);
Test.stopTest();

System.assertNotEquals(null, results, 'Results should not be null');
System.assertEquals(1, results.size(), 'Should return one result');
System.assertNotEquals(null, results[0].recipients, 'Recipients should not be null');
System.assertEquals(0, results[0].recipients.size(), 'Should have empty recipients list');
}
}
Loading