Google sheets, scripts stop working after making a copy. - javascript

I have a spreadsheet that I have built to be used as a template. This spreadsheet has a few scripts in it, the problem I am having is when you make a copy of the spreadsheet, all of my scripts stop working. I have to go into each script and manually authorize them again.
We would be making a copy of the Master spreadsheet for every single job that comes through my department. Roughly 20-30 copies of the master would be made each day, by multiple people.
Is there anyway to avoid this?
Please see sample code and spreadsheet below.
Thanks,
Tyler
https://docs.google.com/a/costco.com/spreadsheets/d/1vcmjVtS2mKwCGfboVFK14yNoksTJ7pq4vDcKIOpG2oU/edit?usp=sharing
function customDocEmail(){
var sheet = SpreadsheetApp.getActiveSheet();
if (sheet.getName() == "Version 1 ") {;
var ss = SpreadsheetApp.getActiveSpreadsheet();
var triggerCell = sheet.getRange("C17").getValue().toString();
var email = sheet.getRange("A17").getValue().toString();
var EMAIL_SENT = new Date() ;
var recipients = "Youremail#gmail.com";
var cellA1 = ss.getSheetByName("Version 1 ").getRange("A1").getValue().toString();
var cellB2 = ss.getSheetByName("Version 1 ").getRange("B2").getValue().toString();
var cellD1 = ss.getSheetByName("Version 1 ").getRange("D1").getValue().toString();
}
var subject = 'New customDoc ' + cellA1+ '-' +cellB2;
var body = ' Hi Stephanie,' + '\n' + '\n' + 'This job ' + cellA1 + '-'+ cellB2+ ', is being created as a CustomDoc.. Please view the specs for this job. ' + '\n' + ss.getUrl() +' '+ '\n' + '\n' +'Thank you,' + '\n' + cellD1 +' ' ;
if (triggerCell =="YES")
{MailApp.sendEmail(recipients, subject, body);
sheet.getRange("C17").setValue("SENT");
}
}
function templateMagix() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getSheetByName("Version 1 ");
var trigger = sheet.getRange("B3").getValue().toString();
var formNumber = sheet.getRange("A23").getValue().toString();
var boom = sheet.getRange("C23").getValue().toString();
if (boom =="BOOM")
sheet.getRange("B3").setValue(formNumber);
}

The reason why you have to authorize your scripts time and again is because each copy that you create is treated as a New Document and so are the scripts attached to that document. And for any new document to be able to run scripts, it is necessary for the user to provide that document permission to run scripts. Being able to make copies and run scripts without having authorized it manually will be somewhat similar to providing a script unauthorized access to run. Which, if it were possible, could be seen as a serious security thread. Therefore, unfortunately so, it is not possible to run scripts without providing them permission to run.
Although, depending on how many scripts you have, your use case and what function(s) they are performing etc., I would suggest that if it is possible combine these functions into one script and call them where necessary. This way, you will have to only provide manual permission to the script once instead of having to do it n number of times (assuming you have n scripts) for each script to be granted permission to run.

I was able to figure out a work around for this and it works flawlessly for my application.
I put all onEdit scripts in the same "Project", then I made a button and assigned my timeStamp Function to it. This prompted the authorization for all of my scripts that required the Auth.
Next I ran into all of the "installed onEdits" not staying installed upon making a copy of the spreadsheet, so the script's still were not functional. A little more digging and research brought me to writing a simple but effective script, that I assigned to my newly created button. Which in turn install's all of my onEdit triggers as well as prompting the authorization and all script's now work as they were intended.
I hope someone dealing with the same issues can find some use in this.
function authoRize(e) {
Browser.msgBox("Great! Let's be friends!");
var sheet = SpreadsheetApp.getActive();
ScriptApp.newTrigger("customDocEmail")
.forSpreadsheet(sheet)
.onEdit()
.create();
var sheet = SpreadsheetApp.getActive();
ScriptApp.newTrigger("templateMagix")
.forSpreadsheet(sheet)
.onEdit()
.create();
var sheet = SpreadsheetApp.getActive();
ScriptApp.newTrigger("GetData")
.forSpreadsheet(sheet)
.onEdit()
.create();
var sheet = SpreadsheetApp.getActive();
ScriptApp.newTrigger("GetPJData")
.forSpreadsheet(sheet)
.onEdit()
.create();
var sheet = SpreadsheetApp.getActive();
ScriptApp.newTrigger("hideSeek")
.forSpreadsheet(sheet)
.onEdit()
.create();
var sheet = SpreadsheetApp.getActive();
ScriptApp.newTrigger("hideSeekOP")
.forSpreadsheet(sheet)
.onEdit()
.create();
var sheet = SpreadsheetApp.getActive();
ScriptApp.newTrigger("hideSeekPJ")
.forSpreadsheet(sheet)
.onEdit()
.create();
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getSheetByName("HOME");
var newDate = new Date() ;
sheet.getRange("A5").setValue(newDate);
goToSheet('Version 1 ');
}

