"Download all attachments in a single zip file" customization is creating issue
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
‎08-13-2015 06:09 AM
Hello,
I have tried to configure a ui action to download all attachments in a single zip file.
I have taken help from servicenowguru : Download Attachments as a ZIP File - ServiceNow Guru
I am able to download the attachments in a single zip file but it is breaking some system functionalities (even for admins), such as :
- Not able to personalize list of records through List mechanic. The slushbucket is not showing any field as available to add/remove.
- Not able to open any workflow.
- "Reset to column defaults" is not appearing through List mechanic.
- on right click on any field it is not showing proper context menu.
- not able to modify any data from list of records.
UI Action :
- Show Insert , Show Update, Client : TRUE
- Table : Task
- Onclick : saveAttachmentsToZip();
- Condition : current.hasAttachments();
//action.setRedirectURL('saveAttachmentsToZip.do?sysparm_sys_id=' + current.sys_id + '&sysparm_table=' + current.getTableName());
//action.setRedirectURL('sys_attachment.do?sys_id=' + current.sys_id + '&table_name=' + current.getTableName());
function saveAttachmentsToZip() {
var url = new GlideURL('saveAttachmentsToZip.do');
url.addParam('sysparm_sys_id', g_form.getUniqueValue()); //gel("sys_uniqueValue").value
url.addParam('sysparm_table', g_form.getTableName());
var frame = top.gsft_main;
if (!frame)
frame = top;
frame.location = url.getURL();
}
I have tried only action.setRedirectURL (Line 1)...but facing same issue.
Processor :
- Type : Script
- Application Scope : Global
- Parameters : sysparm_sys_id,sysparm_table [As expected, without parameters the ui action is not working]
- Path : saveAttachmentsToZip
var sysid = g_request.getParameter('sysparm_sys_id');
var table = g_request.getParameter('sysparm_table');
var theRecord = new GlideRecord(table);
theRecord.addQuery('sys_id', sysid);
theRecord.query();
theRecord.next();
var zipName = 'attachments.zip';
var StringUtil = GlideStringUtil;
var gr = new GlideRecord('sys_attachment');
gr.addQuery('table_sys_id', theRecord.sys_id);
gr.addQuery('table_name', theRecord.getTableName());
gr.query();
if (gr.hasNext()){
g_response.setHeader('Pragma', 'public');
g_response.addHeader('Cache-Control', 'max-age=0');
g_response.setContentType('application/octet-stream');
g_response.addHeader('Content-Disposition', 'attachment;filename=' + zipName);
//var out = new Packages.java.util.zip.ZipOutputStream(g_response.getOutputStream());
var out = GlideZipOutputStream(g_response.getOutputStream());
//var count=0;
while (gr.next()){
var sa = new GlideSysAttachment();
//var binData = sa.getBytes(gr);
var binData = sa.getContent(gr); /* getContent is limited to 5mb */
var file = gr.file_name;
this.addBytesToZip(out, zipName, file, binData);
//count ++;
}
// Complete the ZIP file
out.close();
}
function addBytesToZip (out, dir, file, stream){
// Add ZIP entry to output stream.
//out.putNextEntry(new Packages.java.util.zip.ZipEntry(file));
out.putNextEntry(new GlideZipEntry(file));
out.write(stream, 0, stream.length);
out.closeEntry();
}
Issue snapshot :
Once I am deactivating the processor, the issue is not there. Hence, the issue is causing due to the custom processor.
Please help me to rectify the issue.
Thanks.

- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
‎08-15-2015 06:24 AM
Why did you change what I had in demo022? I reverted the processor to what I had originally and the attachment feature works fine and I cannot reproduce any of the issues that you're reporting.
I noticed that you added 'sysparm_sys_id,sysparm_table' to the parameter list. I believe that's when it started behaving erratically for you. I have fixed the processor script to what I had it as before. Simply take that code and use it in your environment. It is also copied exactly from the SNGuru article.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
‎08-18-2015 07:10 AM
Hello Jacob,
Actually, the SNGuru UI action was not working earlier and I had to modify the script as per the comment provided by some other user.
Now I found the issue and after a small correction in UI Action code, it is working fine (tested in 2-3 snow instances) without processor param :
Actual code in SNGuru :
action.setRedirectURL('exportAttachmentsToZip.do?sysparm_sys_id=' + current.sys_id + '&sysparm_table=' + current.getTableName());
Modified Working UI Action code:
action.setRedirectURL('exportAttachmentsToZip.do?sysparm_sys_id=' + current.sys_id + '&sysparm_table=' + current.getTableName());
However, there is one issue :
The functionality is not working when I have implemented it in an instance (not in demo but in a private instance) :
On click of the UI action the URL is get changed to : https://<<instancename>.service-now.com/exportAttachmentsToZip.do?sysparm_tiny=<<sys_id>>
Could you please tell me why the url is getting changed to 'sysparm_tiny'?
I have checked the scripts (with the script which is working in other instance) again and again but didn't find any mismatch!
Thanks for all your responses and help.
Regards,
Subhankar
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
‎05-31-2016 05:34 AM
Hello Anthony,
Again, I need your help. In the below script, I am able to get Log 1, Log 2 and Log 3 but not able to get Log 4 and Log 5.
Now, I am using Fuji patch 10.
var sysid = g_request.getParameter('sysparm_sys_id');
var table = g_request.getParameter('sysparm_table');
var theRecord = new GlideRecord(table);
theRecord.addQuery('sys_id', sysid);
theRecord.query();
theRecord.next();
gs.info("Log 1 - theRecord sys id : "+theRecord.sys_id+"table name: "+theRecord.getTableName());
var zipName = 'attachments.zip';
var gr = new GlideRecord('sys_attachment');
gr.addQuery('table_sys_id', theRecord.sys_id);
gr.addQuery('table_name', theRecord.getTableName());
gr.query();
gs.info("Log 2 - gr count : "+gr.getRowCount());
if (gr.hasNext()){
gs.info("Log 3 - I am here");
g_response.setHeader('Pragma', 'public');
g_response.addHeader('Cache-Control', 'max-age=0');
g_response.setContentType('application/octet-stream');
g_response.addHeader('Content-Disposition', 'attachment;filename=' + zipName);
var out = new GlideZipOutputStream(g_response.getOutputStream());
gs.info("Log 4 - I am before attachment");
while (gr.next()){
var sa = new GlideSysAttachment();
gs.info("Log 5 - I am inside attachment");
//var binData = sa.getBytes(gr);
var binData = sa.getContent(gr); /* getContent is limited to 5mb */
var file = gr.file_name;
this.addBytesToZip(out, zipName, file, binData);
}
// Complete the ZIP file
out.close();
}
function addBytesToZip (out, dir, file, stream){
// Add ZIP entry to output stream.
out.putNextEntry(new GlideZipEntry(file));
out.write(stream, 0, stream.length);
out.closeEntry();
}
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
‎10-21-2015 09:49 AM
Hi Jacob,
I've implemented the solution from SNGuru on my Fuji instance (processor is on the Task table) but when I try to generate the zip from an incident record nothing is happening (blank screen), I get the following error in System Logs - Warnings:
org.mozilla.javascript.EvaluatorException: GlideRecord.addQuery() - invalid table name: null (<refname>; line 5)
Line(5)
var theRecord = new GlideRecord(table);
evaluateString(JavaScript evaluation error on:
var sysid = g_request.getParameter('sysparm_sys_id');
var table = g_request.getParameter('sysparm_table');
var theRecord = new GlideRecord(table);
theRecord.addQuery('sys_id', sysid);
theRecord.query();
theRecord.next();
var zipName = 'attachments.zip';
var StringUtil = GlideStringUtil;
var gr = new GlideRecord('sys_attachment');
gr.addQuery('table_sys_id', theRecord.sys_id);
gr.addQuery('table_name', theRecord.getTableName());
gr.query();
if (gr.hasNext()){
g_response.setHeader('Pragma', 'public');
g_response.addHeader('Cache-Control', 'max-age=0');
g_response.setContentType('application/octet-stream');
g_response.addHeader('Content-Disposition', 'attachment;filename=' + zipName);
var out = new Packages.java.util.zip.ZipOutputStream(g_response.getOutputStream());
var count=0;
while (gr.next()){
var sa = new GlideSysAttachment();
var binData = sa.getBytes(gr);
var file = gr.file_name;
this.addBytesToZip(out, zipName, file, binData);
count ++;
}
// Complete the ZIP file
out.close();
}
function addBytesToZip (out, dir, file, stream){
// Add ZIP entry to output stream.
out.putNextEntry(new Packages.java.util.zip.ZipEntry(file));
out.write(stream, 0, stream.length);
out.closeEntry();
}
)
Any ideas or pointers ?
Regards
Tony
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
‎08-10-2017 03:53 AM
Hi Jacob,
I liked this approach of downloading all attachments of specific incident in one zip.
I need add more to it, what I need is to download all attachments of all incidents may be 2k-3k in numbers in one go. I tried to do it putting your processor code in while loop but it downloaded only file and stops although through various checkpoints i confirmed that loop is working fine and even function of addBytesToZip is calling expected number of times.
Please check my below code and please help me in understanding this code as well.
var rec = new GlideRecord('incident');
rec.query();
while(rec.next()){
var sysid = rec.sys_id;
var table = 'incident';
var number = rec.number;
var theRecord = new GlideRecord(table);
theRecord.addQuery('sys_id', sysid);
theRecord.query();
theRecord.next();
var zipName = ''+number+' attachments.zip';
var StringUtil = GlideStringUtil;
var gr = new GlideRecord('sys_attachment');
gr.addQuery('table_sys_id', theRecord.sys_id);
gr.addQuery('table_name', theRecord.getTableName());
gr.query();
if (gr.hasNext()){
g_response.setHeader('Pragma', 'public');
g_response.addHeader('Cache-Control', 'max-age=0');
g_response.setContentType('application/octet-stream');
g_response.addHeader('Content-Disposition', 'attachment;filename=' + zipName);
var out = new Packages.java.util.zip.ZipOutputStream(g_response.getOutputStream());
var count=0;
while (gr.next()){
var sa = new GlideSysAttachment();
var binData = sa.getBytes(gr);
var file = gr.file_name;
addBytesToZip(out, zipName, file, binData);
count ++;
}
// Complete the ZIP file
out.close();
}
}
function addBytesToZip (out, dir, file, stream){
// Add ZIP entry to output stream.
out.putNextEntry(new Packages.java.util.zip.ZipEntry(file));
out.write(stream, 0, stream.length);
out.closeEntry();
}
Regards,
Manas