Deploying container-bound Google Apps Script as Web App - google-apps-script

I'm creating a spellchecker using the Google Docs API in an Apps Script (just a script that extends the functionality of a Google Doc), and I wan't to make this service available to users whom download it as a Web App. Problem is that when I've made my (Container-bound) script in the script editor, it is only available in the Google Document through which I created it - that is, if i open a new document, I cannot use the script.
If I "Deploy as Web App", make it available to everyone and paste the given URL, I get an error message saying that the script needs a function called doGet(), which is not in my script.
How do I go about to publish my script as a regular web app?

I would proceed by creating two scripts:
the core functionality would be deployed as a Web App and a simple container-bound script would offer an interface to call the Web App.
Since the Web App is not bound to a document you may want to follow this scheme:
function doGet(e){
if(e.parameter.docId){
doStuff(DocumentApp.openById(e.parameter.docId));
}
}
Now when you deploy the app you will get a link that gives you access to the functionality.
From the container-bound script you can add some UI (e.g. an Anchor element in a side-panel) that links to the web app with the appropriate parameters
ScriptApp.getService().getUrl() + "?docId=" + DocumentApp.getActiveDocument().getId()
or use UrlFetchApp to get the results and display them in the UI.
Unfortunately this is not the same as adding the functionality across all your documents automatically, but rather a way to install only a relatively lightweight hook in each document where you want to add the functionality, instead of the full script.
I am not aware of any method that can achieve that. Note that when you make a copy of a document, the copy will contain all its scripts so you can create a template for documents that need the additional functionality. This can get ackward though if you wish to mix and match multiple scripts.
The advantage of my method is that if you modify the core functionality, the change is immediately available to all your documents making use of it, with no need to update their scripts. On the other hand if the container-script needs to interact heavily with the UI it may get complicate and reduce the usefulness of separating it in two scripts.

The answer is in your question : the main function of your script (the one that builds the UI) must be called doGet() (this is the conventional entry point of any GAS webapp, the function that you implicitly call when opening the webapp url)... but I'm afraid this will not solve your problem...
Even if I don't know what is in your script and how you wrote it I guess that it refers to the doc in which you bound it as the "active document" and that will probably be the most important issue since a webapp has no document attached to it.
Beside that, how would a spell checker work as a standalone app ? could you explain more clearly what you want to do ?

Related

Using Google Apps Script Libraries

I have read all Google documentation on managing and creating libraries, yet I still do not know if they are an appropriate option for the problem I am trying to solve.
I know how to save a version of a standalone script. I know how to add the library to a spreadsheet via the script editor. But I don't understand, very simply, how to trigger the library script within the new spreadsheet.
I have a spreadsheet that serves as an often-copied template within my organization. The template contains a script that (onOpen) accesses data on a separate spreadsheet (a master database) and sets those values on a tab called "admin." The desired result is to have a copy of the master database living within the template sheet (and every subsequent copy of the template sheet). At this point, there are thousands of copies of the template sheet, each running that same script.
Whenever I have to change the script, I have to change it within thousands of sheets. Can I use a library instead? I'd like to be able to create a new version of the script in the library and have all sheets connected to that library experience the change. I understand that the library needs to be in development mode (within each sheet) to do this. I also understand that in order to make this switch, I will probably still have to go into each sheet to add the library. I'm just hoping it will be the last time I have to do such a tedious task.
Any advice or links to solid info is appreciated.
besides making an add-on (already covered in another answer) I will answer your libraries question. They will work for you. What you are missing is the "connect" part.
For this you want to trigger the library code from say, onOpen. The onOpen in the library is not enough and not detected by apps script. Instead each of your spreadsheet's script needs an onOpen(e) which just calls yourlibrary.onOpen(e).
since those "hook" calls rarely change, specially once you stabilize your library api, and using it in "development" mode will let you modify just the library.
whenever one of those hooks needs to change (say a callback from an html GUI needs a new parameter) you need to update all the spreadsheets. to avoid this, make all your callbacks receive a single json object instead of multiple parameters.
Sorry if I am repeating other answers, but I would like to sum up and add something:
You can access your library functions as follows:
From the app using the library you go to the Resources/Libraries. You can see the library name under "Identifier". On the same line where you can select Development mode.
Library name found in resources
Now in your library you have for example a function
function onOpen(e)
{
Browser.msgBox("HELLO!");
}
In the spreadsheet app you wish to access it you use the library name found in the resources, for example "testlibrary"
function onOpen(e)
{
testlibrary.onOpen(e);
}
Now if you have development mode on, the modifications to functions in the library update automatically to your application (spreadsheet) as long as the user using the application has edit access in your library script.
If anyone using your spreadsheet has a restricted access to your library script (meaning only view access) or development selection is off in the application, you have to go to the application's script, Resources/Libraries and select the most recent version of your library to be used in the app everytime you update the library and save a new version of it.
Still, especially if you are using mostly only the onOpen function , I would recommend using the library rather than copy-pasting the function to the script of each spreadsheet, as it is easier to track which scripts are up to date and it is easier to avoid errors and differences between the scripts.
Even in the more restricted case, if you update function in library - as long as you are already calling it in the app - all you have to do is select the new version of the library used.
I hope I had anything to give in this conversation and my language was appropriate, this was my first answer..
A good question Melly. I've been through a bunch of the documentation and some tutorials on this subject but haven't tried adding any libraries yet. My understanding is that once you are connected to a library all you have to do is call the applicable functions. That once a library is connected the functions in the library become an extension of all the other Apps Script classes available in the script editor.

Workflow for integrating Google Docs with my web app through Google Apps Script

