Skip to content

Commit 5bbdcc4

Browse files
authored
Merge branch 'main' into Prevent-Unnecessary-notifications-from-being-sent-out
2 parents 777b10d + 7cf9aaf commit 5bbdcc4

File tree

24 files changed

+659
-0
lines changed

24 files changed

+659
-0
lines changed
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
Background Script provides the list of installed plugins, version installed and version available for the upgrade in the instance
2+
3+
Note: We need to set the basic auth credential in order for the script to work on the instance where we are running it.
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
//Get the instance
2+
var instance_name = gs.getProperty("instance_name");
3+
4+
//build the endpoint
5+
var endPoint = 'https://'+instance_name+'.service-now.com/api/sn_appclient/appmanager/apps?tab_context=installed';
6+
7+
//initialize the RestMessageV2 API.
8+
var request = new sn_ws.RESTMessageV2();
9+
request.setEndpoint(endPoint);
10+
request.setHttpMethod('POST');
11+
12+
//Eg. UserName="admin", Password="admin" for this code sample.
13+
var user = 'admin';
14+
var password = '****';
15+
16+
//set the authentication
17+
request.setBasicAuth(user,password);
18+
19+
//set the request header
20+
request.setRequestHeader("Accept","application/json");
21+
22+
//invoke the API
23+
var response = request.execute();
24+
25+
//Parse the response
26+
var jsonResponse = JSON.parse(response.getBody());
27+
28+
var appsList = jsonResponse.result.apps;
29+
30+
//Print the Header for the response
31+
gs.info("Application name"+" | "+ "Assigned version"+" | " + "Latest version | " + "Hasupdate");
32+
appsList.forEach(function(app){
33+
//Print the plugin details
34+
var hasUpdate = app.update_available == 1 ? "true" : "false";
35+
gs.info(app.name+" | "+ app.assigned_version+" | " + app.latest_version+" | " + hasUpdate);
36+
});
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
var updatedSysIds = [];
2+
var notUpdatedSysIds = [];
3+
4+
var gr = new GlideRecord('< table_name >');
5+
gr.addQuery('< query condition >');
6+
gr.query();
7+
8+
while (gr.next()) {
9+
10+
var relCi = new GlideRecord('cmdb_rel_ci');
11+
relCi.addQuery('child', gr.sys_id);
12+
relCi.addQuery('parent.sys_class_name', '< backend name of the table to which the reference field is referred to >');
13+
relCi.query();
14+
15+
if (relCi.next()) {
16+
// Update the reference field with the referenced table's sys_id
17+
gr.< reference field backend name > = relCi.parent.sys_id;
18+
gr.setWorkflow(false);
19+
gr.update();
20+
updatedSysIds.push(gr.sys_id.toString()); // Add to updated list
21+
}
22+
else {
23+
notUpdatedSysIds.push(gr.sys_id.toString()); // Add to not updated list
24+
}
25+
}
26+
27+
// Print the sys_ids of the records updated and not updated
28+
gs.print("Updated records sys_ids: " + updatedSysIds.join(', '));
29+
gs.print("Not updated records sys_ids: " + notUpdatedSysIds.join(', '));

