The Problem
Organizations using Google Apps have no simple solution for creating central "file servers" where users may add files, forfeiting their ownership to the repository. The problem is mainly that Google does not offer a central file storage option for organizations.
Current Workarounds
There exists several workarounds which offer partial solutions to this problem.
As explained in this article, organizations may create a 'storage' user and use it to build the desired folder structure (Marketing, Operations, etc). These folders can be shared with the appropriate users within the organization and files they add to them are visible to other users, provided that sharing settings are properly configured. The problem with this option is that files added to the file server remain in the ownership of the users and end up counting against their storage quotas.
As described here, there exists paid Google Drive add-ons, such as AODocks which allow organizations to achieve this.
Several fragments of solutions mentioning the use of Google Apps Script, Domain-Wide Delegation of Authority and Drive API, but all are outdated (making reference to the deprecated Documents List API) or incomplete. Novice users with little to no understanding of Google Developer tools are left with confusion.
Objective
Create a simple and free solution which uses a 'storage' user's Drive space as a central file server for users of an organization.
Requisites
- Utilize Google Apps Script and time-based triggers to run the script necessary to change ownership of files and folders added to a folder shared by the 'storage' user.
- Take advantage of Domain-Wide Delegation of Authority and the Drive API to change ownership of those files.
- The script should only have to be implemented by the domain's superuser and not require manual authorization from every user in the organization.
Solution in progress
I've started writing part of the Google Apps Script. However, I'm lacking the pieces which would authenticate to the Drive API using the OAuth credentials created as per this Delegation of Authority post.
var superUserEmail = "admin@mydomain.com";
var folderId = "TARGET_FOLDER_ID"; // This folder belongs to the superuser and is shared so that other members of the organization can edit its contents
var folderObject = DriveApp.getFolderById(this.folderId);
// List all folders, sub folders and files within the folder
var listItems = function(folder) {
var items = [];
function _listItemsRecursive(folder) {
var files = folder.getFiles();
var subfolders = folder.getFolders();
while(files.hasNext()) {
items.push(files.next());
}
while(subfolders.hasNext()) {
_listItemsRecursive(subfolders.next());
}
items.push(folder);
}
_listItemsRecursive(folder);
return items;
}
// Get all the items which don't already belong to the superuser
var getRestrictedItems = function(items) {
var restrictedItems = [];
for(i = 0; i < items.length; i++) {
var item = items[i];
var userEmail = item.getOwner().getEmail();
if(userEmail != superUserEmail) {
restrictedItems.push(item);
}
}
return restrictedItems;
}
// Change ownership to superuser
var changeItemOwner = function(items) {
for(i = 0; i < items.length; i++) {
var item = items[i];
item.setOwner(superUserEmail); //This obviously doesn't work
}
}
function doGet() {
var items = listItems(folderObject);
var restrictedItems = getRestrictedItems(items)
changeItemOwner(restrictedItems);
}
Regarding the actual change of ownership, this post proposes a solution, but using a deprecated method.
function changeOwner(newOwnerEmail, file)
{
var fileId = file.getId();
var oldOwnerEmail = file.getOwner().getEmail();
if (oldOwnerEmail == newOwnerEmail) { return; }
file.removeEditor(newOwnerEmail); //should this be oldOwnerEmail?
var base = 'https://docs.google.com/feeds/';
var options = OAuthApp.getAuth('docs');
options.method = 'POST';
var rawXml = "<entry xmlns='http://www.w3.org/2005/Atom' xmlns:gAcl='http://schemas.google.com/acl/2007'>"
+"<category scheme='http://schemas.google.com/g/2005#kind' "
+"term='http://schemas.google.com/acl/2007#accessRule'/>"
+"<gAcl:role value='owner'/>"
+"<gAcl:scope type='user' value='"+newOwnerEmail+"'/>"
+"</entry>";
options.payload = rawXml;
options.contentType = 'application/atom+xml';
var API_KEY = getAPIKey();
var url = base + oldOwnerEmail+'/private/full/'+fileId+'/acl?v=3&alt=json&key='+API_KEY
try
{
var result = UrlFetchApp.fetch(url, options);
docsObject = Utilities.jsonParse(result.getContentText());
}
catch (err) { Logger.log(err.message) }
}//end changeOwner()
The Question
What I'm looking for is for someone to guide me in updating the changeOwner
function to one which works and utilizes Drive API. One I've implemented it and have a working solution, I plan on writing a detailed step-by-step tutorial on getting to help the rest of the people out there trying to get this working.