How to download / upload the JSON representation of a Google doc? - google-drive-api

Is it possible to download, modify, and upload the JSON representation of a Google doc via an API?
I'm trying to write a server side app to do this. By Google doc, I mean files underlying the rich-text editing features as per https://docs.google.com.
As far as I've understood, the RealTime API should allow me to download the json representation of a doc with a GET request, and upload a new JSON file with a PUT request. From the documentation it sounds ideal. However, responses from GET requests contain null in the data field. I understand that this is because my OAuth2.0 app is not the same app that created the document. I'm not sure if/how I could fix this if I want the files to be treated the same as any other Google doc (as defined above).
The Drive API allows me to download a file with a GET request, however, the supported mime-types do not include JSON. I am aware that I could try and convert them (e.g. via a library like the excellent pandoc) but this require lossy and unpredictable processing to try to guess at what Google's document representation might be via e.g. parsing MS Word documents (ew).
Is there a way to directly import & export docs in Google's own JSON representation?

You may want to try using the Realtime API in an unauthenticated mode, called in-memory mode which allows you to get started with the API without any configuration or login.
To build An Unauthenticated App, you may visit and try the steps given in Google Realtime API Quickstart. You can simply copy the following code into a new file and then open it in a browser.
<!DOCTYPE html>
<html>
<head>
<title>Google Realtime Quickstart</title>
<!-- Load Styles -->
<link href="https://www.gstatic.com/realtime/quickstart-styles.css" rel="stylesheet" type="text/css"/>
<!-- Load the Realtime API JavaScript library -->
<script src="https://apis.google.com/js/api.js"></script>
</head>
<body>
<main>
<h1>Realtime Collaboration Quickstart</h1>
<p>Welcome to the quickstart in-memory app!</p>
<textarea id="text_area_1"></textarea>
<textarea id="text_area_2"></textarea>
<p>This document only exists in memory, so it doesn't have real-time collaboration enabled. However, you can persist it to your own disk using the model.toJson() function and load it using the model.loadFromJson() function. This enables your users without Google accounts to use your application.</p>
<textarea id="json_textarea"></textarea>
<button id="json_button" class="visible">GetJson</button>
</main>
<script>
// Load the Realtime API, no auth needed.
window.gapi.load('auth:client,drive-realtime,drive-share', start);
function start() {
var doc = gapi.drive.realtime.newInMemoryDocument();
var model = doc.getModel();
var collaborativeString = model.createString();
collaborativeString.setText('Welcome to the Quickstart App!');
model.getRoot().set('demo_string', collaborativeString);
wireTextBoxes(collaborativeString);
document.getElementById('json_button').addEventListener('click', function(){
document.getElementById('json_textarea').value = model.toJson();
});
}
// Connects the text boxes to the collaborative string.
function wireTextBoxes(collaborativeString) {
var textArea1 = document.getElementById('text_area_1');
var textArea2 = document.getElementById('text_area_2');
gapi.drive.realtime.databinding.bindString(collaborativeString, textArea1);
gapi.drive.realtime.databinding.bindString(collaborativeString, textArea2);
}
</script>
</body>
</html>
Hope that helps!

Related

Populate word document from html form

