Cannot find method open() - google-apps-script

Cannot find method open().
If it can't find it, why does it let me choose it when I type the dot?
So how am I supposed to open a file? openByID()? Really? Where do I get this magical ID? From getURL? Seriously? This is the only thing that comes up:
SpreadsheetApp.openById(id).getUrl()
but I fail to understand how I'm supposed to get the URL if I don't have an ID to hang it on... leading to a catch 22. Further, I presume in the event I do get the URL I still need to parse it to get the ID... and what magical method have they supplied for that particular incantation?
Clearly, my understanding is lacking. Any help?
function copyTemplate() {
var targetSpreadsheetName="The file";
var targetSpreadsheetID=SpreadsheetApp.open(targetSpreadsheetName).getId();
targetSpreadsheetID.insertSheet("CellData", 1, {template:temp});
// The code below will duplicate the sheet named "CellData" and insert it after
// the 1st sheet and call it "CellData"
var ss = SpreadsheetApp.getActiveSpreadsheet();
var temp = ss.getSheetByName("CellData");
ss.insertSheet("CellData", 1, {template:temp});
}
The question is multi-part.
The error message returned was "Cannot find method open()."
The first question is "Why can't it find method open()?".
The second question is "If in fact, it can't find it, why does it let me choose it when I type the dot?"
The third question is "Considering the fact that the open() method fails to work, how am I supposed to open a file?" The presumed answer I expect to receive from the community is "with openByID()".
That leads to the fourth question which is "Where do I get the ID?". The apparent answer seems to be "getURL()".
And that leads to the fifth question which is "How do I use getURL()?" getURL seems to require an ID. If getURL requires an ID to get the URL, and openByID requires a URL to get the ID, you have an infinite loop. Surely I'm misunderstanding something.
The sixth question is "In the event getURL() ends up being part of the solution, how does one distinguish the ID from the rest of the string returned?"
I hope that clarifies my question.

Well I'll finally try to answer your question, hoping you'll find it clear enough... ;-)
First thing first :
var ss = SpreadsheetApp.open()
does indeed appear in the autocomplete after the dot, what you didn't pay attention to is that the argument is a file, ie an object returned by an appropriate statement.
Now let's see how to get it and , with this example how the other parameters of this file can be obtained :
function myFunction() {
var files = DocsList.find('thisisthesheetIwant');// this is an array of file objects that include the term 'thisisthesheetIwant'
var file = files[0];// I take the first one
var filename = file.getName();//and get its name
var fileId = file.getId();// its ID
var fileurl = file.getUrl();//and its url
// then I show the results in the logger
Logger.log('number of file found = '+files.length+'\n\n'+filename+'\n\n'+fileId+'\n\n'+fileurl+'\n\n')
var ss = SpreadsheetApp.open(file);// using that file object I can open a spreadsheet
var content = ss.getSheets()[0].getDataRange().getValues().toString();// and get the whole content of the first sheet
Logger.log('content = '+content);// there it is
}
The spreadsheet with its code is available here so you can test it by yourself, I named it thisisthesheetIwant hoping you don't have any file with a similar name or content since it wouldn't work as I expected if more than 1 file was returned.
Look at the logger and I hope it will answer your question(s).
it should appear like this below :
And the sheet itself is like this :
EDIT : note that the ID and the URL have a common part, the url is what you can see in your Browser's adress bar, the ID is just a part of it.
Now you can open the same spreadsheet with
SpreadsheetApp.openById(fileId)

Related

Fetch Telegram Post's views with Google Apps Script

