Spreadsheet tracker - javascript

Im having trouble with an script that posts the outcome twice, I have reviewed the script but I cant find the issue.
The script gets the "Timestamp", "Cell address", "Column label" and "Value entered" and post it on the sheet named "Tracker" but it gets posted twice
function onEdit() {
var sheetsToWatch = ['Responses'];
// name of the sheet where the changelog is stored
var changelogSheetName = "Tracker";
var timestamp = new Date();
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getActiveSheet();
var cell = sheet.getActiveCell();
var sheetName = sheet.getName();
// if it is the changelog sheet that is being edited, do not record the change
if (sheetName == changelogSheetName) return;
// if the sheet name does not appear in sheetsToWatch, do not record the change
var matchFound = false;
for (var i = 0; i < sheetsToWatch.length; i++) {
if (sheetName.match(sheetsToWatch[i])) matchFound = true;
}
if (!matchFound) return;
var columnLabel = sheet.getRange(/* row 1 */ 1, cell.getColumn()).getValue();
var rowLabel = sheet.getRange(cell.getRow(), /* column A */ 1).getValue();
var changelogSheet = ss.getSheetByName(changelogSheetName);
if (!changelogSheet) {
// no changelog sheet found, create it as the last sheet in the spreadsheet
changelogSheet = ss.insertSheet(changelogSheetName, ss.getNumSheets());
// Utilities.sleep(2000); // give time for the new sheet to render before going back
// ss.setActiveSheet(sheet);
changelogSheet.appendRow(["Timestamp", "Cell address", "Column label", "Value entered"]);
changelogSheet.setFrozenRows(1);
}
changelogSheet.appendRow([timestamp, cell.getA1Notation(), columnLabel, cell.getValue()]);
}

Google's method documentation makes it seem like you can programmatically check for the existence of some other user's trigger with a function like this:
function triggerLogger() {
// Read installed triggers for the project.
var triggers = ScriptApp.getProjectTriggers();
var installedReport = {};
triggers.forEach(function (t) { installedReport[t.getUniqueId()] = {
event: t.getEventType(),
calledFunction: t.getHandlerFunction(),
source: t.getTriggerSource(),
source_id: t.getTriggerSourceId() || "Time-based triggers have no source id."
}});
// Read "simple" triggers for the project by checking for globals that start with "on".
var simpleReport = {};
for (var thing in this)
if (thing.indexOf("on") === 0 && thing.length > 2)
simpleReport[String(thing)] = {def: this[thing]};
var possibleSimple = Object.keys(simpleReport).length,
message = "Trigger report: " + triggers.length + " installed";
if (possibleSimple) message += ", " + possibleSimple + " possible simple triggers";
message += ".";
// Log to Stackdriver (so the report can be viewed sensibly).
console.log({
message: message,
installed: Object.keys(installedReport).length ?
installedReport : "No detected installed triggers.",
simple: possibleSimple ?
simpleReport : "No simple triggers used",
reportRunAs: Session.getActiveUser().getEmail()
});
}
But the getProjectTriggers() method, despite claiming to get all of the current project's installed triggers, will only obtain your installed triggers for the document, even if you are the owner of the document.
Note that this behavior is accepted as a bug (meaning someone, someday will fix it). If you would like to feel that you have done your part to accelerate that timeline, please star that issue:

Related

Unable to update google sheet value of a cell using google spreadsheet api v4.0