I am new to web development and need your help to figure out how to use the form in HTML and use the data to populate the said field in a word document. Any advice on how to approach this problem is highly appreciated. It would really help if you could post a live example for the below. Please,do let me know if any further explanation is required.
As a new developer, I want to advise you that you are getting into some challenging territory here and many of the solutions might require some heavy experience with programming and MS Word. In this forum, there are many options you can try, but from what I gather you will need to learn about macros.
The second option you could try are some services that will do this for you for a fee. Here are two options. Check out Formstack or Jotform
If you use this type of service, you would create a form action within your html code that will merge the data from the form into the Microsoft Word Document using merge tags.
The third option you can try is using Javascript within the form to populate the Word Document. The code would look more like this:
function Export2Word(element, filename = ''){
var preHtml = "<html xmlns:o='urn:schemas-microsoft-com:office:office' xmlns:w='urn:schemas-microsoft-com:office:word' xmlns='http://www.w3.org/TR/REC-html40'><head><meta charset='utf-8'><title>Export HTML To Doc</title></head><body>";
var postHtml = "</body></html>";
var html = preHtml+document.getElementById(element).innerHTML+postHtml;
var blob = new Blob(['\ufeff', html], {
type: 'application/msword'
});
// Specify link url
var url = 'data:application/vnd.ms-word;charset=utf-8,' + encodeURIComponent(html);
// Specify file name
filename = filename?filename+'.doc':'document.doc';
// Create download link element
var downloadLink = document.createElement("a");
document.body.appendChild(downloadLink);
if(navigator.msSaveOrOpenBlob ){
navigator.msSaveOrOpenBlob(blob, filename);
}else{
// Create a link to the file
downloadLink.href = url;
// Setting the file name
downloadLink.download = filename;
//triggering the function
downloadLink.click();
}
document.body.removeChild(downloadLink);
}
Export HTML Table Data to Excel using JavaScript
HTML Content:
Wrap the HTML content in a container you want to export to MS Word document (.doc).
<div id="exportContent">
<!-- Your content here -->
</div>
Last option would be using PHP, and I recommend watching this video by CodexWorld and reviewing the post that goes along with it here. This is a challenging concept, so I would encourage you to take your time.
Hopefully this will help and best of luck.
Well, I don't know how to exactly do that, I am also a beginner like you. What seems to help you might be connecting your form with Google Sheets. The Google Spread Sheet will store all data submitted via your form. You can then use this data wherever you want.
There is an open source project for this task, you can do that by following the steps stated here: https://github.com/dwyl/learn-to-send-email-via-google-script-html-no-server
You can see it in action here: https://nisootech.vercel.app/#contact-me
There are two parts in your application
Enabling user to input the values in frontend. Which you can build using any frontend technology stack eg: HTML and Plain Javascript(Required for calling the Services), React JS, Angular etc.
Backend Service which will basically does the heavy work
Receiving the input from user.
Creating Word file using any libraries such as
Generate word files using Apache POI ,
Using Node.js to generate dynamic word document using Database value
Downloading the file after its completely generated using the values supplied by user.
download a file from Spring boot rest service
how to download file in react js
For the Backend service you can use technologies like Java and Springboot, Python, Node Js etc.
Building Restful webservices using spring
Use Technology in which you are more comfortable and start building. These Links and documentation you can use to start from basic.
Suggest you to breakdown your problems focus on each specific areas and do the development as per your smaller problems and integrate them later.

AppScript: How to create an upload form?