I'm trying to fetch this number:
Tested this Telegram post:
https://t.me/s/google_sheets/393
I want to do it with a script. Interesting, it was possible for me to achieve this with a formula:
=INDEX( REGEXEXTRACT(SUBSTITUTE(QUERY(FLATTEN(IMPORTDATA("https://t.me/s/google_sheets/393")),,2^99),CHAR(10),), "(.*tgme_widget_message_views"">)(.+)(<\/span><span class=""copyonly"".*)"),2)
This is the script I've tried:
function GET() {
var reg1 = /tgme_widget_message_views">(.+)<\/span><span class="copyonly"/i;
var response = UrlFetchApp.fetch('https://t.me/s/google_sheets/393').getContentText();
var match = response.match(new RegExp(reg1))[1];
Logger.log(match); // 13.4K, expected: 11.2K
}
It gives me the wrong result. I'm willing to do the work with a script because I want an afficient way of fetching multiple URLs at once. The formula will crash in this situation.
My script gives me the wrong result, it may be the number for other Telegram post (https://t.me/google_sheets/374 ), I'm not sure.
Please help me to resolve this issue.
Since the one you are looking for is that specific post and not the others, you may want to limit what you are searching for by appending the id of the post at the end of your regex. Thus we are sure we are looking just until post id 393. As you can see, I added .+google_sheets\/393 in your regex.
function GET() {
var reg1 = /tgme_widget_message_views">(.+)<\/span><span class="copyonly".+google_sheets\/393/i;
var response = UrlFetchApp.fetch('https://t.me/s/google_sheets/393').getContentText();
var match = response.match(new RegExp(reg1))[1];
Logger.log(match); //11.2K
}

I don't manage to parse JSON in google app script

I'm trying to grab song lyrics from the orion.apiseeds lyrics API - it works and I get a JSON, that I'm incapable of parsing.
https://orion.apiseeds.com/api/music/lyric/Oasis/Wonderwall?apikey=xx
gives back
{"result":{"artist":{"name":"Oasis"},"track":{"name":"Wonderwall","text":"Today is gonna be the day that they're gonna throw it back to you.\r\nBy now you should've somehow realized what you gotta do.\r\nI don't believe that anybody, feels the way I do, about you now.\r\n\r\nBackbeat, the word is on the street that the fire in your heart is out.\r\nI'm sure you've heard it all before but you never really had a doubt.\r\nI don't believe that anybody, feels the way I do, about you now.\r\n\r\nAnd all the roads we have to walk are winding.\r\nAnd all the lights that lead us there are blinding.\r\nThere are many things that I, would like to say to you but I don't know how.\r\n\r\nBecause maybe, you're gonna be the one that saves me?\r\nAnd after all, you're my wonderwall.\r\n\r\nToday was gonna be the day but they'll never throw it back to you.\r\nBy now you should've somehow realized what you're not to do.\r\nI don't believe that anybody, feels the way I do, about you now.\r\n\r\nAnd all the roads that lead you there were winding.\r\nAnd all the lights that light the way are blinding.\r\nThere are many things that I, would like to say to you but I don't know how.\r\n\r\nI said maybe, you're gonna be the one that saves me?\r\nAnd after all, you're my wonderwall.\r\n\r\nI said maybe, (I said maybe)\r\nYou're gonna be the one that saves me?\r\nAnd after all, you're my wonderwall.\r\n\r\nI said maybe, (I said maybe)\r\nYou're gonna be the one that saves me? (that saves me)\r\nYou're gonna be the one that saves me? (that saves me)\r\nYou're gonna be the one that saves me? (that saves me)","lang":{"code":"en","name":"English"}},"copyright":{"notice":"Wonderwall lyrics are property and copyright of their owners. Commercial use is not allowed.","artist":"Copyright Oasis","text":"All lyrics provided for educational purposes and personal use only."},"probability":100,"similarity":1}}
My code to fetch this is:
function getLyrics(url) {
var response = UrlFetchApp.fetch(url);
var responseObject = JSON.parse(response.getContentText());
}
Then, that's where the problem arises.
1)
Logger.log(reponseObject); ==> gives the thing I pasted above.
2)
for (var i=0;i<responseObject.length;i++) {
var item = responseObject[i];
Logger.log(JSON.stringify(item));
==> gives NOTHING in the console...
3)
function printJson(myObject) {
// define an array of all the object keys
var headerRow = Object.keys(myObject);
// define an array of all the object values
var row = headerRow.map(function(key){ return myObject[key]});
// define the contents of the range
var contents = [
headerRow,
row
];
// select the range and set its values
var ss = SpreadsheetApp.getActive();
var rng = ss.getActiveSheet().getRange(1, 1, contents.length, headerRow.length )
rng.setValues(contents)
}
===> fills one row with "result" and the next row with all the rest of the JSON.
I feel like i'm missing a basic JSON-related thing...
Thanks for your help
var responseObject = JSON.parse(response.getContentText());
var lyrics = responseObject.result.track.text;
That was easy enough ;-)

