Set file permissions with Google App Script - google-apps-script

I regularly need to change file share permissions on large numbers of files on Google Drive. I would rather not have to do this manually on a file by file basis. I have no issues extracting the File IDs, but can't seem to find any information associated with setting permissions for specific users.
Suppose I have a file with ID - 1132asdfasdf5sdf564sdf
Suppose I have a user named John Smith whose email address is jsmith#email.com and this user is a Google user.
Here's a sample script:
function myFunction() {
// this grabs the ID of the source file
var sourcefile=DriveApp.getFileById("1132asdfasdf5sdf564sdf");
}
Question. Once I grab the file by ID, is it possible to set either edit or view permissions for this specific user?

I haven't tried this, but I would imagine you could use addviewer(email) or addeditor(email). There is also an option for multiple emails.
source: https://developers.google.com/apps-script/reference/drive/file#methods

You can try to use the Drive Service. This service allows scripts to create, find, and modify files and folders in Google Drive.
// Log the name of every file in the user's Drive.
var files = DriveApp.getFiles();
while (files.hasNext()) {
var file = files.next();
Logger.log(file.getName());
}
By using the enum permission, that represents the permissions granted to users who can access a file or folder, besides any individual users who have been explicitly given access. These properties can be accessed from DriveApp.Permission.
VIEW - Users who can access the file or folder are able only to view it or copy it. Passing this value to File.setSharing(accessType, permissionType) throws an exception if the type of file does not support it.
EDIT - Users who can access the file or folder are able to edit it. Unless File.setShareableByEditors(shareable) is set to false, users can also change the sharing settings. Passing this value to File.setSharing(accessType, permissionType) throws an exception if the type of file does not support it.
Try also to check this SO question for more information.

Are you replacing old users with new ones in the permission scheme? If you are, you need to invoke the File or Document class methods removeEditor(s) or removeViewer(s), and then follow up with addEditor(s) or addViewer(s).
The problem with using built in methods (as far as I can tell) is that it is difficult to stop a blizzard of email notifications going out to the users if you are doing bulk permission inserts. You can use the flexibility of the Drive API to specifically stop email notifications, but may experience with calling the Drive API is that it eats up a lot of time.

Related

Get new file id after transferOwnership=true and moveToNewOwnersRoot=true

