How can I read a zip file from Google Drive using Google App Maker? - google-app-maker

I'm building a Google App Maker app which will allow the user to select a zip file from Google Drive, unzip the file and load it into a database. I found the follow script which I've tried calling in a server script but I'm getting the error ""gapi" is not defined". I've tried adding 'https://apis.google.com/js/plus.js?onload=init' as an external resource on the project settings page but didn't resolve the issue. I'm guessing there must be an 'App Maker' way of using the Drive API to do this just haven't find a sample that shows how.
function downloadFile(fileUrl, callback) {
if (fileUrl) {
console.log('fileUrl: ' + fileUrl);
var accessToken = gapi.auth.getToken().access_token;
var xhr = new XMLHttpRequest();
xhr.open('GET', file.downloadUrl);
xhr.setRequestHeader('Authorization', 'Bearer ' + accessToken);
xhr.onload = function() {
callback(xhr.responseText);
};
xhr.onerror = function() {
callback(null);
};
xhr.send();
} else {
console.log('No file Url received.');
callback(null);
}
}

Related

App Maker: Sending Email, client script to server script function not working. Failed due to illegal value in property: a

I am new to AppMaker but I have developer experience.
The application is a Project Tracker Application
What I expect to happen: When creating a project the user uses a User Picker to select the users associated with that project. When the project is created I want to email the users associated with that project.
The issue: On clicking the Add button addProject(addButton) client script function is called.
Inside this function sendEmailToAssignees(project, assignees) is called which should reach out to the Server script and run the notifyAboutProjectCreated(project, assignees) but that is not happening.
Things to know: With logging I never reach 'Trying to send email' so I seem to never reach my server script. Also, On client script when I comment out sendEmailToAssignees function everything runs smooth. I have looked at this documentation as a resource so I feel my implementation is okay. https://developers.google.com/appmaker/scripting/client#client_script_examples
The final error message I get is:
Failed due to illegal value in property: a at addProject
(AddProject:110:24) at
AddProject.Container.PanelAddProject.Form1.Spring.ButtonAdd.onClick:1:1
Am I missing something here? Any help would be greatly appreciated. Thank you!
Client Script
function sendEmailToAssignees(project, assignees) {
google.script.run
.withSuccessHandler(function() {
console.log('Sending Email Success');
}).withFailureHandler(function(err) {
console.log('Error Sending Email: ' + JSON.stringify(err));
})
.notifyAboutProjectCreated(project, assignees);
}
function addProject(addButton) {
if (!addButton.root.validate()) {
return;
}
addButton.datasource.createItem(function(record) {
var page = app.pages.AddProject;
var pageWidgets = page.descendants;
var trainees = pageWidgets.AssigneesGrid.datasource.items;
var traineesEmails = trainees.map(function(trainee) {
return trainee.PrimaryEmail;
});
record.Assignee = traineesEmails.toString();
var assignees = traineesEmails.toString();
var project = record;
updateAllProjects(record);
console.log('update all projects done');
sendEmailToAssignees(project, assignees);
console.log('Send Email done');
if (app.currentPage !== app.pages.ViewProject) {
return;
}
gotoViewProjectPageByKey(record._key, true);
});
gotoViewProjectPageByParams();
}
Server Script
function notifyAboutProjectCreated(project, assignees) {
console.log('Trying to send email');
if (!project) {
return;
}
var settings = getAppSettingsRecord_()[0];
if (!settings.EnableEmailNotifications) {
return;
}
var data = {
appUrl: settings.AppUrl,
assignee: project.Assignee,
owner: project.Owner,
startDate: project.StartDate,
endDate: project.EndDate,
jobType: project.Type,
jobId: project.Id
};
// Email Subject
var subjectTemplate = HtmlService.createTemplate(settings.NotificationEmailSubjectJob);
subjectTemplate.data = data;
var subject = subjectTemplate.evaluate().getContent();
// Email Body
var emailTemplate =
HtmlService.createTemplate(settings.NotificationEmailBodyJob);
emailTemplate.data = data;
var htmlBody = emailTemplate.evaluate().getContent();
console.log('About to send email to:', assignees);
sendEmail_(null, assignees, subject, htmlBody);
}
The reason you are getting this error is because you are trying to pass the client "project record" to the server. If you need to access the project, then pass the record key to the server and then access the record on the server using the key.
CLIENT:
function sendEmailToAssignees(project, assignees) {
var projectKey = project._key;
google.script.run
.withSuccessHandler(function() {
console.log('Sending Email Success');
}).withFailureHandler(function(err) {
console.log('Error Sending Email: ' + JSON.stringify(err));
})
.notifyAboutProjectCreated(projectKey , assignees);
}
SERVER:
function notifyAboutProjectCreated(projectKey, assignees) {
console.log('Trying to send email');
var project = app.models.<PROJECTSMODEL>.getRecord(projectKey);
if (!project) {
return;
}
//Rest of the logic
}
The project record object in the client is not the same as the project record object in the server; hence the ilegal property value error.

