About Google Drive's "state parameter"? - google-apps-script

My App for Google Drive is by Google Script.
When I select files in Drive and then call my App, an official "state parameter" will be sent into my App for further digestion. However, the official document is not clear enough for its setting. I need to collect its info from different area like Google I/O video and examples. Is there a good site to introduce it?
Official Site: https://developers.google.com/drive/web/integrate-open
Especially, for the process, User select files in a Active folder => Run App => App save back files to Active Folder ... but this is the problem. How can I know which is the active folder through the state parameter? Any suitable command?
N.B. It is meaningless to use MyFile.getFolders() command, since one file can belong to several folders, and I cannot distinguish which one is "Active" folder.

The documentation shows some code that gets the id after the file is picked from a Google Drive:
// A simple callback implementation.
function pickerCallback(data) {
if (data.action == google.picker.Action.PICKED) {
var fileId = data.docs[0].id;
alert('The user selected: ' + fileId);
}
}

Related

Google Drive API - Adding new users to Shared Drive

I am using a Google App Script to automate the creation of some Google Accounts inside our of our domain. I have been having a little trouble with some of the API calls and such, however this question is more related to whether or not the Drive API gives me the ability to do something. I have code below that adds editor permissions to the new user for their needed Shared Drives, however I would like to give them 'Content Manager' access to the Shared Drive. From the documentation I have looked at it, it does not seem like this is possible using the Google Drive API however I wanted to ask here to make sure I am not missing something when proceeding with the rest of my automation.
switch(ssValues[i][9]){
case "Accounting":
AdminDirectory.Members.insert(groupMember, "notourcompany");
DriveApp.getFolderById("TH1SDR!v3").addEditor(email);
break;
Does not matter if I need to use a different method or another API to achieve this functionality, I just want to know if it is possible to do this using their API's or SDK's through an App Scripts project.
Documentation:
Folder Class-https://developers.google.com/apps-script/reference/drive/folder
Drive API - Drives - https://developers.google.com/drive/api/v3/reference/drives
Drive API - Permissions - https://developers.google.com/drive/api/v3/reference/permissions
It should be possible to manage users over a Shared Drive utilizing the Drive API. The important thing is that you would need to give access over the API and make sure the parameter or argument for supportsAllDrives is set to true.
There is a sample Java code over the official documentation that shows how you can add permissions to a Shared Drive that is "orphaned" or you can test it over it in the permission.create documentation:
You can test it yourself over here.
As you can see in the image, the function is very similar to the code that was created on an old thread utilizing the Drive API V2, however it is using the argument supportsTeamDrive. Sample code that could be edited:
Edit:
I have updated the code based on the one suggested from the thread to a more simplify version.
// Using Apps Script with Advance Google Services v2 of the Drive API enable
function insertPermission() {
const sharedid= 'sharedDriveID' //ID of the Shared Drive
var resource = {
// enter email address here
value: 'emailtest#domain.com',
type: 'user',
// choose from: "owner" or "fileOrganizer". File Organizer would basically be the contentManager of a SharedDrive.
role: 'fileOrganizer'
};
var optionalArgs = {
sendNotificationEmails: false,
supportsAllDrives: true
};
Drive.Permissions.insert(resource, sharedid, optionalArgs);
}
You can review the thread and code here.
References
https://developers.google.com/drive/api/v3/reference/permissions/create
https://developers.google.com/drive/api/guides/manage-shareddrives
I agree with Ricardo Jose Velasquez Cruz. I'm a super admin in my org and this solution finally allowed it to work for me. I had to tweak the optionalArgs to include useDomainAdminAccess.
// Using Apps Script with Advance Google Services v2 of the Drive API enable
function insertPermission() {
const sharedid= 'sharedDriveID' //ID of the Shared Drive
var resource = {
// enter email address here
value: 'emailtest#domain.com',
type: 'user',
// choose from: "owner" or "fileOrganizer". File Organizer would basically be the contentManager of a SharedDrive.
role: 'fileOrganizer'
};
var optionalArgs = {
useDomainAdminAccess: true,
sendNotificationEmails: false,
supportsAllDrives: true
};
Drive.Permissions.insert(resource, sharedid, optionalArgs);
}

Creating a Google Sheets spreadsheet in the Google Drive app data folder with the client-side API

I would like to create a Google Sheet in the Google Drive App Data folder (API docs at https://developers.google.com/drive/api/v3/appdata) using client side JS.
I can create non-Sheet files like this (after handling all the authentication stuff, as per the browser quickstart for the Sheets API):
gapi.client.drive.files.create({
resource: {
name: 'myfile.txt',
parents: ['appDataFolder'],
mimeType: 'text/plain'
},
fields: 'id'
}).then(res => {
console.log("Created OK: response was ", res);
}).catch(e => {
console.log("Creation failed: error was ", e)
})
However, if I use mimeType: 'application/vnd.google-apps.spreadsheet' then I get this error back:
reason: "notSupportedForAppDataFolderFiles",
message: "Method not supported for files within the Application Data folder."
This error message seems to be entirely undocumented. My suspicion is that this is just not allowed: you can't store Google Sheets in the App Data folder, probably because Sheets aren't really stored as files in Drive at all and they appear so through some sort of UI fakeout by the Drive team. But I have no confirmation of this.
The reason I'd like to do this is that an app which requests access to the App Data folder does not need to request access to all other files. If I can't put a Sheet in the App Data folder, then as far as I'm aware, in order to create a spreadsheet my app will need to request complete access to all the user's spreadsheets, which it completely does not need; it will use its own one and that's it. I don't want to ask for that access because users will (correctly) see that as massive overreach.
The documentation specifies:
The application data folder is automatically created when you attempt to create a file in it.
Use this folder to store any files that the user shouldn't directly interact with.
This folder is only accessible by your application and its contents are hidden from the user and from other Drive apps.
So while there is no direct information about Google sheets not being allowed in the application data folder, one can assume that a Google Sheets file does not meet the mentioned criteria.
As for scopes:
You can use the scope https://www.googleapis.com/auth/drive.file.
This is a narrow scope that gives the application only access to files that have been created by this application, see here
By using this scope, you avoid asking for access to all users files, and thus the users do not need to worry about providing this scopes to the application.

Check if google document is neither edited nor viewed

Does google app script offers a class with a method allowing to check if a document with a given id is edited or viewed.
I'm build an application that allows user to delete google document from the google disk but before moving file to trash I would like to check if the file is neither edited nor viewed.
The similiar question has been posted here, but no solution provided.
Getting a list of active file viewers with apps script
Please note the the lock service is not a solution to this problem.
The Google Drive API must be used to get revisions to a file. The built-in DriveApp service, which is different than the Advanced Drive service, has no capability to get file revisions information, except for getLastUpdated() method, which gets the date when the file was last updated. The Drive API can be used within Apps Script by using the Advanced Drive service.
Advanced Services within Apps Script must be enabled. Click the "Resources" menu, and then choose the Advanced Google services menu item.
After you have enabled the Advanced Drive Service, the "Drive" class will show up in the context menu. Use Ctrl + Space Bar to have a list of available classes displayed in the code editor.
To get revisions to a specific file, use the Revisions class of the Advanced Drive service.
Drive.Revisions.list(fileId)
Check for no revisions:
function trash_If_No_Changes_(fileID) {
var revs;
revs = Drive.Revisions.list(fileID);
if (revs.items && revs.items.length === 0) {
trashFile_(fileID);
}
}
The Advanced Drive Service can also delete a file without sending it to the trash first.
function trashFile_(fileID) {
var i;
/*
This deletes a file without sending it to the trash
*/
for (i=1;i<4;i++) {
try{
Drive.Files.remove(fileID);//deletes a file without sending it to the trash
return;//return here instead of break because if this is successful the task is completed
} catch(e) {
if (i!==3) {Utilities.sleep(i*1500);}
if (i>=3) {
errHndl_(e,'trashFile','Can not delete the file by ID');
return false;
}
};
}
}
If you want to avoid the need to ask the user for broad access to their Drive, then you may want to try setting the scope:
https://www.googleapis.com/auth/drive.file
In the appsscript.json manifest file.

Folder getParents fails to get Team Drive name in Google Script

I'm trying to build up the full path to a document in a team drive using a script. The code looks like this:
var path = [ ]
var folder = id.getParents()
while (folder && folder.hasNext()) {
var f = folder.next()
path.unshift(f.getName())
folder = f.getParents()
}
This script is bound to a document for testing.
But when I get to the root, instead of returning the actual name of the Team Drive, such as "Accounting" or "Marketing" it instead returns "Team Drive". I need to know the actual name of the Team Drive, why am I not getting this info? If I run this in a script bound to a document in My Drive, it instead says "My Drive" at the root - this at least makes sense, because that's the actual name I see in the browser. In Team Drive, the root is actually "Team Drives" not "Team Drive".
Because Team Drives are implemented differently than "regular" Google Drive "folders", the built-in DriveApp is not guaranteed to work properly for all actions that deal with them. It is possible that at some point DriveApp will be updated to fully support Team Drives, but there are a lot of sensible things that Google still has yet to do ;)
Instead, use the "advanced service" Drive, which is a client application that implements version 2 of the Drive REST API, and allows properly handling Team Drive information. As an "advanced service", you must enable this service before you can use it.
To build the full path of a Team Drive item using only the advanced service:
function getTeamDrivePath(fileId) {
// Declare we know how to handle Team Drive items, and that they be included in responses.
var params = {
supportsTeamDrives: true,
includeTeamDriveItems: true
};
// Return only the fields we want, instead of the whole `File` resource.
params.fields = "id,title,parents/id"
// In a Team Drive, a file can have only one parent folder (e.g. "normal" filesystems).
// (parent.isRoot is never true for Team Drive folders so it is not used.)
var path = [], file;
do {
file = Drive.Files.get(fileId, params);
path.unshift(file.title);
fileId = file.parents.length ? file.parents[0].id : null;
} while (fileId);
// Since we also added the file, the last element of the path array is the filename.
path.pop();
// A Team Drive is subject to different permissions than files, and thus its name must be
// obtained via the Team Drives resource. Since `file` points to the Team Drive, use it:
// Requesting incorrect fields will result in an API error, so request the proper ones:
params.fields = "name"
var td = Drive.Teamdrives.get(file.id, params);
path[0] = td.name;
return path;
}
More reading about Team Drives and handling associated with them is available on the Drive REST API reference. I link the v2 versions since they are what is available via Apps Script's "Advanced Service", but the v3 version should be used for 3rd party applications using the client libraries.
Important resources:
About Team Drives
Enabling Team Drives support
Team Drives API Reference
Enabling "Advanced Services" in Apps Script
API Best Practices: Partial Resources & "fields"

how to find files not owned by me in Google apps script

In Google Drive one can search files 'Not owned by me'.
I need access to this from Google Apps Script.
I already tried DocsList.find("Not 'me' in owner"); which appears to be the way to do it in the drive API, but without success (in fact that gets me files with me as owner.) I also replaced me with my email address, with and without quotes, but again without success.
Does anyone know if this is possible (other than by iterating all files and checking getOwner().getEmail() manually, which would take far too long given the enormous amount of files owned by this specific user.)
I think the updated answer as of now is to use DriveApp.searchFiles(params) (https://developers.google.com/apps-script/reference/drive/drive-app#searchFiles(String) ).
Code is something like:
// Log the name of every file in the user's Drive that shared with me
var files = DriveApp.searchFiles('sharedWithMe');
while (files.hasNext()) {
var file = files.next();
Logger.log(file.getName());
}
This function will return an array of all files shared with you. It uses the Advanced Drive Service, which must be enabled before use.
/**
* Get array of files on user's Google Drive that have been shared with them.
* From https://stackoverflow.com/a/15947340/1677912
*
* #returns {Array} Array of file resources
* (see https://developers.google.com/drive/v2/reference/files#resource)
*/
function getSharedWithMe() {
var optionalArgs = {q:"sharedWithMe=true"};
var sharedFiles = Drive.Files.list(optionalArgs);
debugger; // pause in debugger
return sharedFiles.items;
}
You can do the same thing without code, by using the Google Drive SDK "Explorer".
See this previous answer that used this technique to get a list of trashed files.
You'll find the Files List API Explorer at the bottom of the Google Drive SDK documentation page for Files:list. For information about search terms, see Search for files. For our purposes, we'll just use sharedWithMe.
If you leave "fields" blank, you'll get everything that's known about the shared files. You can expand and collapse the results using hard-to-see minus sign tags. But it's helpful to limit the output. I used items(id,selfLink,owners/displayName). Here's how that looks: