"Download all attachments in a single zip file" customization is creating issue

LearnerSubho
Mega Guru

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 :

Issue_for attachment customization.JPG

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.

11 REPLIES 11

Kishore8
Kilo Guru

Markus Kraus
Kilo Sage

Had this requirement, and this thread poped up while doing a search, but the solution posted here works with MidServer which I couldn't use.
The other option would be the "ZIP step" which I also couldn't use due to licensing reasons. So instead I came up with the following implementation:

var os = new Packages.java.io.ByteArrayOutputStream();
var zip = new Packages.java.util.zip.ZipOutputStream(os);

// example with text only file content
var filePath = 'this/can/be/a/path.txt';
var fileContent = 'hello world\nform a file';
zip.putNextEntry(new Packages.java.util.zip.ZipEntry(filePath));
try {
	var bytes = new Packages.java.lang.String(fileContent).getBytes();
	zip.write(bytes, 0, bytes.length);
} finally {
	zip.closeEntry();
}

// example with attachment
var sourceAttSysID = '<some source attachment sys_id>';
var attGr = new GlideRecord('sys_attachment');
if (attGr.get(sourceAttSysID)) {
  var attOS = new Packages.java.io.ByteArrayOutputStream();
  new GlideSysAttachmentInputStream(sourceAttSysID).writeTo(attOS);
  zip.putNextEntry(new Packages.java.util.zip.ZipEntry(attGr.file_name));
	try {
		var bytes = attOS.toByteArray();
		zip.write(bytes, 0, bytes.length);
	} finally {
		zip.closeEntry();
	}
}

zip.close();

var fakeGr = new GlideRecord('sc_cart_item');
fakeGr.setNewGuidValue(gs.generateGUID());

var attSysID = new GlideSysAttachment().write(fakeGr, 'my_zip_file.zip', 'application/zip', os.toByteArray());
// if required, this can be piped to a REST API response,
// just make sure to cleanup the attachment with new GlideSysAttachment().deleteAttachment(attSysID) afterwards
gs.info('source attachment output: ' + attSysID);