Google scripts identify user with installable on-edit on-open triggers
Asked Answered
D

1

-2

We have some apps scripts system on goole sheets. Free g accounts, mostly scripts are bound. Several users. Currently want to read users data for some logs. I hope Session.getActiveUser() method can give current user email. But for this user need to authorize apps script, otherwise user email is empty.

I can expect, our users will manage to follow instructions and to give permissions, if permissions will be strongly demanded.

It is unrealistic to inform all users offline to press some button, run the script, receive demands and to authorize on all of their computers.

So I need some built in way to persist on identifying themselves with running scripts and giving permissions. It is weird, google forces check users authorization to allow them edit, but not showing who is active user to owners scripts.

Ideal can be to run script from installed trigger, on-open, for example. Like


function onOpenInst(e) {
  let user = Session.getActiveUser();
  let email = user.getEmail();
}

Expecting script will require permission and will work after. But it is not asking permission from onOpen / onEdit.

Currently thinking about installing by script a big button on half a page (not found how to remove it after), or hiding pages except one with a button. Not very nice decision. Probably someone can give me better approach.


UPDATE: Later appears, script authorization is not enough to use active user by scripts. There is one bigger problem connected. Most of scripts, even authorized, run as an owner and ignores almost every function which try to distinguish current user from the owner. The only exception which sees user normally is scripts runned by pressing a button. I've put in the answer accepted two ways how this distinguish can be implement.

Dun answered 27/10, 2023 at 17:23 Comment(2)
What types of Questions Should I Avoid Asking?Loupgarou
@Loupgarou thank you for trying make my questions better. I've read the page you pointed. But didn't find any list item that my question is wrong with. Can you explain, what exact principle is violated? I only see possible is - low code. But this case it is not so necessary. Not very clean question at the end? Doubt it is a great problem, it is only paragraph building. Good is question\problem is quite real, exact, described what works, what not works, what the problem is, what is necessary for the satisfied result. And the problem is quite typical in it context.Dun
D
0

Well, I've done a lot of investigations on this topic, so let share some results. Main problem appears next: even installable open/edit triggers run as owner, not as an active user. So one-time authorization will not help for logging current user. Let mention, speaking here about free google accounts users.

When searching, how to identify an Active user with on-edit trigger, found 2 ways. First is to ask every user press a button and to install a separate installable trigger for this user. This way on every edit all triggers will run. On first check we had to skip all, except current. This can work with small number of users, but looks not very stable on long run. Here is a link to this solution: How to get active user email with installabled onEdit trigger?

Second way is to check an active user somehow from on-edit trigger. The only(!) way I found is Session.getTemporaryActiveUserKey() (remember, it is auto-changing every month).

So all the code is like this:

  1. Installable triggers:
function onEditInst(e) { 
  let userAKey = userIdent(e, 'edit')
  if (!userAKey) userGoPermisPage()  
  // other trigger code
}
function onEditInst(e) { 
  let userAKey = userIdent(e, 'edit')
  if (!userAKey) userGoPermisPage()  
  // other trigger code
}
  1. Identification function:
function userIdent(e, eType) { // used by onOpen and onEdit  to get session Active user

  // ident of current user by open edit triggers is only possible by temporaryActiveUserKey, so storing it in docProperties (can also store somewhere on a sheet)    

  // helping consts
  const docProps = PropertiesService.getDocumentProperties()

  // start with reading temporaryActiveUserKey (user working)
  let tempAUKey = Session.getTemporaryActiveUserKey()  
  
  // try to identify user by this key:
  let userKey = docProps.getProperty(tempAUKey)

  if (userKey) { // user ok
    if (eType === 'open') { // report ok
        SpreadsheetApp.getActiveSpreadsheet().toast('User key is valid',`User found (${userKey})`)         
    }
  }
  return userKey // if user ident, have it 
}
  1. If user is not authorized, throw him on 'Permis' page. This page has description, he need to receive a userkey, once a month. And on the very first run he will be asked for a script permission.
function userGoPermis() { // just go to page where to authorize
  let ss = SpreadsheetApp.getActiveSpreadsheet()
  let ws = ss.getSheetByName(models.permis.sheetName) //using global variable var models = {permis:{sheetName:'Permis'}}
  ss.setActiveSheet(ws)
  SpreadsheetApp.getActiveSpreadsheet().toast("Need user confirm","User not recognized")
}
  1. Receive key - this code bound to button on a separate page. On the very first run it will also ask for a script permission. So put some description on a page.
function userPermisButton() {// ask permissions and save/renew user data      

  // debug stuff:  console.log('Session.getActiveUser().getEmail()', Session.getActiveUser().getEmail());
 console.log('tempo', Session.getTemporaryActiveUserKey());
 try { 
 // Get multiple doc properties in one call, then log them all. -
   const docProperties = PropertiesService.getDocumentProperties();
   const data = docProperties.getProperties();
   for (const key in data) {
     console.log('Key: %s, Value: %s', key, data[key]);
   }
 } catch (err) {
   // TODO (developer) - Handle exception
   console.log('Failed with error %s', err.message);
 }

 // helping consts
 const docProps = PropertiesService.getDocumentProperties()

 // start with reading temporaryActiveUserKey (user working)
 let tempAUKey = Session.getTemporaryActiveUserKey()  
 
 // try to identify user by this key: 
 let userKey = docProps.getProperty(tempAUKey)

 if (userKey) { // user ok - case if just manual user check
   SpreadsheetApp.getActiveSpreadsheet().toast('',`User is already identified (${userKey})`)             
   console.log('User already found');
 } else { // unknown user, no such temp key
   
   // in any case identifying user (button is pressed, so we know his email)
   let email = Session.getActiveUser().getEmail()
 
   if (email) {   
     let userKey = Object.keys(users).find(userKey => users[userKey].email === email) // userkey found by email. We use here global var={U1:'[email protected]', U2:'[email protected]', ...}
 if (userKey) { // 2 possibilities here - temp Key was rotated, or temp Key was not ever recorded for this user.
       // let search such user in stored
       let allProps = docProps.getProperties()
       let oldTmpKey = Object.keys(allProps).find(key => allProps[key] === userKey  )
       if (oldTmpKey) { // found such a tempKey for user in old records - and now it was changed
         docProps.deleteProperty(oldTmpKey) // removing old key
       }

       docProps.setProperty(tempAUKey, userKey) // saved tmpKey user
       userMarkIdent(userKey) // optional separate function to log somewhere last key date for user. (not given here, quite usual saving - any way)
       SpreadsheetApp.getActiveSpreadsheet().toast(`Proceed. `,`USER SAVED(${userKey})`)        
     } else { // email not recognized
       SpreadsheetApp.getActiveSpreadsheet().toast(`See the user, but he is not in users list. Call admin.`,`ERROR`)          
       return
     }      
     
   } else { //neither user no email
     SpreadsheetApp.getActiveSpreadsheet().toast(`Give permission and run once again for saving user.`,`PERMISSION REQUIRED FOR IDENTIFICATION SCRIPT RUNNING`)        
   }
 }
 return // no need to return, it is just visual check / save user if need and can
}

There is also an option to corresponds once a month tempKey with an user with login password (not googles, but from your project). Probably, this case any script authorization from user is not necessary at all. But login/password alert or window is.

Dun answered 9/11, 2023 at 15:56 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.