403 while opening a drive link (pdf) with google apps script - google-apps-script

I'm trying to open a print window for a shipping label (in pdf form) from a google drive file link.
This is the .gs code I've written so far:
the drive link is being declared based on an order its associated with, that portion isn't applicable in this instance
function printPdf() {
const sheet = SpreadsheetApp.getActive().getSheets()[4];
const ui = SpreadsheetApp.getUi();
// order ID associated with the label
const orderQuery = sheet.getRange('S:S').createTextFinder(
ui.prompt('Enter an order ID', '', ui.ButtonSet.OK).getResponseText()
).matchEntireCell(true).findNext();
let url;
// drive link is in column 'O'
if (orderQuery) url = sheet.getRange(orderQuery.getRow(), 15).getValue();
const template = HtmlService.createTemplateFromFile('check-out-modeless');
template.url = url;
const html = template.evaluate();
ui.showModelessDialog(html, 'Print Label');
}
and the HTML looks like this:
<!DOCTYPE html>
<html>
<head>
<base target="_top">
</head>
<body>
<iframe src="<?= url ?>" style="width:100%; height:100%;"></iframe>
<script>
window.print();
google.script.host.close();
</script>
</body>
</html>
So far I
made sure the drive like is id-based rather than preview-based
verified that the drive link is accessible from my account
I used an incognito window as well to avoid conflicts from being logged in to more than one account
recorded network headers to see if there was any indication of why the server is declining access
Beyond those I can't think of any other way to solve this aside from maybe utilizing blobs & DriveApp

Related

How do I get the title I set through HtmlOutput's setTitle from the html side?

I want to fetch the title I set using setTitle method of HtmlOutput within the html source file, i.e., client-side, but it seems that calling document.title returns me empty string when I call it within my html file.
Main.gs:
function onOpen() {
var spreadsheet = SpreadsheetApp.getActive();
var menuItems = [
{name: 'Build Form...', functionName: 'buildForm_'},
];
spreadsheet.addMenu('Test', menuItems);
}
function buildForm_(){
const reportTitle = "Some Title"
const htmlForm = HtmlService.createHtmlOutputFromFile('HTML_Sidebar')
.setTitle(reportTitle);
SpreadsheetApp.getUi()
.showSidebar(htmlForm)
}
HTML_Sidebar.html:
<!DOCTYPE html>
<html>
<head>
<base target="_top">
</head>
<body>
<button onmouseup="seeTitle()" id="seeTitleButton">See title</button>
<script>
function seeTitle() {
document.getElementById("seeTitleButton").textContent = "(" + document.title + ")"
}
</script>
</body>
</html>
Google Apps Script's documentation doesn't seem to specify a client-side method in the HTML Service to query the title, and I was hoping that someone in the community could point me towards the right direction.
The issue is that <title> is assigned to a outer iframe than the one your userAppCode lives in (userHtmlFrame) so when you call the document node you are reading from the iframe your app is contained in, which does not have the title.
A work around would be to use the PropertiesService and store the title as a script property when setting it. And retrieving it from the properties when you want to use it. You still would need to use google.script.run to call a function on the server-side which would fetch the title and return it to the client.
Use getTitle():
Gets the title of the output page. Note that the <title> HTML element is ignored.
var output = HtmlService.createHtmlOutput('<b>Hello, world!</b>');
Logger.log(output.getTitle());
Source: https://developers.google.com/apps-script/reference/html/html-output#gettitle

Upload File To Google Drive Using Google Apps Script

Trying to created a Google Apps Script to prompt me to choose a file to upload to Google Drive as described here
But I am receiving an error
Uncaught ScriptError: TypeError: Cannot read property 'getAs' of
undefined
I have watched the YouTube video a couple of times now, but I don't see that I am doing anything incorrectly. Any ideas?
function doGet(){
return HtmlService.createHtmlOutputFromFile("form.html")
}
function upload(e){
// logic to upload the file
var destination_id = 'enter your folder id here' //folder id
var img = e.imageFile
var contentType = 'img/png'
var destination = DriveApp.getFolderById(destination_id)
var img = img.getAs(contentType)
destination.createFile(img)
}
<!DOCTYPE html>
<html>
<head>
<base target="_top">
</head>
<body>
<form>
<input type="file" name="imageFile"/>
<input type="button" value="Upload" onclick="google.script.run.upload(this.parentNode)">
</form>
</body>
</html>
The code has an error
replace
var contentType = 'img/png'
by
var contentType = 'image/png'
Applyng the above fix, the code worked fine for me.
NOTE: While code doesn't throw any error using the default runtime (Chrome V8), the file was not correctly uploaded but using the old runtine (Mozilla Rhino) it works fine.
Regarding the specific error that you got, perphaps you didn't publish the code shown in the question as a new version of your web application. Try using the link to test the latest code.
Related
Google Apps script web app automatically linked to latest code?

