How to search within Google for Business domain? - google-apps-script

Specifically users.
Currently I have script like this:
function findUsers(s) {
var users = UserManager.getAllUsers();
var r = new Array;
Logger.log("User Count" + users.length );
for( var i = 0 ; i < users.length ; i++ )
{
var u = users[i];
var n = formatUserName( u );
n = n.toUpperCase();
if( n.indexOf( s.toUpperCase() ) > -1 )
{
r.push(u);
}
}
return r;
}
This works, but is a little slow and I know it will get slower, as more users are migrated because of how UserManager.getAllUsers() currently works
So before I go off and look at ways of 'caching' the domain data myself...I'm wondering if there is a efficient way to search for objects within our domain via APIs or GAScript objects?
When you use the control panel for the domain you can search, fast and efficiently...
For my current task, I may abandon searching the domain myself and require the correct user name.

Here are your choices
1) Make use of the Google Apps Profiles API ( https://developers.google.com/google-apps/profiles/#Retrieving ) from within Google Apps Script. This requires use of oAuth. If you haven't used oAuth, try the oAuth Service Library ( https://developers.google.com/apps-script/notable-script-libraries ) to ease your pain of getting it to work.
2) The second option is what you've already noted. Cache the results in, say, a spreadsheet.
3) Irrespective of 1 or 2, you should open an issue in the Issue tracker if there isn't one already.

Related

Return Collection of Google Drive Files Shared With Specific User

I'm trying to get a collection of files where user (let's use billyTheUser#gmail.com) is an editor.
I know this can be accomplished almost instantly on the front-end of google drive by doing a search for to:billyTheUser#gmail.com in the drive search bar.
I presume this is something that can be done in Google App Scripts, but maybe I'm wrong. I figured DriveApp.searchFiles would work, but I'm having trouble structuring the proper string syntax. I've looked at the Google SDK Documentation and am guessing I am doing something wrong with the usage of the in matched to the user string search? Below is the approaches I've taken, however if there's a different method to accomplishing the collection of files by user, I'd be happy to change my approach.
var files = DriveApp.searchFiles(
//I would expect this to work, but this doesn't return values
'writers in "billyTheUser#gmail.com"');
//Tried these just experimenting. None return values
'writers in "to:billyTheUser#gmail.com"');
'writers in "to:billyTheUser#gmail.com"');
'to:billyTheUser#gmail.com');
// this is just a test to confirm that some string searches successfully work
'modifiedDate > "2013-02-28" and title contains "untitled"');
Try flipping the operands within the in clause to read as:
var files = DriveApp.searchFiles('"billyTheUser#gmail.com" in writers');
Thanks #theAddonDepot! To illustrate specifically how the accepted answer is useful, I used it to assist in building a spreadsheet to help control files shared with various users. The source code for the full procedure is at the bottom of this post. It can be used directly within this this google sheet if you copy it.
The final result works rather nicely for listing out files by rows and properties in columns (i.e. last modified, security, descriptions... etc.).
The ultimate purpose is to be able to update large number of files without impacting other users. (use case scenario for sudden need to immediately revoke security... layoffs, acquisition, divorce, etc).
//code for looking up files by security
//Posted on stackoverlow here: https://stackoverflow.com/questions/62940196/return-collection-of-google-drive-files-shared-with-specific-user
//sample google File here: https://docs.google.com/spreadsheets/d/1jSl_ZxRVAIh9ULQLy-2e1FdnQpT6207JjFoDq60kj6Q/edit?usp=sharing
const ss = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("FileList");
const clearRange = true;
//const clearRange = SpreadsheetApp.getActiveSpreadsheet().getRangeByName("ClearRange").getValue();
//if you have the named range setup.
function runReport() {
//var theEmail= SpreadsheetApp.getActiveSpreadsheet().getRangeByName("emailFromExcel").getValue();
//or
var theEmail = 'billyTheUser#gmail.com';
findFilesByUser(theEmail);
}
function findFilesByUser(theUserEmail) {
if(clearRange){
ss.getDataRange().offset(1,0).deleteCells(SpreadsheetApp.Dimension.ROWS)
}
var someFiles = DriveApp.searchFiles('"' + theUserEmail + '" in writers');
var aListOfFiles = []
while(someFiles.hasNext()){
var aFile = someFiles.next();
aListOfFiles.push([aFile.getId()
,aFile.getName()
,aFile.getDescription()
,aFile.getSharingAccess()
,aFile.getSharingPermission()
,listEmails(aFile.getEditors())
,listEmails(aFile.getViewers())
,aFile.getMimeType().replace('application/','').replace('vnd.google-apps.','')
,aFile.getDateCreated()
,aFile.getLastUpdated()
,aFile.getSize()
,aFile.getUrl()
,aFile.getDownloadUrl()
])
}
if(aListOfFiles.length==0){
aListOfFiles.push("no files for " + theUserEmail);
}
ss.getRange(ss.getDataRange().getLastRow()+1,1, aListOfFiles.length, aListOfFiles[0].length).setValues(aListOfFiles);
}
function listEmails(thePeople){
var aList = thePeople;
for (var i = 0; i < aList.length;i++){
aList[i] = aList[i].getEmail();
}
return aList.toString();
}

