Can a GAS Library be used a script template? - google-apps-script

I've built a system within a spreadsheet that uses custom menus to move through a process. The script is stored in a template file, which is generated from a separate overview spreadsheet (via script) when required. Basically, each newly generated spreadsheet is a Product Tracker.
When the template is copied for a new Product Tracker the script is out-of-date if the template is updated. Would extracting the bound script from the template and creating a library from it make sense for my application?
I've nearly finished developing the template for a particular product, but I would like to roll it out for multiple products with slightly different templates which means it would be difficult to have a generic script that could be published within my Google Workspace Domain as an add-on (would probably need an add-on for each product).
Reading up on Libraries, Google warns that they can be slow. Currently, each script takes around 10 seconds to run and performs operations such as hide/show sheets, change tab colours, add/remove protection, send emails etc. There are already calls to another library, would this affect it as well? Would this be really slow as a library?
Thanks in advance!
Edit:
There are 10 buttons on the menu, one for each stage. The API's below are used at every stage. Reading through the execution logs, the scripts vary in execution time from 4 - 6 seconds depending on the stage.
"oauthScopes": [
"https://www.googleapis.com/auth/spreadsheets",
"https://www.googleapis.com/auth/userinfo.email",
"https://www.googleapis.com/auth/drive",
"https://www.googleapis.com/auth/gmail.send",
"https://www.googleapis.com/auth/userinfo.email",
"https://www.googleapis.com/auth/script.container.ui"
],
Edit2:
Bastardised the code to remove certain information.
The script below is similar across around 9 scripts.
function doThing() {
var activeUser = Session.getActiveUser().getEmail();
var activeUserName = activeUser.split('#domain.com')[0]
// spreadsheets
const ss = SpreadsheetApp.getActive();
// sheets
const 1 = ss.getSheetByName("1.");
const 1b= ss.getSheetByName("1b.");
const 2 = ss.getSheetByName("2.");
const 3 = ss.getSheetByName("3.");
const 4 = ss.getSheetByName("4.");
const 5 = ss.getSheetByName("5.");
const 6 = ss.getSheetByName("6.");
const 7 = ss.getSheetByName("7.");
const 8 = ss.getSheetByName("8");
const 9 = ss.getSheetByName("9.");
const shipSheet = ss.getSheetByName("Shipping");
const buildEvalSheet = ss.getSheetByName("Build Evaluation");
// build Number
const buildNumber = 1.getRange(buildNumberCell).getValue();
// get the active user email address and log it
Logger.log("Active User Email: " + activeUser);
Logger.log("Running 3");
// this prevents non-authorised users from running the script
// see the permissionGroups object in the Variables script file for more information
// set a variable relative to the department using the buttons
var criteria = 'department'
// run the permissions function in the library
var automationPermission = EmailPermissionsLibrary.checkPermissions(activeUserName, criteria);
// run if true
if (automationPermission) {
// set tab colours for previous & current
1.setTabColor("GREEN");
1b.setTabColor("GREEN");
2.setTabColor("GREEN");
3.setTabColor("GREEN");
// protect
3.activate()
protect();
statusUpdate()
if (emailBoolean) {
// send information to Sales and Shipping
//create html email
var htmlEmail = "<html><body>";
htmlEmail += "<p>Hello,</p>"
htmlEmail += "<p>" + buildNumber + " message</p>"
// send email
MailApp.sendEmail({
to: 'email#domain.com',
subject: buildNumber + " message",
htmlBody: htmlEmail,
replyTo: activeUser
});
}
shipping()
buildEvalShow()
}
// error message if the user is not authorised
else {
SpreadsheetApp.getUi().alert('This account does not have authorisation')
Logger.log(activeUser + " does not have required permissions")
}
}
Will this script be slow as a library?
// set a variable relative to the department using the buttons
var criteria = 'department'
// run the permissions function in the library
var automationPermission = EmailPermissionsLibrary.checkPermissions(activeUserName, criteria);
// log permission
Logger.log(automationPermission)
// run if true
if (automationPermission) {
Logger.log("Running");
// show sheet
sheet.activate();
// check that the #### hasn't already ran by doing a row count
// if it hasn't, the following should return 1 which will be the titles
var sheetR = sheet.getLastRow();
if (sheetR <= 1) {
// summary table size
const sumTableRowCount = 12;
const sumTableColCount = 3;
for (i = 1; i <= 3; i++) {
var results = eval("prodQC" + [i] + "Sheet");
sumTable = sheet2.getRange(45, 2, sumTableRowCount, sumTableColCount).getValues();
var something = sheet2.getLastRow() + 2;
// create the title
var title = "Title " + i;
// write the title
sheet.getRange(sheetR, 1).setValue(title);
// Remove checks
if (i >= 2) {
var sheetRL= sheet.getLastRow();
sheet.getRange(buildEvalSheetLastRow, 4).removeCheckboxes();
sheet.getRange(buildEvalSheetLastRow, 6).removeCheckboxes();
}
// recount last row and add 1 to stop overwrite
var sheetR = sheet.getLastRow() + 1;
// write the QC summary table to the sheet
sheet.getRange(sheetR, 1, sumTableRowCount, sumTableColCount).setValues(sumTable);
// set checkboxes next to values on JIRA col
sheet.getRange(sheetR, 4, sumTableRowCount, 1).insertCheckboxes();
// set checkboxes next to values on the CPACC col
sheet.getRange(sheetR, 6, sumTableRowCount, 1).insertCheckboxes();
// add data validation to the Choose One col
// last row
var sheetR = sheet.getLastRow();
// set range to be from row 3, col 8, to last row
var range = sheet.getRange(4, 8, sheetR, 1);
// set the data validation to only accept values from the array
range .setDataValidation(SpreadsheetApp.newDataValidation()
.setAllowInvalid(false)
.requireValueInList(
[
"list item 1",
"list item 2",
"listed item 3"
],
true)
.build()
);
// add data validation to the Impact and Deadline cols
// set range to be from row 3, col 11, to last row for 2 cols
var cols = sheet.getRange(4, 11, sheetR, 2);
// set the data validation to only accept values from the array
cols .setDataValidation(SpreadsheetApp.newDataValidation()
.setAllowInvalid(false)
.requireValueInList(
[
"1",
"2",
"3",
"4",
"5"
],
true)
.build()
);
}
// remove all non-failures
// last row
var sheetR = sheet.getLastRow();
// range of values from A1, across 3 columns and to the last row
var range = sheet.getRange(1, 1, sheetR, 3);
// Default text from Production QC Template
var removeVal1 = "something";
// Modified text when the QC is complete
var removeVal2 = "something else";
// Default text from Production QC Template
var removeVal3 = "another thing";
// get values from the range to check in the For loop below
var rangeVals = range.getValues();
// Reverse the 'for' loop.
for (let i = rangeVals.length - 1; i >= 0; i--) {
// if matching values above are in the target range, delete the row
if (
rangeVals[i][2] === removeVal1 ||
rangeVals[i][2] === removeVal2 ||
rangeVals[i][2] === removeVal3) {
buildEvalSheet.deleteRow(i + 1)
}
}
} else { // if there is already more rows than expected).alert('this has done something');
}
} else { // error message if the user is not authorised
SpreadsheetApp.getUi().alert('This account does not have authorisation')
Logger.log(activeUser + " does not have required permissions")
}
}