How to monitor page activity of a google site using Google Apps Script

Problem
I want to be able to monitor user activity on my google site using Apps Script, specifically which pages users are accessing. I can not use Google Analytics (it is not within my contract with Google). Apps Script has so far been able to return user ID (email address) of the user when a page is accessed, however I can not work out how to return which page(s) are activated by that user.
What I have done so far
I have created a web app and deployed / embedded it within to 2 pages in a test google site. It returns the values to a table in a linked google sheets file. Here is the script:
function doGet(event) {
return HtmlService.createHtmlOutputFromFile('UserLog.html');
}
function getPage(pageTitle) {
var user = Session.getActiveUser();
var ss = SpreadsheetApp.getActive();
var db = "Webapp Log";
var db_ss = ss.getSheetByName(db);
var now = new Date();
var page = pageTitle;
var values = [now,user,page,"User activated webapp",Session.getTemporaryActiveUserKey()];
db_ss.getRange(db_ss.getLastRow()+1, 1, 1, 5).setValues([values]);
};
The "UserLog.html" code is this:
<html>
<head>
<base target="_top">
</head>
<body>
<script>
var page = [Solution]
google.script.run.getPage(page);
</script>
</body>
</html>
And so far the return values look like this (with addresses anonymised):
Table Values
As you can see, the 'Page' field is blank.
What I need
Use the embedded web app to return the activated page URL OR to return another unique aspect of the activated page, for example the page title or "page 1", "page 2", etc. (all pages on the site have a unique title).
How can this be done? Is this even possible?
You can do it with e.parameters
E.g. incorporate a parameter page that you append at the end of the WebApp URL.
When you embedd the WebApp URL in each page, assign a unique value to page, like https://script.google.com/a/XXX/macros/s/XXX/exec?page=1, https://script.google.com/a/XXX/macros/s/XXX/exec?page=2
Now, in Apps Script you just have to slightly modify your doGet() function to retrieve the page:
function doGet(event) {
var page = event.parameter.page;
return HtmlService.createHtmlOutputFromFile('UserLog.html');
}
The rest depends on your preferences. The easiest would be to directly paste the value of page into the spreadsheet from the doGet() function - this will avoid passing the parameter to the html file and then, with google.script.run back to a .gs function.

Google Script for opening a URL in dedicated browser (Internet Explorer) by click in Spreadsheets