Firebase storage download the raw text I uploaded and not just the url

I uploaded a raw String 'Test' to the firebase storage using the sample provided here and it went through successfully.
But when I tried to "download" the string I uploaded, using the sample below, apparently he only example on how to download data from firebase storage it returns the url of the string file.
storageRef.child('path/to/string').getDownloadURL().then(function(url) {
// I get the url of course
}).catch(function(error) {
// Handle any errors
});
How do I get the contents of the file from the callback url which is 'Test' (The string I uploaded.)
The short answer is that in the Web Storage SDK you can only get a download URL that represents that data. You'll need to "download" the file using an XMLHttpRequest (or equivalent):
storageRef.child('path/to/string').getDownloadURL().then(function(url) {
var XMLHttp = new XMLHttpRequest();
XMLHttp.onreadystatechange = function() {
if (xmlHttp.readyState == 4 && xmlHttp.status == 200)
var response = xmlHttp.responseText; // should have your text
}
XMLHttp.open("GET", url, true); // true for asynchronous
XMLHttp.send(null);
}).catch(function(error) {
// Handle any errors from Storage
});

How to specify the location of kml file when using geoxml3 parser with meteor js

I have been trying to parse a kml file using the geoxml3 parser. The geoxml3.js file is put in the public folder. The parser is working fine if I put the kml file inside the public folder.
geoXml.parse('doc.kml'); // this is working fine
But how can I make it work if the kml file is located somewhere else, say in the 'uploads' folder outside the public folder. I have tried,
geoXml.parse(uploadPath+'/doc.kml');
but this is not working. How should I specify the file path ? I can't put the kml files in the public folder as any change inside the folder will make the page refresh.
Please help me out.
Haven't tried this one, but Assets.getText() may be what you're looking for. The documentation
specifies that you pass it a file path relative to your private directory.
Well, could not resolve the path issue. Assets.getText() is dependent on the private folder and also it doesn't stop the server from restart. But found an alternative solution, where you can upload the file to any folder within your project app and read from it.
// On client side
Meteor.call('getKmlString', kml_file_name, function(error, kml_string) {
if (error) {
console.log('ERROR in getting kml string');
console.log(error);
} else {
console.log('GOT Kml String');
geoXml.parseKmlString(kml_string);
}
});
// On server side
Meteor.startup(function() {
// code to run on server at startup
return Meteor.methods({
getKmlString: function(kml_file_name) {
var content = '';
var fs = Npm.require('fs');
var encoding = encoding || 'binary';
var chroot = Meteor.chroot || 'uploads';
var path = chroot + (path ? '/' + path + '/' : '/');
var content = fs.readFileSync('../../../../../' + path + kml_file_name, "utf-8", function read(err, data) {
if (err) {
throw err;
}
});
return content;
},
});
});

[meteor][0.6.*] With meteorjs, how to download file with Meteor.http?