error - "Method Range.getValue is heavily used by the script"

I posted this question previously but did not tag it properly (and hence why I likely did not get an answer) so I thought I would give it another shot as I haven't been able to find the answer in the meantime.
The below script is giving me the message in the title. I have another function which is using the same getValue method but it is running fine. What can I change in my script to avoid this issue?
function trashOldFiles() {
var ffile = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("CtrlSht").getRange("B3:B3").getValue();
var files = DriveApp.getFilesByName(ffile);
while (files.hasNext()) {
var file = files.next();
var latestfile = DriveApp.getFileById(listLatestFile());
if(file.getId() ==! latestfile){
file.setTrashed(true);
}
}
};
Is it an error or an execution hint(the light bulb in the menu)?
are you using that method on other part of your code? probably in listLatestFile()?
I got the same execution hint by calling getRange().getValue() in listLatestFile() (using a loop)
and the hint always mentioned that the problem was when calling
var ffile = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("CtrlSht").getRange("B3:B3").getValue();
in the function trashOldFiles() even when the actual problem was in other function.
Check if you are calling it in other place in your code, probably inside a loop.
OK, so Gerardo's comment about loops started to get me thinking again. I checked some other posts about how to re-use a variable and decided to put the listLatestFile() value in my spreadsheet -
var id = result[0][1];
SpreadsheetApp.getActiveSpreadsheet().getSheetByName("CtrlSht").getRange("B5:B5").setValue(id);
//Logger.log(id);
return id;
and then retrieved the latest file ID from the spreadsheet to use as a comparison value for the trashOldFiles() function which worked a treat.
function trashOldFiles() {
var tfile = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("CtrlSht").getRange("B3:B3").getValue();
var tfiles = DriveApp.getFilesByName(tfile);
var lfile = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("CtrlSht").getRange("B5:B5").getValue();
while (tfiles.hasNext()) {
var tfile = tfiles.next();
if(tfile.getId() !== lfile){
tfile.setTrashed(true);
}
}
};
Not sure if that approach was best practice but it did work for me. If anyone has suggestions for achieving this in a more elegant way, I'm all ears.

addEditors to Document from formSubmit