Related

multiple users using google spreadsheet as data entry form and Database, overwriting each others data

I want to make a sales entry system with google spreadsheet for multiple users.
User 1 will use the data entry form tab named "Main", using inputdata1()
User 2 will use the data entry form tab named "Sub", using inputdata2()
Each of them will write data in a new row that I found it by using the getlastrowspecial function (e.g. it this case lets say its row 10)
If both of them execute the code simultaneously. Sometimes I will see User 1's data being written on row 10 and User 2's data overwriting User 1's data in the same row on row 10. The checking to see if the row is empty before written is not working. I wanted to keep User 2 to wait until User 1's code is completely executed. I dont mind if User 2 need to call the function again.
Please help if there is any method to do this. Thank you very much!
var ss = SpreadsheetApp.getActiveSpreadsheet()
var db = ss.getSheetByName("DB")
var mainInput = ss.getSheetByName("Main")
var subInput = ss.getSheetByName("Sub")
function inputData1() {
var input1 = mainInput.getRange("E2:I2").getValues()
Logger.log(input1)
var lr = getLastRowSpecial(db, "A1:I")
Logger.log(lr)
if (db.getRange(lr + 1, 5).getValue() !== "") {
SpreadsheetApp.getUi().alert("Please try again")
return
} else {
db.getRange(lr + 1, 5, 1, input1[0].length).setValues(input1)
}
}
function inputData2() {
var input2 = subInput.getRange("E2:I2").getValues()
var lr = getLastRowSpecial(db, "A1:I")
if (db.getRange(lr + 1, 5).getValue() !== "") {
SpreadsheetApp.getUi().alert("Please try again")
return
} else {
db.getRange(lr + 1, 5, 1, input2[0].length).setValues(input2)
}
}
// following function getLastRowSpecial() for getting the last row with blank row"
function getLastRowSpecial(sheetlastrow, rangeString) {
var rng = sheetlastrow.getRange(rangeString).getValues();
var lrIndex;
for (var i = rng.length - 1; i >= 0; i--) {
lrIndex = i;
if (!rng[i].every(function (c) { return c == ""; })) {
break;
}
}
return lrIndex + 1;
}
Replace Range.setValues() with Sheet.appendRow(), like this:
current:
db.getRange(lr + 1, 5, 1, input1[0].length).setValues(input1)
new:
db.appendRow(input1[0]);
If you need the values to start in column E, use this:
db.appendRow([null, null, null, null].concat(input1[0]));
Alternatively, follow Cooper's advice and use the Lock Service. If you choose to go this route, also consider using the appendRows_() utility function.

