Web Apps Script: No output - google-apps-script

I am trying to display a Google Visualization GeoMap on my website. I created the code in the Code Playground and saved it as an Apps Script in my website. The page goes through the load process but nothing is displayed.
Here is the code:
function doGet() {
var app = UiApp.createApplication();
function drawVisualization() {
var query = new google.visualization.Query(
'https://docs.google.com/a/mantisnetworks.co/spreadsheet/ccc?key=0AoNHsySj5NxGdGt0dmxva3ZPb3dLYVpVZ2Z4TThNbGc&usp=drive_web#gid=0');
query.send(handleQueryResponse);
}
function handleQueryResponse(response){
if(response.isError()){
alert('Error in Query:' + response.getMessage()+''+response.getDetailedMessage());
return;
}
var data = response.getDataTable();
var geochart = new google.visualization.GeoMap(document.getElementById('visualization'));
var options = {};
options['dataMode'] = 'regions';
options['resolution'] = 'provinces';
options['region'] = 'LS';
options['width'] = '600px';
options['height'] = '300px';
geochart.draw(data, options);
}
app.close();
return app;
}

Google Apps Script is based on Javascript, but as a server-side environment it does not have access to all client-side javascript constructs. The Google visualizations, for instance, are provided as the Charts Service. Using that service, you'll find support for much of the visualization API. However, you won't find GeoMap.
The code you've provided in your question needs to be reworked considerably to work properly in Google Apps Script. Start with the example given on the Charts Service page, then adapt to your situation.
You do have another alternative within Google Apps Script, which is to use the HTML service to "host" an HTML page containing "real" javascript. Javascript that's embedded in HTML pages can be made to run on the client browser, so the example you cooked up in the playground should work. A full run-down of this option is beyond the scope of your question, but if you're interested in it you could start by scanning previous questions about the HTML Service.

Related

Google Sheets Advanced Google Services URL Shortener 403 Error: Forbidden

I am trying to create a small application in in Google Sheets to sorten URLs on my personal google account. I am using the following code which I found here: Google Sheets Function to get a shortened URL (from Bit.ly or goo.gl etc.)
function onOpen() {
SpreadsheetApp.getUi()
.createMenu("Shorten")
.addItem("Go !!","rangeShort")
.addToUi()
}
function rangeShort() {
var range = SpreadsheetApp.getActiveRange(), data = range.getValues();
var output = [];
for(var i = 0, iLen = data.length; i < iLen; i++) {
//var url = UrlShortener.Url.insert({longUrl: data[i][0]});
var url = UrlShortener.Url.insert({longUrl: 'www.google.com'});
output.push([url.id]);
}
range.offset(0,1).setValues(output);
}
I created a new Google Cloud Project and enabled the URL shortener API in the project and on the Google sheet. The problem is that when I try and run the code I get an err on the line: var url = UrlShortener.Url.insert({longUrl: 'www.google.com'});
error 403, message:forbidden
when i try an execute the rangeShort() function. I have no idea how to fix this. Any ideas would be most appreciated! Thanks!
As it turns out, like Ruben mentioned, Google has moved away from their URL shortener. So after much research ans testing here is the solution:
Step 1
Migrate Google Cloud Project over to Firebase or create a new Firebase Project. See steps here
Step 2
Create a dummy project in order to create a base URL for the shortening. See this youtube video
Step 3
Get the Web API Key from your new Firebase Project (not the app you just created)
Step 4
Check the left side menu on the screen and navigate to Grow->Dynamic Links. You should see the new application you created and a URL at the top of the application. This will become the base of the new shortened URLs.
Step 5
Create the code in Google Apps Script inside the code builder from within Google Sheets. Here is the code that worked for me (I passed the url into this function) (This code is based on the answer found here):
function api_call(url){
var req='https://firebasedynamiclinks.googleapis.com/v1/shortLinks?key=[YOUR PROJECT WEB API KEY FROM STEP 3]';
var formData = {
"longDynamicLink": "[YOUR APPLICATION URL BASE FROM STEP 4]?link=" + url,
"suffix" : {
"option" : "UNGUESSABLE"
}
};
var options = {
'method': 'post',
'contentType': 'application/json',
'payload': JSON.stringify(formData)
};
var response = UrlFetchApp.fetch(req, options);
var res=JSON.parse(response);
return res.shortLink;
}
Additional Information
Documentation on Creating Dynamic Links in Firebase
Documentation on using UrlFetchApp() in Google Apps Script
If the url shortener service was used in your project before March 30,2018
Instead of
www.google.com
use
https://www.google.com
Reference: https://developers.google.com/url-shortener/v1/url/insert
but if your project was created on or after March 30, 2018
From https://developers.google.com/url-shortener/v1/
Starting March 30, 2018, we will be turning down support for goo.gl URL shortener. Please see this blog post for detailed timelines and alternatives.
Just to be clear, please note, from the linked blog post:
For developers
Starting May 30, 2018, only projects that have accessed URL Shortener
APIs before today can create short links.
I can attest to #alutz's answer here with a small addition/correction to their code.
Use encodeURIcomponent() for the input url while assigning it to the Long Dynamic Link in case you have more than one custom parameters.
"longDynamicLink": "[YOUR APPLICATION URL BASE FROM STEP 4]?link=" + encodeURIcomponent(url),
This allowed me to pass in multiple arguments for my telegram bot like chat_id, text and parse_mode.