Related

How to split JSON data from app script on a spreadsheet getting info from Wialon platform

I've collected some code to get this work, this GPS platform (Wialon) is for tracking vehicles and it has some functions to get notifications, one of them is to send them via server GET / POST method, so I have the following result in one cell:
{"|2020/08/13 18:57|CR-03 FR|0 km|🦂|JESUS SALVADOR GARCIA SCOTT|":""} //example
I separated some values by "||||" characters just to split them easily by SPLIT() formula in Google Sheets, but I want a cleaner result from the script, this is what I got from this code:
Please if you can help me to get this FINAL result, it didn't have to be necessarily formatted (date), this already splitted and separated by "|":
In this code are other functions that send the same data to a Telegram Group, ignore it, just put it here in case helps to anyone.
var token = "FILL IN YOUR OWN TOKEN"; // 1. FILL IN YOUR OWN TOKEN
var telegramUrl = "https://api.telegram.org/bot" + token;
var webAppUrl = "FILL IN YOUR GOOGLE WEB APP ADDRESS"; // 2. FILL IN YOUR GOOGLE WEB APP ADDRESS
var ssId = "FILL IN THE ID OF YOUR SPREADSHEET"; // 3. FILL IN THE ID OF YOUR SPREADSHEET
var adminID = "-XXXXXXXXX"; // 4. Fill in your own Telegram ID for debugging
function getMe() {
var url = telegramUrl + "/getMe";
var response = UrlFetchApp.fetch(url);
Logger.log(response.getContentText());
}
function setWebhook() {
var url = telegramUrl + "/setWebhook?url=" + webAppUrl;
var response = UrlFetchApp.fetch(url);
Logger.log(response.getContentText());
}
function sendText(id,text) {
var url = telegramUrl + "/sendMessage?chat_id=" + id + "&text=" + encodeURIComponent(text);
var response = UrlFetchApp.fetch(url);
Logger.log(response.getContentText());
}
function doGet(e) {
return HtmlService.createHtmlOutput("Hi there");
}
function doPost(e) {
try {
// this is where telegram works
var data = JSON.parse(e.postData.contents);
var text = data.message.text;
var id = data.message.chat.id;
var name = data.message.chat.first_name + " " + data.message.chat.last_name;
var answer = "Hi " + name;
sendText(id,answer);
SpreadsheetApp.openById(ssId).getSheets()[0].appendRow([new Date(),id,name,text,answer]);
if(/^#/.test(text)) {
var sheetName = text.slice(1).split(" ")[0];
var sheet = SpreadsheetApp.openById(ssId).getSheetByName(sheetName) ? SpreadsheetApp.openById(ssId).getSheetByName(sheetName) : SpreadsheetApp.openById(ssId).insertSheet(sheetName);
var newText = text.split(" ").slice(1).join(" ");
sheet.appendRow([new Date(),id,name,newText,answer]);
sendText(id,"your text '" + newText + "' is now added to the sheet '" + sheetName + "'");
}
} catch(e) {
sendText(adminID, JSON.stringify(e,null,4));
}
}
This is the notification panel in the GPS platform and how it should be configured with the App Script:
I believe your goal as follows.
You want to split the following value in a cell of Google Spreadsheet.
{"|2020/08/13 18:57|CR-03 FR|0 km|🦂|JESUS SALVADOR GARCIA SCOTT|":""}
Sample formula:
=QUERY(ARRAYFORMULA(SPLIT(REGEXEXTRACT(SUBSTITUTE(A1:A5," km","|km"),"\|(\w.+)\|"),"|",TRUE,FALSE)),"select Col2,Col1,Col6,Col3,Col4")
The flow of this formula is as follows.
Put | to 0 km using SUBSTITUTE.
Retrieve |2020/08/13 18:57|CR-03 FR|0 km|🦂|JESUS SALVADOR GARCIA SCOTT| from {"|2020/08/13 18:57|CR-03 FR|0 km|🦂|JESUS SALVADOR GARCIA SCOTT|":""} using REGEXEXTRACT.
Split it with | using SPLIT.
Rearrange the columns using QUERY.
Result:
When your sample value is used with above formula, it becomes as follows.
Note:
Above proposed answer uses the built-in functions of Google Spreadsheet. If you want to convert above using Google Apps Script, please tell me. At that time, can you provide the sample values including {"|2020/08/13 18:57|CR-03 FR|0 km|🦂|JESUS SALVADOR GARCIA SCOTT|":""} from the response of the API? By this, I would like to think of the solution.
References:
SUBSTITUTE
REGEXEXTRACT
SPLIT
QUERY

