4

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.

  1. 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.

  2. As described here, there exists paid Google Drive add-ons, such as AODocks which allow organizations to achieve this.

  3. 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.

Community
  • 1
  • 1
Sebastien
  • 2,607
  • 9
  • 30
  • 40
  • Your recursive function will have timeout issues if there are too many items. You need to find a better algorithm to change ownership incrementally (recovering from a timeout). If you do that part i can help with the api part. – Zig Mandel Feb 03 '15 at 15:19
  • The recursive function simply builds the list of files and folders in the specified folder. In fact, the array of items going into the final function, which actually makes the API calls and changes the ownership, will only contain the items where a change it required. And given our operations should only be a few files per week. I only plan on running doGet() with trigger about once per hour. – Sebastien Feb 03 '15 at 17:52
  • "end up counting against their storage quotas" If they are Drive for Work customers, storage quota wouldn't matter since it is unlimited for 5 or more users, or 1TB for fewer. If you are Apps for Work with 30GB of storage per user, wouldn't your centralized account run into quota issues if the individual users are? – Dan McGrath Feb 03 '15 at 19:08
  • Problem is, even if few files need this per week, you are still traversing the entire tree every time. If it timeouts it will get forever stuck. Try somehow remembering your tree position so you can continue where you stopped, or use drive change feeds to more efficiently detect what files were added. – Zig Mandel Feb 03 '15 at 22:40
  • @DanMcGrath Good point, but we can always increase the storage of the central account. Beyond the question of storage space, it's more of a centralization issue. The documents stored in this shared space are production archives which don't belong to one person but to the company. – Sebastien Feb 04 '15 at 09:08
  • @ZigMandel I see. I'll look into change feeds. – Sebastien Feb 04 '15 at 09:08

0 Answers0