Trouble deploying sheets addon

Our website spits out CSV files that we use as event rosters, but they include way too much data. There's no feasible way to change what's included in the export, so an admin assistant must edit & format for print. It's repetitive and time consuming, so I figured it's the perfect time to learn Google Apps Script.
Thanks to the incredible knowledge shared here on stack overflow, a total noob like me can cobble together a script that does what I need! Just by using snippets from other answers, I was able to automate:
Delete unwanted & empty columns
Rename & auto-resize columns
Sort by the last name column
Generate print-ready PDF that saves in the same Drive directory.
But now I'm having trouble testing and deploying the script as an addon so my co-workers can use it. When I run a "test as addon" the sheet opens, but nothing happens. I've tried all the variables for installation config and searched for others having the same trouble, but can't find anything so I think the problem is prbly somewhere on my end - script or user error.
Once I get it to test correctly, I'm not entirely sure about how to correctly deploy the addon to our domain and get all the permissions, etc setup correctly. I've read up and now I feel more confused than ever! So two questions:
What's wrong w/ my testing?
Once it tests successfully, what's the easiest way I can let all of our domain's apps users utilize the script?
Here's the script:
function expCalc() {
DeleteColumns();
RemoveEmptyColumns();
RenameColumns();
ResizeColumns();
Sort();
SavePDF();
}
//delete unwanted columns
function DeleteColumns() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getActiveSheet();
var dataRange = sheet.getRange("A1:AH200");
var data = sheet.getRange("A1:AH200");
var values = data.getValues();
var numRows = values.length;
var numCols = values[0].length;
for (var col = numCols - 1; col > 0; col--) {
for (var row = 0; row < numRows; row++) {
switch (values[row][col]) {
case "Group":
case "ID":
case "Reg ID":
case "Reg Date":
case "Type of Payment":
case "Transaction ID":
case "Coupon Code":
case "# Attendees":
case "Date Paid":
case "Price Option":
case "Event Date":
case "Event Time":
case "Website Check-in":
case "Tickets Scanned":
case "Check-in Date":
case "Seat Tag":
case "BLS Add-on items (received at class):":
case "Company Name":
case "Address":
case "Address 2":
case "City":
case "State":
case "Zip":
sheet.deleteColumn(col + 1); // delete column in sheet (1-based)
continue; // continue with next column
break; // can't get here, but good practice
}
}
}
}
//Remove Empty Columns
function RemoveEmptyColumns() {
var sh = SpreadsheetApp.getActiveSheet();
var maxColumns = sh.getMaxColumns();
var lastColumn = sh.getLastColumn();
sh.deleteColumns(lastColumn + 1, maxColumns - lastColumn);
}
//Rename Columns
function RenameColumns() {
SpreadsheetApp.getActiveSheet().getRange('A1').setValue('Type');
SpreadsheetApp.getActiveSheet().getRange('B1').setValue('Paid');
SpreadsheetApp.getActiveSheet().getRange('C1').setValue('Price');
SpreadsheetApp.getActiveSheet().getRange('D1').setValue('Amt');
SpreadsheetApp.getActiveSheet().getRange('E1').setValue('Class');
SpreadsheetApp.getActiveSheet().getRange('F1').setValue('First Name');
SpreadsheetApp.getActiveSheet().getRange('G1').setValue('Last Name');
SpreadsheetApp.getActiveSheet().getRange('H1').setValue('Email');
SpreadsheetApp.getActiveSheet().getRange('I1').setValue('Phone');
}
//Auto-Resize Columns
function ResizeColumns() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getSheets()[0];
sheet.autoResizeColumn(1);
sheet.autoResizeColumn(2);
sheet.autoResizeColumn(3);
sheet.autoResizeColumn(4);
sheet.autoResizeColumn(5);
sheet.autoResizeColumn(6);
sheet.autoResizeColumn(7);
sheet.autoResizeColumn(8);
sheet.autoResizeColumn(9);
}
//Sort by last name
function Sort() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getSheets()[0];
sheet.sort(7);
}
//Save PDF
function SavePDF(optSSId, optSheetId) {
// If a sheet ID was provided, open that sheet, otherwise assume script is
// sheet-bound, and open the active spreadsheet.
var ss = (optSSId) ? SpreadsheetApp.openById(optSSId) : SpreadsheetApp.getActiveSpreadsheet();
// Get URL of spreadsheet, and remove the trailing 'edit'
var url = ss.getUrl().replace(/edit$/, '');
// Get folder containing spreadsheet, for later export
var parents = DriveApp.getFileById(ss.getId()).getParents();
if (parents.hasNext()) {
var folder = parents.next();
} else {
folder = DriveApp.getRootFolder();
}
// Get array of all sheets in spreadsheet
var sheets = ss.getSheets();
// Loop through all sheets, generating PDF files.
for (var i = 0; i < sheets.length; i++) {
var sheet = sheets[i];
// If provided a optSheetId, only save it.
if (optSheetId && optSheetId !== sheet.getSheetId()) continue;
//additional parameters for exporting the sheet as a pdf
var url_ext = 'export?exportFormat=pdf&format=pdf' //export as pdf
+
'&gid=' + sheet.getSheetId() //the sheet's Id
// following parameters are optional...
+
'&size=letter' // paper size
+
'&portrait=false' // orientation, false for landscape
+
'&fitw=true' // fit to width, false for actual size
+
'&sheetnames=false&printtitle=false&pagenumbers=false' // hide optional headers and footers
+
'&gridlines=true' // hide/show gridlines
+
'&fzr=false'; // do not repeat row headers (frozen rows) on each page
var options = {
headers: {
'Authorization': 'Bearer ' + ScriptApp.getOAuthToken()
}
}
var response = UrlFetchApp.fetch(url + url_ext, options);
var blob = response.getBlob().setName(ss.getName() + ' - ' + sheet.getName() + '.pdf');
folder.createFile(blob);
}
}
/**
* Dummy function for API authorization only.
* From: https://stackoverflow.com/a/37172203/1677912
*/
function forAuth_() {
DriveApp.getFileById("Just for authorization"); // https://code.google.com/p/google-apps-script-issues/issues/detail?id=3579#c36
}
Great use for an add-on. In order to make it work as an add-on you need to create an onOpen() trigger so that the users can interact with your code.
Refer to the onOpen() docs here: https://developers.google.com/apps-script/guides/triggers/#onopen
See an example here: https://developers.google.com/apps-script/add-ons/#user_interfaces