I was searching for an SDK or API to create and/or edit Google Docs files, but (correct me if I'm wrong) it seems Google Apps Script is the way to integrate your app with G Suite. I'm now trying to grasp the basic workflow for a basic document editing operation.
For instance, say we have a Quote Template document that serves as the template for our business to create quotations for customers. From within our web app system, we would press a button that would duplicate that file with a new name and maybe replace some variables.
Now, here's where I am in a gray area. I'd think we would have to install some sort of SDK (PHP/Js/Ruby library) in our project, that would let us create a new file based on the template, and call some replacePattern(regex, value) method.
However, the more I read, it looks like the approach is different, where you would create a Google Apps Script and, from our web app, we make HTTP calls to a REST API that will run said script. Then, this script would do the creating document and replacing values.
Am I correct in assuming this is the basic workflow to integrate our web app with G Suite products, or am I missing something essential?
Yes, that would be the basic workflow. There is no public Google Docs REST API, so apps script at the moment is the only way to automate docs. If you want to integrate it with a current tool you can expose the script using the Execution API. There are client libraries, though being a REST API they can be accessed from anywhere you can make a http request. Links to the client libraries can be found in their respective quick starts found below:
https://developers.google.com/apps-script/guides/rest/
All of the business logic can be handled by the script such as copying a template, replacing values, and setting permissions to the file.
The DocumentApp service docs can be found at:
https://developers.google.com/apps-script/reference/document/

Calling apps script function from drive UI

I just implemented a function which operates on a File object in Google Drive(*). Long story short: the function doSomething(file) { ... } exists (in a standalone Google Apps Script) and is well tested.
I want to call this from the Drive UI, e.g. using context menu -> Open With ... (but really any sensible means would be OK).
Is there a straightforward way to achieve this? I prefer not to go through 'registering an app in the Chrome store' whole shebang when all I need is a glorified macro for myself.
I just finished listening to https://www.youtube.com/watch?v=0HVJMIeb3aE which comes closest so far but it seems to skip the technical details of exactly what I need.
(*) There is a rather frustrating repetitive per-file workflow within my organization whereby one needs to switch all write accesses to read-only, then assign ownership to a given user then change your own rights to read-only.
This can absolutely be done in Apps Script. There is a bit of set-up. That video you posted was the one I used to figure it out. When your app is attached to the drive ui your registered mime-types will have your app in the right-click menu.
I made a barebones framework that is highly commented about this process. It also shows how I handle the cases of being installed from the chrome store and called launched from chrome/chrome app launcher. You can make a copy of it here:
https://script.google.com/d/1nrwcxTjzysJl2DMSNB3BHyYfJLEbm02-ekusjUg4V9abzLZ3R_1Yqctj/edit?usp=sharing
*note: This assumes a bit of apps script familiarity. As the '13 IO videos were my first intro to apps script I'm fairly certain it is not that bad to get going.

Sharing Google Docs content-bounded scripts

I have created some content bounded scripts (Tools->Script Editor) for private use. The scripts add a sidebar, and use a timer to copy the content from the sidebar to a Google document at the cursor position. It is important that the insertion happens at the cursor.
I want to share these scripts with others, as well as add them to old documents. All suggestions I have seen so far involves creating a template document with these scripts and then sharing the template document. This option is not feasible for me. One of the concerns is, these scripts need to be added to existing documents. Creating a new document, and merging it with the old one is not working (the original documents are complex, and migrated documents loose formatting).
Is there an easy way to share/insert these scripts? So far, I have failed to implement any of the below obvious options:
Export Script Editor project to somewhere, and then import it in another document.
Create an app script in drive, and then import it in an existing document.
Publish this as add-on (N/A since this is not a public project, and not complete yet either).
I'm not sure if it is feasible to publish my scripts as a webapp, then write a simple container-bound application to call my webapp with document id as suggested at Deploying container-bound Google Apps Script as Web App
However, this requires webapp to insert the text at cursor position of the active window. I doubt that is possible.
I'm hoping that somebody found an easier way, and willing to share it.
I appreciate any help.
Sincerely,
Converting your script to an add-on is the recommended way to distribute across multiple users and documents. We understand this solution doesn't always work when the script is not meant for general consumption. Add-ons can be published only to a single domain however, so if all of your users are within a Google Apps domain then add-ons may still be an option.

Invoking apps script within another apps script

Is there any way to invoke a Google Apps Script which serves content and limited to a domain within another Google Apps Script which is invoked by a user who is in that domain? Basically the content serve script is something which runs on administrator of the domain and serves private information.
I think it should work when content serving script is made, available to anonymous usage, but I wanted the content serving script to be available only within domain.
You could publish the first script as a web service, and then just call the functions remotely.
This can be done because when you publish as a web application you set the permissions with which the script gets executed.
https://developers.google.com/apps-script/execution_web_apps
Unfortunately, this isn't possible, as the script request aren't executed in the name of the author neither the user executing it, setting anonymous usage for the script should work.
But you can pass an argument through post or get. so even if anyone can invoke the script, only the script invoked with a key argument will do something
The question that remain is what to use: get or post
I don't know if request made by the script are done in https, so it's maybe a better solution to use post.
is a library what you're looking for? Remember this may slow down executions (vs just binding the script to multiple files like normal)
https://support.google.com/docs/thread/13371261?hl=en
Yes, it is possible. The simplest solution is to create an Apps Script library. You can use either a standalone script or a bound script as the library. I prefer to use a standalone to make it easier to access, and you won't be able to use functions that are specific to bound scripts that could mess up your script.
HERE is a quick video demonstrating how to get a GAS library setup.
https://www.youtube.com/watch?v=TqWtSp4IJcg&feature=youtu.be