How do I use momentsjs in Google Apps Script?

I'm trying to utilize the momentjs library in Google Apps Script but I'm not clear on how to do so. I'm not sure how to add the library, so obviously running something like the following results in "Reference Error: 'moment' is not defined":
var a = moment([2007, 0, 29]);
var b = moment([2007, 0, 28]);
var difference = a.diff(b);
Most people try to use the library with the key ending in 48. That library is pretty dated (it is version 2.9 which is pretty old).
Using eval and UrlFetchApp.fetch moment.js or any other external library can be used easily in google app scripts.
function testMoment() {
eval(UrlFetchApp.fetch('https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.18.1/moment.min.js').getContentText());
var date = moment().format("MMM Do YY");
Logger.log(date)
}
You may either host the moment.js on your own server, or use a CDN like cloudflare CDN to reference the library.
For cloudflare, here is the page which shows moment.js versions and their urls:
https://cdnjs.com/libraries/moment.js/
As of writing this post 2.18.1 is the latest version.
For the example posted by OP it will look like this:
function testMomentDifference() {
eval(UrlFetchApp.fetch('https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.18.1/moment.min.js').getContentText());
var a = moment([2007, 0, 29]);
var b = moment([2007, 0, 28]);
var difference = a.diff(b);
Logger.log(difference);
}
The moment script ID for the Google Apps Script IDE has changed. It is now "15hgNOjKHUG4UtyZl9clqBbl23sDvWMS8pfDJOyIapZk5RBqwL3i-rlCo"
You can add moment and moment.tz to app scripts by creating a new Script file and adding the following code:
var cacheExpire = 3600;
var momentCache = "momentCache";
var momentUrl = "https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.22.1/moment.min.js"
var momentTzCache = "momentTzCache";
var momentTzUrl = "https://cdnjs.cloudflare.com/ajax/libs/moment-timezone/0.5.16/moment-timezone-with-data-2012-2022.min.js"
useCachedOrLive(momentCache,momentUrl);
useCachedOrLive(momentTzCache,momentTzUrl);
function useCachedOrLive(cacheToCheck, url){
var cache = CacheService.getUserCache();
var cachedData = cache.get(cacheToCheck);
console.log(cacheToCheck);
if(cachedData !== null){
console.log("using cached " + cacheToCheck)
eval(cachedData);
}
else
{
console.log("getting live " + cacheToCheck);
var response = UrlFetchApp.fetch(url).getContentText();
cache.put(cacheToCheck, response, cacheExpire);
eval(response);
}
}
This uses the cache service to reduce round trip calls and you can modify it to include a subset of data if you want.
Thanks to apadana for getting me started!
There is a better and best way to use moment
Do not use UrlFetchApp, to avoid quota exceeded, caching, and server issues
Download moment.min.js and momemt-timzone.min.js in last versions
and integrate the full files in apps script like the below screen
There is no problems in long run with this approach, just update the files any time when you need.
After adding the two files, just publish a new version and include it in any other script
For example:
I will create a script with name "MomentAPI" and include the two
files mentioned, and publish a new version.
in other script with name "myScript" I will include the library
"MomentAPI" with its script id as known
then will use it like the below examples
const moment = MomentAPI.moment; // init the library
const start = moment().startOf('day').toDate(); // Dec 06 00:00:00
const end = moment().endOf('day').toDate(); // Dec 06 23:59:59
const d = moment(1767139200000).tz('America/New_York').format('ha'); // 7am EST
Using external Javascript library is not so easy... Depending on the context in which you want to use it (a webapp of a document embedded script) the approach will be different.
I didn't try it in client JavaScript and I'm not sure caja will allow it but I found this post that shows a possible way to include it using a Google Script Library that a user has build and if I read the post it seems to work...
The "user" is a Google developper so he knows for sure what he is talking about ;) please update here if it worked for you.

Error when trying to get the URL of a page in a Google Apps Script