How to check Gmail Thread for Replies from Email

I am creating a basic CRM that needs to mark when a thread has been replied to.
I have created a script that can scan my inbox for threads from a list of emails in a sheet, check the last message in each thread and collect the .getFrom in order to see if I was the last to reply.
However, I can't figure out how to check if there has been a response from the person who's been contacted throughout the whole thread.
Here's the script that checks for the last message. (It's an extract of a larger script in case any references are missing):
Example Sheet
function UpdateStatus() {
// Connect to our active sheet and collect all of our email addresses in column G
var sheet = SpreadsheetApp.getActiveSheet();
var totalRows = sheet.getLastRow();
var range = sheet.getRange(2, COLUMN_WITH_EMAIL_ADDRESSES, totalRows, 1);
var emails = range.getValues();
// Attempt to iterate through 100 times (although we'll timeout before this)
for (var cntr = 0; cntr<100; cntr++ ) {
// If we've reached the end of our last, wrap to the front
if (lastRowProcessed >= totalRows) lastRowProcessed = 1;
// Increment the row we're processing
var currentRow = lastRowProcessed+1;
// Get the email address from the current row
var email = emails[currentRow-2][0];
// If the email address field is empty, skip to the next row
if (!email) {
lastRowProcessed = currentRow;
cache.put("lastRow", currentRow, 60*60*24);
continue;
}
// Look for all threads from me to this person
var threads = GmailApp.search('from:me to:'+email);
// If there are no threads, I haven't emailed them before
if (threads.length == 0) {
// Update the spreadsheet row to show we've never emailed
var range = sheet.getRange(currentRow,13, 1, 4 ).setValues([["NEVER", "", "", ""]] );
// And carry on
lastRowProcessed = currentRow;
cache.put("lastRow", currentRow, 60*60*24); // cache for 25 minutes
continue;
}
// Beyond a reasonable doubt
var latestDate = new Date(1970, 1, 1);
var starredMsg = "";
var iReplied = ""
// Iterate through each of the message threads returned from our search
for (var thread in threads) {
// Grab the last message date for this thread
var threadDate = threads[thread].getLastMessageDate();
// If this is the latest thread we've seen so far, make note!
if (threadDate > latestDate) {
latestDate = threadDate;
// Check to see if we starred the message (we may be back to overwrite this)
if (threads[thread].hasStarredMessages()) {
starredMsg = "★";
} else {
starredMsg = "";
}
// Open the thread to get messages
var messages = threads[thread].getMessages();
// See who was the last to speak
var lastMsg = messages[messages.length-1];
var lastMsgFrom = lastMsg.getFrom();
// Use regex so we can make our search case insensitive
var re = new RegExp(email,"i");
// If we can find their email address in the email address from the last message, they spoke last
// (we may be back to overwrite this)
if (lastMsgFrom.search(re) >= 0) {
iReplied = "NO";
} else {
iReplied = "YES";
}
}

Google Apps Script admin SDK speed

i'm creating a google sheet which translates given data from schools to a admin SDK Upload to Google Apps.
I know there a create user limit of 10 per second, hence the 120ms Delay time.
but, when coloring each row in sheets which is processed the speed is around 500ms - 2 seconds per entry.
Which causes the script to stop at the maximum execution time, because there are more than 600 users to be added.
Where does it go wrong?
function UploadUsers() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sh = ss.getSheetByName("Upload");
ss.setActiveSheet(sh);
var column = sh.getRange('A1:I5000');
var values = column.getValues(); // get all data in one call
var uploadRows = 0;
while ( values[uploadRows][0] != "" ) {
uploadRows++;
}
var i=0
var uiACU = SpreadsheetApp.getUi();
var ACUsersMessage0= "Upload Users";
var ACUsersMessage1= "Indien u op OK drukt worden er : "+ uploadRows + " Users aangemaakt! "
var result = uiACU.alert(
ACUsersMessage0,
ACUsersMessage1,
uiACU.ButtonSet.OK_CANCEL);
if (result == uiACU.Button.OK) {
for (i=0; i<uploadRows;i++){
var uniqueId=[i][0];
var mailAdress=values[i][3];
var voorNaam=values[i][1];
var achterNaam=values[i][2];
var Ou=values[i][8];
var Pass=values[i][4];
Utilities.sleep(12);
AdminDirectory.Users.insert ({
"kind": "admin#directory#user",
"password" : Pass,
"primaryEmail": mailAdress,
"orgUnitPath": Ou,
"changePasswordAtNextLogin": "TRUE",
"name": {
"givenName": voorNaam,
"familyName": achterNaam,
},
"externalIds": [
{
"value": uniqueId,
"type": "account",
"customType": "gappsUniqueId"
}
]
})
ss.getRange("D"+ (i+1)).setBackground("red")
}
} else {
//Full Stop
}
}
It goes wrong because every google script function has the 6minutes execution time, you can convey this in a couple of ways:
Read the best practices, the most important thing in there is to do thing in batches, instead of getting just a ROW and turn it RED, get several ROWs and do the sime, 1 ROW costs you 500ms, 20 ROWs will cost 505ms. There's probably a way for batch insert the users also, but I don't use the AdminSDK.
If there's no Batch for user insert, you can monitor the time of execution of the function in the beggining of the for(), if the time comes close the 6minutes (I recommend stopping at 5), save the last ROW inserted in the properties service, create a Progamatic Trigger that will run the function again in 7minutes, then paint the ROWs red. It will take a long time to run entirely, but will work.
function insertUsers(){
var timeStart = new Date().getTime();
var rowStart = PropertiesService.getScriptProperties().getProperty('lastRow') || 0;
for( from rowStart to endOfSheet ){
if( (new Date().getTime()) - timeStart > (5 * 60 * 1000) ){
PropertiesService.getScriptProperties().setProperty('lastRow', currentRow);
createTriggerToRun-insertUsers-in6Minutes;
return 1;
}
// code to insert users here
}
}

Google Apps Script: Display single column based on user email

I am trying to develop a gradebook with Google Spreadhseets, but I only want to display individual grades based on user email. Is there a Google Apps Script function that looks at a logged in user's email, searches the spreadhseet for it (it would be at the top of a column) and then displays that column back to the user?
I think the best solution would probably be to create a small webapp Ui that shows only the relevant column in a html table. Depending on your programming skills it can be quite easy to setup. I could have suggested an example but you gave too few information about the type of data that are in the spreadsheet... User's data are in a single column but I suppose there is also some kind of headers or row identifiers that must be shown to understand what is shown ?
Users will have to authorize the webapp in order to let you identify them when they are logged in.
Edit : here is a simple example of a possible solution that you can start from.
I assumed mails are in row 1, descriptions in column A.
var ss = SpreadsheetApp.openByUrl('https://docs.google.com/spreadsheet/ccc?key=0AnqSFd3iikE3dGdQOXZpRmJnT0xjQklkdEZING5YREE#gid=0');
var sh1 = ss.getSheetByName('sheet1');
var logsheet = ss.getSheetByName('logsheet');
var data = sh1.getDataRange().getValues();
var user = Session.getEffectiveUser()
function doGet() {
var app = UiApp.createApplication();
if(!getcol(user)){
var warn = app.createTextBox().setWidth('500').setValue("Your results are not available or you don't have permission to view these data");// if user is not in the list, warning + return
app.add(warn)
return app
}
var grid = app.createGrid(data.length, 2).setBorderWidth(1).setCellPadding(2);
var text = app.createTextBox().setName('text').setId('text').setValue(user+' | idx'+getcol(user) ).setWidth('300px');
var btn = app.createButton('press here to confirm you have view these results');
var handler = app.createServerHandler('log').addCallbackElement(grid);
btn.addClickHandler(handler);
var col = getcol(user)
grid.setWidget(0,1,text).setText(0, 0, 'Results for');
grid.setStyleAttribute('textAlign','center')
for(n=1;n<data.length;++n){
grid.setText(n, 0, data[n][0])
grid.setText(n, 1, data[n][col])
}
app.add(grid).add(btn)
return app
}
function log(e){
var text = e.parameter.text
var app = UiApp.getActiveApplication();
// add user name to the log sheet + timestamp + eventually send a mail etc...
return app
}
function getcol(mail){
if(data[0].toString().indexOf(mail.toString())!=-1){
for(zz=1;zz<data[0].length;++zz){
if(data[0][zz] == mail){var colindex=zz;break}
}
return colindex
}
return false
}
EDIT2 :
To print numbers with the desired number of decimals you can use the recently implemented printf function like this :
grid.setText(n, 1, Utilities.formatString('%.2f',data[n][col]));// 2 decimals, no leading 0
to show dates like you want use formatDate()
Utilities.formatDate(date, Session.getTimeZone(), "MM-dd")
EDIT3 :
here is a version that handles the different types of data :
var ss = SpreadsheetApp.openByUrl('https://docs.google.com/spreadsheet/ccc?key=0AnqSFd3iikE3dGdQOXZpRmJnT0xjQklkdEZING5YREE#gid=0');
var sh1 = ss.getSheetByName('sheet1');
var logsheet = ss.getSheetByName('logsheet');
var data = sh1.getDataRange().getValues();
var user = Session.getEffectiveUser()
Logger.log(user)
function doGet() {
var app = UiApp.createApplication();
if(!getcol(user)){
var warn = app.createTextBox().setWidth('500').setValue("Your results are not available or you don't have permission to view these data");// if user is not in the list, warning + return
app.add(warn)
return app
}
var grid = app.createGrid(data.length, 2).setBorderWidth(1).setCellPadding(2).setStyleAttribute('background','#ffeeaa').setId('grid');
var text = app.createTextBox().setName('text').setId('text').setValue(user+' | idx'+getcol(user) ).setWidth('300px');
var btn = app.createButton('press here to confirm you have view these results');
var handler = app.createServerHandler('log').addCallbackElement(grid);
btn.addClickHandler(handler);
var col = getcol(user)
grid.setWidget(0,1,text).setText(0, 0, 'Results for');
grid.setStyleAttribute('textAlign','center')
for(n=1;n<data.length;++n){
grid.setText(n, 0, string(data[n][0]));
grid.setText(n, 1, string(data[n][col]));
}
grid.setStyleAttributes(n-1, 0, {'fontWeight':'bold','background':'#ffff99'})
grid.setStyleAttributes(n-1, 1, {'fontWeight':'bold','background':'#ffff99'})
app.add(grid).add(btn)
return app
}
function log(e){
var text = e.parameter.text
var app = UiApp.getActiveApplication();
app.getElementById('grid').setStyleAttribute('background','#bbffbb')
// add user name to the log sheet + timestamp + eventually send a mail etc...
return app
}
function string(value){
Logger.log(typeof(value))
if (typeof(value)=='string'){return value};// if string then don't do anything
if (typeof(value)=='number'){return Utilities.formatString('%.1f / 20',value)};// if number ther format with 1 decimal
if (typeof(value)=='object'){return Utilities.formatDate(value, Session.getTimeZone(), "MM-dd")};//object >> date in this case, format month/day
return 'error'
}
function getcol(mail){
if(data[0].toString().indexOf(mail.toString())!=-1){
for(zz=1;zz<data[0].length;++zz){
if(data[0][zz] == mail){var colindex=zz;break}
}
return colindex
}
return false
}