Rule on Central to trigger Signal/Rule on 4 different hosts

We have recently setup a privilege within “central” and this privilege is also set at midnight on 4 other hosts named say A, B, C and D. This privilege is used on the User object.

When we add a new user in “Central” host, we add the privilege and it all works.
However as the midnight rule hasn’t ran yet on all other hosts, they don’t have access to that privilege yet - when they access say “host A” they dont have correct access privileges and are shown a message.

I need a way of triggering a signal on “host A”, “host B”, “host C” and “host D” when the User record is created on “Central” host.

This way I can ensure the privileges are identical across central and hosts immediately.

Thanks in advance for any help!
JonathanFS :smiley:

Hi Jonathan

Have you tried the same events found on the buttons within “Groups” under your Central Admin section (e.g. Group Sync - Send Recently Modified). I usually run this and this helps to update all other hosts with changes to user roles etc.

Alternatively, maybe updating through an API call within central to the 4 hosts to send and receive the relevant roles/privileges?

I believe Privileges are not synced currently, so I will look at API Calls.

I don’t want to move/copy any data, I just need to fire a signal from central on 4 hosts.

Enjoy your weekend Andrew.
Thanks

Hi Andrew

I had a look at the Code Studio Signal Action for “Group Sync - Send All” and it had 95% of the coding I needed to get it to work. Thanks

I’ll run through quickly what I did in case anyone else wants to do something similar.
See attachment

I copied the code studio signal action for “Group Sync - Send All” and created a new code studo signal action named “Netcall User Privilege Sync - Send All” with the details shown, basing it on the original code - This was on Central.

/*-------------------------------------------------------
Script to sync user privileges by sending batches of 
internal users' details to remote applications.
-------------------------------------------------------*/

// Fetch all remote applications and their last sync date
// This list will be used to update user privileges
var applicationList = cs.search({
    'base_object_id': cs.ref('obj_remote_applications'),  // Reference to remote applications
    'selects': [
        ':id',                                             // ID of the remote application
        'remote_application_name',                         // Name of the remote application
        'remote_application_api_endpoint',                 // API endpoint for communication
        'remote_application_api_token',                    // API token for authentication
        'remote_application_last_group_and_membership_sync_datetime'  // Last sync date
    ],
    'return': 'data'
});

cs.log('***** Netcall User Privilege Sync - Send All *****');
cs.log('Applications to Update: ' + applicationList.length);  // Log the number of applications to update

// Fetch all internal users that need to be synced
var internalUserList = cs.search({
    'base_object_id': cs.ref('obj_users'),  // Reference to internal users object
    'selects': [
        ':id',                                 // User ID
        'internal_user_username',              // Username
        'internal_user_forename',              // First name
        'internal_user_surname',               // Last name
        'internal_user_email_address',         // Email address
        'internal_user_mobile_number',         // Mobile number
        'internal_user_timezone'               // Timezone of the user
    ],
    'order': [{'field_path': ':id', 'direction': 'ASC'}],  // Order by user ID in ascending order
    'return': 'data'
});

// Set batch size to control the number of users processed in each batch
const batchSize = 50;  // Max number of users in a single batch
var batchCount = Math.floor(internalUserList.length / batchSize);  // Total number of batches
cs.log('Internal user batch count: ' + (batchCount + 1));  // Log the number of batches (1-indexed)

// Initialize empty arrays for each batch
// This creates an array of arrays, where each sub-array will hold a group of users
var batches = Array.from({ length: batchCount + 1 }, () => []);  // Create (batchCount + 1) empty arrays
cs.log('There are ' + internalUserList.length + ' internal users in ' + (batchCount + 1) + ' batches');

// Define the structure of the payload to be sent in the API request
var internalUserData = {
    "payload": {
        "function": "",  // Will be set to the action to perform
        "data": []       // Will contain the actual batch of user data
    }
};

