Skip to content

Commit 2770103

Browse files
authored
Merge branch 'main' into Flow-Actions/script-for-concatenating
2 parents e39995c + 77bce1e commit 2770103

File tree

20 files changed

+433
-0
lines changed

20 files changed

+433
-0
lines changed
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
var staleDays = 7;
2+
var closeDays = 14;
3+
var reminderGR = new GlideRecord('task');
4+
reminderGR.addActiveQuery();
5+
reminderGR.addEncodedQuery('sys_updated_onRELATIVELE@dayofweek@ago@' + staleDays);
6+
reminderGR.query();
7+
while (reminderGR.next()) {
8+
gs.eventQueue('task.reminder', reminderGR, reminderGR.assigned_to, staleDays + ' days without update.');
9+
}
10+
11+
var closeGR = new GlideRecord('task');
12+
closeGR.addActiveQuery();
13+
closeGR.addEncodedQuery('sys_updated_onRELATIVELE@dayofweek@ago@' + closeDays);
14+
closeGR.query();
15+
while (closeGR.next()) {
16+
closeGR.state = 3; // Closed
17+
closeGR.update();
18+
}
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
The script identifies tasks that haven’t been updated for a set period, sends reminder notifications to assigned users, and, if still inactive after additional time, automatically closes them. This helps keep task lists current and reduces manual follow-ups.
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
//To Encrypt password field
2+
var grIncident = new GlideRecord('incident');
3+
if (grIncident.get('dc1c4143476202101b589d2f316d4390')) {
4+
grIncident.setDisplayValue('u_pass', 'demo@123');
5+
grIncident.update();
6+
}
7+
//NOTE: You can't use the setValue() API for the Password2 field
8+
9+
//To print cipher text
10+
var grIncident = new GlideRecord('incident');
11+
if (grIncident.get('dc1c4143476202101b589d2f316d4390')) {
12+
gs.info('Encrypted cipher test of password ' + grIncident.getValue('u_pass'));
13+
}
14+
15+
//To decrypt password field
16+
var grIncident = new GlideRecord('incident');
17+
if (grIncident.get('dc1c4143476202101b589d2f316d4390')) {
18+
var result = grIncident.u_pass.getDecryptedValue();
19+
gs.info("Decrypted password- " +result);
20+
}
21+
//NOTE: The getDecryptedValue() API isn't scoped. It's available globally.
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
Dear ServiceNow Community,
2+
3+
4+
The GlideEncrypter API uses 3DES encryption standard with NIST 800-131 A Rev2 has recommended against using to encrypt data after 2023. ServiceNow offers alternative cryptographic solutions to the GlideEncrypter API.
5+
6+
Glide Element API to encrypt/decrypt password2 values through GlideRecord.
7+
8+
Below are the sample scripts I ran in my PDI: For Password fields.
9+
10+
Note: 'u_pass' is Password (2 Way Encrypted) field.
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
# Overview
2+
This code snippet helps ServiceNow developers manage group memberships automatically by integrating with an external API. It retrieves group membership data from a specified API endpoint and updates user-group relationships in ServiceNow accordingly.
3+
4+
This is useful for organizations where user groups are managed dynamically in external systems, and developer want a seamless and up-to-date integration with ServiceNow.
5+
6+
# How It Works
7+
The script:
8+
- Fetches API Data: It connects to an external API (specified by the `apiEndpoint` variable) to retrieve the current group membership details.
9+
- Parses API Response: The response is parsed to extract user information (based on email) and group identifiers.
10+
- Updates Group Memberships:
11+
- For each member in the response, the script queries the `sys_user` table to locate the user in ServiceNow based on their email address.
12+
- Once a user is found, the script creates a new record in the `sys_user_grmember` table, associating the user with the appropriate group.
13+
14+
# Implementation
15+
- Define the `apiEndpoint` URL, replacing `https://your-group-api.com/members` with the actual endpoint from which group membership data will be fetched.
16+
- Ensure that any necessary authentication for the API is configured, such as API keys or tokens.
17+
- This script uses email as a unique identifier for users. Adjust `userGR.addQuery('email', member.email)`; if another identifier is needed.
18+
- Deploy the script as a Business Rule in ServiceNow, setting the appropriate table and conditions under which it should execute. For example, it could run on a schedule or be triggered by a specific update.
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
// Script to update group memberships based on API data
2+
(function executeRule(current, previous /*null when async*/) {
3+
var apiEndpoint = 'https://your-group-api.com/members';
4+
var request = new sn_ws.RESTMessageV2();
5+
request.setEndpoint(apiEndpoint);
6+
request.setHttpMethod('GET');
7+
8+
var response = request.execute();
9+
var responseData = JSON.parse(response.getBody());
10+
11+
// Update group memberships
12+
responseData.members.forEach(function(member) {
13+
var userGR = new GlideRecord('sys_user');
14+
userGR.addQuery('email', member.email);
15+
userGR.query();
16+
17+
if (userGR.next()) {
18+
var groupMembership = new GlideRecord('sys_user_grmember');
19+
groupMembership.initialize();
20+
groupMembership.group = member.group_id;
21+
groupMembership.user = userGR.sys_id;
22+
groupMembership.insert();
23+
}
24+
});
25+
})(current, previous);
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
# Overview
2+
This ServiceNow script automates backing up critical record data (such as task or incident records) to an external storage solution. Designed to run as a Business Rule, it helps maintain redundancy for sensitive information by copying specific record details to a backup API whenever a record is created or modified.
3+
4+
# How It Works
5+
- Data Extraction: Collects key record fields (such as `sys_id`, `number`, `short_description`) from `current`.
6+
- API Call: Sends a `POST` request with record data to an external backup endpoint.
7+
- Logging: Outputs API response for monitoring.
8+
9+
# Implementation
10+
1. Update the `setEndpoint` URL to match your backup API endpoint.
11+
2. Modify the `recordData` with table data structure as needed.
12+
3. Ensure the Business Rule is triggered on the appropriate conditions (e.g., on record insert/update) in the target table.
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
// Script to back up critical table data to external storage
2+
(function executeRule(current, previous /*null when async*/) {
3+
var recordData = {
4+
sys_id: current.sys_id.toString(),
5+
number: current.number.toString(),
6+
short_description: current.short_description.toString()
7+
};
8+
9+
// Call external API to store data
10+
var request = new sn_ws.RESTMessageV2();
11+
request.setEndpoint('https://your-backup-api.com/backup');
12+
request.setHttpMethod('POST');
13+
request.setRequestBody(JSON.stringify(recordData));
14+
15+
var response = request.execute();
16+
gs.info("Backup response: " + response.getBody());
17+
})(current, previous);
18+
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
// In this before insert or update Business Rule, we are fetching a reference field value from higher-level parents in hierarchy when there is a field containing the parent record in the children and our use-case reference field is present in all the tables in hierarchy
2+
// I would be referring to "reference field name we want to populate" as "r1"
3+
// I would be referring to "reference field containing parent record" as "parent"
4+
5+
6+
(function executeRule(current, previous /*null when async*/ ) {
7+
if (current.r1 == "" && !JSUtil.nil(current.parent.r1)) // Populate 'use-case reference field' from parent's value for the reference field'
8+
current.r1 = current.parent.r1;
9+
else if (current.< reference field name we want to populate > == "" && !JSUtil.nil(current.parent.parent.r1)) // Populate 'use-case reference field' from 'parent of parent'
10+
current.r1 = current.parent.parent.r1;
11+
12+
})(current, previous);
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
This is a "**before insert/update**" Business Rule
2+
We are fetching a reference field value from higher-level parents in hierarchy
3+
when there is a field containing the parent record in the children and
4+
our use-case reference field is present in all the tables in hierarchy
5+
6+
In the code, we are referring to "reference field name we want to populate" as "_r1_"
7+
In the code, we are referring to "reference field containing parent record" as "_parent_"
8+
9+
The "**JSUtil.nil**" is being used to check for empty/null value for the field.
10+
11+
12+
Through the code we are checking the empty value of the use-case reference field and dot walking to parents and fetching the value from them if it exists
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Effectively validates the short description field ensuring data quality and preventing invalid input.
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
// Client Script to Validate Special Charecters
2+
function onSubmit() {
3+
var shortDescription = g_form.getValue('short_description');
4+
var specialCharsRegex = /[^a-zA-Z0-9\s]/g;
5+
var specialChars = description.match(specialCharsRegex);
6+
if (specialChars) {
7+
alert('Description contains invalid characters: ' + specialChars.join(', '));
8+
return false;
9+
} else {
10+
return true;
11+
}
12+
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
/**
2+
* @param {params} params
3+
* @param {api} params.api
4+
* @param {any} params.event
5+
* @param {any} params.imports
6+
* @param {ApiHelpers} params.helpers
7+
*/
8+
function handler({ api, event, helpers, imports }) {
9+
console.log(`DEBUG Event ${event.elementId} ${event.name}`, event);
10+
}
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
# DEBUG Event UX Client Script
2+
3+
This repository provides a simple UX Client Script for logging events to the console. Named `DEBUG Event`, this client script is designed to assist in debugging by outputting key event details to the console, helping developers track event triggers and properties in real-time.
4+
5+
## Features
6+
7+
- **Console Logging**: Logs event details, including `elementId` and `name`, to the console for easy tracking.
8+
- **Simplified Debugging**: Useful for monitoring and debugging UX interactions without complex setup.
9+
10+
## Script Overview
11+
12+
```javascript
13+
/**
14+
* @param {params} params
15+
* @param {api} params.api
16+
* @param {any} params.event
17+
* @param {any} params.imports
18+
* @param {ApiHelpers} params.helpers
19+
*/
20+
function handler({ api, event, helpers, imports }) {
21+
console.log(`DEBUG Event ${event.elementId} ${event.name}`, event);
22+
}
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
/**
2+
* @param {params} params
3+
* @param {api} params.api
4+
* @param {any} params.event
5+
* @param {any} params.imports
6+
* @param {ApiHelpers} params.helpers
7+
*/
8+
function handler({ api, event, helpers, imports }) {
9+
console.log(`DEBUG State:`, { ...api.state });
10+
}
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
# Debug State UX Client Script
2+
3+
This repository contains a UX Client Script called `Debug State`, designed to log the current client state to the console. This script is useful for developers who want to inspect the state object in real time, making debugging more efficient by allowing quick access to current state values.
4+
5+
## Features
6+
7+
- **Console Logging of State**: Logs the entire `state` object to the console, enabling developers to track and inspect state changes.
8+
- **Efficient Debugging**: Simplifies the debugging process by providing direct access to the client's state.
9+
10+
## Script Overview
11+
12+
```javascript
13+
/**
14+
* @param {params} params
15+
* @param {api} params.api
16+
* @param {any} params.event
17+
* @param {any} params.imports
18+
* @param {ApiHelpers} params.helpers
19+
*/
20+
function handler({ api, event, helpers, imports }) {
21+
console.log(`DEBUG State:`, { ...api.state });
22+
}
23+
```
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
/**
2+
* This data broker creates or updates a user preference of the given name with the given value
3+
* @param {{name: string, value?: string}} inputs inputs from the properties field above
4+
*/
5+
function transform({ name, value }) {
6+
const lib = "Data Broker";
7+
const func = "Create/Update User Preference";
8+
try {
9+
if (!name) throw new Error("Missing required param 'name'");
10+
11+
12+
gs.getUser().savePreference(name, value);
13+
} catch (e) {
14+
gs.error(`${lib} ${func} - ${e}`);
15+
throw new Error(e);
16+
}
17+
}
18+
19+
/**
20+
* Make sure to select that this data broker mutates data
21+
* Input this in the properties field:
22+
*
23+
[
24+
{
25+
"name": "name",
26+
"label": "Name",
27+
"description": "The name of the user preference to create or update",
28+
"readOnly": false,
29+
"fieldType": "string",
30+
"mandatory": true,
31+
"defaultValue": ""
32+
},
33+
{
34+
"name": "value",
35+
"label": "Value",
36+
"description": "The value to store in the user preference",
37+
"readOnly": false,
38+
"fieldType": "string",
39+
"mandatory": false,
40+
"defaultValue": ""
41+
}
42+
]
43+
*/
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
# Create/Update User Preference Data Broker
2+
3+
This repository provides a data broker for creating or updating user preferences in ServiceNow. The broker allows you to specify a preference name and value, storing or updating it in the user’s preferences.
4+
5+
## Features
6+
7+
- **Create or Update User Preferences**: Provides a simple interface for adding or modifying preferences by name and value.
8+
- **Error Handling**: Logs errors if the preference name is missing or if an unexpected issue arises.
9+
10+
## Template Overview
11+
12+
```javascript
13+
/**
14+
* This data broker creates or updates a user preference of the given name with the given value
15+
* @param {{name: string, value?: string}} inputs inputs from the properties field above
16+
*/
17+
function transform({ name, value }) {
18+
const lib = "Data Broker";
19+
const func = "Create Update User Preference";
20+
try {
21+
if (!name) throw new Error("Missing required param 'name'");
22+
23+
gs.getUser().savePreference(name, value);
24+
} catch (e) {
25+
gs.error(`${lib} ${func} - ${e}`);
26+
throw new Error(e);
27+
}
28+
}
29+
```
Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
# Transform Data Broker Template
2+
3+
This repository provides a starter template for creating Transform Data Brokers in ServiceNow’s UX framework. This template includes error handling, input validation, and JSDoc annotations for a streamlined setup.
4+
5+
## Features
6+
7+
- **JSDoc Type Annotations** for clarity and type-checking.
8+
- **Destructured Inputs** for simplified parameter handling.
9+
- **Error Logging & Propagation**: Logs errors while allowing the data resource to fail if needed.
10+
- **Properties Example**: Provides an example of what the properties should look like
11+
12+
## Template Overview
13+
14+
```javascript
15+
/**
16+
* @param {{param1: string, param2: number, param3?: boolean}} inputs
17+
* Inputs from the properties field above; param1 and param2 are mandatory.
18+
* @returns {string} The value returned after transformation.
19+
*/
20+
function transform({ param1, param2, param3 }) {
21+
const lib = "Data Broker";
22+
const func = "<insert data broker name here>";
23+
let res;
24+
25+
try {
26+
if (!param1) throw new Error("Missing required param 'param1'");
27+
if (!param2) throw new Error("Missing required param 'param2'");
28+
29+
// Add transformation logic here
30+
31+
return res;
32+
} catch (e) {
33+
gs.error(`${lib} ${func} - ${e}`);
34+
throw new Error(e);
35+
}
36+
}
37+
38+
/**
39+
* TIPS
40+
* Make sure to flag mutates data if your data resource changes any data
41+
* Properties structure (these are the inputs for your data resource):
42+
[
43+
{
44+
"name": "param1",
45+
"label": "Param 1",
46+
"description": "An example of the first param as a string, mandatory",
47+
"readOnly": false,
48+
"fieldType": "string",
49+
"mandatory": true,
50+
"defaultValue": ""
51+
},
52+
{
53+
"name": "param2",
54+
"label": "Param 2",
55+
"description": "An example of the second param as a number, mandatory",
56+
"readOnly": false,
57+
"fieldType": "number",
58+
"mandatory": true,
59+
"defaultValue": ""
60+
},
61+
{
62+
"name": "param3",
63+
"label": "Param 3",
64+
"description": "An example of the third param as a boolean, optional",
65+
"readOnly": false,
66+
"fieldType": "boolean",
67+
"mandatory": false,
68+
"defaultValue": ""
69+
}
70+
]
71+
*/
72+
```

0 commit comments

Comments
 (0)