Google Drive uploads file OK but cannot view it - javascript

The code below is working at loading a PDF file (created with jsPDF) into my Google Drive folder. It is essentially Google Drive the Quickstart code modified.
The PDF generated looks OK when viewed inside the browser that is opened with "docMenu.output('dataurlnewwindow');"
The PDF file appears OK in my Google Drive folder, but when I go to view it I get a grey screen with "Failed to load PDF document". I have no execution errors in console / inspect.
What have I missed? Have I messed up by pulling the Blob (data URI) and feeding it to Google Drive upload?
Many thanks!
<script type="text/javascript">
var CLIENT_ID = 'my-client-id';
var SCOPES = 'https://www.googleapis.com/auth/drive';
var FOLDER_ID = 'my-folder-id';
/**
* Called when the client library is loaded to start the auth flow.
*/
function handleClientLoad() {
window.setTimeout(checkAuth, 1);
}
/**
* Check if the current user has authorized the application.
*/
function checkAuth() {
gapi.auth.authorize(
{'client_id': CLIENT_ID, 'scope': SCOPES, 'immediate': true},
handleAuthResult);
}
/**
* Called when authorization server replies.
* #param {Object} authResult Authorization result.
*/
function handleAuthResult(authResult) {
if (authResult && !authResult.error) {
// Access token has been successfully retrieved, requests can be sent to the API.
var docMenu = new jsPDF('p', 'cm', 'a5'); <-- Create PDF document
docMenu.text(2, 1, "Testing"); <-- Add text here...
docMenu.text(2, 5, "Testing");
docMenu.text(2, 10, "Testing");
docMenu.text(2, 15, "Testing");
docMenu.text(2, 20, "Please order and pay at the counter.");
docMenu.output('dataurlnewwindow'); <-- Displays PDF perfectly
var MyBlob = docMenu.output('blob'); <-- get PDF Blob
MyBlob.name = "test.pdf"; <-- Give it a file name
insertFile(MyBlob); <-- send it to Google Drive upload routine
} else {
alert("FAILED AUTHORIZING");
}
}
/**
* Start the file upload.
* #param {Object} evt Arguments from the file selector.
*/
function uploadFile(evt) {
gapi.client.load('drive', 'v2', function() {
var file = evt.target.files[0];
insertFile(file);
});
}
/**
* Insert new file.
* #param {File} fileData File object to read data from.
* #param {Function} callback Function to call when the request is complete.
*/
function insertFile(fileData, callback) {
const boundary = '-------314159265358979323846';
const delimiter = "\r\n--" + boundary + "\r\n";
const close_delim = "\r\n--" + boundary + "--";
var reader = new FileReader();
reader.readAsBinaryString(fileData);
reader.onload = function(e) {
var contentType = fileData.type || 'application/octet-stream';
var metadata = {
'title': fileData.name,
'mimeType': contentType,
'parents': [{"id":FOLDER_ID}]
};
var base64Data = btoa(reader.result);
var multipartRequestBody =
delimiter +
'Content-Type: application/json\r\n\r\n' +
JSON.stringify(metadata) +
delimiter +
'Content-Type: ' + contentType + '\r\n' +
'Content-Transfer-Encoding: base64\r\n' +
'\r\n' +
base64Data +
close_delim;
var request = gapi.client.request({
'path': '/upload/drive/v2/files/',
'method': 'POST',
'params': {'uploadType': 'multipart'},
'headers': {
'Content-Type': 'multipart/mixed; boundary="' + boundary + '"'
},
'body': multipartRequestBody});
if (!callback) {
callback = function(file) {
console.log(file)
};
}
request.execute(callback);
}
}
</script>

Do you think you need to change the file's permissions in Google Drive when it is created so that "anyone with a link" can view it or make it public?
Could it be the file is corrupt and Google Drive can't read it, but the docMenu.output method somehow isn't affected by the corruption? I have had something similar happen before.
I don't really have any experience with creating PDFs, but I hope my suggestion may at least point you in the right direction if it's correct.

For those who it may help, the above code works perfectly for me in creating and uploading PDF files to Google Drive using jsPDF.
The issue I was facing was one of Drive not liking this PDF for some reason (as it is reported with other PDFs in forums).
The file downloads OK and opens perfectly in Acrobat, Foxit and others... the problem is with Google.

Related

serve .ics file to webcal:// instead of download by browser