Looking for a google apps script that permanently deletes from gmail trash

User is receiving a large volume of unwanted emails from a specific sender.
Blocking moves the email to spam, while filtering moves the email to trash. Both of these still expose the user to the emails if those folders are checked.
What I'm looking for is a script that will permanently delete emails from the specified email address either when the emails are received, or on a frequent schedule.
I have almost no familiarity with google scripts or js, the best I have as relates to code is some rudimentary vba.
Researching this issue brought me to using google apps as a potential solution as gmail does not provide any automated way to permanently delete email. Below is some code I found googling around, although I can't get very far with it due to my total lack of apps script knowledge.
function DeleteEmailByLabel(e) {personsemail#gmail.com}
var bannedLabel = 'BLOCKEDSENDER';
var deleteLabel = GmailApp.getUserLabelByName(bannedLabel);
if ( deleteLabel != null ) {personsemail#gmail.com}
var threads = deleteLabel.getThreads();
for (var i = 0; i < threads.length; i++) {
Gmail.Users.Messages.remove('me', threads[i].getId());
}
} else {
deleteLabel = GmailApp.createLabel(bannedLabel);
}
}
I expect the above code to run and remove email from my test account, from the trash folder. However instead I get this error. This looks like basic syntax stuff but I'm out of my league here.
Missing ; before statement. (line 1, file "filename")
Thanks in advance.
Before you could use this in the Apps Script, please note to do the following:
Create a filter in the user's Gmail account such that a specific & unique label is allocated to such emails (you can "mark them as read" or "send them to spam"; it wouldn't matter)
This function uses some of the advanced Gmail APIs and as such, require you to enable them from the script editor first, before running the script. To achieve this, go to:
Resources > Advanced Google Services... > Scroll all the way down to Gmail API > toggle the off button to on
function deleteEmails() {
var bannedLabel = 'BLOCKEDSENDER' // replace with the label name, as setup in filters
var deleteLabel = GmailApp.getUserLabelByName(bannedLabel);
if ( deleteLabel != null ) {
var threads = deleteLabel.getThreads();
for (var i=0; i<threads.length; i++) {
Gmail.Users.Threads.remove('me', threads[i].getId());
}
} else {
// do something
}
}

Google Drive Auto-Expire - Unshare Multiple Files Simultaneously?

Good Evening! I'm Aaron Ayres, an 8th grade mathematics teacher at Noblesville West Middle School in Noblesville, Indiana. Recently for a school-wide incentive my school is using Google Drive to share a "pass" that grants nominated students access to rewards and other treats during the month they are nominated. We typically have about 80 students who are nominated on a monthly basis for their hard work - each educator in the building nominates one student each month based on multiple criteria.
Instead of having to manually go through my folder and un-share the individual passes at the end of the month, I have been researching for a more efficient method of allowing the passes to expire. I came across Amit Argawal's Auto-expire script (http://www.labnol.org/internet/auto-expire-google-drive-links/27509/) and I think it could potentially work but it only expires one file at a time. Is there a way I can modify the script (or create a new script) to reference multiple, sharable links in the script editor so the sharing access to each individual students' pass expires at the end of the month? In other words, is there a way for the script to expire all 80+ passes at the same date and time? I'm a novice to Google Scripts so I'm wondering if I am not formatting my list or URL references correctly so the script recognizes multiple files, or perhaps I could revise the script to recognize an array of links instead of a single variable url link.
Thanks in advance for the assistance!
I hope you have the full script at your hand.Please give the URLs in a list, separated with commas. Are the passwords different for each student? Otherwise you could have just added the URL of the folder without changing the original script at all.
However, Please try changing these portions of the script:
// Enter the full list of URLs(separated with comma) of the public Google Drive file or folder
var URL_LS = ["https://drive.google.com/open?id=0B_NmiOlCM-VTcFp6U1hydTM2MzVCY3AzMUpuTEtVWUhXRXNz", "https://drive.google.com/file/d/0B_NmiOlCM-VTNXFqOU1jTG5JdHJVQ3ZGUGNqZklJNWludllr/view?usp=sharing"] ;
var URL_LN = URL_LS.length;
// Enter the expiry date in YYYY-MM-DD HH:MM format
var EXPIRY_TIME = "2016-02-18 09:46";
And again,replace the autoExpire() as follows:
function autoExpire() {
var id, asset, i, email, users;
try {
for (var j = 0; j < URL_LN; j++) {
var URL = URL_LS[j];
var id = URL.match(/[-\w]{25,}/g);
if (id) {
id = id[id.length-1];
asset = DriveApp.getFileById(id) ? DriveApp.getFileById(id) : DriveApp.getFolderById(id);
if (asset) {
asset.setSharing(DriveApp.Access.ANYONE, DriveApp.Permission.NONE);
asset.setSharing(DriveApp.Access.ANYONE_WITH_LINK, DriveApp.Permission.NONE);
users = asset.getEditors();
for (i in users) {
email = users[i].getEmail();
if (email !== "") {
asset.removeEditor(email);
}
}
users = asset.getViewers();
for (i in users) {
email = users[i].getEmail();
if (email !== "") {
asset.removeViewer(email);
}
}
}
}
}
} catch (e) {
Logger.log(e.toString());
}
}

