Get email address of shared users in Google Drive SDK - google-drive-api

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

Related

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.

How does listing files/folders inside of google drive work?

I have been reading the reference and also used the API explorer, but I cannot for the life of me manage to get a full list of what's inside a specific folder of my google drive.
As far as I understand, the following code should list all files inside the folder that has the given folderID. That does work; but only on files that I created from my app. Folders/files created with or uploaded through the web UI will not show up in the response.
const folders = await drive.files.list({
q: "'<folderID>' in parents",
trashed: false,
spaces: ['drive']
});
In a different post I found that the scope might be the issue, but as far as I know I have already given my app the highest available scope:
const SCOPES = ['https://www.googleapis.com/auth/drive'];
I appreciate any help on this matter. :)
Your symptoms are consistent with using drive.file scope instead of drive. Is it possible that you granted access using drive.file and haven't yet repeated the grant procedure with drive?
The other possible explanation is that you are in two different Drive Accounts. Many people use a Service Account because the Google docs refer to this as server-to-server, without realising that the Service Account is a totally different account to their User Account, ie. the one with the Drive UI. So your app will be uploading and reading files in the Service Account, your UI-created files are in your User Account.

How can my Google Apps Script be run by others the Sheet is shared with?

I've got a Google Apps Script that works fine for me. Others who the sheet is shared with that try to use it get the message:
You do not have access to perform that action. Please ask the owner of
this item to grant access to you.
The script is used to update an existing sheet with new rows of data. It's triggered using a menu item added to the UI and does the following:
Finds a .xlsx file in a GDrive folder (this file is exported by a web service and manually placed by us into the GDrive Folder, we have no control over the contents of the file or its format)
Converts the file from .xlsx to .gsheet using UrlFetchApp (uploadType=media&convert=true)
Changes the filename and folder location of the resulting .gsheet using UrlFetchApp. The folder location now matches that of the .xlsx file (when a file is converted using UrlFetchApp the resulting file seems to be placed in the root of GDrive)
Gets the .gsheet using DriveApp and then opens it for access by the script
Stores all the data from the .gsheet into a 2d array using column headers as the keys for each element in a row
Stores all the ID values (unique) of the existing data from the destination sheet into a 1d array
Compares the two arrays and removes any rows from the 2d array that contain an ID that matches one in the 1d array, leaving only new data in the 2d array
Loops through each row of the 2d array and then through each column of the destination sheet adding data from the 2d array row to a new row at the bottom of the data in the destination sheet, using the value of the column header as the key for each element
I know there's no problem with the code because it works fine for me so it must be a problem with permissions, but I can't figure out how. The sheet is shared with them and the GDrive folder that the files are stored in is shared with them. When I first ran the script myself, I had to grant permissions for the script to access the GDrive folder, which has obviously now been done.
I'm the developer of our group and not the user of the data but atm I'm having to run the script to update the data for the users every time it needs doing instead of them just doing it themselves, which is... annoying.
Any help in trying to figure out where the problem is here greatly appreciated.
EDIT: Reading through this again its occurred to me that when the file is converted, at first its saved to the GDrive root which is why I then have to change the folder. Being the root, it's not shared with the users of this file. Could this be the reason? If so, how can I get around this? Can I specify at convert time which folder the resulting file should be saved to?
To fix this, you need to deploy the script as a web app (the idea comes from #MarioR answer, but the settings are different):
With the owner account, open the sheet, then script editor
Click on Publish and then Deploy as web app
For Execute the app as, choose User accessing the web app and for Who has access to the app, choose Anyone
The first time the users try to use the script, they will have to allow the script (if they get a This app isn't verified, they should click on Advanced at the bottom and then Go to <script name> (unsafe)). After this, they may need to refresh the sheet to be able to run the script.
If the owner shares the sheet to a new user, after the script has been deploy as a web app, the new user may need to wait 15 minutes (or so) before being allowed to authorize the script (meanwhile this user will continue to get the red warning).
Only the owner can deploy as a web app, the other users who try do to it won't get a message error, just a popup Fetching Data that remains stuck forever!)
To change the owner: open the sheet with the owner account, click on Share > Advanced > Click on the arrow that triggers the dropdown next to the "owner-to-be" > Set as owner
In my experience, I created a Spreadsheet that retrieves G Suite License information for users every time the Spreadsheet is opened. What I did was that I created the script with a Super Admin but when the Spreadsheet was shared the other users had the same problem until I went to Publish > Deploy as Webb App from the Apps Script menu, I leave the options like this image
That worked for me, I hope it works for you. After this update, all users with Edit rights on the spreadsheet were able to retrieve the information on behalf of the Super Admin every time the spreadsheet opens. Just make sure to execute the App as you and not as the user who will use the script or spreadsheet.
Usually other users are not able to run scripts that required admin rights but this resolves my issue. Please let me know if this worked for you!
Greetings.
I've got "doGet" after trying out the script as a Web App. What does "doGet" mean?
I confirm #MagTun's and #browly's solution to share the file and wait for 15 minutes. I faced this problem last week even if I had given Edit permission to the file programatically. Tricky because some users get the screen to grant permission (correct) but some get either "You need permission" message or "Sorry, unable to open file at this time" (wrong). But I observed that after some time, the user is able to run the script with or without requesting access to the file explicitly. So there's really nothing else needed but wait for about 15 minutes and it prompts for permission consistently. Thanks for the tips, it confirmed the solution to my problem.

Set file permissions with Google App 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.

Granting APP authorization to Google Drive files

I am trying to authorize files on my google drive with specific APP authorization I created. As files on my google drive can only be manipulated by its authorized app, is there any way I can convert these "None" authorized file with APP authorization? And, if yes, by which function?
I looked all over the tutorial document but only find discussion about permission. The only method I can think about is uploading these files to google drive with upload function from my created app. But I guess there is a much smarter way. Do any one has the same experience?
Here list my steps to create authorized file:
First, I start my app from using sample code, DrEdit. https://developers.google.com/drive/examples/python;
From the code, I successfully open new files and saw them listed on my google drive.
From view authorized app, I can clear see these apps created from my app have their authorization signed with app ID. The other files original belong to me have these authorization signed as "None".
I had the same issue and had to change the scope from https://www.googleapis.com/auth/drive.file to https://www.googleapis.com/auth/drive which gives full access to all drive files rather than just the ones created by the app.