0
votes

I have a gradebook web app script which looks at a logged in student's email address, finds the email in the gradebook, and then displays the student's grades based on the column the email is in. The only problem is this only works if the spreadhseet is made public. How can I keep the spreadhseet private and still make this script work? I know that if I choose "Anyone with the link" it is unlikely someone will find the spreadsheet, but I'd prefer it to stay private. In addition, from the "Deploy as Web App" interface, the app must be executed as the user, not myself. Any ideas?

var ss = SpreadsheetApp.openByUrl('https://docs.google.com/spreadsheet/ccc?key=ID');
var sh1 = ss.getSheetByName('StudentGrades');
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).setWidth('300px').setBorderWidth(1).setCellPadding(0).setCellSpacing(0).setStyleAttribute('borderCollapse','collapse').setId('grid');
       var text = app.createLabel(user).setWidth('300px');
       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':'#fff','border':'1px solid #000'});//left column css attributes
         grid.setStyleAttributes(n-1, 1, {'fontWeight':'bold','background':'#fff','border':'1px solid #000'});//right column css attributes
       }
       app.add(grid);
       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
}
4

4 Answers

0
votes

As I was suggesting in another of your posts you could setup a 'manual login' that will allow you to keep the spreadsheet private while running the webapp as yourself.

That implies that you'll have to create a list of user/password keys/values and that each student will have to enter his user name and password (you'll have to send them that information by email along with the link to the webapp) in a front end login screen before they gain access to the results display part.

I guess the best place to hold that list would be in script properties in the form of key:value.

If you need more that this to implement that solution (and if you think you'll go that way) feel free to ask.


EDIT following your comment :

Ok, I understand it can be unpleasant :)

Just wondering, wouldn't it be easier to store these data in the script itself in a scriptDB that you could automatically update with the spreadsheet values ? The update would have to be executed by you (or by a timer trigger you create so that it runs on your account) and so the spreadsheet would remain private.

The students could then access the webapp with their accounts without accessing the spreadsheet.

0
votes

From that service accessed as the user, call through urlget another apps script service published as yourself. That one does the ss-related work. Might get timeouts on the service call though.

0
votes

Why not setup a google group for each of your classes? Then add the google group to the SHARE permissions for the appropriate spreadsheet(s). This would have the added benefit of allowing you to easily send emails to your various classes via the appropriate google group. Under this scenario, your grade spreadsheets remain private and are only accessible by you and those email addresses listed in your google group.

0
votes

I am a domain admin running the Google Apps for Education suite with many similar applications in place. You don't mention if you have administration rights for the domain or not, but I assume you do?

I keep all spreadsheets private and run the web apps as myself (giving the script the necessary access) which I think is precisely what you are aiming for?

I think your main issue stems from using .getEffectiveUser() which isn't providing you with what you need. I use Session.getActiveUser.getEmail() and then iterate through student objects (this is essentially just a sheet of student details returned as objects using the standard getRowsData function) to match the email value (if not found user = unknown).

This works perfectly for me with a student base of over 2000, all the data is private and the apps respond quickly serving personalised information.

If you'd like to see an example app please let me know, it's a little large to post here.