I'm Working on creating script that will perform the actions described below. so far, I've managed to get the first two parts to function, but am now stuck on getting anything more to work. I've reviewed several response forums and tried the suggestions, but no success.
Desired script flow:
form submitted from spreadsheet form
completes fields:
Timestamp
Username (email collected on submission)
Student
Grade
Intervention Plan
Core Reading/Math
Team (email list)
1 script runs onFormSubmit that then creates a copy of a template document, renames that new copy to the e.value "student" submitted in form,
2 then replaces selected text strings within the document with values submitted in the form.
3 Add editors to new document and sends notification with desired instructions
4 creates event (one week from submission date) event details include instructions and link to shared document for team members to complete with their input, sends event invitation to email list.
Here is the working script so far.
function formSubmitValues(e) {
var timeStamp = e.values[0];
var userEmail = e.values[1];
var student = e.values[2];
var grade = e.values[3];
var conern = e.values[4];
var readingCore = e.values[5];
var mathCore = e.values[6];
var interventions = e.values[7];
var team = e.values[8].toString(); // "just to be sure"..Henrique says add .toString this allowed the replaceText part to work
//Makes copy of template document and renames
var tempID = ("1Rq0pDAnuGNfL6W3GB0ZuLeWM2uYzHpKzoyxoXlwjtgE") // use document ID from Template Document
var copyId = DocsList
.getFileById(tempID)
.makeCopy(student + " Initial Referral") // names new copy as student's name
.getId();
// trying to add editors to new document using email list generated in form submit value of "team"
DocsList.getFileById(copyId).addEditors([team]);
// replaces text within template with selected fields from formSubmitValues
var doc = DocumentApp.openById(copyId)
var body = doc.getActiveSection();
body.replaceText("%STUDENT%", student);
body.replaceText("%DATE%", timeStamp);
body.replaceText("%TEACHER%", userEmail);
body.replaceText("%TEAM%", team);
return doc;
}
REPORTED ISSUE RESPONSE: Here is what they said: "The function takes an array or strings, like: DocsList.getFileById(copyId).addEditors(['parent#domain.com', 'parent2#domain.com']);
I tried entering emails directly into script like this and things worked.
So my problem is not the 'addEditors method, but lies in getting the form submitted emails to be passed correctly. Any suggestions on how I would do this?
I have tried what I believe to be all combinations of using .toString(), or not, and using .Split(',').
RE-DEFINE PROBLEM : So it is an issue of how the emails are passed from the e.values form submit.
Here is where I'm at:
When I type emails into script directly: .addEditors(['parent#domain.com', 'email2#domain.net', 'email3#gmail.com']) it works, (I did have to move the addEditors method in the script to go right after the .makeCopy instead of at the end.)
This is what the Execution Transcript shows:
File.addEditors([[parent#domain.com, email2#domain.net]]) and it runs the rest of the script. note: One part I don't understand is the single quotes i.e. 'email' They must be typed in the script, but don't show up on Transcript when run. I've tried putting them around emails in the form, but it makes them show in Transcript and still doesn't run anyway.
So this is what script looks like now:
var tempID = ("1Rq0pDAnuGNfL6W3GB0ZuLeWM2uYzHpKzoyxoXlwjtgE") // use document ID from Template Document
var copyId = DocsList
.getFileById(tempID)
.makeCopy(student + " - TestingCopy") // names new copy as student's name + text
.addEditors([team.split(',')])
.getId();
But when I use the var team with or without .split(',') it does not work. But in the Transcript it shows:
File.addEditors([[rreynolds#domain.net, parent#domain.com]])
which looks identical as to what shows when it does work, but that is the last thing shown in Transcript and editors are not added to document and the script does not finish.
I'm obviously not understanding something here. Is there a way I could get the emails in the team e.values to be treated in a way that the addEditors method is requiring? In the spreadsheet cell they appear as a CSV. i.e rreynolds#domain.net, parent#domain.com
Do they have to be read one at a time, or something?
I'm learning a lot, and appreciate all your help. I am sorry for the confusion with all the comments, but am not sure of the correct way to address issues in this forum. For example: should I go back and edit my original script to show the current version, or add it someplace else? I'm trying to keep the conversation flowing, so that it is easier for others to follow - Thanks rob
please let me give a last (hopefully) clear answer : (thanks for sharing the spreadsheet, this is far more easy to work on ;-)
here is your code fully working.
I have created some intermediate variables to show how it works.
function formSubmitEditors(e) {
// defines spreadsheet form events on submit of form. This function formSubmitEditors is triggered on formSubmit
var timeStamp = e.values[0];
var fileName = e.values[1];
var team = e.values[2].replace(/, /g,"|"); // remove unwanted spaces and commas replace by | for visibility ;-)
Logger.log(team);// contains | as separators
var teamArray = team.split('|');
Logger.log(teamArray.length+' : '+teamArray);// check that it is an array of x elements
//Makes copy of template document and renames
var tempID = '1Rq0pDAnuGNfL6W3GB0ZuLeWM2uYzHpKzoyxoXlwjtgE' // use document ID from Template Document
var copyId = DocsList
.getFileById(tempID)
.makeCopy(fileName + " - TestingCopy") // names new copy as student's name + text
.getId(); //
var file = DocsList.getFileById(copyId).addEditors(teamArray);
// replaces merged-text values within template with selected fields from formSubmitValues
var doc = DocumentApp.openById(copyId)
var body = doc.getActiveSection();
body.replaceText("%FILE%", fileName);// you wrote %FILENAME% in place of %FILE%
body.replaceText("%DATE%", timeStamp);
body.replaceText("%TEAM%", team);// it will be shown with | as separators, if you don't like it replace team by teamArray.toString() to get commas again.
}
EDIT : I removed the toString() for team event, not necessary since e.parameters are already strings.
EDIT2 : to be complete and do what you needed in the initial question you could replace the end of the code with this one that creates the Cal event on next week and sends invites with link to the doc.
var file = DocsList.getFileById(copyId).addEditors(editorsArray);
var fileurl = file.getUrl();
Logger.log(fileurl)
// replaces merged-text values within template with selected fields from formSubmitValues
var doc = DocumentApp.openById(copyId)
var body = doc.getActiveSection();
body.replaceText("%FILE%", fileName);
body.replaceText("%DATE%", timeStamp);
body.replaceText("%MAILS%", editors);
var Cal = CalendarApp.getCalendarsByName('testencodage')[0];// replace with your calendar name you want to use
var newEvent = Cal.createAllDayEvent('Fill the questionnary', new Date(new Date(newtimeStamp).getTime()+7*24*3600*1000), { guests : e.values[2] , sendInvites : true , description :"Don't forget to fill this document "+fileurl})
}
I'd suggest a couple of things
Add a few Logger.log statements in your code to print out debug information.
Add a try ... catch block around the entire section of code and print out the exception. See if you are getting any exception.
Last, use the Execution transcript window to see where your script stopped, if it did.
There are 2 ways to add an editor by email : addEditors([emailAddresses]) and addEditor(emailAddress)
The first has an "s" and needs an array of email adress strings, the second takes a single string as argument. You should use the second or add [brackets] to the email string in your code.
concerning you comment // need to figure out where/how to: .addEditors(email1,email2,etc);
// is this done from DocsList or DocumentApp class?
addEditor() and addEditors() belong to the file class, a member of DocsList class , you can add user(s) using user(s) objects or user(s) email(s) as explained in the doc.
It could be used like this DocFile.addEditors([email1,email2])
EDIT : A lot of comments on this post, sorry about that, it has become quite uneasy to read... I tested these addEditors feature with spreadsheet and it works as expected, using simple array for multiple user emails and string for single email. The document service seems to have a problem with the addEditor() method and it should be reported to the issue tracker.
REPORTED I've reported issue #1512 - Rocketrob

Unable to make a copy of a doc even with the right ID

I have a script that goes through a spreadsheet, retrieves values from the cells and inserts the values in a doc. The code works perfectly but I've noticed that when I make a copy of the doc, run the same code and pass the doc ID within the code I get the following error:
No item with the given ID could be found, or you do not have permission to access it.
I've tried to make the doc public but I get the same error. Interestingly if I create a new doc and pass that doc ID to the function it works just fine.
the code:
var templateid = "1IrEbukq3cVKg9MAPT-Aanfe4XCzoc-RCJKq6sOpQKGU"; // get template file id
var copyDoc = DocsList.getFileById(templateid).makeCopy(docName);
I'm not sure I understood exactly when you problem occurs but I'd guess it is when you try to access copyDoc.
This is because you try to access it by its ID (as it appears from the error message) and you don't have it : from the code you write here copyDoc is a document, if you want its Id just add .getId() at the end like this :
var copyDoc = DocsList.getFileById(templateid).makeCopy(docName).getId();
Hoping I had the right guess ;-)
You could also do that like this so you'll have everything ready to use :
var doctemplate = DocumentApp.openById("1IrEbukq3cVKg9MAPT-Aanfe4XCzoc-RCJKq6sOpQKGU");// this can be placed outside the function as a global variable
var docname="new name for the copy";
var copydoc=DocsList.copy(doctemplate,docname);
var copydocId = copydoc.getId();
Edit : corrected error in code following jwesonga comment (thx)