Skip to content

Commit a206a0f

Browse files
authored
Merge branch 'main' into SCIM-Payload-Generator
2 parents ea1c649 + c71bf3f commit a206a0f

File tree

279 files changed

+5692
-57
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

279 files changed

+5692
-57
lines changed
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
Use Case: Find the Total Number of Records in a Table Using the ATF Step "Run Server Side Script"
2+
3+
Using existing ATF steps (without scripting), it is very difficult to find the record count of a table.
4+
5+
By using the ATF test step "Run Server Side Script" with a simple script, we can count the records and also log/pass the count to the next ATF step if required.
6+
7+
Steps:
8+
9+
Navigate to Automated Test Framework >> Tests >> Click on New Test.
10+
Give a name to the test and provide a description.
11+
Go to the Test Steps related list and click Add Test Step.
12+
Navigate to Server and choose Run Server Side Script.
13+
Add the script (the script is in the script.js file).
14+
Save the test and run it to see the results.
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
(function(outputs, steps, params, stepResult, assertEqual) {
2+
// add test script here
3+
var gr = new GlideAggregate('incident');
4+
gr.addAggregate('COUNT');
5+
gr._query();
6+
if (gr.next()) {
7+
return gr.getAggregate('COUNT'); // pass the step
8+
stepResult.setOutputMessage("Successfully Calculated the Count");
9+
} else {
10+
stepResult.setOutputMessage("Failed to Count");
11+
return false; // fail the step
12+
}
13+
14+
})(outputs, steps, params, stepResult, assertEqual);
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
## Description
2+
The planned lines of the ServiceNow burndown chart do not take holidays into account.
3+
By using this Python snippet, you can create a burndown chart with planned lines that take holidays into account.
4+
The generated burndown chart can also be automatically deployed as an image to Slack and other tools.
5+
6+
## Requirements
7+
OS: Windows/MacOS/Unix
8+
Python: Python3.x
9+
ServiceNow: More than Vancouver
10+
Plugins: Agile Development 2.0 (com.snc.sdlc.agile.2.0) is installed
11+
12+
## Installation
13+
Clone the repository and place the "Burndown Chart" directory in any location.
14+
Execute the following command to create a virtual environment.
15+
<code>python3 -m venv .venv
16+
macOS/Unix: source .venv/bin/activate
17+
Windows: .venv\Scripts\activate
18+
pip install -r requirements.txt
19+
</code>
20+
21+
## Usage
22+
1. Go to the Burndown Chart directory.
23+
2. Prepare the following values ​​according to your environment:
24+
- InstanceName: Your instance name (e.g. dev000000 for PDI)
25+
- Credentials: Instance login information in Base64 (Read permission to the rm_sprint table is required.)
26+
- Sprint Name: Target sprint name from the Sprint[rm_sprint] table
27+
28+
3. Run the command to install the required modules.
29+
<code>pip install -r equirements.txt</code>
30+
31+
5. Run sprint_burndown_chart.py.
32+
<code>python3 sprint_burndown_chart.py INSTANCE_NAME BASE64_ENCODED_STRING(USERID:PASSWORD) SPRINT_NAME</code>
33+
example:
34+
<code>python3 sprint_burndown_chart.py dev209156 YXBpOmpkc0RhajNAZDdKXnNmYQ== Sprint1</code>
35+
36+
When you run it, a burndown chart image like the one shown will be created.
37+
![figure](https://github.com/user-attachments/assets/50d3ffc2-4c66-4f4d-bb69-c2b98763621d)
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
jpholiday==0.1.10
2+
matplotlib==3.9.2
3+
numpy==2.0.2
4+
pandas==2.2.3
5+
pytz==2024.2
6+
requests==2.32.3
7+
urllib3==1.26.13
Lines changed: 138 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,138 @@
1+
import argparse
2+
import pprint
3+
import requests
4+
import datetime
5+
import matplotlib.dates as mdates
6+
import pandas as pd
7+
import matplotlib.pyplot as plt
8+
import urllib.request
9+
import urllib.parse
10+
import json
11+
import datetime
12+
from pytz import timezone
13+
14+
# ---- #
15+
# init #
16+
# ---- #
17+
point_dict = {}
18+
total_points = 0
19+
done = 0
20+
undone = 0
21+
parser = argparse.ArgumentParser()
22+
parser.add_argument('instancename')
23+
parser.add_argument('authstring')
24+
parser.add_argument('sprintname')
25+
args = parser.parse_args()
26+
BASIC = 'Basic ' + args.authstring
27+
28+
# ---------- #
29+
# Get Sprint #
30+
# ---------- #
31+
params = {
32+
'sysparm_query': 'short_description=' + args.sprintname
33+
}
34+
param = urllib.parse.urlencode(params)
35+
url = "https://" + args.instancename + ".service-now.com/api/now/table/rm_sprint?" + param
36+
req = urllib.request.Request(url)
37+
req.add_header("authorization", BASIC)
38+
with urllib.request.urlopen(req) as res:
39+
r = res.read().decode("utf-8")
40+
obj = json.loads(r)
41+
# Get the start and end dates of a Sprint
42+
start_date = obj['result'][0]['start_date']
43+
start_date = (datetime.datetime.strptime(start_date, '%Y-%m-%d %H:%M:%S') + datetime.timedelta(hours=9)).date()
44+
print(start_date)
45+
end_date = obj['result'][0]['end_date']
46+
end_date = (datetime.datetime.strptime(end_date, '%Y-%m-%d %H:%M:%S') + datetime.timedelta(hours=9)).date()
47+
# Initializing the points array
48+
while start_date <= end_date:
49+
point_dict[str(start_date)] = 0
50+
start_date = start_date + datetime.timedelta(days=1)
51+
# --------- #
52+
# Get Story #
53+
# --------- #
54+
params = {
55+
'sysparm_query': 'sprint.short_descriptionLIKE' + args.sprintname
56+
}
57+
param = urllib.parse.urlencode(params)
58+
url = "https://" + args.instancename + ".service-now.com/api/now/table/rm_story?" + param
59+
req = urllib.request.Request(url)
60+
req.add_header("authorization", BASIC)
61+
with urllib.request.urlopen(req) as res:
62+
r = res.read().decode("utf-8")
63+
obj = json.loads(r)
64+
# Story Loop
65+
for name in obj['result']:
66+
if len(name['story_points']) > 0:
67+
total_points += int(name['story_points'])
68+
if name['closed_at'] != '':
69+
close_date = datetime.datetime.strptime(
70+
name['closed_at'], '%Y-%m-%d %H:%M:%S')
71+
close_date = close_date.date()
72+
if name['state'] == '3':
73+
if str(close_date) in point_dict:
74+
point_dict[str(close_date)] += int(name['story_points'])
75+
else:
76+
point_dict[str(close_date)] = int(name['story_points'])
77+
if name['state'] == '3':
78+
done += int(name['story_points'])
79+
else:
80+
undone += int(name['story_points'])
81+
counta = 0
82+
for i in point_dict.items():
83+
counta += int(i[1])
84+
point_dict[i[0]] = total_points - counta
85+
plt.xkcd()
86+
fig, ax = plt.subplots()
87+
# Creating a performance line
88+
x = []
89+
y = []
90+
plt.ylim(0, total_points + 5)
91+
counta = 0
92+
for key in point_dict.keys():
93+
if datetime.datetime.today() >= datetime.datetime.strptime(key, '%Y-%m-%d'):
94+
x.append(datetime.datetime.strptime(key, '%Y-%m-%d'))
95+
y.append(point_dict[key])
96+
# Holiday determination
97+
DATE = "yyyymmdd"
98+
def isBizDay(DATE):
99+
Date = datetime.date(int(DATE[0:4]), int(DATE[4:6]), int(DATE[6:8]))
100+
if Date.weekday() >= 5:
101+
return 0
102+
else:
103+
return 1
104+
# Get the number of weekdays
105+
total_BizDay = 0
106+
for key in point_dict.keys():
107+
if isBizDay(key.replace('-', '')) == 1:
108+
total_BizDay += 1
109+
# Creating an ideal line
110+
x2 = []
111+
y2 = []
112+
point_dict_len = len(point_dict)
113+
average = total_points / (total_BizDay - 1)
114+
for key in point_dict.keys():
115+
dtm = datetime.datetime.strptime(key, '%Y-%m-%d')
116+
x2.append(dtm)
117+
y2.append(total_points)
118+
# If the next day is a weekday, consume the ideal line.
119+
if isBizDay((dtm + datetime.timedelta(days=1)).strftime("%Y%m%d")) == 1:
120+
total_points -= average
121+
days = mdates.DayLocator()
122+
daysFmt = mdates.DateFormatter('%m/%d')
123+
ax.xaxis.set_major_locator(days)
124+
ax.xaxis.set_major_formatter(daysFmt)
125+
plt.title("" + args.sprintname + " Burndown")
126+
plt.plot(x2, y2, label="Ideal", color='green')
127+
plt.plot(x2, y2, marker='.', markersize=20, color='green')
128+
plt.plot(x, y, label="Actual", color='red')
129+
plt.plot(x, y, marker='.', markersize=20, color='red')
130+
plt.grid()
131+
plt.xlabel("Days")
132+
plt.ylabel("Remaining Effort(pts)")
133+
plt.subplots_adjust(bottom=0.2)
134+
plt.legend()
135+
# Viewing the graph
136+
# plt.show()
137+
# Saving a graph
138+
plt.savefig('figure.png')
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
Script to be used to add bookmark for ITIL users. This will help add favorites for SLAs for
2+
- My Group Tasks
3+
- SLAs for My Tasks
4+
- Tasks Assigned to Me
5+
- My approvals
6+
to all ITIL users.
7+
Replace the addQuery value to get the favorites applied from the backend to required audience
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
var jsonFavList = {
2+
"SLA for My Group Tasks": "task_list.do?sysparm_query=assignment_groupDYNAMICd6435e965f510100a9ad2572f2b47744&sysparm_first_row=1&sysparm_view=",
3+
"SLA for My Tasks": "task_list.do?sysparm_query=assigned_toDYNAMIC90d1921e5f510100a9ad2572f2b477fe&sysparm_first_row=1&sysparm_view=",
4+
"Tasks Assigned to Me": "task_list.do?sysparm_query=stateNOT INclosed_complete,closed_abandoned^assigned_toDYNAMIC90d1921e5f510100a9ad2572f2b477fe",
5+
"My approvals": "sysapproval_approver_list.do?sysparm_query=approverDYNAMIC90d1921e5f510100a9ad2572f2b477fe&sysparm_first_row=1&sysparm_view="
6+
};
7+
8+
var g = new GlideRecord("sys_user_has_role");
9+
g.addEncodedQuery("role=282bf1fac6112285017366cb5f867469");//considering sys_id for ITIL role is 282bf1fac6112285017366cb5f867469
10+
g.query();
11+
while (g.next()) {
12+
for (var fav in jsonFavList) {
13+
var grBookMark = new GlideRecord("sys_ui_bookmark");
14+
grBookMark.addEncodedQuery("user=" + g.user + "^title=" + fav + "^url=" + jsonFavList[fav]);
15+
grBookMark.query();
16+
if (!grBookMark.next()) {
17+
grBookMark.initialize();
18+
grBookMark.pinned = true;
19+
grBookMark.title = fav;
20+
grBookMark.url = jsonFavList[fav];
21+
grBookMark.user = g.user;
22+
grBookMark.insert();
23+
}
24+
}
25+
}
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
function addComments(tableName,recSysId, userName, fieldName){
2+
var rec = new GlideRecord(tableName);
3+
if(rec.get(recSysId)){
4+
rec[fieldName].setJournalEntry('This is my comment',userName);
5+
rec.update();
6+
}
7+
}
8+
9+
addComments(tableName,recSysId,userName,fieldName);
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
There have been scenarios where you are working on an integration and one of the usecase is to add comments on a record. In this scenario once you add comments directly
2+
to the record by assigning the value in the comments or work_notes field, it captures it as a integration user in the activity formatter. But with setJournalEntry()
3+
method you can pass the user_name and it will add the comment on behalf of the user whose user_name is passed. In this way it easy to track who is actually modifying
4+
the record or adding the comments. Hope this will be a helpful snippet.
5+
6+
In this function the paramters are defined as:
7+
tableName: Name of the table on which you are adding the comments.
8+
recSysId: sys_id of the record for which the comment is getting added.
9+
userName: user_name of the user who is adding the comments
10+
fieldName: It can be either comments or work_notes or any custom journal entry field.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
/*
2+
This script is used to add the [no_audit=true] attribute to multiple dictionary entries in bulk.
3+
Can be used for other attributes as well.
4+
NB: The attribut sys_id must be verified before the script execution!
5+
*/
6+
7+
var encodedQuery = '<insert encoded query here>'
8+
9+
//Verify this is in your instance before script execution
10+
var noAuitAttributeSysID = '96ea04dfeb321100d4360c505206fe7d';
11+
12+
var grSD = new GlideRecord('sys_dictionary');
13+
grSD.addEncodedQuery(encodedQuery);
14+
grSD.query();
15+
while (grSD.next()) {
16+
17+
18+
var grExistingAttribute = new GlideRecord('sys_schema_attribute_m2m');
19+
grExistingAttribute.addQuery('schema', grSD.getUniqueValue());
20+
grExistingAttribute.addQuery('attribute', noAuitAttributeSysID); //
21+
grExistingAttribute.query();
22+
23+
if(grExistingAttribute.hasNext()){
24+
grExistingAttribute.next();
25+
26+
if(grExistingAttribute.getValue('value')=='false'){
27+
grExistingAttribute.setValue('value', 'true');
28+
grExistingAttribute.update();
29+
}
30+
}else{
31+
32+
var grDicitionaryAttributeM2M = new GlideRecord('sys_schema_attribute_m2m');
33+
grDicitionaryAttributeM2M.initialize();
34+
grDicitionaryAttributeM2M.setValue('schema', grSD.getUniqueValue());
35+
grDicitionaryAttributeM2M.setValue('attribute', noAuitAttributeSysID)
36+
grDicitionaryAttributeM2M.setValue('value', 'true');
37+
grDicitionaryAttributeM2M.insert();
38+
}
39+
40+
}
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
A background script add the no-audit attribute to multiple dictionary entries.
2+
The no-audit attribute will exclued the specified attributes from the system audit process and will not produc audit track at all.
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Description: This is a script that assigns roles to users in bulk based on specific conditions such as department,location or job title. This script can simplify the process of managing user roles and permissions. Use Case: Assign the 'itil' role to all users in the 'IT' department who are located in a specific region.
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
// Define the role to be assigned
2+
var roleName = 'itil';
3+
4+
// Define the conditions for user selection
5+
var department = 'IT';
6+
var location = 'San Diego';
7+
8+
// Fetch the role record
9+
var roleGR = new GlideRecord('sys_user_role');
10+
roleGR.addQuery('name', roleName);
11+
roleGR.query();
12+
if (!roleGR.next()) {
13+
gs.error('Role not found: ' + roleName);
14+
return;
15+
}
16+
17+
// Fetch users matching the conditions
18+
var userGR = new GlideRecord('sys_user');
19+
userGR.addQuery('department.name', department);
20+
userGR.addQuery('location.name', location);
21+
userGR.query();
22+
23+
var count = 0;
24+
while (userGR.next()) {
25+
// Check if the user already has the role
26+
var userRoleGR = new GlideRecord('sys_user_has_role');
27+
userRoleGR.addQuery('user', userGR.sys_id);
28+
userRoleGR.addQuery('role', roleGR.sys_id);
29+
userRoleGR.query();
30+
if (!userRoleGR.next()) {
31+
// Assign the role to the user
32+
var newUserRoleGR = new GlideRecord('sys_user_has_role');
33+
newUserRoleGR.initialize();
34+
newUserRoleGR.user = userGR.sys_id;
35+
newUserRoleGR.role = roleGR.sys_id;
36+
newUserRoleGR.insert();
37+
count++;
38+
}
39+
}
40+
41+
gs.info('Assigned role "' + roleName + '" to ' + count + ' users.');
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
var obj ={};
2+
obj.name = 'Mohit Kaushik';
3+
obj.email ='[email protected]';
4+
obj.contact = '1234567890';
5+
6+
var str = JSON.stringify(obj,null,4);
7+
8+
var encryption = GlideStringUtil.base64Encode(str);
9+
gs.info(encryption);
10+
11+
var decrypt = GlideStringUtil.base64Decode(encryption);
12+
gs.info(JSON.stringify(decrypt,null,2));
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
This code is an example to encrypt or decrypt the payload using base64Encode and decode methods of GlideStringUtil API.
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
var myGroups = [];
2+
var grGroup = new GlideRecord("sys_user_group");
3+
grGroup.addActiveQuery();
4+
grGroup.query();
5+
while (grGroup.next()) {
6+
var gaGroupMember = new GlideAggregate("sys_user_grmember");
7+
gaGroupMember.addQuery("group",grGroup.sys_id.toString());
8+
gaGroupMember.addAggregate('COUNT');
9+
gaGroupMember.query();
10+
var gm = 0;
11+
if (gaGroupMember.next()) {
12+
gm = gaGroupMember.getAggregate('COUNT');
13+
if (gm == 0)
14+
myGroups.push(grGroup.name.toString());
15+
}
16+
}
17+
gs.print(myGroups);

0 commit comments

Comments
 (0)