Skip to content

Commit 87c34bf

Browse files
authored
Merge branch 'ServiceNowDevProgram:main' into main
2 parents 5ed3841 + e679717 commit 87c34bf

File tree

9 files changed

+202
-0
lines changed

9 files changed

+202
-0
lines changed
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
# UI Action to kill flow timers
2+
3+
UI page that shows you all timers that a flow context [sys_flow_context] is waiting for. Shows sys_id of the sys_trigger, the datetime when the wait will finish and how long until that time. Select the checkbox and submit the modal form to kill that timer.
4+
5+
## How to use
6+
7+
1. Create ui action on [sys_flow_context] and input the script from *UI action.js* in the script field. Check client and set Onclick as *openTimerDialog()*
8+
2. Create ui page with name *timer_kill_dialog* and copy the HTML, client script and processing script from the *UI page for ui action.js* file
9+
3. Navigate to active flow context that is waiting for timers and click the ui action from step 1 and kill timer/s. Flow will progress as soon as the flow engine processes the flow.fire events
10+
11+
![image](timer.png)
12+
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
//Onlick: openTimerDialog()
2+
3+
//open dialog using glidemodal and timer_kill_dialog ui page, pass in current sys_flow_context sysid
4+
function openTimerDialog() {
5+
var dialog = new GlideModal("timer_kill_dialog");
6+
dialog.setTitle("Kill timers");
7+
dialog.setPreference('sysparm_id', g_form.getUniqueValue());
8+
dialog.render();
9+
}
Lines changed: 100 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,100 @@
1+
//name: timer_kill_dialog
2+
3+
//HTML:
4+
<?xml version="1.0" encoding="utf-8" ?>
5+
<j:jelly trim="false" xmlns:j="jelly:core" xmlns:g="glide" xmlns:j2="null" xmlns:g2="null">
6+
<g:evaluate var="jvar_timers" object="true">
7+
// executed server side, gets wait jobs for current flow context and returns object with information about timers
8+
var array = [];
9+
var waitJob = new GlideRecord("sys_trigger");
10+
waitJob.addQuery("state", "0")
11+
.addCondition("name", "flow.fire")
12+
.addCondition("script", "CONTAINS", RP.getParameterValue("sysparm_id"));
13+
waitJob.query();
14+
while (waitJob.next()) {
15+
var obj = {};
16+
obj.sys_id = waitJob.getUniqueValue();
17+
obj.waitUntil = waitJob.getValue("next_action");
18+
var now = new GlideDateTime()
19+
obj.timeLeft = GlideDateTime.subtract(now, new GlideDateTime(waitJob.getValue("next_action"))).getDisplayValue()
20+
array.push(obj)
21+
}
22+
array;
23+
</g:evaluate>
24+
25+
<style>
26+
table td {
27+
padding: 8px;
28+
}
29+
30+
table thead td {
31+
font-weight: bold;
32+
background-color: #f0f0f0;
33+
}
34+
</style>
35+
36+
<!-- submittable form that shows the wait jobs in [sys_trigger] for context and a checkbox to select timers to kill -->
37+
<g:ui_form>
38+
<input type="hidden" id="sysids" name="sysids" value="" />
39+
<div style="padding: 20px; font-family: sans-serif;">
40+
<table>
41+
<tbody>
42+
<thead>
43+
<td>timer sys_id</td>
44+
<td>next action</td>
45+
<td>time left</td>
46+
<td>kill?</td>
47+
</thead>
48+
<j:forEach var="jvar_timer" items="${jvar_timers}">
49+
<tr>
50+
<td>
51+
${jvar_timer.sys_id}
52+
</td>
53+
<td>
54+
${jvar_timer.waitUntil}
55+
</td>
56+
<td>
57+
${jvar_timer.timeLeft}
58+
</td>
59+
<td>
60+
<g:ui_checkbox name="${jvar_timer.sys_id}">
61+
</g:ui_checkbox>
62+
</td>
63+
</tr>
64+
</j:forEach>
65+
</tbody>
66+
</table>
67+
<g:dialog_buttons_ok_cancel ok="return okDialog()" />
68+
</div>
69+
</g:ui_form>
70+
</j:jelly>
71+
72+
//Client script:
73+
// handler for clicking ok on modal. gathers the sys_ids for the timers that have checked checkbox
74+
function okDialog() {
75+
var c = gel('sysids');
76+
var sysids = [];
77+
$j('input[type="checkbox"]:checked').each(function () {
78+
var checkboxId = $j(this).attr('id').replace("ni.", "");
79+
sysids.push(checkboxId);
80+
});
81+
c.value = sysids.toString();
82+
return true;
83+
}
84+
85+
//Processing script:
86+
// queries for timer jobs and sets the job and new flow.fire event to process instantly -> timer on flow completes
87+
var waitJob = new GlideRecord("sys_trigger");
88+
waitJob.addQuery("sys_id", "IN", sysids);
89+
waitJob.query();
90+
while (waitJob.next()) {
91+
var currentScript = waitJob.getValue("script");
92+
var now = new GlideDateTime().getValue();
93+
var replaceScript = currentScript.replace(/gr\.setValue\('process_on',\s*'[^']*'\)/, "gr.setValue('process_on','" + now + "')");
94+
waitJob.setValue("script", replaceScript);
95+
waitJob.setValue("next_action", now);
96+
waitJob.update();
97+
}
98+
//redirect back to bottom of nav stack
99+
var urlOnStack = GlideSession.get().getStack().bottom();
100+
response.sendRedirect(urlOnStack);
44 KB
Loading
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
var userId = ['abel.tuter', 'abraham.lincoln']; //example
2+
var workItems = ['INC0009009', 'INC0009005'];
3+
/* Beginning of function*/
4+
5+
var gi = GlideImpersonate();
6+
var currUser = gs.getUserID();
7+
8+
// If the logged in user doesn't have impersonating roles.
9+
if (!gi.canImpersonate(currUser)) {
10+
gs.info("You don't have access to impersonate");
11+
}
12+
for (var id in userId) {
13+
var userGr = new GlideRecord('sys_user');
14+
userGr.addQuery('user_name', userId[id]);
15+
userGr.query();
16+
if (!userGr.hasNext()) {
17+
// If the user id mentioned is incorrect
18+
gs.print("Cannot find user from user id " + user[id] + ". Please Validate the user id");
19+
} else if (userGr.active == 'false') {
20+
//If the persona is inactive
21+
gs.print(id + " is inactve.");
22+
} else {
23+
gi.impersonate(userGr.sys_id);
24+
// Analysis report
25+
gs.print("Access result for " + gs.getUserDisplayName + ":");
26+
for (var item in workItems){
27+
var taskGr = new GlideRecord('task');
28+
taskGr.addQuery('number', workItems[item]);
29+
taskGr.query();
30+
gs.print(workItems[item] + " Read: " + taskGr.canRead() + ", Write: " + taskGr.canWrite());
31+
}
32+
33+
}
34+
35+
}
36+
// End impersonation. Impersonate back to logged in user
37+
gi.impersonate(currUser);
11.2 KB
Loading
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
In scenarios where it's necessary to verify Read/Write access for multiple users across various work items (such as Incidents, Tasks, etc.), traditional methods like impersonating individual users or using the Access Analyzer plugin can be time-consuming. This utility streamlines the process by enabling simultaneous access analysis for multiple users by impersonating them and can be executed efficiently via a background script.
2+
3+
userId- Array containing the user id of personas whose access to be analyzed.
4+
5+
workItems- Work items extending the 'task' table.
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Use the script as Business Rule script on Catalog Task table which runs After Insert and will copy all MRVS values from RITM to Catalog Task for quick actions at the Catalog Task itself for reviewing and getting the work completed.
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
(function executeRule(current, previous /*null when async*/ ) {
2+
3+
// Copies the values from a multi-row variable set into a variable so we can view the values on a catalog task.
4+
var variables = [];
5+
var catItem = current.request_item.cat_item.toString();
6+
var variableSets = [];
7+
var getVariableSets = new GlideRecord('io_set_item');
8+
getVariableSets.addQuery('sc_cat_item', catItem);
9+
getVariableSets.query();
10+
while (getVariableSets.next()) {
11+
variableSets.push(getVariableSets.getValue('variable_set'));
12+
}
13+
var getCatalogVariables = new GlideRecord('item_option_new');
14+
var qry = 'cat_item=' + catItem +
15+
'^active=true' +
16+
'^NQvariable_set.sys_idIN' + variableSets.toString() +
17+
'^active=true';
18+
getCatalogVariables.addQuery(qry);
19+
getCatalogVariables.query();
20+
while (getCatalogVariables.next()) {
21+
variables.push(getCatalogVariables.getValue('sys_id'));
22+
}
23+
var variablesCount = variables.length;
24+
var currentTaskID = current.sys_id.toString();
25+
for (var i = 0; i < variablesCount; i++) {
26+
var getTaskVars = new GlideRecord('sc_item_variables_task');
27+
getTaskVars.addQuery('task', currentTaskID);
28+
getTaskVars.addQuery('variable', variables[i]);
29+
getTaskVars.setLimit(1);
30+
getTaskVars.query();
31+
if (!getTaskVars.hasNext()) {
32+
getTaskVars.initialize();
33+
getTaskVars.setValue('task', currentTaskID);
34+
getTaskVars.setValue('variable', variables[i]);
35+
getTaskVars.insert();
36+
}
37+
}
38+
})(current, previous);

0 commit comments

Comments
 (0)