I am unable to update the sheets row value of a particular cells. I am using google api v4.0 and google spreadsheet npm package. I am getting an error using it in discord bot js. The error is
(node:5956) UnhandledPromiseRejectionWarning: TypeError: rows2[i].save
is not a function
at checkStatus (D:\discortbot\src\bot.js:95:30)
My code is as follows:
sheet3 = doc2.sheetsByIndex[sheetIndex]; // Data from back which I have checked is coming correctly!
var rows2 = await sheet3.getRows({
});
rows2 = rows2.map(a=>a._rawData);
var size = rows2.length;
for(var i=0;i<size;i++){
if(rows2[i][0]==email){
rows2[i].candidateID = userID;
rows2[i].RoleID = sheetarr[2];
//rows2[i].save(); This one is also not working
console.log(rows2[i].candidateID); // Values are printing in console
console.log(rows2[i].RoleID); // Values are printing in console
await rows2[i].save(); // Error giving me
verified = 1;
break;
}
}
if(verified==1){
message.author.send("Your account has been verified.Welcome to Outscal batch!");
}else{
}
I am not able to understand why I am getting this error? Kindly help me in solving this.
How about the following modification?
Modified script:
Before you use this script, please confirm the variables you want to use, again.
var sheet3 = doc2.sheetsByIndex[sheetIndex];
var rows2 = await sheet3.getRows();
// rows2 = rows2.map(a=>a._rawData); // Removed
var size = rows2.length;
for (var i = 0; i < size; i++) {
if (rows2[i]._rawData[0] == email) { // Modified
rows2[i].candidateID = userID;
rows2[i].RoleID = sheetarr[2];
console.log(rows2[i].candidateID); // Values are printing in console
console.log(rows2[i].RoleID); // Values are printing in console
await rows2[i].save();
verified = 1;
break;
}
}
if (verified == 1) {
message.author.send("Your account has been verified.Welcome to Outscal batch!");
} else {
}
Reference:
node-google-spreadsheet

OnEdit() google script trigger use in function

I'm working on a small project in Google Apps Scripts using Google spreadsheet / Google Forms.
I want to help students in large class sizes find people to study with by entering the class into a Google Form. From there they would be automatically emailed a list of people taking the same class as them, who are also looking for people in the same class or lecture to study with. The student inputs their name, school Id number, email, class CRN#, Class Name and instructor. Its put into the Google spreadsheet and I manipulate it like a CSV file.
I want to use the onEdit() trigger so that when information is added or edited, an email will be sent out. I'm not understanding how the onEdit() event trigger works.
This is my code for the class sorting:
function studyBudy2() {
var ss =
SpreadsheetApp.openById("1ZxTdRdhy0iR6HH7jB75KL4g-SCr7nPZEilXrzECe7yg").getActiveSheet();
var numOfStu = ss.getLastRow();
/*var range = ss.getRange(2, 4, numOfStu-1);
var values = range.getValues();
// get emails out of spreadsheet
for (var row in values) {
for (var col in values[row]) {
emails = values[row][col]
Logger.log(emails);
// sends emails
MailApp.sendEmail(emails, "pls work","now");
}
}
*/
var theMass = []
var rAnge = ss.getRange(2,1,numOfStu-1,7);
var vAlues = rAnge.getValues()
for (var row in vAlues) {
var student = [];
var buzznumber = vAlues[row][2];
var classCRN = vAlues[row][4];
var class = vAlues[row][5];
var proffessor = vAlues[row][6];
student.push(buzznumber);
student.push(classCRN);
student.push(class);
student.push(proffessor);
theMass.push(student);
}
for (var i = 0; i < numOfStu-2; i++){
var theStudent = theMass[i]
var theCRN = theStudent[1];
var theClass = theStudent[2];
var theProffessor = theStudent[3];
var theBuzznumber = theStudent[0];
Logger.log(theClass);
for (var j= 1; j < numOfStu-1; j++){
if (i+j <= numOfStu-2 && theMass[i+j][1] == theCRN && (i+j != i)){
Logger.log("Youre in the same Section!")
}
else if (i+j <= numOfStu-2 && theMass[j+i][2] == theClass && theProffessor != theMass[j+i][3] && (i+j != i)){
Logger.log("Youre taking the same Course!");
}
else if(j+i <= numOfStu-2 && theClass == theMass[j+i][2] && theProffessor == theMass[j+i][3] && (i+j != i)){
Logger.log("Youre in the same lecture!");
}
else if (j+i > numOfStu-2){
continue;
}
}
}
}
I'm thinking the onEdit() function should be implemented as another function but does it go in another function or in this studyBudy2 function?
function onEdit(e) {
var activeSheet = SpreadsheetApp.openById("1ZxTdRdhy0iR6HH7jB75KL4g-SCr7nPZEilXrzECe7yg").getActiveSheet();
var row = e.range.getRow();
var studentNum = row+1;
}
onEdit is a reserved function name which purpose is to declare a function to be used as a simple trigger.
function onEdit(e){
//do something
}
Besides creating an onEdit simple trigger, we could create a on-edit installable trigger. Functions to be used for installable triggers could be named as we wish but to avoid confusions it's better to avoid using reserved functions names and spreadsheet build-in functions names.
If studyBudy2() function does what you needs to triggered when a edit is made on the spreadsheet, you could rename it as onEdit, declara an onEdit function that call studyBudy2() or create an installable trigger that calls studyBudy2().
Bear in mind that only edits made by users directly on the spreadsheet will fire a simple/installable on edit trigger. If you want something fire when a form response is submitted then you should use a on form submit installable trigger.
For further details please read https://developers.google.com/apps-script/guides/triggers/