Background Scripts/readME.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
In this piece of code, we are querying a table for some records and then updating a particular reference field's value of those records to the value of the specific parent class to which it has a cmdb_rel_ci relationship.
2+
We are also printing the sys_ids pf the records which would be updated and the ones that would be skipped.
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
function onChange(control, oldValue, newValue, isLoading) {
2+
if (isLoading) return;
3+
4+
var passportNumber = g_form.getValue('passport_number');
5+
var dateOfIssue = g_form.getValue('date_of_issue');
6+
var age = parseInt(g_form.getValue('age'), 10);
7+
var dateOfExpiry = g_form.getValue('date_of_expiry');
8+
9+
// Passport Number Validation
10+
var passportPattern = /^[A-Z][1-9][0-9][A-Z0-9]{5}$/;
11+
if (passportNumber && !passportPattern.test(passportNumber)) {
12+
g_form.showFieldMsg('passport_number', "The entered number is invalid passport number format. It must be 8 characters long, start with an uppercase letter, followed by a number between 1-9, then 0-9, and the rest alphanumeric.", "error");
13+
g_form.clearValue('passport_number');
14+
} else {
15+
g_form.hideFieldMsg('passport_number');
16+
}
17+
18+
// Date of Expiry Calculation based on date of issue
19+
if (dateOfIssue && age) {
20+
var issueDate = new GlideDate();
21+
issueDate.setValue(dateOfIssue);
22+
var expiryDate = new GlideDate();
23+
expiryDate.setValue(issueDate);
24+
25+
if (age >= 18) {
26+
expiryDate.addYears(5); // Adult - add 5 years
27+
} else {
28+
expiryDate.addYears(10); // Under 18 - add 10 years
29+
}
30+
31+
g_form.setValue('date_of_expiry', expiryDate.getByFormat('yyyy-MM-dd')); // Set expiry date in correct format
32+
g_form.hideFieldMsg('date_of_expiry');
33+
} else if (!dateOfIssue) {
34+
g_form.showFieldMsg('date_of_issue', "Please enter the Date of Issue first.", "info");
35+
} else if (!age) {
36+
g_form.showFieldMsg('age', "Please enter your age first.", "info");
37+
}
38+
}
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
This OnChange Catalog Client Script is for validating passport number, date of issue, and date of expiry.
2+
3+
It follows the specified rules(As per indian passport):-
4+
- The passport number should be 8 characters long, with the first character as an uppercase letter, the second and third characters as numbers (1-9 for the first digit, 0-9 for the second digit).
5+
- The date of expiry should be calculated based on the date of issue:
6+
- 1. If the user is an adult (18 years or older), the expiry date should be exactly 5 years from the date of issue.
7+
2. If the user is under 18, the expiry date should be exactly 10 years from the date of issue.
8+
9+
Passport Number Validation:
10+
The passportPattern uses a regular expression:
11+
^[A-Z] – The first character must be an uppercase letter.
12+
[1-9][0-9] – The second and third characters are numbers; the first is between 1-9, and the second between 0-9.
13+
[A-Z0-9]{5}$ – The last five characters are alphanumeric.
14+
If the passport number does not match this pattern, the script displays an error message and clears the field.
15+
16+
Date of Expiry Calculation:
17+
- After the date of issue and age are provided, the script calculates the expiry date by adding 5 years for adults (18 or older) or 10 years for minors (under 18).
18+
- The calculated expiry date is automatically set in the date_of_expiry field in the yyyy-MM-dd format.
19+
- Prompts are displayed if necessary fields like date_of_issue or age are missing before attempting the expiry date calculation.
20+
21+
This Client Script will ensure that the entered passport information and expiry date meet the requirements, providing a seamless and guided experience for the user.
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
# Adding Placeholder Text in Resolution Notes
2+
3+
To maintain consistency and ensure specific information is captured in resolution notes, process owners may require fulfillers to follow a predefined format when resolving tickets.
4+
5+
By adding **placeholder** text in the resolution notes, fulfillers are reminded of the required information(e.g., Root cause, Steps taken, Resolution provided), reducing the risk of missing important details. The placeholder disappears as soon as the fulfiller begins entering their notes, ensuring it doesn't interfere with their input.
6+
7+
## How It Works
8+
9+
### When?
10+
- The placeholder text is automatically added when the state of the ticket changes to Resolved (6).
11+
12+
### What Happens?
13+
- A placeholder text appears in the resolution notes field to guide the fulfiller.
14+
- As soon as the fulfiller starts typing, the placeholder disappears.
15+
- This ensures consistency and alignment with the process requirements.
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
function onChange(control, oldValue, newValue, isLoading, isTemplate) {
2+
if (isLoading || newValue === '') {
3+
return;
4+
}
5+
var res = g_form.getElement('close_notes');
6+
if (newValue == 6)
7+
res.placeholder = "1. Root Cause" + "\n" + "2. Steps taken" + "\n" + "3. Resolution provided"; //Placeholder text as required
8+
else
9+
res.placeholder = "";
10+
}
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
# Redact Sensitive Information
2+
3+
When users create an incident or HR case via the self-service portal, they may occasionally enter sensitive information (e.g., personal identifiers, account numbers).
4+
To prevent misuse of such data, **fulfillers** can redact sensitive information from the short description or description fields.
5+
6+
This ensures that confidential information is safeguarded and not accessible for unauthorized use or distribution.
7+
8+
## Prerequisites
9+
10+
1. Custom Field:
11+
Add a custom field to the form to hold the redacted text.
12+
Example: u_redact (Redact).
13+
14+
2. OnSubmit Client Script:
15+
Create an onsubmit client script to redact sensitive information.
16+
This script will update the **short description** and **description** field with custom value as required.
17+
18+
**Note**: Data that has been redacted cannot be recovered.
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
function onSubmit() {
2+
var redact = g_form.getValue("u_redact"); //custom field on the form to redact information
3+
if (redact == true) {
4+
var answer = confirm(getMessage('Do you want to redact sensitive information')); //Confirm the user who wants to redact information
5+
if (answer) {
6+
g_form.setValue('short_description', 'Short Description is redacted as it contained sensitive information'); //Custom short_description post redacting
7+
g_form.setValue('description', 'Description is redacted as it contained sensitive information'); //Custom description post redacting
8+
g_form.setValue('work_notes', 'The Description and Short Description has been redacted.'); //Adding work notes to track who redacted the short_description and description
9+
g_form.setReadOnly('short_description', true);
10+
g_form.setReadOnly('description', true);
11+
g_form.setReadOnly('u_redact', true)
12+
} else {
13+
g_form.setValue('u_redact', false);
14+
return false;
15+
}
16+
}
17+
}
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
## Fix script to remove leading and trailing spaces from a field in bulk
2+
3+
- we often encounter in a situation that a field has leading or trailing spaces and we want to remove it
4+
- This fix script helps to remove leading and trailing spaces from a field in bulk number.
5+
- Just for an example I have taken incident table and short description as a field.
6+
- feel free to modify and use it as per your requirement.
7+
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
var page = 1;
2+
var count = 0;
3+
var infoMsg = 'Fix Script to remove leading or trailing spaces from short_description. \n';
4+
var sd = ''; //sd inshort for shortdescription
5+
6+
7+
var regExSpacecheck = /^\s+|\s+$/g; //regular expression to check if a sentence has leading and trailing spaces.
8+
9+
var grInc = new GlideRecord('incident');
10+
grInc.addEncodedQuery('short_descriptionISNOTEMPTY');
11+
grInc.query();
12+
while (grInc.next()) {
13+
14+
if (regExSpacecheck.test(grInc.short_description)) {
15+
16+
infoMsg += 'incident record found with leading or trailing space for short_description: ' + grInc.sys_id + '\n';
17+
infoMsg += 'Sd ' + grInc.short_description + 'Contains leading or trailing spaces \n';
18+
sd = grInc.short_description;
19+
sd = sd.trim(); //trimmed value of short description
20+
infoMsg += 'sd is ' + sd + '\n';
21+
22+
if (regExSpacecheck.test(sd)) {
23+
infoMsg += 'sd: ' + sd + ' still has a trailing space\n';
24+
} else {
25+
infoMsg += 'sd: ' + sd + ' no longer contains trailing space \n';
26+
}
27+
//Replace the value for u_location_svid with the trimmed version
28+
grInc.setValue('short_description', sd);
29+
grInc.setWorkflow(false);
30+
grInc.update();
31+
32+
count++;
33+
34+
if (count == 50) {
35+
gs.info(infoMsg);
36+
page++;
37+
count = 0;
38+
infoMsg = 'Fix Script to remove leading or trailing spaces from short_description (' + page + ')\n';
39+
}
40+
41+
}
42+
43+
}
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
Suppose you want to gather data about incident resolution in your system.
2+
Specifically, you need to find the total number of incidents, the average time to resolution (in hours), and the number of incidents per assignment group.
3+
This information can help analyze the efficiency of different groups and improve incident handling.
4+
5+
Below are the added Aggregations:
6+
7+
inc.addAggregate('COUNT') gets the total count of resolved incidents.
8+
inc.addAggregate('AVG', 'calendar_duration') calculates the average calendar duration for incident resolution (measured in hours).
9+
inc.addAggregate('COUNT', 'assignment_group') counts incidents per assignment group, and ga.groupBy('assignment_group') groups the result by assignment group to produce totals per group.
10+
11+
Result:
12+
- It fetches total counts, average resolution time, and group-specific counts.
13+
- Logs the total number of resolved incidents and the average resolution time.
14+
- For each assignment group, it logs the group’s sys_id and the corresponding incident count.
15+
16+
Benefits of Using GlideAggregate:
17+
- Reduces the number of queries and records you need to process, as it performs calculations at the database level.
18+
- Works well with large datasets, making it suitable for summary reports and dashboards.
19+
- Allows grouping and multiple aggregations (e.g., AVG, COUNT, MIN, MAX) on various fields in a single query.
20+
21+
This GlideAggregate example provides a consolidated view of incident resolution statistics, which can aid in optimizing group efficiency and improving response times.
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
// Create a GlideAggregate instance for the Incident table
2+
var inc = new GlideAggregate('incident');
3+
4+
// Filter for resolved incidents only
5+
inc.addQuery('state', 6);
6+
7+
// Add aggregations
8+
inc.addAggregate('COUNT'); // Total number of incidents
9+
inc.addAggregate('AVG', 'calendar_duration'); // Average resolution time in hours
10+
inc.addAggregate('COUNT', 'assignment_group'); // Count of incidents per assignment group
11+
inc.groupBy('assignment_group'); // Group by assignment group to get the count per group
12+
inc.query();
13+
14+
var totalIncidents = 0;
15+
var averageResolution = 0;
16+
var results = [];
17+
18+
while (inc.next()) {
19+
totalIncidents = inc.getAggregate('COUNT');
20+
averageResolution = inc.getAggregate('AVG', 'calendar_duration');
21+
22+
// Get assignment group and incident count per group
23+
var groupSysId = inc.assignment_group.toString();
24+
var groupIncidentCount = inc.getAggregate('COUNT', 'assignment_group');
25+
26+
results.push({
27+
groupSysId: groupSysId,
28+
groupIncidentCount: groupIncidentCount
29+
});
30+
}
31+
32+
// Display results in logs
33+
gs.info("Total Resolved Incidents are: " + totalIncidents);
34+
gs.info("Average Resolution Time (hours) is: " + averageResolution);
35+
36+
results.forEach(function(result) {
37+
gs.info("Assignment Group: " + result.groupSysId + " | Incident Count: " + result.groupIncidentCount);
38+
});
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
var html = '<div id="someid"><span>Hello World</span></div>'; // insert your html content
2+
var outputString = html.replace(/<\/?[^>]+(>|$)/g, ""); // output will a string without the HTML tags
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Will accept a html and remove all the html tags and give a string from it.
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
/*
2+
UI Action
3+
Client - true
4+
action name - open_item
5+
show update - true ( As per your requirement)
6+
onClick - openItem();
7+
Workspace Form button - true
8+
Format for Configurable Workspace - true
9+
*/
10+
11+
//Workspace client script:
12+
function onClick() {
13+
var result = g_form.submit('open_item');
14+
if (!result) {
15+
return;
16+
}
17+
result.then(function() {
18+
var params = {};
19+
params.sysparm_parent_sys_id = g_form.getUniqueValue();
20+
params.sysparm_shortDescription = g_form.getValue('short_description');
21+
//add params as required, These params can be parsed and used in the record producer.
22+
g_service_catalog.openCatalogItem('sc_cat_item', 'recordproducer_sysid_here', params);
23+
//Use the record producer sys_id in second parameter.
24+
});
25+
}
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
/*
2+
Catalog Client script on the record producer/catalog item you want to open from ui action
3+
Name - ParseURL
4+
Type - Onload
5+
Applies on catalog item view - true
6+
*/
7+
8+
function onLoad() {
9+
10+
11+
g_form.setValue('task',parseURL('sysparm_parent_sys_id'));
12+
g_form.setValue('description',parseURL('sysparm_description));
13+
14+
function parseURL(paramName) {
15+
16+
var url = decodeURIComponent(top.location.href); //Get the URL and decode it
17+
var workspaceParams = url.split('extra-params/')[1]; //Split off the url on Extra params
18+
var allParams = workspaceParams.split('/'); //The params are split on slashes '/'
19+
20+
//Search for the parameter requested
21+
for (var i=0; i< allParams.length; i++) {
22+
if(allParams[i] == paramName) {
23+
return allParams[i+1];
24+
}
25+
}
26+
}
27+
}
28+
/*
29+
pass the parameter name which was used in the ui action to parse the value here.
30+
Example - parseURL('sysparm_description) as I am passing description value in the params from ui action.
31+
*/
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
When we want to open a catalog item with details from current record and map it to the opened catalog form then we can use this code.
2+
3+
This UI Action and catalog client script Redirects you to the record producer or catalog item( based on the sys id provided) and auto-populates the fields from the parent record to the catalog item/record producer variables.
4+
5+
1. UI Action
6+
Client - true
7+
action name - open_item
8+
show update - true ( As per your requirement)
9+
onClick - openItem();
10+
Workspace Form button - true
11+
Format for Configurable Workspace - true
12+
13+
2. Catalog Client script.
14+
Type - Onload
15+
Applies on catalog item view - true
16+
Name - ParseURL
17+
18+
Note : Above UI Action works in Configurable workspace and opens the catalog item/record producer in workspace itself.

0 commit comments

Comments
 (0)