how to download an attachment in browser? - gmail-api

I'm using the Gmail API in browser and want to allow the user to download email attachments. I see https://developers.google.com/gmail/api/v1/reference/users/messages/attachments/get but it returns JSON and base64 data. I don't think I can get that data in memory then trigger a "download" to save the file locally. Even if I could I don't think it would be efficient - it would probably download the file in memory vs. streaming it to a file. I think I need a direct link to a file that returns the correct file name and raw binary data (not base64). Is there a way to do this? Right now the only way I see is to proxy requests.

You can get the data from the base64 and save it to file locally.
If you are getting the attachment in Java, you can use the FileOutputStream class (or f.write() in Python) to write the bytes to file and save it locally with a path.
You can try with the following sample code from Google Developer page:
public static void getAttachments(Gmail service, String userId, String messageId)
throws IOException {
Message message = service.users().messages().get(userId, messageId).execute();
List<MessagePart> parts = message.getPayload().getParts();
for (MessagePart part : parts) {
if (part.getFilename() != null && part.getFilename().length() > 0) {
String filename = part.getFilename();
String attId = part.getBody().getAttachmentId();
MessagePartBody attachPart = service.users().messages().attachment().
get(userId, messageId, attId).execute();
byte[] fileByteArray = Base64.decodeBase64(attachPart.getData());
FileOutputStream fileOutFile =
new FileOutputStream("directory_to_store_attachments" + filename);
fileOutFile.write(fileByteArray);
fileOutFile.close();
}
}
}

Related

How can I convert a filled iText PDF template into an Input Stream?