Loop in Google Apps Script, handle an error, fatal error, stops the script, loop stops

I am using Google Apps Script
I have a Google Sheet where column 1 has 120 domain names (120 rows) and i need to write the status of these domains as "Domain Verified" / "Domain Not Verified" in Column 7
I wrote a script which is using Admin Directory API service and using AdminDirectory.get.domains.verified which results in boolean (True = domain verified, False = domain not verified) to check the status of domains to see if they are verified domains in google.
my below script works absolutely fine, it checks for each domain name row and puts the status as either in column 7, however the problem is that my loop stops as soon as it comes to any domain which is NOT yet registered in Google, in the logs it says "Execution failed: Domain not found. (line 36, file "Code") [1.412 seconds total runtime]"
where i expect it to be running till the last row (120th) regardless of the result.
What I actually want is, regardless of the result, my loop should cover all 120 rows, can you help?
Here is my Script-:
function domainList() {
var ss = SpreadsheetApp.getActiveSpreadsheet()
var sheet = ss.getActiveSheet()
var data = sheet.getRange("B2:B").getValues()
var customer = "my_customer"
for(i=0; i<data.length; i++){
var dcheck = AdminDirectory.Domains.get(customer, data[i]);
var status = dcheck.verified
if(status === true){
status = "Domain Verified"}
else if(status === false){
status = "Domain Not Verified"}
else if(status === ({})){
continue;
}
Logger.log(status)
var range = ss.getSheets()[0].getRange(2+i, 7).clear()
var range = ss.getSheets()[0].getRange(2+i, 7)
range.setValue(status)
}}
You could try putting some of the code into a try/catch and if there is an error, simply continue looping:
try {
var dcheck = AdminDirectory.Domains.get(customer, data[i]);
if (dcheck) {//Check for truthy value
var status = dcheck.verified;
} else {
continue;//If "get" returned a falsy value then continue
}
} catch(e) {
continue;//If error continue looping
}
Here's another way of doing the same thing. I wasn't clear on what this if(status === ({})) was so I thought it might be interesting to make that third alternative a little less narrow because if it's expected to be boolean and it's neither true nor false then it's not clear to me what else is left. It might take a while but I'd try to run through this with the debugger. But I'm not familiar with AdminDirectory so I'm kinda guessing here.
function domainList()
{
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getActiveSheet();
var data = sheet.getRange("B2:B").getValues();
var customer = "my_customer";
var value = '';
for(i=0; i<data.length; i++)
{
value = '';
var dcheck = AdminDirectory.Domains.get(customer, data[i]);
var status = dcheck.verified;
switch(status)
{
case true:
value = 'Domain Verified';
break;
case false:
value = 'Domain Not Verified';
break;
default:
value = 'unknown';
}
Logger.log(status);
var range = ss.getSheets()[0].getRange(2+i, 7)
range.clear();
range.setValue(value);
}
}

SharePoint 2013 JSOM User Key From Person Field

