Google Drive Auto-Expire - Unshare Multiple Files Simultaneously? - google-apps-script

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());
}
}

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();
}

My first Apps Script - can this be more efficient?

I am a maths teacher who is learning programming and this is my first attempt at using Apps Script. I have used this site to find various bits of code and put them together to form a script that works (thank you to the numerous posters on this site who have unknowingly helped me already!).
My question is: can it be polished and made more efficient? I'm assuming it probably can - I'm grateful for help anyone is kind enough to provide.
Outline:
There are 2 existing Google Sheets - "DATA", containing a list of students and their data; "TEMPLATE", used to create a separate Google Sheet for each student.
The script collects the StudentID numbers from DATA and creates a new Google Sheet for each student based on the TEMPLATE Google Sheet.
Put the studentID in the filename and copy the studentID to cell U1 in the first tab [TEMPLATE contains 2 tabs] then hide the 2nd tab [called 'import'].
Add the student as a viewer.
Restrict copy/download/print for the viewer.
Many thanks,
Dan
function createSheets()
{
// ID of the Google Sheet to be used as a template for the student Sheets
var templateId = '###TEMPLATE###';
// Collect all the studentIDs from DATA and store in a variable called 'students'
var students = Sheets.Spreadsheets.Values.get('###DATA###', '###SheetName###');
for(var i = 0; i < students.values.length; i++)
{
var studentId = students.values[i][0];
// Make a copy of the template file
var documentId = DriveApp.getFileById(templateId).makeCopy().getId();
// Rename the copied file
DriveApp.getFileById(documentId).setName(studentId + ' Learner Map');
// Insert the studentId in cell U1 (of the first tab?)
SpreadsheetApp.openById(documentId).getRange('U1').setValue(studentId);
// Hide the 'import' tab
SpreadsheetApp.openById(documentId).getSheetByName('import').hideSheet();
// Add the student as a viewer
SpreadsheetApp.openById(documentId).addViewer(studentId + '###EMAIL EXTENSION##');
// Restrict copy/download/print for the viewer
// get the file with the Advanced Drive API (REST V2)
var file = Drive.Files.get(documentId);
Logger.log('File "%s", restricted label was: %s', file.title, file.labels.restricted);
// set the restricted label
file.labels.restricted = true;
//update the file
Drive.Files.update(file, documentId);
// check the updated file
var updatedFile = Drive.Files.get(documentId);
Logger.log('File "%s", restricted label is: %s', updatedFile.title, updatedFile.labels.restricted);
}
}

Sorting Google Docs into Google Drive folders based upon a common string in file and folder names

I have hundreds of Google Docs, and lots of Google Folders. They share a common string in the filename. The Docs need to go into the corresponding Folder, and I'd like to automate this with some Script.
What I want to do is as follows:
I have hundreds of Google Docs which follow a similar pattern in the filename:
SURNAME, Forename_userID_fileName
So for instance,
DOE, Jane_jd5678_Document3
PUBLIC, Tom_tp9123_reportTPS
SMITH, John_js1234_finaldocument
and so on and so forth.
I also have corresponding Folders in a Google Team Drive, set up as follows:
SURNAME, Forename (userCode) (userID) - userType
So for instance,
DOE, Jane (145374578) (jd5678) - AET Full Time
PUBLIC, Tom (673468714) (tp9123) - NR Full Time
SMITH, John (874512456) (js1234) - AET Part Time
The common string between the files and the folder names is the userID string.
Currently I download all the Docs, and then upload drag-and-drop into each corresponding folder. Takes ages! I was hoping there is a bit of Apps Script that I can do to automate this but I really don't know where to start at all. Anyone have any pointers?
This StackOverflow question seems to want to do what I want to do, but as I'm such a beginner with Apps Script I can't really decipher the solution.
This is a basic example to point you in the right direction using the basic Google Apps Script DriveApp (as opposed to the advanced Script Services version or other Google Drive API methods). The main concern that comes to mind is the script timing out if this example takes too long to complete. If that happens, you'll need a more complex solution. You could also chunk it up by having the idRegex only work on, e.g., surnames A-D then E-G, etc. The example regular expression could match random files you have with underscores; you may want to find a more complicated regular expression if that is a concern.
function organizeFilesById() {
var idRegex = /_[A-z]+[0-9]+_/;
var files = DriveApp.getFiles();
while (files.hasNext()) {
var file = files.next();
var filename = file.getName();
var id = idRegex.exec(filename);
if (! id) {
continue;
} else {
id = id[0];
}
var query = "title contains '" + id + "'";
var folders = DriveApp.searchFolders(query);
if (folders.hasNext()) {
var folder = folders.next();
Logger.log("Will add %s to %s", filename, folder.getName());
//folder.addFile(file); // uncomment line to actually do it
} else {
Logger.log("No folder found for %s", filename);
// could create folder or just report "folder not found"
}
}
}

Google Apps Scripts: Insert additional text into a text file

I'm trying to develop a method for adding Google Tasks to my running task list named todo.txt and is housed in Google Drive. I've found a way to grab the tasks. Of course, the data will nee to be manipulated as well (e.g., concatenate date formats to conform to todo.txt rules) but I'll deal with that next.
The question I have is how to insert them to the top of the todo.txt without overwriting the existing text contained within it. I have read in other circumstances, that I may need to read the current text out, add the new info and then write the whole thing back as an overwrite. Is this necessary? And, if so, how do I do it?
Below is the code I've written thus far, substituting logger.log for the destination file since I don't know how to do it. I;m not a programmer, so polease forgive any ignorance here. Thanks.
function listTasks(taskListId) {
var taskListId = '12345'; //this is the ID of my Google Tasks (the source data)
var name2="Text Journals"; //this is the folder in which my todo.text resides
var name="todo.txt"; //this is the name of my todo file (the destination)
var dir = DriveApp.getFoldersByName(name2).next()
var tasks = Tasks.Tasks.list(taskListId);
if (tasks.items) {
for (var i = 0; i < tasks.items.length; i++) {
var task = tasks.items[i];
Logger.log('Task with title "%s" and dute: "%s" and notes "%s" and status "%s" was found.',
task.title, task.due, task.notes, task.status);
}
} else {
Logger.log('No tasks found.');
}
}

Counting unique domain names from a column

I wrote a google apps script which fetches the G Suite (google apps) users from the AdminDirectory API
As on output, i get the domain name in front of every user (used replace to extract domain name from each user email id).
what i want to do-:
1. Count the number of users on each domain in one column, so end result should look like this-:
Column - I (exaxple)
domainA.com = 120 users
domainB.com = 28 users
etc....
Any help is appreciated.
I think there is probably a way to shorten this code, but something like this will work. You will have to figure out how to read the correct columns in and output to the correct columns, but hopefully, this will help out:
var emails = [
'someone#testA.com',
'someone#testB.com',
'someone#testA.com',
'someoneelse#testA.com'
];
function countDomains() {
var domainCounts = {};
var domains = emails.map(function(domain) {return domain.split('#')[1];});
domains.forEach(function(each) {
if(domainCounts.hasOwnProperty(each)) {
domainCounts[each]++;
} else {
domainCounts[each] = 1;
}
});
Logger.log(domainCounts);
}