Access hidden Google calendars from CalendarApp?

I have a web app that creates a hidden calendar
var cal = CalendarApp.createCalendar("Timetable");
cal.setSelected(true);
cal.setHidden(true);
But the same web app starts with code to look for an existing calendar and delete it first
var cals = CalendarApp.getCalendarsByName("Timetable");
for (var i = cals.length; i--; ) {
cals[i].deleteCalendar();
}
However, CalendarApp.getCalendarsByName does not find the "Timetable" calendar.
I have also tried
var cals = CalendarApp.getAllCalendars();
for (var i = cals.length; i--; ) {
if (cals[i].getName()=='Timetable') {
cals[i].deleteCalendar();
}
}
and
var cals = CalendarApp.getAllOwnedCalendars();
for (var i = cals.length; i--; ) {
if (cals[i].getName()=='Timetable') {
cals[i].deleteCalendar();
}
}
none of which are able to find the calendar called "Timetable."
However, the new calendar is created properly and listed in the UI under calendar settings, and if I check the box to make it visible again then all versions of this code find the "Timetable" calendar and delete it, before creating a new one.
Does anyone have any ideas on how I can get a handle to my hidden calendar based only on its name?
My web app executes as the person accessing the script, and is creating this secondary calendar in the user's own Google calendar.
I don't think this is possible using Apps Script built-in Calendar API (the CalendarApp).
You'll have to use the actual Calendar API directly. Luckily it is available as an "Advanced Service" (in your script see the menu Resources > Advanced Google Services, follow the instructions and enable the Calendar API).
Here's a snippet to get a hidden calendar by name:
function getCalIdFromName(name) {
var cals = Calendar.CalendarList.list({showHidden:true,
minAccessRole:'owner', fields:'items(id,summary)'}).items;
for( var i = 0; i < cals.length; i++ )
if( cals[i].summary == name )
return cals[i].id;
return null;
}
function deleteTimetable() {
Calendar.Calendars.remove(getCalIdFromName('Timetable'));
}
Trying to limit the CalendarList results I included the criteria to only return the users own calendars. Since this seems to be your scenario, but you can just omit that to retrieve all.
Another caveat, this simple code that does not handle pagination. Hopefully your users will not own more than 100 calendars (which would require pagination control).
Anyway, it is probably much easier to just store the calendar id right after you created it, using the Properties Service for example. And then retrieve it by id when you need to delete or operate on it (also because the user might change the calendar name).

Exceeded maximum execution time in Google App Script with Contacts API

I am creating an script responsible of generating a report containing info about a set of groups and its contacts in google app script.
If I select a few groups, everything goes OK but If I select several (20 or more), then the scripts launches the "Exceeded maximum execution time" error.
How could I reduce the script time execution?
Thanks!
My (reduced) script
var allContactsInfo = []
/II. For each group
for(var i = 0 ; i < numberOfGroups ; i++)
{
var selected = eventInfo.parameter["group"+i]
var contactInfo = []
//III. If it has been selected by the user
if(selected)
{
//IV. Get the contact group and contacts
var contactGroup = ContactsApp.getContactGroupById(eventInfo.parameter["group_"+i+"_id"])
var contacts = contactGroup.getContacts()
//IV. Iterate over each group contact
for (var j=0; j < contacts.length; j++)
{
var contact = contacts[j];
contactInfo.push(contact.getGivenName())
contactInfo.push(contact.getFamilyName())
var groups = contact.getContactGroups()
var groupsAsArray = []
for (var k = 0 ; k < groups.length; k++)
{
groupsAsArray.push(groups[k].getName())
}
contactInfo.push(groupsAsArray.sort().join())
//V. Add the contact into the array
allContactsInfo.push(contactInfo)
}
}
...
...
//VI. Fill the spreadsheet with the array built within the loop
sheet.getRange(1, 1, allContactsInfo.length, headers.length).setValues(allContactsInfo);
UPDATE
After some tests, I have found the bottleneck is produced returning user's groups (via contact.getContactGroups()).
Returning name, surnames, emails, addresses and phones works OK but If I include user's groups too, then timeout exception appears...
UPDATE 2
Here it is my working solution, hope it helps :)
https://github.com/antacerod/google-app-script-6-minutes-limitation
Finally I have found another SO post.
It shows a nice workaround related to checkbox setValue method implementation and its second parameter (Sets whether the CheckBox should be checked and optionally fires an event if the value changes as a result of this call)
In my case, it works like a charm!
Access the workaround