I have a Google Drive document which writes values to a Google Drive spreadsheet using Google Apps Scripts.
The script associated with the document looks a lot like this:
// must change value to actual spreadsheet ID
RobProject.spreadsheetID = "spreadsheetID";
function onOpen()
{
// do stuff;
}
Each time I create a spreadsheet and its related documents, I manually change the value spreadsheetID to the spreadsheet's ID so the documents know to which spreadsheet they should write their values.
I would like a programmatic way to fill in the correct value for spreadsheetID into the Documents' scripts.
When I search for "edit scripts programmatically," I get tutorials for creating Google Apps Scripts, not editing scripts with scripts. Is there any way to edit Google Apps Scripts with a Google Apps Script?
If I understand correctly, you are working with a document and a spreadsheet. The document needs to know the Id of the spreadsheet.
There are some ways to access the Google Apps Script code through the API, but that is only for standalone projects, not for container-bound scripts (unfortunately).
You could consider using a naming convention for the document and spreadsheet so that you could use the Drive service to get from the document to the spreadsheet (DriveApp.getFilesByName()). Or possibly organize them by folder (DriveApp.getFoldersByName(), folder.getFiles()).
If you wanted to store the spreadsheet Id in a project property, you could build a UI in the document that let the user open up the list of files in Drive and pick the associated spreadsheet and then store the Id (ScriptProperties.setProperty('SpreadsheetId')).
Don't forget that onOpen has a parameter. You could use following code:
// Define global variable somewhere
RobProject = {};
function onOpen(e) {
RobProject.sSheet = e.source; // maybe the spreadsheet object is as useful as the ID
RobProject.spreadsheetID = e.source.getId();
// do stuff;
}
Please, for your own sake, don't try to write selfmodifying code.
Related
I have a standalone script that uses the Sheets API. There are only two calls:
SpreadsheetApp.openById(spreadsheetID).getSheetByName("Answers")
SpreadsheetApp.openById(otherspreadsheetID).getSheetByName("Questions").getDataRange().getValues()
So it reads from one file and writes to a different file. The script is set to run as a webapp as me, so on initial run, by default, this triggers a broad scope to view/edit/delete all sheets. I want to limit that. I see this is a scope I could manually set: https://www.googleapis.com/auth/drive.file (docs).
But I don't get how to then set my two spreadsheets as files that have been "opened or created" by the app so that the scope is valid for those files. I tried creating a function that creates two new sheets (I figured this counts as "a drive file that you created with this app") but even the Spreadsheetapp.create() function throws a "do not have permission" error.
I might be misunderstanding how this scoping works?
Issue and workaround:
When SpreadsheetApp.openById() is used, the scope of https://www.googleapis.com/auth/spreadsheets is used. It seems that this is the current specification.
So, as a workaround, how about using Sheets API? When the Sheets API is used, you can use the scope of https://www.googleapis.com/auth/drive.file.
As an important point, the official document of the scope of https://www.googleapis.com/auth/drive.file is as follows.
Per-file access to files created or opened by the app. File authorization is granted on a per-user basis and is revoked when the user deauthorizes the app.
So, when you want to retrieve the data from the Spreadsheet using the scope of https://www.googleapis.com/auth/drive.file, at first, the Spreadsheet is required to be created by the scope. In this answer, I would like to introduce the following flow.
Set the scope of https://www.googleapis.com/auth/drive.file to Google Apps Script project.
Create a new Spreadsheet.
Retrieve values from the Spreadsheet.
Usage:
1. Set scope.
Please create a new Google Apps Script. From your question, I understood that you are using the standalone type. For this, please set the scope of https://www.googleapis.com/auth/drive.file to the manifest file. Ref Please add "oauthScopes": ["https://www.googleapis.com/auth/drive.file"] to the file of appsscript.json. By this, the specific scope can be used.
2. Create a new Spreadsheet.
Before you use this script, please enable Sheets API at Advanced Google services. When you run the following script, a new Spreadsheet is created and you can see the spreadsheet ID at the log. Please copy the ID. This ID is used in the next script. By this, a new Spreadsheet is created by the scope of https://www.googleapis.com/auth/drive.file.
function createNewSpreadsheet() {
const id = Sheets.Spreadsheets.create({properties: {title: "sample"}}).spreadsheetId;
console.log(id)
}
When you try to retrieve the values from the existing Spreadsheet which is not created by this Google Apps Script project, an error of Requested entity was not found. occurs. So in this section, a new Spreadsheet is created by this Google Apps Script project.
3. Get values from Spreadsheet.
Before you use this script, please open the created Spreadsheet and check the sheet name. And, as a sample, please put the sample values to the cells. When you run the following script, the values are retrieved from the Spreadsheet and you can see them at the log.
function getValues() {
const spreadsheetId = "###"; // Please set the spreadsheet ID.
const obj = Sheets.Spreadsheets.Values.get(spreadsheetId, "Sheet1");
const values = obj.values;
console.log(values)
}
References:
Manifest structure
Method: spreadsheets.create
Method: spreadsheets.values.get
I've set up a script that essentially copies the contents from a 'template' folder within my google drive and moves the copied contents to a newly created folder elsewhere. The 'Template' folder will always hold 9 individual spreadsheets, each with their own unique bounded script.
The problem I'm having is that every time I copy the spreadsheets over, I have to reauthorise access for each of the 9 scripts before I can start using the functionality I've created.
I'd like to be able to assign or grant permission for the bound script to access the services it needs to during the process I use to copy the spreadsheet to a new location.
Here is an example of the code I use to copy over the spreadsheets. Is there anyway to access the script to assign permissions here?
function copyContents(template_folder, new_folder){
var files = template_folder.getFiles();
while (files.hasNext()) {
var file = files.next();
var file_name = file.getName()
var copied_file = file.makeCopy(file_name,new_folder)
// Assign permissions here...
}
}
It's not possible to grant authorization programmatically as this implies a security risk. The alternative is to publish your bounded scripts as add-ons so you authorize them once and you will be able to use them on any spreadsheet.
Bear in mind that you still should have to enable the addons on each of the documents you want to use them but this usually as simple as having a an onOpen menu that runs with ScriptApp.authMode.NONE
Note: I'm pretty sure that this was already asked and answered on this site.
Similar questions without answers with positive score
Installable onEdit trigger in google spreadsheet script when copying a template spreadsheet script
Google Script Carrying over triggers when copying a spreadsheet
Within a Standalone App ScriptI'm creating a new spread sheet using the following line:
var new_ss = SpreadsheetApp.create("File_Name");
Now I wanna link a predefined App Script to this spreadsheet. How to do this? I couldn't find any method within the Documentation or by searching Google
I found the ScriptApp, but it doesn't provide any methods. I also found the API, but i don't think its available within App Script
I was looking for the same answer and bacuase I haven't find it, I change my approach. I created a script bound to a Google Sheet. When a new Google Sheet is needed I make a copy of the "template" Google Sheet with the bound script. I have a sheet name Parameters so the users can control the bound script.
I'm trying to create a Google Script to access a range of cells from a Google Docs spreadsheet that I don't own but is shared. The spreadsheet is shared in a way that means it is publicly readable, but can't be written to. (Normal users can comment, but not edit)
When I try to run this script, I get an error: "You do not have permissions to access the requested document." I've authorized Google Scripts to my account, but that doesn't seem to be enough to do a getValues() call.
Here's my script so far:
function myFunction() {
var spreadsheet = SpreadsheetApp.openByUrl("https://docs.google.com/spreadsheets/d/1g24uo61ITTveZrUGx4ZY5nMoJp-n1NCxq5r4WMhAJU0/");
// I can access the name, this runs fine:
Logger.log(spreadsheet.getName());
SpreadsheetApp.setActiveSpreadsheet(spreadsheet);
SpreadsheetApp.setActiveSheet(spreadsheet.getSheets()[0]);
// fetch this sheet
sheet = spreadsheet.getActiveSheet();
var range = sheet.getRange(3,3,22,1);
// This next line fails:
var slicesAndCounts = range.getValues();
Logger.log(slicesAndCounts);
}
(The URL is the actual public spreadsheet, so this code should run as is)
Is there some way I can access the values in the spreadsheet from Google Scripts? I've considered trying to make a private copy of the spreadsheet, but I only need it for the duration of the script and I'm not sure if I can create a temporary copy easily. That solution also seems a bit heavy, considering I feel like I should be able to read the spreadsheet given I can access it via my browser or the Google Sheets app.
How about using Sheets API? At SpreadsheetApp, it seems that users cannot retrieve values from the shared spreadsheet. I think that the reason may be due to that the access token cannot use at SpreadsheetApp. In my environment, the same error also occurs. So I would like to propose to use Sheets API. When Sheets API is used, the access token is also used. By this, users can retrieve values from the shared spreadsheet.
In order to use this sample script, please enable Sheets API at Advanced Google Services and API console.
Enable Sheets API v4 at Advanced Google Services
On script editor
Resources -> Advanced Google Services
Turn on Google Sheets API v4
Enable Sheets API v4 at API console
On script editor
Resources -> Cloud Platform project
View API console
At Getting started, click Enable APIs and get credentials like keys.
At left side, click Library.
At Search for APIs & services, input "sheets". And click Google Sheets API.
Click Enable button.
If API has already been enabled, please don't turn off.
If now you are opening the script editor with the script for using Sheets API, you can enable Sheets API for the project by accessing this URL https://console.cloud.google.com/apis/library/sheets.googleapis.com/
About sample script :
The result of this sample is the same to that of your script. The values are retrieved from the range of 3,3,22,1 of 1st sheet in the shared spreadsheet.
In this sample script, it uses file ID of Spreadsheet. In your case, that is 1g24uo61ITTveZrUGx4ZY5nMoJp-n1NCxq5r4WMhAJU0 for https://docs.google.com/spreadsheets/d/1g24uo61ITTveZrUGx4ZY5nMoJp-n1NCxq5r4WMhAJU0/.
In this sample script, a1Notation is used for the range. In your case, getRange(3,3,22,1) is C3:C24.
For this script, when {ranges: "C3:C24"} is used, it means the 1st sheet of the spreadsheet. If you want to retrieve values from more than 2nd sheet, please use the sheet name like sheet2!C3:C24 and sheet3!C3:C24.
Script :
function myFunction() {
var spreadsheetId = "1g24uo61ITTveZrUGx4ZY5nMoJp-n1NCxq5r4WMhAJU0";
var slicesAndCounts = Sheets.Spreadsheets.Values.batchGet(spreadsheetId, {ranges: "C3:C24"}).valueRanges[0].values;
Logger.log(slicesAndCounts);
}
References :
Advanced Google Services : https://developers.google.com/apps-script/guides/services/advanced
Sheets API v4: https://developers.google.com/sheets/api/
If this was not useful for you, I'm sorry.
In a standalone Google Script, I have made a created a Google Sheet using its API, by using it's SpreadsheetApp.create() function, and filled the spreadsheet with data.
I have to add this file to Google Drive, but I have no idea how. I'm assuming that the create() method doesn't add it to drive automatically. Thanks!
When you use SpreadsheetApp.create() it creates a new spreadsheet that is natively (and obviously) in your Drive. There is no need to add it to your drive and it actually doesn't make any sense.
You can eventually check that easily with this small code :
function testCreate(){
var newSs = SpreadsheetApp.create("new test spreadsheet");
Browser.msgBox("file in drive is "+DriveApp.getFileById(newSs.getId()).getName());
}
note : run this from a spreadsheet (any spreadsheet) because it uses the Browser.msgBox() method that only works in spreadsheets.