Can anyone help me to get the user info from a person column using javascript? So far I have been able to read the list item and return a SP.FieldUserValue from which I can get a numeric Id (not sure what this ID is) and the display name. e.g.
var ManVal = oListItem.get_item("RecruitingManager").get_lookupValue();
var ManId = oListItem.get_item("RecruitingManager").get_lookupId();
How do I take this one step further to create a sp user object?
Ultimately what I'm trying to achieve is to retrieve the details from the list and then populate a people editor.
Ok, I've got it.
Here is my code, hope it helps somebody. I haven't included the method to retrieve the list item, just the line from that function where I'm getting the value of the person.
var _lineManager;
var lineManager = oListItem.get_item("RecruitingManager").get_lookupId();
_lineManager = oWebsite.getUserById(lineManager);
getLineManager();
function getLineManager() {
context.load(_lineManager);
context.executeQueryAsync(onGetUserNameSuccessLM, onGetUserNameFailLM);
}
function onGetUserNameSuccessLM() {
alert(lineManager.get_title());
var schema = {};
schema['PrincipalAccountType'] = 'User,DL,SecGroup,SPGroup';
schema['SearchPrincipalSource'] = 15;
schema['ResolvePrincipalSource'] = 15;
schema['AllowMultipleValues'] = false;
schema['MaximumEntitySuggestions'] = 50;
schema['Width'] = '280px';
var users = new Array(1);
var defaultUser = new Object();
defaultUser.AutoFillDisplayText = lineManager.get_title();
defaultUser.AutoFillKey = lineManager.get_loginName();
defaultUser.Description = lineManager.get_email();
defaultUser.DisplayText = lineManager.get_title();
defaultUser.EntityType = "User";
defaultUser.IsResolved = true;
defaultUser.Key = lineManager.get_loginName();
defaultUser.Resolved = true;
users[0] = defaultUser;
SPClientPeoplePicker_InitStandaloneControlWrapper('peoplePickerDivLinMan', users, schema);
}
function onGetUserNameFailLM(sender, args) {
alert('Failed to get user name. Error:' + args.get_message());
}
The person field (actually called "people picker") has a specific JavaScript function which you might find useful: GetAllUserInfo()
There is a nice article on MSDN:
How to: Use the client-side People Picker control in apps for SharePoint
The relevant code is:
// Get the people picker object from the page.
var peoplePicker = this.SPClientPeoplePicker.SPClientPeoplePickerDict.peoplePickerDiv_TopSpan;
// Get information about all users.
var users = peoplePicker.GetAllUserInfo();
var userInfo = '';
for (var i = 0; i < users.length; i++) {
var user = users[i];
for (var userProperty in user) {
userInfo += userProperty + ': ' + user[userProperty] + '<br>';
}
}
$('#resolvedUsers').html(userInfo);
// Get user keys.
var keys = peoplePicker.GetAllUserKeys();
$('#userKeys').html(keys);
So basically you have to cast your field to a SPClientPeoplePicker and can then use GetAllUserInfo to iterate over all users in the field.

GAS Click Event Handler causing "Unexpected Error" in UI Web App