I need to move a file from one user in our domain to another. I am accomplishing this by creating a new Permission and setting transferOwnership and moveToNewOwnersRoot to true. It works fine.
But after I move the file to the new owner's root, I want to move it into a nested folder. I can do that with a PATCH to the /drive/v3/files/fileId endpoint, but I need to know what the file id is. When the create permission call moved the file, the file get's a new id, but I can't see a way to get it. The create permission call returns a permission, not the associated file. Is there a way to get the file id from a permission id?
Thanks DalmTo, you are correct that the file id does not change just because you transfer ownership. Makes sense. It works now that I'm not making a false assumption, but it's so slow. I'm making 4 API calls just to copy a file into another user's drive in a mirrored folder structure.
Copy the file on the origin user's drive
Share the copied file with the destination user in order to prevent an email notification being automatically sent out to the origin user during the ownership transfer (an email notification is still sent to the destination user, but that's ok).
Transfer the copied file to the destination user's root.
Set the parent of the copied file to the folder id that mirrors the origin user's parent folder.
Wish there was a way to combine some of these calls, and I may need to do more to check for existing share permissions, for example. And this is for every file. I don't understand why this use case isn't better supported by the Drive API.

GAS getSharingAccess() restriction scopes

Question
Is there any way to restrict the scope [drive.readonly] to only apply to current sheet?
I need to call getSharingAccess(), only on current sheet.
Background
We have built a public google addon thats calling our API with a customer uniqe API-Key.
To check that the sheet is not shared with others (must be private to user), we check if Sheet is shared.
If sheet is shared we give a warning to user.
var docId = SpreadsheetApp.getActiveSpreadsheet().getId();
var access = DriveApp.getFileById(docId).getSharingAccess();
Problem
The scope drive.readonly is giving full read access to all files on users drive.
We only need to check current sheet if this is shared.
We dont need access to all files on users drive.
Many users are afraid to give this full access to any addon.
https://www.googleapis.com/auth/drive.readonly
https://developers.google.com/apps-script/reference/drive/file#getsharingaccess
Thanks,
Br,
Henrik
Answer:
There's no way to get information of which types of Permission (anyone, domain, etc.) are associated with current spreadsheet while using a scope that is restricted to this file.
Explanation:
Using scope spreadsheets.currentonly, you can know whether the file has been shared with specific users (eg. Spreadsheet.getViewers()), but not if it has been shared with all users in a domain, or made public.
In order to get this information, you would at least need the scope drive.metadata.readonly, which is a restricted scope, the same as drive.readonly (see scopes).
drive.file cannot be used for that, since it only gives access to files created or opened by your project, and this doesn't seem to include container files for your bound script.
The easiest way to retrieve this information via drive.metadata.readonly (the more restricted scope you can use) is by doing the following:
Enable Advanced Drive Service.
Set the following explicit scopes in your manifest file (necessary to set a less permissive scope; otherwise Apps Script would automatically set drive.readonly or drive):
"oauthScopes": [
"https://www.googleapis.com/auth/spreadsheets.currentonly",
"https://www.googleapis.com/auth/drive.metadata.readonly"
]
Copy and run the following function to list the types of permission associated with this file:
function getCurrentFilePermissions() {
const ssid = SpreadsheetApp.getActive().getId();
const permissions = Drive.Permissions.list(ssid);
const permissionTypes = permissions["items"].map(permission => permission["type"]);
console.log(permissionTypes);
return permissionTypes;
}
Notes:
DriveApp.getFileById(id) requires drive or drive.readonly, metadata scopes cannot be used for that. That's why the Advanced Service is used.
Considering that methods for managing access for specific users (e.g. getEditors(), addViewer(user), I'd suggest filing a feature request in Issue Tracker for adding methods to manage other types of access (e.g. DOMAIN, ANYONE), using this template.
I have not tried this, but the Drive API has a get method that lets you retrieve a Files resource. The Files resource has a shared property that apparently indicates whether the file is shared or private to the owner.
It seems to be possible to specify the https://www.googleapis.com/auth/drive.file scope or the https://www.googleapis.com/auth/drive.metadata.readonly scope when sending a get request.
You can try the endpoint with the Try this API panel — enter a spreadsheet ID in the fileId box, shared in the fields box, and untick the Google OAuth 2.0 checkbox. The spreadsheet must be readable by the world for this test to work.
Another test to try against the get endpoint:
const response = UrlFetchApp.fetch(endpoint + '?' + parameters, { headers : { 'Authorization' : 'Bearer ' + ScriptApp.getOAuthToken() }});
It may also be worth trying DriveApp and the Advanced Drive Service and the https://www.googleapis.com/auth/drive.file scope.
As said, I have not tried any of the above, and you will have to do your own research to find if there is a solution there. Let us know how it goes.

How to setOwner() of file after uploading it to a folder in Drive?

Desired Behaviour
This is my first attempt at a google apps script and I want a user to be able to upload a document to a shared folder (with edit access), but then change the permissions of the file so that the user cannot delete the file and can only view it.
(If this is not specifically possible, I am interested in any method that achieves the same result - ie an admin has edit access to a folder of documents uploaded by users with view only access).
What I've Tried
This answer:
https://stackoverflow.com/a/10821130
Points to a method called setOwner(emailAddress)
So I tried:
// define the target folder to create the file in
var driveFolder = DriveApp.getFoldersByName("My Folder").next();
// create a file in the target folder and set a different owner
var driveFile = driveFolder.createFile(formBlob).setOwner("test#gmail.com");
Current Behaviour
The file ownership is not changing.
Developer Tools > Console error is:
Uncaught ScriptError: Invalid argument: sharing.user
With questions about that particular error here:
Trying to change owner on files in Google Drive
Other Settings
Publish > Deploy as web app > Execute the app as > "User accessing the web app"
Publish > Deploy as web app > Who has access to the app > "Anyone"
According to
Change your sharing settings - Google Drive Help the ownership of uploaded files can't be transferred. For an alternative approach see Google Forms file upload complete example
You have to create a google site and use the upload feature then you can change settings.
Since the file one person directly in google is "not yours" you cannot change it. but if you receive it through a site page you will be the owner.

DriveApp File.makeCopy() not copying document body

Using the following syntax for Google DriveApp:
var folderVar= DriveApp.getFolderById(corporateFolderId);
var fileVar= DriveApp.getFileById(fileId);
fileVar.makeCopy(title, folderVar);
fileVar.setTrashed(true);
As you can see, I'm trying to copy the recently generated file from my logged-in user drive to a folder on my corporate account that I have permissions to. I then trash the document from my logged-in user drive. This is in fact performing the copy, and the title is correct, but the document body is empty. I am performing this after document creation, so order of operations is fine. Logging shows that the same document file ID that is in my logged-in user account (but trashed) is the one being copied, but the new document in the corporate folder is blank.
Any tips are greatly appreciated, thanks.
You said you're performing the script after Document Creation, do you are also saving it?.

Get email address of shared users in Google Drive SDK

Because of the simply mind boggling lack of a notify feature in Google drive that notifies people of new files being added to their shared folders, i'm forced to write one. My first version of this system was written using Google App Script. I had to kill that version because the load my client has goes way above and beyond the quota limits for app script and the system shuts down at about 9:30 in the morning.
So I rewrote the app in GAE/GWT and got pretty far along, not I think I have hit another problem. I can't find a way to get the list of shared users on a folder/file. The way the system works, he creates a file. That file is put in a folder, and he launches this app and hits the button. This app then scans the folders and if it finds a new file, it goes into the files permissions, gets the list of email addresses the file is shared with, and sends them an email saying there is a new file. But, the Drive SDK returns everything about the people that a file is shared with, except their email addresses. Is there some switch that I am not finding in the documents yet that would give me these email addresses?
I would really hate to have to rewrite this thing yet again.
There is some discussion about this, the email address is hidden for privacy. You can get the Id of the user that has access to the file, but not the email address.
email ids related to shared google drive file
Google drive api change ownership of files?
value attribute for Permissions Resource not populated in responses
If you have access to the user's permissionId and the fileId, which it sounds like you do, you can get their email address for the file using the Permissions API's get() method (JavaScript version):
var fileId = 'Some Drive fileId';
gapi.client.drive.about.get().execute(function (data) {
gapi.client.drive.permissions.get({
'fileId': fileId,
'permissionId': data.permissionId
}).execute(function (perms) {
console.log(perms.emailAddress);
});
});
See also:
Permissions Resource
About Resource