In my meteor app, the server try to download some file to store them on filesystem.
I use Meteor.http package to do that, but in fact, if file are downloaded, they seems to be corrupted.
var fileUrl = 'http://cdn.sstatic.net/stackoverflow/img/sprites.png?v=5'; //for example
Meteor.http.call("GET", fileUrl, function funcStoreFile(error, result) {
"use strict";
if (!error) {
var fstream = Npm.require('fs'),
filename = './.meteor/public/storage/' + collectionId;
fstream.writeFile(filename, result.content, function funcStoreFileWriteFS(err) {
if (!err) {
var Fiber = Npm.require('fibers');
Fiber(function funcStoreImageSaveDb() {
MyfileCollection.update({_id: collectionId}, {$set: {fileFsPath: filename}});
}).run();
} else {
console.log('error during writing file', err);
}
});
} else {
console.log('dl file FAIL');
}
});
I did a symlink from public/storage to ../.meteor/public/storage to enable direct download from url (http://localhost:3000/storage/myfileId)
When i compare the file downloaded with this system and the same file downloaded directly from a browser, they are different. What's wrong with my conception?
I had a similar problem and made a solution based on this discussion:
on https://github.com/meteor/meteor/issues/905
By using the request library, which meteor is using under the hood as well, one can avoid the problem with binary downloads. Besides I would recommend not saving small files to the filesystem but base64 encoded in mongodb directly. This is the easiest solution, if you plan to deploy to meteor.com or other cloud services.
An other glitch I found when saving files to the public dir in development is that meteor is reloading the files for every change in the public dir. this can lead to data corruption as chunks of the file are being downloaded. Here some code i am using based on the above discussion.
Future = Npm.require("fibers/future")
request = Npm.require 'request'
Meteor.methods
downloadImage: (url) ->
if url
fut = new Future()
options =
url: url
encoding: null
# Get raw image binaries
request.get options, (error, result, body) ->
if error then return console.error error
base64prefix = "data:" + result.headers["content-type"] + ";base64,"
image = base64prefix + body.toString("base64")
fut.ret image
# pause until binaries are fully loaded
return fut.wait()
else false
Meteor.call 'downloadImage', url, (err, res) ->
if res
Movies.update({_id: id}, {$set: {image: res}})
Hope this is helpful.

Why is my node static file server dropping requests?

I have a standard node.js static file server that I want to use to serve normal html, js, css, and jpg files in the same directory (ie- a typical HTML5 single page app). I would expect that the node server can handle this properly. What I see is different.
The index.html file is served, but then subsequent requests are dropped (ie- they never make it to the server). In my chrome dev tools, I see things like this:
GET http://projectcoho.cloudfoundry.com/css/coho.css http://projectcoho.cloudfoundry.com/:7
GET http://projectcoho.cloudfoundry.com/sencha-touch/sencha-touch-debug.js http://projectcoho.cloudfoundry.com/:8
GET http://projectcoho.cloudfoundry.com/coho-debug.js http://projectcoho.cloudfoundry.com/:8
But, these resources exist on the server and you can reach them if you enter their URL directly. And for these requests, my callback in app.js is never invoked (I can tell this because console.log is never called for these files.
Here is the app.js file:
var path = ".";
var port = process.env.VCAP_APP_PORT || 3000;;
var file = new(static.Server) (path, {
cache: 600
});
mime.define({
'text/css': ['css'],
'text/javascript': ['js'],
'image/jpeg': ['jpg', 'jpeg']
});
http.createServer(function (request, response) {
var uri = url.parse(request.url).pathname;
var filename = libpath.join(path, uri);
console.log("URI: " + request.url + " , filename: " + filename);
libpath.exists(filename, function (exists) {
console.log("Serving " + filename);
if (!exists) {
console.log("Not found");
response.writeHead(404, {
"Content-Type": "text/plain"
});
response.write("404 Not Found\n");
response.end();
return;
}
if (fs.statSync(filename).isDirectory()) {
filename += '/index.html';
}
var type = mime.lookup(filename);
file.serveFile(filename, 200, {'content-type' : type}, request, response);
});
}).listen(port);
What am I missing here?
I am using node v0.6.15
In the end, the answer was that my cache.manifest file was incorrect. The client application was looking for resources in a cache, but the didn't exist. When I corrected the manifest, things started working.

Resources