Need some clarity with GAS userProperties - google-apps-script

I'm programming a Telegram bot with GAS. Am I right in thinking that whenever I store something using userProperties, like
userProperties.setProperty('name', 'Alex');
the value gets stored for this particular instance of the script AND this particular user? Does it mean that if there are 10 more or less simultaneous instances of this script by ten different users, I will later be able to retrieve each user's respective name by calling
var username = userProperties.getProperty('name');
I get the impression that sometimes there's some sort of interference happening that results in retrieving values different from those stored for this or that user. Would appreciate some clarity here.

IMPORTANT:
UserProperties has been deprecated, use PropertiesService.getUserProperties() instead.
As you can see in the documentation
getUserProperties()
Gets a property store that only the current user
can access, and only within this script.
So indeed, if the script can be accessed by several users, PropertiesService.getUserProperties() will always retrieve the properties of the specific user who runs the script, and if there will be 10 simultaneous script executions - each user executing the script will retrieve different user properties.

Related

Fetching AdWords Data for 150+ accounts for a period of 2 weeks in a single Google AdWords Script

We're building a platform that fetches data from the AdWords accounts under our AdWords Manager account and saves the data onto BigQuery to be viewed online via nice charts and tables.
As you all know, Adwords numbers need a few days to stabilize. So, every day at 12am we need to refetch all the data for the past 2 weeks and overwrite the data we already have saved for these 2 weeks (we're basically updating the numbers we have).
Our AdWords manager account has 150+ accounts under it. So, when we run the script that fetches the data for all these accounts for the past 2 weeks, understandably, the script times out because it needs more than 65 minutes to be done with the task.
When we looked online for solutions, the only thing we could find was using the "executeInParallel" function provided by the Adwords Script. This should allow us to run a function on several accounts at the same time. Unfortunately, the "executeInParallel" function cannot be called on more than 50 accounts. Since we have 150+ accounts, we cannot call the "executeInParallel" function on them.
We tried splitting the accounts into groups of 50 and calling the "executeInParallel" function on these groups. However, the "executeInParallel" function cannot be called more than once in a single script. This means that we're not able to use this solution.
The only other solution we can think of is to create a script for each one of the 14 days and have each script would fetch the data of all the accounts for a specific day. So, Script1 would fetch the data for today -1. Script2 would fetch the data for today -2 ... Script14 would fetch the data for today -14.
Does anyone else have another solution that we can use?
I never used the adwords apps script service but I see it works with iterators so in apps script we are used to use that with Drive service. What I would do, based on this example script :
var accountSelector = AdsManagerApp
.accounts()
.withCondition("Impressions > 100")
.forDateRange("LAST_MONTH")
.orderBy("Clicks DESC");
var accountIterator = accountSelector.get();
while (accountIterator.hasNext()) {
var account = accountIterator.next();
}
What you can do :
You create a json object where you will store the account id treated.
You store this json in a script property, you have to use json.stringify in order to save the json as text in theproperty.
You use trigger to restart program before it goes over time limit.
Idea is :
You start the program
you initiate the json by getting the property, if empty create blank json
you initiate account selector
you start the while(), inside you test first before to get data if the account is already treated, i.e. have an entry in the json.
If not you get the data and once done you add an entry in the json
I recommend to do that for 10 account for example and not waiting time overdue
When 10 accounts are treated you go out the while (break;) to push the json in the script property
Last, you create a trigger to rerun the function after 90 seconds.
ScriptApp.newTrigger("myFunction")
.timeBased()
.after(90 * 1000)
.create();
Don't forget to delete triggers before to create a new one
Don't forget when you finish iterator to stop everything and reset property for newt run.
Stéphane

Gathering user data on a Google Add-on to determine usage levels appropriate for monetization

I have a Google Sheets Add-on about which I'd like to determine feasibility of monetizing. To do this I'd like to see frequency level of users; users per domain as well as how often they use the add-on.
I've read a bit about properties in the documentation, and I'm pretty sure that is at the heart of what I need to work on to start getting this data. My question is about routing that to a form I can use to crunch numbers.
I have considered just having the Properties Service send the user's email and date generated in the Add-on (not the current date, but the date for the content generated). Once that gets sent to a spreadsheet in my drive, I can use a script bound to the spreadsheet to determine if the user has been logged yet. If so, we move the date to the row for that user. If not, we create a new entry. I can also have the script order users based on domain so I can see domains with heavier usage.
I've never done this before, so I'm looking to see if I'm thinking in the right direction or if I'm overlooking something.

How to get the user property for the "active user" in google apps script custom function

I've published a Google Apps Script standalone spreadsheet add-on, while I met some problem using PropertiesService.getUserProperties() in a custom function.
If User A has installed the add-on and saved some data in the user property.
Then User A shared the spreadsheet to User B. When user B run the custom function, he can get the saved data in user property for user A. This is not what I suppose user Property works. Both User A and B should get their own saved data.
So what is the active user for a shared spreadsheet? I don't want all the spreadsheet viewers to get the saved data for the spreadsheet creator. Is there anything I'm doing wrong in code or "Cloud Platform project" option?
In other words, how can I get different data saved in user properties for different viewers in a shared spreadsheet?
I tried to get the active user email in a custom function, but it does not work.
Please note, I can't use Session.getActiveUser in the custom function, because Google Apps Script Custom function does not support Session service. It will get an invalid permission exception.
https://developers.google.com/apps-script/guides/sheets/functions#Advanced
Thanks,
After writing tons of code to test different scenarios, I believe it has no way to solve the above problem.
So I will use a workaround to achieve the goal. In case someone also run into the trouble. I will put down my test results here.
If Google account A shared spreadsheet to Google account B.
In custom function, they all get A's user property.
From a webpage, call into server function via script.run, both A and B can
get their own user property.
Custom functions can't access PropertiesServices.userProperties() (maybe the exception is the spreadsheet owner).
According to https://developers.google.com/apps-script/guides/sheets/functions
Unlike most other types of Apps Scripts, custom functions never ask users to authorize access to personal data. Consequently, they can only call services that do not have access to personal data, specifically the following:
While Properties is included on the list and there isn't any note for this service, since the custom function doesn't ask users to authorize to access personal data it should not return PropertiesServices.userProperties() as it potentially store user personal data.

Google Apps Script - communication between script

HiMy problem is following: I would like to create small web page, on which it will be possible to create event in Google Calendar, but with some restrictions. In my case this calendar could be edited by my flatmates to reserve washing machine. This reservation cannot overlap and also all of us has limited number of days when we can use it. I have created private calendar, and I have created script which validate requests, and if everything is ok add event to calendar. This script is executed as me (because only I have permission to edit this calendar).
But I have problem with fetching information which user execute this script (me or one of my flatmate). Class Session contains 2 methods getActiveUser() and getEffectiveUser() but active user does not work (I guess because privacy protection policy). But if I create another script which is executed as user accessing the web I can get active user.
Does anybody know if is it possible to communicate somehow between this 2 scripts embedeed on the same site? I want to pass email of active user from one script to another. Or maybe do you know better solution how to solve this problem?
Regards
Adam
As you noticed, you need to set the script to run as the user accessing it to get his email. Then, instead of accessing the calendar directly (which you obviously can't) you can call another script published, but running as yourself allowing anonymous access that will receive this request from the "viewing" script and create the calendar events for it.
After you publish this "background" script, get its url and use it on a UrlfetchApp.fetch call to it. Then pass the parameters as url paremeters (or on payload if you prefer to use post instead of get).
The background script may even use ContentService to give nice return values to the calling script.
Sure, you can do so, but it's not as simple as you'd like. Make your admin level script run a web service that responds to the other script. It can probably be hacked as you can't authenticate the users, but comon, this is a washing macine!

Session.getActiveUser().getEmail() workaround for distributing grades from a spreadsheet

My students all have a Google account, but use different emails (like john#hotmail.com).I tried to write a webapp that would get from my grade spreadsheet the row with the webapp's user's email address, so that each student would only see his or her grades. That webapp uses: Session.getActiveUser().getEmail()
This only works for users in the same domain as the script, I have to run the script as the webapp user (which is ok -- my students trust me that far!). Here is that restriction:
Returns a User object describing the current user. In
limited-privilege executions (such as in response to onOpen or
onEdit), we only return the identity of the active user if both the
user and the script owner are part of the same domain. This is to
protect the privacy of consumer users, who may not want their email
address exposed.
My script works, but I have to put the table of grades directly in the script and update the webapp each time I update my spreadsheet. Yeck!
I can't share my grade spreadsheet because then they would see each other's grades. So now I am brainstorming other workarounds.
Here is one example:
Share a second spreadsheet, copy the grades from my spreadsheet with an update function that encrypts the grades. The webapp sucks up the data from the shared spreadsheet and decrypts. Now a simple update of a spreadsheet is all that is needed -- the webapp doesn't need to be republished. (There are some simple encryption options, like base64encode with maybe a little scrambling...?)
Find a way to automatically update the webapp and republish. (Don't know how to do that.)
????
Any suggestions?
PS: if 1 seems feasible, some suggestions for simple encryption code?
There are some simple encryption options, like base64encode with maybe a little scrambling...?
Yes, the GAS has functions to encode/decode using the Base64 algorithm - Utilities.base64Encode, Utilities.base64Decode, but I think, it is not an option even with a little scrambling. Students are very clever. My opinion is to use a JavaScript implementation of a encryption algorithm, for instance the Blowfish. There are a number of its implementations on JavaScript (here and here). These implementations should work in the GAS environment without any changes or with small modifications. It is should be sufficient to copy and paste the source code to the GAS Editor.
I dont understand why you say "My script works, but I have to put the table of grades directly in the script and update the webapp each time I update my spreadsheet"
It is very easy to create a webapp that shows a part of a spreadsheet using a flextable for example. Each instance of the app will have a user related content automatically and you will only have to update your master spreadsheet to get what you want. I don't know why you want to encode data for this... I think the user identification through the google login should be enough, don't you ?
Here is an example of such a webapp, the numbers you see are taken from a specific column in a master spreadsheet (for this public copy I set the app as running as "me" to avoid the authorization process but in real every user is identified and sees only his data).
The Spreadsheet itself and the code are viewable here, do not hesitate to come back if you need further information.
Is it an option to sync your sheet with a scriptDB?
And then query the DB where user=loginID