Written by

Question Paul Hula · May 22, 2020

CSP - Download file, manipulate and return as attachment

Hi All,

   It must be the groundhog days but I can't solve something that I know I've done before.  I have a legacy CSP page on a version of Cache without JSON and just pure Cache.

  I need a CSP page that takes a .xlsx file, manipulates the file (in COS) and then returns a new manipulated file.

  My CSP Page gets the file fine, the problem is then returning the response with the new file as an attachment.  I don't want to pipe to a new csp page with a different content-type so was sure I can set %response.Headers etc to get the reply stream I want.

So my CSP Page (which contains a lot of CSP tags)

<csp:if condition='$data(%request.MimeData("FileStream",1))'>

blah blah

s sc=##class(something).method(iStream, .oStream)

kill %request.Data ; Wrong!
set %request.Data("STREAMOID",1)= ##class(%CSP.StreamServer).Encrypt(oid) ; Wrong!

So oStream contains the stream of the new attachment, how can I get CSP to serve this up as an attachment?, the above is obviously wrong as I'm resetting the %request.Data but manipulating %response doesn't help me at all.

Anyone remember CSP as I certainly have tried to block it from memory...

Comments

Paul Hula  May 22, 2020 to Henrique Dias

Hi Henrique,

  Not exactly, the excel isn't the problem, it's when I return the XLS to the browser I need the browser to interprut it as a attachment, the problem is the %response creation.

0
Oliver Wilms · May 22, 2020

Hello Paul,

I like to work on this problem. In preparation, I found a zen page in Samples namespace and added a file upload control. I define a CSP page to go to on submit. How do I attach a file to a CSP page? Then you want to manipulate the file when received by CSP page. Does the user see the attached file on the CSP page?  Our team has a CSP page that receives an incoming file and then it is passed along to a business service in HealthConnect production. Where do you want the modified file to go?

0
Eduard Lebedyuk · May 23, 2020

.xlsx file, manipulates the file (in COS)

How are you manipulating xlsx in InterSystems ObjectScript?

0
Paul Hula  May 23, 2020 to Eduard Lebedyuk

Hi All,

  Thanks for the replies, I certainly haven't explained the problem very well!, so short summary;

CSP page shows file browser (working) that takes a stream (working) sends the file to a Method (working) and then returns a new file into the same CSP page session (not working)

I appreciate this means the CSP will be "stuck" while the method creates the new file.  I have limited access to change any of this under the hood to send to a directory or use an integration engine or any other alternative.

   For Excel we use activate, as said the Excel and sending the file is not the problem.

    Regards

0
Rubens Silva · May 25, 2020

%CSP.StreamServer is just a helper to cut short some manual labor.

What you need to do is write the file stream back to the device and change three Content-* headers as follows.

Your CSP page has an OnPreHTTP just like every %CSP.Page extended class. You can use this method to modify the Content-Type, Content-Disposition and Content-Length headers. In your case you'll need to use the <script> tag syntax for creating the method.

The example below assumes you're using a class instead.

NOTE: If you really customize your %CSP.Page or %CSP.REST. You don't even need to use the OnPreHTTP method. But I'll be using it here for educational purposes.

ClassMethod OnPreHTTP() As %Boolean [ ServerOnly = 1 ]
{
   set file = %request.GetMimeData("FileStream")
   if '$isobject(file) return 0
   
   do ##class(%CSP.StreamServer).FileClassify("XLS", .contentType, .isBinary, .charset)
   do %response.SetHeader("Content-Type", contentType)
   do %response.SetHeader("Content-Disposition", "attachment; filename=""_file.FileName_""")

  return 1
}

ClassMethod OnPage() As %Status [ ServerOnly = 1 ]
{
  set iStream = %request.GetMimeData("FileStream")
  $$$QuitOnError(##class(something).method(iStream, .oStream))
  
  do %response.SetHeader("Content-Length", oStream.Size)
  
  do oStream.Rewind()
  do oStream.OutputToDevice()
  
  return $$$OK
}
0