I've written a Google apps script which first creates and displays a line chart within the UI app and then re-draws the graph based on selected list box values using a Click-button event handler to trigger when the graph "refreshes".
The issue I'm trying to resolve is that when published as a web application when triggering the click event I receive:
Error Encountered: An unexpected error occurred
The code runs perfectly from a spreadsheet (except for some pesky permissions issues where other users are asked to download the panel object; I'll get to that later), and I'm really stuck as to why it won't translate.
Here's the code for what it's worth:
function doGet(){
var app = UiApp.createApplication().setWidth(800).setHeight(650).setTitle('FLEET Chart');
var e = 'undefined';
lb(app);
return click(e, app);
}
function lb(app){
var lb = app.createListBox(true).setId('myId').setName('myLbName');// add items to ListBox
var lb2 = app.createListBox(true).setId('myId2').setName('myLbName2');
var lb3 = app.createListBox(true).setId('myId3').setName('myLbName3');
var bttn = app.createButton('Refresh').setId('myBttn');
lb3.addItem('2011').addItem('2012');
lb2.addItem('January')
.addItem('February')
.addItem('March')
.addItem('April')
.addItem('May')
.addItem('June')
.addItem('July')
.addItem('August')
.addItem('September')
.addItem('October')
.addItem('November')
.addItem('December');
lb.addItem('Drug1')
.addItem('Drug2')
.addItem('Drug3')
.addItem('Drug4');
var mypanel = app.createHorizontalPanel().setVisible(true);
mypanel.add(lb).add(lb2).add(lb3).add(bttn);
app.add(mypanel);
var handler = app.createServerChangeHandler('click').addCallbackElement(mypanel);
handler.addCallbackElement(bttn);
bttn.addClickHandler(handler);
}
function click(e, app) {
var valuelb = new Array('Drug1','Drug2','Drug3','Drug4');
var valuelb2 = new Array ('January','February','March','April','May','June','July','August','September','October','November','December');
var valuelb3 = new Array('2011','2012');
var SS = SpreadsheetApp.openById('0Am8DRqAEaxH7dF9NWFJLSTdWZGRxeEFfMkFjNlFCT2c');
var sheeteff = SS.getSheetByName('Efficiency');
var data = sheeteff.getDataRange().getValues();
if (String(e) != 'undefined') {
app.setWidth(800).setHeight(650).setTitle('FLEET Chart');
var valuelb = String(e.parameter.myLbName);
if (valuelb.indexOf(',') != -1) {
var valuelb = e.parameter.myLbName.split(',');
}
var valuelb2 = String(e.parameter.myLbName2);
if (valuelb2.indexOf(',') != -1) {
var valuelb2 = e.parameter.myLbName2.split(',');
}
var valuelb3 = String(e.parameter.myLbName3);
if (valuelb3.indexOf(',') != -1) {
var valuelb3 = e.parameter.myLbName3.split(',');
}
SS.getSheetByName('Sheet2').getRange(1,1).setValue(String(valuelb2) + ' ' + valuelb.indexOf(','));//for unformation purposes
lb(app);
}else{
SS.getSheetByName('Sheet2').getRange(1,1).setValue(String(e));//for information purposes
}
var usedata = ArrayLib.filterByText(ArrayLib.filterByText(ArrayLib.filterByText(data, 3, valuelb), 1, valuelb2), 0, valuelb3);
//Build data table
var dataTable = Charts.newDataTable();
//Add Column types
dataTable.addColumn(Charts.ColumnType.DATE, data[0][2]);
dataTable.addColumn(Charts.ColumnType.NUMBER, data[0][9]);
dataTable.addColumn(Charts.ColumnType.NUMBER, data[0][8]);
//Add rows
for(var j=0; j<usedata.length; j++){
dataTable.setValue(j, 0, usedata[j][2]);
dataTable.setValue(j, 1, usedata[j][9]);
dataTable.setValue(j, 2, usedata[j][8]);
}
//Create and build chart
var chart = Charts.newLineChart()
.setDataTable(dataTable)
.setTitle('Efficiency over Time \nConfiguration: [' + valuelb + ']\n' + 'Month: [' + valuelb2 + ']\n' + 'Year: [' + valuelb3 + ']')
.setXAxisTitle('Time')
.setYAxisTitle('Percentage')
.setDimensions(750, 600)
.setPointStyle(Charts.PointStyle.MEDIUM)
.build();
app.add(chart);
return app;
}
I've not gone through your entire code but definitely see this wrong - you have set doGet as the function to be called on a handler. No problems with that except you try to call UiApp.createApplication() for the second time which isn't allowed.
I suggest you change the handler to call another function (lb, maybe) instead of doGet.
I also have "Unexpected Errors" in my code. To fix them, I wrote a simple library which helps to find problems in server handlers. Here is an example demonstrating how to use the library. The example source code is here. To add the library to a script is necessary to use the Mr6TKHuVEJGjYr-NnLUNbEkFO7CoOZA03 project key in the Resources->Manage Libraries dialog. The library uses the ScriptProperties Service to store own internal variables.

Categories

Resources