Google Scripts: Pull Google Document Based on User ID / Email

Good Morning Stack!
I was looking for some advice for some expanded functionality on a Google Script that helps me track and process absence requests. The process is as follows:
A user submits their form responses
The form responses are stored on a spreadsheet
A google doc, pre-created, is pulled and the values from the spreadsheet are implanted in the document.
The document is converted to a PDF
That PDF is automatically emailed to me.
However, some work policies have changed and I now need this form to have a signature that is unique to the person filling the form. In the past we simply printed the resulting PDF and had the person sign off on it.
I know I do not have the technicality to add on any sort of Electronic Signature functionality, nor is emailing that PDF to them an option as it doesn't create a fillable PDF (and my users don't really know how to digitally sign items anyways)
So what I was thinking is to create a form unique to each of the 15-20 users of this process and instead of a getFileByID, have the script check the Google Users account / email and pull the file created for them and stored in my drive instead.
As follows is my current, functional, script. How could I make this work?
function onFormSubmit(e) {
var Last_Name = e.values[2];
var First_Name = e.values[3];
var Middle_Initial = e.values[4];
var Work_Location = e.values[5];
var Job_Title = e.values[6];
var Contact_Number = e.values[7];
var Start = e.values[8];
var End = e.values[9];
var Time = e.values[10];
var Reason = e.values[11];
var D = new Date();
var copyId = DriveApp
.getFileById("1sdfjlsdf55asdfnk565enasdfnsnsd2")
.makeCopy("AbsenceRequest" + Last_Name + Start).getId();
var copyDoc = DocumentApp.openById(copyId)
var copyBody = copyDoc.getActiveSection();
copyBody.replaceText('keyLastName', Last_Name);
copyBody.replaceText('keyFirstName', First_Name);
copyBody.replaceText('keyMiddleInitial', Middle_Initial);
copyBody.replaceText('keyWorkLocation', Work_Location);
copyBody.replaceText('keyJobTitle', Job_Title);
copyBody.replaceText('keyContactNumber',Contact_Number);
copyBody.replaceText('keyStart', Start);
copyBody.replaceText('keyEnd', End);
copyBody.replaceText('keyTime', Time);
copyBody.replaceText('keyDate', D);
copyDoc.saveAndClose();
var pdf = DriveApp.getFileById(copyId).getAs("application/pdf");
var Email = "email#email.org" + "," + "email#email.org";
var Subject = "Absence Request"
var Body = "This is an absence request"
MailApp.sendEmail(Email, Subject, Body, {attachments: pdf});
DriveApp.getFileById(copyId).setTrashed(true);
}

Adding to a Google Doc from a Google Spreadsheet Using Apps Script

