Receiving emails with attachments from SendGrid in Rails 3.2.x - ruby-on-rails-3

I can successfully receive email from SendGrid and process its data.
My problem is the emails attachments.
When I look at what is posted for each attachment I get something in the lines of:
"attachment12"=>#<ActionDispatch::Http::UploadedFile:0x00000008a793f8
#original_filename="image036.png",
#content_type="image/png",
#headers="Content-Disposition: form-data;
name=\"attachment12\";
filename=\"image036.png\"\r\n
Content-Type: image/png\r\n",
#tempfile=#<File:/tmp/RackMultipart20120620-35076-1xav4k1>
>
Rather than the
Array
(
[attachment1] => Array
(
[name] => Upload.csv
[type] => text/csv
[tmp_name] => /tmp/phpo34iHI
[error] => 0
[size] => 76
)
)
Which is quoted in the Parse API shown enter link description here
Obviously, Rails is being elegant as always.
However, my questions are:
Where are the files, where they downloaded as implied? I cannot find them (I would be worried if this happened)
I am actually reading into ActionDispatch::Http::UploadedFile, according to the docs I should be able to do params['attachment12'].read
I will post my findings
Production is Heroku so I would need to either stick the files in some sort of container like the DB, Mongo or S3
I am guessing the file is actually at sendgrid but their support does not understand my question and revert me back to the parse api! There is probably a URL but I cannot get to the bottom of it with their support. Unfortunately.

The files are actually POSTed to your server but you get an ActionDispatch::Http::UploadedFile to work with. If you take a look at the class description you can see you have a couple of things available to you:
The original_filename attribute obviously, but you can use .read to actually read out the contents and save it or you can probably pass the tempfile directly to whatever gem you are using.
If you can tell me what kind of upload solution you use (paperclip, carrierwave) if any, I can help you a bit better.

Yes, the file was actually uploaded to your server already and is being stored in the tempfile attribute of the UploadFile. You can use the following to access the full file path:
params['attachment12'].tempfile.to_path.to_s
Source: How to retrieve a FileBlob from 'ActionDispatch::Http::UploadedFile' instance?
And just to make it clear, the files aren't actually on SendGrid's servers at this point in the process. They have already been posted to you and are stored somewhere on your server (probably in the /tmp directory).

Related

JSZip reports missing bytes when reading back previously uploaded zip file

I am working on a webapp where the user provides an image file-text sequence. I am compressing the sequence into a single ZIP file uisng JSZip.
On the server I simply use PHP move_uploaded_file to the desired location after having checked the file upload error status.
A test ZIP file created in this way can be found here. I have downloaded the file, expanded it in Windows Explorer and verified that its contents (two images and some HTML markup in this instance) are all present and correct.
So far so good. The trouble begins when I try to fetch that same ZIP file and expand it using JSZip.loadAsync which consistently reports Corrupted zip: missing 210 bytes. My PHP code for squirting back the ZIP file is actually pretty simple. Shorn of the various security checks I have in place the essential bits of that code are listed below
if (file_exists($file))
{
ob_clean();
readfile($file);
http_response_code(200);
die();
} else http_response_code(399);
where the 399 code is interpreted in my webapp as a need to create a new resource locally instead of trying to read existing resource data. The trouble happens when I use the result text (on an HTTP response of 200) and feed it to JSZip.loadAsync.
What am I doing wrong here? I assume there is something too naive about the way I am using readfile at the PHP end but I am unable to figure out what that might be.
What we set out to do
Attempt to grab a server-side ZIP file from JavaScript
If it does not exist send back a reply (I simply set a custom HTTP response code of 399 and interpret it) telling the client to go prepare its own new local copy of that resource
If it does exist send back that ZIP file
Good so far. However, reading the existent ZIP file into PHP and sending it back does not make sense + is fraught with problems. My approach now is to send back an http_response_code of 302 which the client interprets as being an instruction to "go get that ZIP for yourself directly".
At this point to get the ZIP "directly" simply follow the instructions in this tutorial on MDN.

Updated JSON file is not reading during runtime

Team,
I have service to register a user with certain data along with unique mail id and phone no in JSON file format as a body (for ex: registerbody.json).
Before Post call I am generating unique mail id , phone no and updating the same json file (registerbody.json) fields which is in the same folder where feature file locates. I see the file is updated with the required data during runtime.
I used read () method and performed POST request
Surprisingly read method is not taking updated JSON file instead it is reading old data in the registerbody.json file.
Do you have any idea on this, why it is picking up old data even though file is updated with the latest information?
Please assist me with this.
Karate uses the Java classpath, which is typically target/test-classes. So if you edit a file in src/test/java Karate won't see it unless it is copied. This copying is automatically done when you build / compile your code.
My suggestion is use target/ as a temp folder and then you can read using the file: prefix:
* def payload = read('file:some.json')
Before Post call I am generating unique mail id , phone no and updating the same json file (registerbody.json)
You are making a big mistake here, Karate specializes in updating JSON based on variables. I suggest you take 5 minutes and read this part of the docs VERY carefully: https://github.com/intuit/karate#reading-files
Especially the part about embedded expressions: https://github.com/intuit/karate#embedded-expressions

Debugging ActiveMerchant; need full request and response. How to?