I'm trying to use an existing PDF template and iText to fill in the document, then send the file to our database.
However, I cannot figure out how to convert the finished iText PDF into a usable form - I can display it to the user easily enough, but I cannot get it into a File, InputStream, or even byte[] format to upload to our Database.
public ActionForward doIt(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws java.lang.Exception
{
int docid = Integer.parseInt(form.getDocumentTemplateId());
byte[] byteTemplate = TemplateDb.getTemplate(docId);
PdfReader pdfReader = new PdfReader(byteTemplate);
PdfStamper pdfStamper = new PdfStamper(pdfReader, response.getOutputStream());
AcroFields acroFields = pdfStamper.getAcroFields();
acroFields.setField(//And then I set my acro fields, which works fine);
ByteArrayInputStream inByteStream = new ByteArrayInputStream(byteTemplate );
// This is me calling a separate function to upload the Input Stream - but all that the inByteStream object contains is a blank template
DocumentManager.uploadDocument(inByteStream);
pdfStamper.close();
pdfReader.close();
}

ADF: How to get path of file when using InputFile Component

I am using jdeveloper version 11.1.1.5.0. In my use case I have created Mail Client Send Mail program where I used ADF InputFile component to attach File on mail.
But problem is that InputFile Component only return path of file(only get file name). And in my mail program DataSource class use full path to access file name.
UploadedFile uploadfile=(UploadedFile) actionEvent.getNewValue();
String fname= uploadfile.getFilename();//this line only get file name.
So how can I get full path using adf InputFile component or any other way to fulfill my requirement.
You could save the uploaded file in a path at the server. Only take care about naming that file, because of concurrency of users you should follow a policy about it, for example, adding te time in milliseconds to the name of the file. Like this...
private String writeToFile(UploadedFile file) {
ServletContext servletCtx =
(ServletContext)FacesContext.getCurrentInstance().getExternalContext().getContext();
String fileDirPath = servletCtx.getRealPath("/files/tmp");
String fileName = getTimeInMilis()+file.getFilename();
try {
InputStream is = file.getInputStream();
OutputStream os =
new FileOutputStream(fileDirPath + "/"+fileName);
int readData;
while ((readData = is.read()) != -1) {
os.write(readData);
}
is.close();
os.close();
} catch (IOException ex) {
ex.printStackTrace();
}
return fileName;
}
This method also returns the new name of the uploaded file. You can replace getTimeInMilis() with any naming policy you like.
It would be a security issue if a web app is able to see anything other than the data stream for an uploaded file. The directory structure of the client would not be exposed to the webapp. As such, unless you plan to upload the file from the same host as the server, you will not have access to the file path on the client.
Note: Using answer instead of comment due to reputation threshold

Converting com.google.api.services.drive.model.File to java.io.File

So I want to create a java.io.File so that I can use it to generate a multipart-form POST request. I have the file in the form of a com.google.api.services.drive.model.File so I'm wondering, is there a way I can convert this Google File to a Java File? This is a web-app that uses the Google App Engine SDK, which prohibits every approach I've tried to make this work
No, you it doesn't seem like you can convert from com.google.api.services.drive.model.File to java.io.File. But it should still be possible to generate a multipart-form POST request using your data in Drive.
So the com.google.api.services.drive.model.File class is used for storing metadata about the file. It's not storing the file contents.
If you want to read the contents of your file into memory, this code snippet from the Drive documentation shows how to do it. Once the file is in memory, you can do whatever you want with it.
/**
* Download the content of the given file.
*
* #param service Drive service to use for downloading.
* #param file File metadata object whose content to download.
* #return String representation of file content. String is returned here
* because this app is setup for text/plain files.
* #throws IOException Thrown if the request fails for whatever reason.
*/
private String downloadFileContent(Drive service, File file)
throws IOException {
GenericUrl url = new GenericUrl(file.getDownloadUrl());
HttpResponse response = service.getRequestFactory().buildGetRequest(url)
.execute();
try {
return new Scanner(response.getContent()).useDelimiter("\\A").next();
} catch (java.util.NoSuchElementException e) {
return "";
}
}
https://developers.google.com/drive/examples/java
This post might be helpful for making your multi-part POST request from Google AppEngine.
In GoogleDrive Api v3 you can download the file content into your OutputStream. You need for that the file id, which you can get from your com.google.api.services.drive.model.File:
String fileId = "yourFileId";
OutputStream outputStream = new ByteArrayOutputStream();
driveService.files().get(fileId).executeMediaAndDownloadTo(outputStream);

ImagesService.getServingUrl fails with IllegalArgumentException and no error message for Cloud Storage object

Here's the code:
public static String getNotFoundUrl(int size) {
try {
BlobKey blob_key = BLOB_STORE.createGsBlobKey("/gs/web_content/placeholder_img.png");
// Simple Test to make sure blob_key points at the right thing.
byte[] image_data = BLOB_STORE.fetchData(blob_key, 0, 100);
Application.getLogger().warning(new String(image_data));
// This parts works and gets the first 100 bytes.
ServingUrlOptions opts = ServingUrlOptions.Builder.withBlobKey(blob_key);
if(size > 0) opts.imageSize(size);
return IMAGES_SERVICE.getServingUrl(opts);
} catch(IllegalArgumentException e) {
Application.getLogger().warning("Unable to serve placeholder image from Cloud Storage.");
Application.getLogger().warning(e.getMessage());
Application.logException(e);
return "/placeholder_img.png";
}
}
I have also tried using
ServingUrlOptions.Builder.withGoogleStorageFileName
and got the same results.
In my mind the blob_key is definitely valid because I'm able to use
BlobstoreService.fetchData
to read the first 100 bytes and it's not throwing an exception and is successfully reading the data.
The only thing that's different about this then other situations is the file I"m trying to access was uploaded via the Cloud Console Web UI rather then through the AppEngine SDK.
The problem was permissions. Make sure that your application has permissions to the cloud storage project that you're trying to access.

Using BlobRequest.CopyFrom fails with 404 Not Found error

Hope you can help.
I'm trying to copy a blob using the Protocol namespace along with a shared access signature, but the WebResponse always throws a 404 Not Found error. I have successfully used the Get/Post/Delete/List methods (where the 404 would be thrown if the permissions were insufficient), but I cannot find the answer here.
Here's some simple code that I am using:
Uri uriFrom = new Uri("file://mymachine/myfile.txt");
Uri uriTo = new Uri("file://mymachine/myfile1.txt");
//get shared access signature - set all permissions for now
uriTo = GetSharedAccessSignature(uriTo, SharedAccessPermissions.Write |
SharedAccessPermissions.Read | SharedAccessPermissions.List);
//NOTE: This returns my uriTo object in the following format:
//http://mystoragespace.blob.core.windows.net/mycontainer/steve1.txt?se=2011-07-04T12:17:18Z&sr=b&sp=rwdl&sig=sxhGBkbDJpe9qn5d9AB7/d2LK1aun/2s5Bq8LAy8mis=
//get the account name
string accountName = uriTo.Host.Replace(".blob.core.windows.net", string.Empty);
//build the canonical string
StringBuilder canonicalName = new StringBuilder();
canonicalName.AppendFormat(System.Globalization.CultureInfo.InvariantCulture,
"/{0}/mycontainer{1}", accountName, uriFrom.AbsolutePath);
//NOTE: my canonical string is now "/mystoragespace/mycontainer/myfile.txt"
//get the request
var request = BlobRequest.CopyFrom(uriTo, 300, canonicalName.ToString(),
null, ConditionHeaderKind.None, null, null);
request.Proxy.Credentials = CredentialCache.DefaultNetworkCredentials;
//perform the copy operation
using (HttpWebResponse response = request.GetResponse() as HttpWebResponse)
{
//do nothing. the file has been copied
}
So, my uriTo seems to have the appropriate permissions (I've tried various combinations) and the canonical string seems to have the correct source string. I'm not using snapshot functionality. The proxy isn't a problem as I've successfully used other methods.
Hope someone can help...
Many regards,
Steve
From Creating a Shared Access Signature:
The following table details which operations are allowed on a resource for a given set of permissions.
...
Create or update the content, block list, properties, and metadata of the specified blob. Note that copying a blob is not supported.

Resources