I am using Google Chrome (as G-Suite is used by the users for standard/collaboration processes) and I am looking for a Google Script that opens a URL out of Google Spreadsheet in a new internet explorer application.
Background: I have a Google Sheets document with lots of tabs. The first tab is the "landing page", linked to the tabs and to external Google Documents or other URLs, using macros / Google Script. The problem is that I have one online application that only runs in Internet Explorer. So I need to have a script forcing to open the URL in a new Internet Explorer application.
Everything I found was on how to open a new window or tab, but I did not find anything saying "open a url in a dedicated browser" (here: Internet Explorer). I am looking for something like the script below, I used for opening external links out of Google Spreadsheets, but additionally saying "do this with Internet Explorer":
function open link in new window() {
var js = " \
<script> \
window.open('https://www.externalwebapplicationthatonlyrunsonwindowsexplorer.com', '_blank', 'width=800, height=600'); \
google.script.host.close(); \
</script> \
";
var html = HtmlService.createHtmlOutput(js)
.setHeight(10)
.setWidth(100);
SpreadsheetApp.getUi().showModalDialog(html, 'Loading, please wait...');
}
Although it's not possible to force open links in specific browser, it is possible to detect the user agent string as the previous answer states. You can use use HtmlService.getUserAgent():
function testInternetExplorer(){
var html = HtmlService.createHtmlOutput(js)
.setHeight(10)
.setWidth(100);
var ui = SpreadsheetApp.getUi();
var response = ui.alert('This app link is available only on Internet Explorer.\n Proceeding to use outdated browsers may cause serious damage to your device, data and privacy.\nAre you sure you want to continue?', ui.ButtonSet.YES_NO);
if(response == ui.Button.YES) {
if(/Trident|MSIE/.test(HtmlService.getUserAgent())){
ui.showModalDialog(html, 'Loading, please wait...');
} else {
ui.alert("Internet Explorer is not detected.\n Cannot proceed.")
}
}
}
It's not possible for you to force which browser opens a link in Google Apps Script or in JavaScript - this can't be decided by a script, only the end-user that is using the device.
You can however use a conditional that only loads the script if the browser is detected to be Internet Explorer like this though:
function doGet(e){
var browser = HtmlService.createHtmlOutput('index')
var browser2 = browser.getContent();
if (browser2.indexOf('Netscape') !== -1){
if (browser2.indexOf('Trident') !== -1 || browser2.indexOf('MSIE') !== -1){
// run your code
}
return noMessage();
}
else {
return noMessage();
}
}
function noMessage(){
return HtmlService.createHtmlOutput('This page will only run in Internet Explorer.');
}
And the index.html:
<!DOCTYPE html>
<html>
<head>
<base target="_top">
</head>
<body>
<p id="x"></p>
<script>
document.getElementById("x").innerHTML = navigator.appName + " " + navigator.userAgent;
</script>
</body>
</html>
This just checks the navigator settings for Internet Explorer-like strings and runs the script based on that. It's not a perfect workaround, but sadly forcing the browser like that is simply impossible.

Auto submit google form after a time limit

I want to use app script in my Google form to automatically submit the form in 20 minutes if the user doesn't click on submit within 20 minutes. Anyway to implement this????
No, you cannot control the client-side of Google Forms, even if you add an Apps Script to it, because Apps Script runs on the server.
One possible solution is to serve your form as a Google Apps Script web app. At that point you can write client-side JavaScript and use window.setTimeout to submit the form after 20 minutes.
Here are some example files, Code.gs and quiz.html, that can provide a basic skeleton to start the web app. A blank project will have Code.gs as the default file, then you have to add File > New > HTML file to start the other file.
You can enter the id of any spreadsheet you own in the commented out lines in Code.gs to append the response into that spreadsheet. (You can also automate that process by creating a new spreadsheet as needed. Example of creating spreadsheet to hold data for Apps Script example can be found here.
// file Code.gs
function doGet() {
return HtmlService.createHtmlOutputFromFile("quiz");
}
function doPost(request) {
if (request.answer) {
console.log(request.answer); // View > Execution transcript to verify this
//var ss = SpreadsheetApp.openById(id).getSheetByName("Quiz Responses");
//ss.appendRow([request.answer /* additional values comma separated here */ ]);
}
}
<!DOCTYPE html>
<!-- file quiz.html -->
<html>
<head>
<base target="_top">
</head>
<body>
<h1>Quiz</h1>
<form>
What is Lorem Ipsum?
<input name="loremipsum" type="text"/>
<button>Submit</button>
</form>
<script>
const button = document.querySelector("button");
const timeLimitMinutes = 1; // low number for demo; change to 20 for application
const timeLimitMilliseconds = timeLimitMinutes * 60 * 1000;
// For this demo we are not going to serve a response page, so don't try to.
button.addEventListener("submit", submitEvent => submitEvent.preventDefault());
// attach our custom submit to both the button and to the timeout
button.addEventListener("click", submitForm)
window.setTimeout(submitForm, timeLimitMilliseconds)
function submitForm() {
button.setAttribute("disabled", true);
document.querySelector("h1").textContent = "Quiz submitted";
// for demo: submitting just a single answer.
// research Apps Script documentation for rules on submitting forms, certain values not allowed
// consider a helper function `makeForm()` that returns a safe object to submit.
const answer = document.querySelector("input").value;
google.script.run.doPost({ answer });
}
</script>
</body>
</html>
Test with Publish > Deploy as web app...