I am developing an Add-on for Gmail using AppScript.
My objective is to create something similar to the image below. Any hints?
Problem
File upload in Gmail Add-ons. In short - not exactly. Gmail Add-ons use CardService class to build the Ui - and it doesn't have a file input type, nor any drag-and-drop functionality. But there is a workaround.
Step 1. Create trigger widget
Then, ensure that your Card contains a CardSection with an ImageButton, TextButton or KeyValue widget (KeyValue is deprecated, use DecoratedText) that has an OpenLink action set on them. When using the setUrl(url) method to setup URL to open on widget click, use the current project's URL (when deploying both as WebApp and Add-on) that can be accessed dynamically via ScriptApp.getService().getUrl() call.
Step 2. Create file submit form
In the Add-on project, create an Html file that will handle the file upload. You can use sample one or create your own implementation. the sample file uses FileReader Web API to handle the submitted file (note that client-to-server communication in Google Apps Script requires preventing submit event handler and calling a server-side function via goolge.script.run API only).
<!DOCTYPE html>
<html>
<head>
<base target="_top">
</head>
<body>
<form>
<input name="file" type="file" />
<button id="submit" type="submit">Save file</button>
</form>
<script>
var form = document.forms[0];
form.addEventListener('submit', (event) => {
event.preventDefault();
var file = form.elements[0].files[0];
var reader = new FileReader();
reader.readAsArrayBuffer(file);
reader.onload = () => {
var buffer = reader.result;
var data = Array.from(new Int8Array(buffer));
google.script.run.withSuccessHandler((server) => {
top.window.close();
}).saveFile(data,file.name,file.type);
};
});
</script>
</body>
</html>
Step 3. Setup doGet()
In your WebApp code, add the required doGet() function that will show the file upload form that we created during step 2. It can be as simple as a couple lines of code (just make sure to return the html file parsed by HtmlService):
function doGet() {
var html = HtmlService.createHtmlOutputFromFile('file name from step 2');
return html;
}
Step 4. Handle file upload
In your WebApp code, add handler that will receive file data (this sample assumes you read it as byte[], see step 2 for details).
function saveFile(upload,name,mime) {
var blob = Utilities.newBlob(upload,mime,name);
var file = DriveApp.createFile(blob);
Logger.log(file.getUrl()) //test upload;
//handle file as needed;
return;
}
Step 5. Deploy as WebApp
Lastly, you will have to deploy your Add-on as both WebApp (or bundle with one) and an Add-on. Assuming you've already configured manifest for the Add-on, go to "Publish" menu, select "Deploy as web app", create a deployment and allow access to anyone.
Notes
This method won't allow you to easily update the Ui to show which files were uploaded, but you can add a withSuccessHandler() call to google.script.run that on successful server-side handling of the uploaded file closes the window with the form, save state info to cache / user properties. Then, if you set the OpenLink's OnClose property to RELOAD_ADD_ON (see step 1), you will be able to conditionally update Ui to notify the user of successful upload.
UPDATE: after Tanaike's comment I reworked the upload process to better handle files: changed binary string file read to ArrayBuffer transformed to Int8Array and uploaded as an Array instance.
Current issue is the .g* files upload (despite correct transfer). Will update the answer when solved.
References
OpenLink class reference;
FileReader Web API reference on MDN;
newBlob() method reference (Utilities class);
Client-to-server communication in GAS guide;
Creating and serving HTML in GAS guide;
Web Apps guide;

Logging service allowing simple <img/> interface