I have some code that is using ics.js framework which uses fileSaver.js (https://github.com/eligrey/FileSaver.js) to create and save a calendar invite (.ics) into the users browser.
Through testing/research I have learned that mobile browsers do not like downloading a file via this javascript download mechanism, and try to render them as text files in the browser instead of trigger iOS/Android to open the calendar program like desktop does.
I was told the way to get these files to open on mobile is to present them to the browser as a "webcal://" link, pointing to my .ics file.
So how do I hijack the download function of fileSaver.js, and force the browser to load that .ics blob/file via "webcal://myInvite.ics" to trigger the calendar app to recognize the file on mobile?
Tried using the URL saving method from FileSaver.js but it does not work :(
https://github.com/eligrey/FileSaver.js#saving-urls
I also made sure the MIME type was being set.
ics.js
/**
* Download calendar using the saveAs function from filesave.js
* #param {string} filename Filename
* #param {string} ext Extention
*/
'download': function (filename, ext) {
if (calendarEvents.length < 1) {
return false;
}
ext = (typeof ext !== 'undefined') ? ext : '.ics';
filename = (typeof filename !== 'undefined') ? filename : 'webcal://calendar';
var calendar = calendarStart + SEPARATOR + calendarEvents.join(SEPARATOR) + calendarEnd;
var blob;
if (navigator.userAgent.indexOf('MSIE 10') === -1) { // chrome or firefox
blob = new Blob([calendar]);
blob = new Blob([calendar], { type: 'text/calendar;charset=' + document.characterSet });
} else { // ie
var bb = new BlobBuilder();
bb.append(calendar);
blob = bb.getBlob('text/x-vCalendar;charset=' + document.characterSet);
}
saveAs("webcal://", filename + ext);
// saveAs(blob, filename + ext);
return calendar;
},
myApp.js
////////////////////////////////////////////
// ics generator
///////////////////////////////////////////
const calForm = document.querySelector('#add-cal-form');
var el = document.getElementById('add-cal-form');
if(el){
calForm.addEventListener('submit', (e) =>{
e.preventDefault();
var cal = ics();
cal.addEvent('Demo Event', 'This is an all day event', 'Nome, AK', '8/7/2019', '8/7/2019');
cal.addEvent('Demo Event', 'This is thirty minute event', 'Nome, AK', '8/7/2019 5:30 pm', '8/7/2019 6:00 pm');
cal.download();
});
}
If I try to save as URL (saveAs("webcal://", filename + ext);) I get this error
Failed to execute 'createObjectURL' on 'URL': No function was found that matched the signature provided.
If I use the default download example (saveAs(blob, filename + ext);) then it works fine on desktop spawning the download in the browser. On mobile it will download and render the file as text inside the browser.

File path of image on server

I have an image saved on my server which I want to display on the client.
EDIT: I select an image from a list of up to 80. This image is then resized if needed and returned to the client.
My server is running on IIS7 # localhost:1337 .
Server file location:
C:\inetpub\wwwroot\API\Cyber\4076\1\img\resized\1.jpg
This is the path that's returned when I return the absolute path to the client (see code below). The client however can't find this file.
My Client is running on IIS7 #localhost:15536.
With the help of firebug I can set the source of the Image object in the client application to the location of the file on the server under localhost.
localhost:1337/Cyber/4076/1/img/resized/1.jpg
It then correctly displays the image.
Question
What changes do I make so that the changes I did manually happen automatically? How do I create/return the second link and use it in the client opposed to the first link?
Server API call
/// <summary>
/// Method to retrieve files from the server. Files will be searched in the requested map depending on size.
/// The resized image will be saved on the server and the location will be send to the client.
/// </summary>
/// <returns>A response message with the location of the newly resized file.</returns>
public HttpResponseMessage getFileResized(string name, int collectionId, int maxWidth, int maxHeight, int version = 1)
{
// create real file path
string basePath = FileService.GetPath(collectionId, CollectionType.collection, version) + #"\img\"; //HostingEnvironment.MapPath("~/Cyber/" + collectionId + "/img/");
string filePath = basePath + #"resized\";
// Standard location of the file when it's uploaded to the server.
string fileBase = basePath + name;
// New location for the resized file on the server.
string fileExact = filePath + name;
try
{
if (!File.Exists(filePath))
{
// create new directories for resizes
Directory.CreateDirectory(filePath);
}
if (//File.Exists(fileBase)) &&
!File.Exists(fileExact))
{
Logger.log("File found but resize missing. Creating resized...");
ImageService.createResizedFile(name, basePath, maxWidth, maxHeight);
}
// check if path and file exist
string file = Directory.GetFiles(filePath, name, SearchOption.TopDirectoryOnly).FirstOrDefault();
if (file != null)
{
// retrieve the file location, write headers and return it
HttpResponseMessage response = Request.CreateResponse(HttpStatusCode.Accepted);
response.Headers.Location = new Uri(file);
return response;
}
else
{
// file does not exist at the selected location
Logger.log("Resized image file does not exist on location: {0}.", fileExact);
throw new HttpResponseException(HttpStatusCode.NotFound);
}
}
catch (DirectoryNotFoundException)
{
throw new HttpResponseException(HttpStatusCode.NotFound);
}
}
Client retrieves the file location like this
HttpResponseMessage responseMessage = client.GetAsync("api/file/getFileResized?name=" + fileName + "&collectionId=" + CollectionId
+ "&maxWidth=" + maxWidth + "&maxHeight=" + maxHeight + "&version=" + Version).Result;
string sourceResponse = "";
if (responseMessage.IsSuccessStatusCode)
{
sourceResponse = responseMessage.Headers.Location.AbsolutePath;
return Json(new { OK = 1, message = sourceResponse, refresh = true }, "text/html");
}
The source is put into the image src with javascript and Jquery
$("#editorModal").on("shown.bs.modal", function () { showImage(); })
function showImage() {
console.log("ShowImage resizedSource");
console.log(resizedSource);
$("#selectedImage").attr("src", resizedSource);
}
resizedSource is set in this handler
function getResizedImage() {
$.ajax({
url: "/NextprintPhotobook/GetResizedImageFile",
type: "POST",
data: JSON.stringify({ imageSource: imageSource }),
dataType: "json",
contentType: 'application/json; charset=utf-8',
success: function (data) {
if (data.OK != 1) {
showError("Er is een fout opgetreden bij het openen van de foto. Data niet OK.", data.message, data.refresh);
}
console.log("getResizedImage data.message");
console.log(data.message);
resizedSource = data.message;
},
error: function (data) {
showError("Er is een fout opgetreden bij het openen van de foto.");
}
});
}
Simply save the image path in the <appSettings> block of web.config with respect to your server
<add key="ImagePath" value="localhost:1337/Cyber/4076/1/img/resized/" />
And then get the path from this key and the image name from database. Then finally create a URL like this:
ImageUrl = ConfigurationManager.AppSettings["ImagePath"]+ ImageName;
Where ImageName is the name of image extracted from database. Return the ImageUrl to the client which will be
localhost:1337/Cyber/4076/1/img/resized/1.jpg
when ImageName=1.jpg
Or you can also do the following for dynamic application path
var context = HttpContext.Current;
string appPath = string.Format("{0}://{1}{2}{3}",
context.Request.Url.Scheme,
context.Request.Url.Host,
context.Request.Url.Port == 80 ? string.Empty : ":" + context.Request.Url.Port,
context.Request.ApplicationPath);
And use this appPath for setting the relative path to the localhost dynamically.

Trying to set file thumbnail to Google Drive using javascript

I am trying to add a thumbnail to my files that I am uploading to Drive using Javascript. I am trying to follow the directions at https://developers.google.com/drive/v3/web/file#uploading_thumbnails
To create my web-safe base64 image, I converted a simple red-square image to base64 using an online converter, which produced
data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mP4z8DwHwAFAAH/VscvDQAAAABJRU5ErkJggg==
then I took everything following data:image/png; and replaced / with _ and removed the ='s:
iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mP4z8DwHwAFAAH_VscvDQAAAABJRU5ErkJggg
I then added the following to my original header in my request:
contentHints: {
thumbnail: {
image: "iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mP4z8DwHwAFAAH_VscvDQAAAABJRU5ErkJggg",
mimeType: "image/png"
}
}
However, I am failing to see any thumbnails for my files, in either the list or grid view in Google Drive.
Any thoughts as to what's going on?
Here's my entire file-saving code:
function saveFile(content) {
var boundary = '-------314159265358979323846';
var header = JSON.stringify({
title: "My file",
mimeType: "application/myFile",
parents: ['root'],
contentHints: {
thumbnail: {
image: "iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mP4z8DwHwAFAAH_VscvDQAAAABJRU5ErkJggg",
mimeType: "image/png"
}
}
});
var method = 'POST';
var path = "/upload/drive/v2/files";
var body = [
"\r\n--" + boundary + "\r\nContent-Type: application/json\r\n\r\n" + header,
"\r\n--" + boundary + "\r\nContent-Type: " + this.mimeType + "\r\n\r\n" + (content.getContentAsJSON()),
"\r\n--" + boundary + "--"].join('');
var request = gapi.client.request({
path: path,
method: method,
params: {
uploadType: 'multipart'
},
headers: {
'Content-Type': 'multipart/related; boundary="' + boundary + '"'
},
body: body
});
request.execute(file);
};
As you are using v3, the end-point URL path should be
var path = "/upload/drive/v3/files";
For v2, the reference is at https://developers.google.com/drive/v2/web/file#uploading_thumbnails It has a different structure/syntax
By the way, please take note that "If Drive can generate a thumbnail from the file, then it will use the generated one and ignore any you may have uploaded."
I have also found that your thumbnail image does not meet this requirement: "The minimum width for thumbnails is 220px."
You may try with the below instead, which is 220x20 px
"iVBORw0KGgoAAAANSUhEUgAAANwAAAAUCAYAAADm4VNYAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsQAAA7EAZUrDhsAAABaSURBVHhe7dMxAcAgEMDALzo61r-zaoAFDZnulijI87_fHiCxboGA4SBkOAgZDkKGg5DhIGQ4CBkOQoaDkOEgZDgIGQ5ChoOQ4SBkOAgZDkKGg5DhIGQ4yMwcJVwCVCif97cAAAAASUVORK5CYII"

How to import data into Fusion Table directly?

Below code is working fine. I can upload the data into Google Drive. Instead of Upload a data into Google Drive.
How to import data or ImportRows into Google Fusion Table directly? Can anyone help me and correct what I need to do.
E.g:
var request = gapi.client.request({
'path': '/upload/drive/v2/files',
'method': 'POST',
'params': {'uploadType': 'multipart'},
'headers': {
'Content-Type': 'multipart/mixed; boundary="' + boundary + '"'
},
Working Code :
<html>
<head>
<meta http-equiv="Content-type" content="text/html;charset=UTF-8">
<script type="text/javascript">
var CLIENT_ID = '607567025394-rmte05500pvsoj12dsrie1cbei5te506.apps.googleusercontent.com';
//var SCOPES = 'https://www.googleapis.com/auth/drive';
var SCOPES = 'https://www.googleapis.com/auth/fusiontables';
/**
* Called when the client library is loaded to start the auth flow.
*/
function handleClientLoad() {
window.setTimeout(checkAuth, 1);
}
/**
* Check if the current user has authorized the application.
*/
function checkAuth() {
gapi.auth.authorize(
{'client_id': CLIENT_ID, 'scope': SCOPES, 'immediate': true},
handleAuthResult);
}
/**
* Called when authorization server replies.
*
* #param {Object} authResult Authorization result.
*/
function handleAuthResult(authResult) {
var authButton = document.getElementById('authorizeButton');
var filePicker = document.getElementById('filePicker');
authButton.style.display = 'none';
filePicker.style.display = 'none';
if (authResult && !authResult.error) {
// Access token has been successfully retrieved, requests can be sent to the API.
filePicker.style.display = 'block';
filePicker.onchange = uploadFile;
} else {
// No access token could be retrieved, show the button to start the authorization flow.
authButton.style.display = 'block';
authButton.onclick = function() {
gapi.auth.authorize(
{'client_id': CLIENT_ID, 'scope': SCOPES, 'immediate': false},
handleAuthResult);
};
}
}
/**
* Start the file upload.
*
* #param {Object} evt Arguments from the file selector.
*/
function uploadFile(evt) {
gapi.client.load('drive', 'v2', function() {
var file = evt.target.files[0];
insertFile(file);
});
}
/**
* Insert new file.
*
* #param {File} fileData File object to read data from.
* #param {Function} callback Function to call when the request is complete.
*/
function insertFile(fileData, callback) {
const boundary = '-------314159265358979323846';
const delimiter = "\r\n--" + boundary + "\r\n";
const close_delim = "\r\n--" + boundary + "--";
var reader = new FileReader();
reader.readAsBinaryString(fileData);
reader.onload = function(e) {
var contentType = fileData.type || 'application/octet-stream';
var metadata = {
'title': fileData.name,
'mimeType': contentType
};
var base64Data = btoa(reader.result);
var multipartRequestBody =
delimiter +
'Content-Type: application/json\r\n\r\n' +
JSON.stringify(metadata) +
delimiter +
'Content-Type: ' + contentType + '\r\n' +
'Content-Transfer-Encoding: base64\r\n' +
'\r\n' +
base64Data +
close_delim;
var request = gapi.client.request({
'path': '/upload/drive/v2/files',
'method': 'POST',
'params': {'uploadType': 'multipart'},
'headers': {
'Content-Type': 'multipart/mixed; boundary="' + boundary + '"'
},
'body': multipartRequestBody});
if (!callback) {
callback = function(file) {
console.log(file)
};
}
request.execute(callback);
}
}
</script>
<script type="text/javascript" src="https://apis.google.com/js/client.js?onload=handleClientLoad"></script>
</head>
<body>
<!--Add a file picker for the user to start the upload process -->
<input type="file" id="filePicker" style="display: none" />
<input type="button" id="authorizeButton" style="display: none" value="Authorize" />
</body>
</html>
Fusion Tables also have a REST API. you can make the calls in the same way you are calling the Drive REST API.
For example to import rows you would need modify the api call and change the path to "upload/fusiontables/v2/tables/tableId/import"
It also uses POST method.
I see you have the correct scope for fusion tables: https://www.googleapis.com/auth/fusiontables
You'll also need to provide the data you want to import.
Hope this helps.

How do i force download Video in AngularJs from Amazon S3?

I have written code to download a video uploaded to amazon s3 using aws javascript sdk. Everything works fine but for some videos open up in the browser and start playing. Here is the code below:
View:
Download Video
Controller:
$scope.downloadVideo = function (video) {
videoLocation = video.video_location;
var bucketPath = videoLocation.substring(0, videoLocation.lastIndexOf("/") + 1);
bucketPath = bucketPath.substring(0, bucketPath.length - 1);
var fileName = videoLocation.substring(videoLocation.lastIndexOf("/") + 1, videoLocation.length);
var videoSignedUrl = VideoFactory.downloadVideo(bucketPath,fileName);
$window.open(videoSignedUrl);
}
VideoFactory :
downloadVideo: function (bucketPath,fileName) {
bucketName = aws.bucket_name;
options = {
accessKeyId : 'XXXXXXXXXXXXXXXXXXXXX',
secretAccessKey : 'XXXXXXXXXXXXXXXXXXXXXXXXXXX',
region : 'XXXXXX'
}
var params = {
Bucket: bucketName + '/'+ bucketPath, Key: fileName, Expires: 60
};
var s3 = new AWS.S3(options);
var url = s3.getSignedUrl('getObject', params);
return url;
}
So when videos open up in a new window they start getting downloaded at the bottom of the browsers. But for some unknown videos they open up in a window and start playing. How can i stop this in angularjs. What is the suggested workaround and how do others handle this kind of issues??
I did google but most of the stackoverflow answers here say to open files in window and browsers automatically downloads it.
Try this solution it may help you.enter link description here
View:
Download Video
<a id="ExportToExcel" style="display: none;"></a>
Controller:
$scope.downloadVideo = function (video) {
videoLocation = video.video_location;
var bucketPath = videoLocation.substring(0, videoLocation.lastIndexOf("/") + 1);
bucketPath = bucketPath.substring(0, bucketPath.length - 1);
var fileName = videoLocation.substring(videoLocation.lastIndexOf("/") + 1, videoLocation.length);
var videoSignedUrl = VideoFactory.downloadVideo(bucketPath,fileName);
document.getElementById("ExportToExcel").href = videoSignedUrl;
document.getElementById("ExportToExcel").click();
}
The trick that worked was making the video as an attachment during the video upload to S3 :
options = {
accessKeyId : 'xxxxxxxxxxxxxxxxxxxxxxx',
secretAccessKey : 'xxxxxxxxxxxxxxxxxxxxxxxxxxxxx',
region : 'xxxxxx'
}
var s3 = new AWS.S3(options);
var params = {
Bucket : bucketName + '/' + bucketStructure,
Key: fileName,
ContentType: file.type,
Body: file,
ServerSideEncryption: 'AES256',
ACL : 'private',
ContentDisposition: 'attachment; filename=' + fileName,
ContentType: 'application/octet-stream'
};
s3.putObject(params, function(err, data) {
if(err) {
// There Was An Error With Your S3 Config
console.log('AWS Error : '+err.message);
return false;
}
else {
console.log('AWS Video upload done!');
}
})
This would make the video to force download automatically when a signed url was used. Has worked for most of the video mime types for me.

Categories

Resources