// Loop through all internal users and assign them to batches
internalUserList.forEach((user, index) => {
    // Retrieve the user's role from the user record
    var userRole = cs.record(user[':id']).get(cs.ref('internal_user_userrole'), 'displayable');
    
    // Prepare the current user's data in a structured format
    var currentUser = {
        'central_user_id': user[':id'],                           // Central user ID
        'username': user[cs.ref('internal_user_username')],       // Username
        'user_role': userRole,                                    // User's role
        'forename': user[cs.ref('internal_user_forename')],       // First name
        'surname': user[cs.ref('internal_user_surname')],         // Last name
        'email_address': user[cs.ref('internal_user_email_address')],  // Email address
        'mobile_number': user[cs.ref('internal_user_mobile_number')],  // Mobile number
        'timezone': user[cs.ref('internal_user_timezone')]        // Timezone
    };
    
    // Determine which batch the current user belongs to
    var currentBatch = Math.floor(index / batchSize);
    
    // Add the user to the appropriate batch
    batches[currentBatch].push(currentUser);
});

// Loop through each remote application and send the batch data
applicationList.forEach(app => {
    // Extract application details (name, endpoint, and API token)
    var appName = app[mats.ref('remote_application_name')];           // Application name
    var endpoint = app[mats.ref('remote_application_api_endpoint')];  // API endpoint for sending requests
    var token = app[mats.ref('remote_application_api_token')];        // API token for authentication
    
    // Log details of the current application being processed
    cs.log(`\nApp Name: ${appName}`);
    cs.log(`Endpoint: ${endpoint}`);
    cs.log(`Token: ${token}`);
    cs.log('----------------------------------------------------------------------------------');
    
    // Loop through each batch and send it to the current application
    batches.forEach((batch, batchIndex) => {
        // Set the function to execute within the remote application
        internalUserData['payload']['function'] = 'set_netcall_user_privilege';		
        
        // Assign the current batch of user data to the payload
        internalUserData['payload']['data'] = batch;

        // Log the details of the payload being sent
        cs.log(`Payload function: ${internalUserData['payload']['function']}`);
        cs.log('Sending payload: ' + JSON.stringify(internalUserData));

        // Send the batch data to the application using a POST request
        var response = cs.curl(endpoint, JSON.stringify(internalUserData), {
            verb: 'POST',  // HTTP method
            headers: {
                'API-Authentication': token,           // Use the API token for authentication
                'Content-Type': 'application/json',    // Specify that the payload is in JSON format
                'Accept': 'application/json, multipart/form-data'  // Accept responses in JSON or form-data
            }
        });
        
        // Log the response from the API
        cs.log('Response: ' + JSON.stringify(response));
    });
});

This code above (code studio signal action) is called from a button the Admin > Groups page named Netcall User Privilege Sync - Send All.

The button event triggers the rule “Netcall User Privilege Sync - Send All.”
The event response fires the rule “Netcall User Privilege Sync - Send All.”
The rule triggers the Code studio signal action “Netcall User Privilege Sync - Send All”.

Which in turn triggers the API Function “set_netcall_user_privilege” for each user that matches, for each host.

This checks if the user is a match, it then triggers the event which fires the Rule I want to run against a User object.

So on Central we have a

  • Code Studio Signal Action - Netcall User Privilege Sync - Send All
  • Rule & Event & Button to trigger (with the same name)

On each host we have a

  • API Function named - set_netcall_user_privilege
  • Event that is triggered by a match in the User API function search

Note I haven’t copied the “Netcall User” privilege setting for a user, I merely run the same rule on each host that I run on Central that sets this privilege. I may update this to copy the value in Central.

Here is API Function - set_netcall_user_privilege that we need on each host.
Basics Tab

I didnt need all these fields, but helped to see the users details when developing
Request Data

Response Data

I hope this explains enough to help someone.

Thanks for pointing me in the right direction Andrew, the code above is not completed but it is a good start.
JonathanFS