I'm looking to do some dead-simple logging from a web app (client-side) to some remote service/endpoint. Sure, I could roll my own, but for the purpose of this task, let's assume I want an existing service like Logentries/Splunk/Logstash so that my viewers can still log debugging info if my backend goes down.
Most logging services offer an API where I can import some <script/> onto my page and then use an API like LE.log('string', data); [Logentries example]. However that pulls in a JS dependency and uses cross-domain XHR for probably well-founded reasons (like URI length limitations).
My question is if anyone can point me to a service that will let me send simple query params to a "pixel" endpoint (similar to how Google Analytics does it). Something like:
<script>
new Image().src = 'http://something.io/pixel/log/<API_TOKEN>?some_data=1234';
</script>
-- or, in pure HTML --
<img src="http://something.io/pixel/log/<API_TOKEN>?some_data=1234" style="display:none" />
I'd assume some of the big names in the logging-as-a-service space would have something like this but I've not found anything (or it's too specific to turn up any search results).
This would not be for analytics so much as error logging, debugging, etc. Fire-and-forget sort of stuff.
Any advice appreciated.
It's possible to do this with Logentries, they offer a pixel tracker.
They require that data is sent in a base64 encoding, but that's quite simple in Javascript.
From their documentation:
var encoded = encodeURIComponent(btoa("Log message"));
This data can then be used in a pixel tracker like this:
<img src="https://js.logentries.com/v1/logs/{API-TOKEN}?e={ENCODED_DATA}/">

HTML5+jQuery+phonegap mobile app security

I'm new to this area and I'm developing a HTML5 mobile app that calls a restful webservices api and exchange JSON objects.
I want to authenticate the client once and give a a key/token that can be used afterwards until a pre-defined expiration date. I have 4 questions:
How can I secure the serverside webservices api? any tools whatsoever?
Can I use the local storage to store the key/token?
What are the phonegap security tools I can use for the client side?
How can I use OAUTH in this case?
How can I secure the serverside webservices api? any tools whatsoever?
OAuth may be overkill for your need, verify that you really need to use such a powerful (and complex) standard.
Two examples of PHP server side software that you may use:
Solberg-OAuth
SimpleSAMLphp
Can I use the local storage to store the key/token?
Yes! Be aware that you MUST use the OAuth 2.0 implicit grant flow in order to obtain the token at the client side.
What are the phonegap security tools I can use for the client side?
ChildBrowser is a plugin to open a separate browserwindow for the authentication process.
I've written a javascript library JSO that can do OAuth 2.0 for you. Other libraries exists as well.
https://github.com/andreassolberg/jso
How can I use OAUTH in this case?
Using JSO with Phonegap and ChildBrowser
Using JSO to perform OAuth 2.0 authorization in WebApps running on mobile devices in hybrid environment is an important deployment scenario for JSO.
Here is a detailed instruction on setting up JSO with Phonegap for iOS and configure OAuth 2.0 with Google. You may use it with Facebook or other OAuth providers as well.
Preparations
Install XCode from App Store, and iOS development kit
Install Phonegap 2.0, Cordova 2.0
Setup App
To create a new App
./create /Users/andreas/Sites/cordovatest no.erlang.test "CordovaJSOTest"
Install ChildBrowser
The original ChildBrowser plugin is available here.
https://github.com/purplecabbage/phonegap-plugins/tree/master/iPhone/ChildBrowser
However, it is not compatible with Cordova 2.0. Instead, you may use this fork of ChildBrowser which should be working with Cordova 2.0:
https://github.com/Shereef/ChildBrowserOnCordova200
What you need to do is to copy these files:
https://github.com/Shereef/ChildBrowserOnCordova200/tree/master/ChildBrowserOnCordova200/Plugins
in to your WebApp project area, by using drag and drop into the Plugins folder in XCode.
Now you need to edit the file found in Resources/Cordova.plist found in your WebApp project area.
In this file you need to add one array entry with '*' into ExternalHosts, and two entries into Plugins:
ChildBrowser -> ChildBrowser.js
ChildBrowserCommand -> ChildBrowserCommand
as seen on the screenshot.
(source: erlang.no)
Setting up your WebApp with ChildBrowser
I'd suggest to test and verify that you get ChildBrowser working before moving on to the OAuth stuff.
In your index.html file try this, and verify using the Simulator.
<script type="text/javascript" charset="utf-8" src="cordova-2.0.0.js"></script>
<script type="text/javascript" charset="utf-8" src="ChildBrowser.js"></script>
<script type="text/javascript">
var deviceready = function() {
if(window.plugins.childBrowser == null) {
ChildBrowser.install();
}
window.plugins.childBrowser.showWebPage("http://google.com");
};
document.addEventListener('deviceready', this.deviceready, false);
</script>
Setting up JSO
Download the latest version of JSO:
https://github.com/andreassolberg/jso
The documentation on JSO is available there as well.
The callback URL needs to point somewhere, and one approach would be to put a callback HTML page somewhere, it does not really matter where, although a host you trust. And put a pretty blank page there:
<!doctype html>
<html>
<head>
<title>OAuth Callback endpoint</title>
<meta charset="utf-8" />
</head>
<body>
Processing OAuth response...
</body>
</html>
Now, setup your application index page. Here is a working example:
<script type="text/javascript" charset="utf-8" src="cordova-2.0.0.js"></script>
<script type="text/javascript" charset="utf-8" src="ChildBrowser.js"></script>
<script type="text/javascript" charset="utf-8" src="js/jquery.js"></script>
<script type="text/javascript" charset="utf-8" src="jso/jso.js"></script>
<script type="text/javascript">
var deviceready = function() {
var debug = true;
/*
* Setup and install the ChildBrowser plugin to Phongap/Cordova.
*/
if(window.plugins.childBrowser == null) {
ChildBrowser.install();
}
// Use ChildBrowser instead of redirecting the main page.
jso_registerRedirectHandler(window.plugins.childBrowser.showWebPage);
/*
* Register a handler on the childbrowser that detects redirects and
* lets JSO to detect incomming OAuth responses and deal with the content.
*/
window.plugins.childBrowser.onLocationChange = function(url){
url = decodeURIComponent(url);
console.log("Checking location: " + url);
jso_checkfortoken('facebook', url, function() {
console.log("Closing child browser, because a valid response was detected.");
window.plugins.childBrowser.close();
});
};
/*
* Configure the OAuth providers to use.
*/
jso_configure({
"facebook": {
client_id: "myclientid",
redirect_uri: "https://myhost.org/callback.html",
authorization: "https://www.facebook.com/dialog/oauth",
presenttoken: "qs"
}
}, {"debug": debug});
// For debugging purposes you can wipe existing cached tokens...
// jso_wipe();
// jso_dump displays a list of cached tokens using console.log if debugging is enabled.
jso_dump();
// Perform the protected OAuth calls.
$.oajax({
url: "https://graph.facebook.com/me/home",
jso_provider: "facebook",
jso_scopes: ["read_stream"],
jso_allowia: true,
dataType: 'json',
success: function(data) {
console.log("Response (facebook):");
console.log(data);
}
});
};
document.addEventListener('deviceready', this.deviceready, false);
</script>
How can I secure the serverside webservices api? any tools whatsoever?
Depends on which language the web service is written, php has zend framework for creating web services / nusoap etc. So all of the languages do provide info on how to secure the webservice.
Can I use the local storage to store the key/token?
Yes you can use local storage look at the phonegap documentation
What are the phonegap security tools I can use for the client side?
I dont think so there are any but you can search for some plugins or create your own plugin. Depends on what kind of security do you want to implement.
How can I use OAUTH in this case?
Here is a library for OAuth and this seems to be helpful. You can create a phone gap plugin to interact with the library or use a javascript oauth library(its with sample also).

Rails JSON API - Domain issue?

I finished Ryan Bates #348 video for creating a JSON API using the rails-api gem. I have it working as in the example. However, in his example he has the page that calls the API in the same project. My goal is to separate out the client app from the API app.
I created a second rails app that simply includes the page that does a JSON request for the API data and a post when submitting the form. I have the client app running on localhost:3000 and the API running on localhost:4000.
Below is the client side code. It successfully submits a new deal record, but the
GET doesnt load the list of deals. When looking in the logs it appears it is requesting it as HTML. When the page was apart of the same API project, the same code was making the call as JSON in the logs.
<script src="//ajax.googleapis.com/ajax/libs/jquery/1.7.2/jquery.min.js" type="text/javascript"></script>
<script type="text/javascript" charset="utf-8">
$(function() {
function addDeal(deal) {
$('#deals').append('<li>' + deal.name + '</ul>');
}
$('#new_deal').submit(function(e) {
$.post('http://localhost:4000/deals', $(this).serialize(), addDeal);
this.reset();
e.preventDefault();
});
$.getJSON('http://localhost:4000/deals', function(deals) {
$.each(deals, function() { addDeal(this); });
});
});
</script>
<div id="container">
<h1>My Deals</h1>
<form id="new_deal">
<input type="text" name="deal[name]" id="deal_name">
<input type="submit" value="Add">
</form>
<ul id="deals"></ul>
</div>
Because of Cross Origin Policy you have following options:
Use jsonp (don't do this since you have your server :) check below )
Manage Cross Origin Resource Sharing on server, recently I wrote answer here how to achieve this
You could use rails ActiveResource::Base to conect to your api, but it may be slow, and you would repeating yourself unless there is some presentation logic you need on backend. BTW, check Nibbler gem it may be somewhat better... it really depends what you need to do in backend.
Anyhow. I would avoid approach 1, its kinda overhead especially if you want to POST, PUT or DELETE, and you can allows use option 2 if you have pure javascript app running as UI. But even if you are building JS agnostic app you always need a bit of backend processing so option 3 is probably something you'd prefer.