I am writing a Google Apps Script to be embedded into Google Sites to retrieve the names and URLs for child pages of the current page. When I call the getURL() function I am getting the following error:
'TypeError: Cannot find function getURL in object WebPage.'
My code is as follows:
function doGet() {
var app = UiApp.createApplication();
var pages = SitesApp.getActivePage().getChildren();
for (var i = 0; i < pages.length; i++) {
Logger.log(pages[i].getURL());
}
return app;
}
I am new to Google Apps Scripts so am struggling to work out what this means. Any help would be greatly appreciated.
Use pages[i].getUrl()
You should use the autocomplete feature in the script editor to avoid such typing errors (control space after the dot : page[i].here type CTRL space and you'll see all possible methods...)
Note : the general rule in javascript is to use the so called camelCase format : getRange, createLabel ... there are only a few exceptions like setHTML but every rule must have exceptions doesn't it ?

Embed a list of forms in Google Site per DocList

I used the code given in
Embedding Google DocList in a Google Site
to embed a list of files (taken from a folder in Google drive) in a page of Google Sites. I like to know, if there's a way to modify the links on the output-page, so that they direct to the live-form of the spreadsheet and not to the spreadsheet-mode as it's set in the script.
EDIT : sorry about that, forget this first answer as there is actually a method to get form urls !!
here is how it works
function myFunction() {
var ss=SpreadsheetApp.getActive()
var formurl = ss.getFormUrl()
Browser.msgBox(formurl)
}
so it would be quite easy to embed a list in a site page,
here is a small code that does the job, online version here (needs authorization) be patient : can be slow to show up...
function doGet() {
var app=UiApp.createApplication().setTitle('Available Forms').setStyleAttribute('padding', '25');
var user = Session.getEffectiveUser().getUserLoginId();
app.add(app.createLabel('Available forms in Drive for '+user).setStyleAttribute('background', '#dddd33').setPixelSize(500, 18).setHorizontalAlignment(UiApp.HorizontalAlignment.CENTER).setStyleAttribute('fontWeight', 'bold'))
var flex=app.createFlexTable().setId('flex').setWidth('500').setBorderWidth(1).setCellPadding(2).setStyleAttribute('borderColor', '#dddd33');
var index = 0
var docs = DocsList.getAllFiles()
for (var n in docs){
if(docs[n].getFileType()=="spreadsheet"){
var ss=SpreadsheetApp.openById(docs[n].getId())
if(ss.getFormUrl()){
flex.setText(index, 0, docs[n].getName())
flex.setWidget(index, 1, app.createAnchor('open form', ss.getFormUrl()))
++ index
}
}
}
app.add(flex)
return app
}
again sorry that I forgot this feature.
-Forms are embedded in spreadsheet and don't appear as individual entities in your drive. Their ID (or URL) are not available from apps-script.... I'm afraid you'll have to encode the URLs manually.-
You could create a Document and name it the title of your Google Form. Stick the URL of the form inside the doc.

Is OAuth possible from a Google Apps Script gadget on a site?

I have developed a google apps script in a spreadsheet that uses oAuth.
I now copied the same script to a gadget that runs on a site. When I want to run the function that uses oauth I get the following error:
Unexpected exception upon serializing continuation
This happens both when I run the actual gadget on a site or when I run the function from the script editor. The exact same code works when called from the script editor in the spreadsheet.
Am I doing something wrong or is it simply not possible to use oAuth with UrlFetchApp.fetch when using a site gadget?
Thanks,
Jan
Here's some sample code of what I'm trying to do, you'll need to include real api secrets from the Google Api console to test it.
function CalendarApiBug( ) {
var oAuthConfig = UrlFetchApp.addOAuthService('agenda scheduler');
oAuthConfig.setRequestTokenUrl("https://www.google.com/accounts/"+
"OAuthGetRequestToken?scope=https://www.googleapis.com/auth/calendar");
oAuthConfig.setAuthorizationUrl("https://www.google.com/accounts/OAuthAuthorizeToken");
oAuthConfig.setAccessTokenUrl("https://www.google.com/accounts/OAuthGetAccessToken");
oAuthConfig.setConsumerKey('replacemewithsomethingreal');
oAuthConfig.setConsumerSecret('replacemewithsomethingreal');
this.baseUrl = 'https://www.googleapis.com/calendar/v3/';
this.calendarsList = null;
this.getBaseUrl = function() {
return this.baseUrl;
} //CalendarApiBug.getBaseUrl
this.getFetchArgs = function() {
return {oAuthServiceName:'agenda scheduler', oAuthUseToken:"always"};
} //CalendarApiBug.getFetchArgs
this.getCalendarList = function(refresh){
if (refresh != true && this.calendarsList != null )
return this.calendarsList;
var fetchArgs = this.getFetchArgs();
fetchArgs.method = 'get';
var url = this.baseUrl + 'users/me/calendarList';
this.calendarsList = Utilities.jsonParse(UrlFetchApp.fetch(url, fetchArgs).getContentText());
return this.calendarsList;
} //CalendarApiBug.getCalendarList
}
function test(){
var api = new CalendarApiBug();
Logger.log(api.getCalendarList(false));
}
The oAuth approval dialog only becomes visible when running the code from inside the Script Manager. In order to publish your Apps Script code to a Site, you would have needed to publish that version of the script as a service. Open the code editor for that script and make sure that you can run the functions with the script editor first. This will verify your oAuth approval has been stored.
Why use Oauth in a Google Apps Script for the Calendar service?