Rails 3.0.10 and activemerchant gem 1.29.3
My app works fine in sandbox, but transactions in production mode are failing with "Security header is not valid", "ErrorCode"=>"10002"
We initiated a support request with paypal, after reviewing all the configuration parameters a million times and they feel we're hitting an incorrect endpoint. They've asked for a full trace for the transaction, including headers, etc, so I'm trying to figure out how to do that. I found this article
which suggested adding this to the config block
ActiveMerchant::Billing::PaypalGateway.wiredump_device = File.new(File.join([Rails.root, "log", "paypal.log"]), "a")
But that just results in an empty log; nothing gets dumped to it.
So, how can I obtain this info from the GATEWAY object, if possible? Here's the production config, the format of which is identical to what's used in staging env.
::GATEWAY = ActiveMerchant::Billing::PaypalGateway(
:login => 'me_api1.blah...',
:password => 'string...',
:signature => 'longer string...'
)
Thanks.
Needed to add the additional line as follows:
ActiveMerchant::Billing::PaypalGateway.wiredump_device.sync = true
Within the same config block in the environment
Somewhere in the class library you're using there should be a function to output this for you (if it's a well built library, that is.)
Even without that, though, you should be able to look in that PaypalGateway function to see where/how it's setting the endpoint. It's either hard-coding the value or it'll be setting different endpoints based on some sandbox option you have configured somewhere else in the class.
It's hard to tell you more than that without getting a look a the actual class library you're using, but I can concur that it must be either incorrect credentials or an incorrect endpoint. I've never once seen that security header error when it wasn't simply invalid credentials, which means either your values are incorrect or you're hitting the wrong endpoint.
If you want to post that whole function (or maybe even the whole library as the endpoint could be getting set from some other function) I can take a look and find the problem for you.

How to read params from Transloadit upon successful upload to s3

i am using Transloadit to process and store my pic to amazon s3. The upload works fine, however upon successful redirect back to my app i get an error when trying to access one of the vales from the hash of params sent by transloadit.
<%= params[:transloadit][:ok] %>
The error returned is
can't convert Symbol into Integer
and the hash of params looks like this:
{"transloadit"=>"{\"ok\":\"ASSEMBLY_COMPLETED\",
\"message\":\"The assembly was successfully completed.\",
\"assembly_id\":\".........\",
\"assembly_url\":\"http://api2.donnie.transloadit.com/assemblies/....\",
\"bytes_received\":351697,
\"bytes_expected\":351697,.........}
I am using the gem transloadit/rails-sdk for easy integration into my app. On their github page they say and i quote:
"If you want to use the automatic transload parameter decoding, you have to include the Transloadit::Rails::ParamsDecoder module into your controller
class YourController
include Transloadit::Rails::ParamsDecoder
end
that way the param[:transloadit] is automatically decoded for you, if it exists"
I am not sure what they mean by this (even if i include this into my controller i get an error with a different set of params). What is the purpose of this line?
All i need is to access the params[:transloadit][:ok] parameter. How can i get hold of this parameter? thanks
I had a similar problem. If you use key names instead of symbols, it might help. I'm not sure why, but that's what I had to do. Try params["transloadit"]["ok"] or some variation of that.

Stopping invalid file type or file name submissions in coldfusion

So, I'm having this lovely issue where people like to submit invalid file types or funky named files... (like.. hey_i_like_"quotes".docx) Sometimes they will even try to upload a .html link...
How should I check for something like this? It seems to create an error every time someone submits a poorly named item.
Should I create a cfscript that checks it before submission? Or is there an easier way?
If it was before submission it would be javascript not cfscript. Javascript can always be got round, so I'd say you'd be better doing it server-side with ColdFusion. Personally I'd just wrap the whole thing in a try/catch (you should do this anyway as a matter of course with all file upload type things), and throw an error back at them if their filename is no good.
When you say submit are you using cffile to allow your users to upload file.
If so, use the attribute "accept" with a try and catch around. for example....
<cftry>
<cffile action = "upload"
fileField = "FileContents"
destination = "c:\files\upload\"
accept="image/jpg, application/msword"
>
<cfcatch type="Any" >
<p>sorry we could not upload your file!</p>
</cfcatch>
</cftry>
I personally would not use "just" JavaScript as this could be disabled and you are back in the same boat.
Hope this helps.
On the server, as part of validation, use reFindNoCase() along with an appropriate regex to check for a properly formatted file path. You can find lots of example regex expressions for a file path on the internet, such at this one. Hope that helps.
As #Duncan pointed out, a client-side validation would most likely be in JavaScript. Personally, if I had time/resources, I would do this as a convenience for the end user. If they upload an enormous PDF when a DOCX is required by the system, it would be annoying for them not to receive a message until the upload is complete.
As far as filenames go, it seems to me that the simplest solution (and one I've used in the past) is to assume all filenames are bad, and rename them. There are several ways to do this. If you need to preserve the original filename, I would just use urlEncodedFormat() ot clean the filename into something that is web-friendly. If you need to preserve all versions, you can append a date/time stamp, so bob.xocx becomes bob_201104051129.docx or somesuch. If you must keep the original filename without any changes, I would recommend seting up a DB table as a pinter system, keeping the original name, timestamp, and other metadata there and referring to the file by renaming it to the ID.
But urlEncodedFormat() is probably enough for what you've outlined.
For user experience it's best to do it client-side but it's not bad at all to double check server side too.
For the client side part, I recommend using the jQuery validation plugin, easy to use.