I'm new to using the DocumentApp in Google Apps, so looking for some help!
I'm trying to create an FAQ (in a Google Doc) automatically from a spreadsheet. If certain conditions are met in the spreadsheet row, I want the script to find the category of the question in the document and insert a new question and response underneath it (pushing anything already there back).
So I'd have a document that looks like this:
https://docs.google.com/document/d/1fjb3RO6hUY6n7x0bu6WvtcleMWRNC8VQ9U82hXiGqcY/edit?usp=sharing
And a spreadsheet that looks like this:
https://docs.google.com/spreadsheets/d/1fb3ceqP6142_C7QQ1PfkWtVNswOyzOxkWCofvauf4Ps/edit?usp=sharing
And this is the code I'm trying to use. I'm getting a ton of errors- mainly because I don't have a good grasp on what the different elements involved are. Can anyone point me in the right direction?
function insertnewquestion() {
//(works fine)Get active document and related spreadsheet
var doc = DocumentApp.getActiveDocument().getBody();
var ss = SpreadsheetApp.openById("xxxxxxx");
var sheet = ss.getSheetByName("xxxxx");
//(works fine)Go through the various rows in the spreadsheet up to the last row
for (var row = 2; row <= sheet.getLastRow(); ++row) {
var status = sheet.getRange(row,4).getValue();
var question = sheet.getRange(row,1).getValue();
var response = sheet.getRange(row,2).getValue();
var category = sheet.getRange(row,3).getValue();
var date = sheet.getRange(row,5).getValue();
//(works fine)find rows with blank status and a response filled in
if (status !== "Entered" && response !== "") {
//(errors! this is where i need help) find the pertinent header
var categoryposition = body.findText(category); //looking for the category header- new text should be added after this, the idea is that what was already under this header will move down
var questionheader = categoryposition.appendText(question); //trying here to add in question text after where the category was found
questionheader.setHeading(DocumentApp.ParagraphHeading.HEADING3); //set question text as heading 3 (so it shows up on table of contents)
questionheader.appendText("\r"+"\r"+response+"\r\r"); //add line breaks and then the response text in normal font, then more line breaks to put space between new stuff and old stuff
//(works fine)Mark in the spreadsheet that it was entered in FAQ and the date so that it isn't double entered next time the script runs
sheet.getRange(row,4).setValue("Entered");
var currentTime = new Date()
var month = currentTime.getMonth() + 1
var day = currentTime.getDate()
var year = currentTime.getFullYear()
var date = (month + "/" + day + "/" + year)
sheet.getRange(row,5).setValue(date);
}
else {continue}
}
//(need help!) Refresh table of contents to include new questions
//no idea how to do this!
}
In the code you are referring to body.findText(category); where it should be doc.findText(category);. Also for the line:
var categoryposition = body.findText(category);
it returns the RangeElement — a search result indicating the position of the search text, or null if there is no match
Before adding any lines of code you have to check for null value in categoryposition.
The text class has a method to insert text in particular offset value to particular String value gives as shown here.
Hope that is helpful.

Automatically Detect New entry and create another new row

I have one google spreadsheet with two sheets that have same number of rows.
What I want to do:
When a new entry is written after the last row of Sheet1, it will automatically copy the last row of Sheet2 and paste it after that. (The new row will be in the last row after this, and both sheets will have same row again)
Since I don't use google script too much, I don't know how to accomplish it. Which functions or formula shall I use?
Thanks in advance.
You can use the onEdit() function, and the getLastRow() method, and copyTo()
function onEdit(){
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getSheets()[0];
// This logs the value in the very last cell of this sheet
var lastRow = sheet.getLastRow();
var lastColumn = sheet.getLastColumn();
var lastCell = sheet.getRange(lastRow, lastColumn);
Logger.log(lastCell.getValue());
var lastRowAndCol = lastRow + ":" + lastRow;
var newRowOnEnd = (lastRow+1) + ":" + (lastRow+1);
Logger.log('lastRowAndCol: ' + lastRowAndCol);
Logger.log('newRowOnEnd: ' + newRowOnEnd);
sheet.getRange(lastRowAndCol).copyTo(sheet.getRange(newRowOnEnd));
};
Google Documentation - onEdit
Google Documentation - getLastRow
copyTo

Array element assignment in Google (Apps) Script

I'm associating a Google (Apps) Script with a Google Spreadsheet.
The entire script works except for the following line:
headers[0] = headers[0] + ":";
Removing this line allows the script to run. Adding it makes it fail.
The array is initialized beforehand as follows.
var s = SpreadsheetApp.getActiveSheet();
var headers = s.getRange(1,1,1,s.getLastColumn()).getValues()[0];
What's wrong with my element assignment, and how do I fix it?
Thanks.
The very simple test function:
function whenOpen() {
var s = SpreadsheetApp.getActiveSheet();
var headers = s.getRange(1,1,1,s.getLastColumn()).getValues()[0];
Logger.log('Array of headers: ' + headers);
Logger.log('First header: ' + headers[0]);
headers[0] = headers[0] + ":";
Logger.log('Modified header: ' + headers[0]);
}
Runs perfectly for me: http://prntscr.com/58a6fx
I don't get any errors, so I suspect the issue is more complex then this one line, as it does not appear to be the culprit. If you try it yourself in a fresh script (Bound to a spreadsheet, with some values in the headers, ofc), it should run with issue.

Categories

Resources