Google Drive API: Where or How to find Shared Drive ID? - google-drive-api

I'm trying to use Google's APIs Explorer to run a method (drive.permissions.create) in which I grant a user access to an entire Google Shared Drive (not specifically a file or folder).
After executing the command, I get the following error:
An error occurred. See the response for details.
Request
POST https://www.googleapis.com/drive/v3/files/0AKppN1yZFzBbUk9PVA/permissions?emailMessage=Test&key={YOUR_API_KEY}
{
"role": "organizer",
"type": "user",
"emailAddress": "test#test.com"
}
Response
{
"error":{
"errors":[
{
"domain":"global",
"reason":"notFound",
"message":"File not found: 0AKppN1yZFzBbUk9PVA.",
"locationType":"parameter",
"location":"fileId"
}
],
"code":404,
"message":"File not found: 0AKppN1yZFzBbUk9PVA."
}
}
I acquired value, 0AKppN1yZFzBbUk9PVA, from another command I thought would give me the ID of the Shared Drive I'm trying to share(drive.drives.list). However, this value is incorrect. Where or how can I find the ID of the Shared Drive I'm trying to give access to?
Also, if I'm missing another value to input other than a correct Id for the command to be successful, please let me know. There is still so much I don't know about how Google Drive's API works (or APIs for that matter).
Thanks in advance!

For Shared Drives you need to set supportsAllDrives to true.

Related

Is it possible to initiate Google Drive File Approval via API?

Google Drive Approvals are now out of beta and allow for a user to request one or more other parties to approve/reject a document, then lock it as non-editable. Is there a way to do this via the Google Drive/Google Docs/Google Slides API, or do you have to use the Web GUI?
I have found a workaround to know if a document is approved or not (unfortunately not to start an approval flow):
Open the document you want to start approval;
Click File > Approval > Start new Approval flow, select option "Lock file before sending approval request"
Call API /drive/v3/files/:fileId?fields=contentRestrictions, the response will look like this:
{
"contentRestrictions":[
{
"readOnly":true,
"restrictingUser":{
"kind":"drive#user",
"displayName":"........",
"me":true,
"permissionId":"........",
"emailAddress":".........."
},
"restrictionTime":"2022-04-27T11:03:42.430Z",
"type":"globalContentRestriction"
}
]
}
Back to the document, make the approval, and file will be locked.
Call again API /drive/v3/files/:fileId?fields=contentRestrictions, and now the response response will look like this:
{
"contentRestrictions":[
{
"readOnly":true,
"reason":"Locked for File Approval",
"restrictingUser":{
"kind":"drive#user",
"displayName":"......",
"me":true,
"permissionId":".......",
"emailAddress":"........"
},
"restrictionTime":"2022-04-27T10:54:24.594Z",
"type":"globalContentRestriction"
}
]
}
The difference is in the "reason" field, "Locked for File Approval" means that the file was approved.
P.S.: I don't how trustable this workaround is, I tested several and it seems consistent.
P.S.: I don't know if there is a better way to do it, just could find this one at the moment

Google Drive Rest API - How to check if file has changed

Is there a reliable way, short of comparing full contents, of checking if a file was updated/change in Drive?
I have been struggling with this for a bit. Here's the two things I have tried:
1. File version number
I upload a plain text file to Google Drive (simple upload, update endpoint), and save the version from the file metadata returned after a successful upload.
Then I poll the Drive API (get endpoint) occasionally to check if the version has changed.
The trouble is that within a second or two of uploading the file, the version gets bumped up again.
There are no changes to the file content. The file has not been opened, viewed, or even downloaded anywhere else. Still, the version number increases from what it was after the upload.
To my code this version number change indicates that the remote file has been changed in Drive, so it downloads the new version. Every time!
2. The Changes endpoints
As an alternative I tried using the Changes api.
After I upload the file, I get a page token using changes.getStartPageToken or changes.list.
Later I use this page token to poll the Changes API for changes, and filter the changes for the fileId of uploaded file. I use these options when polling for changes:
{
"includeRemoved": false
"restrictToMyDrive": true
"spaces": "drive"
}
Here again, there is the same problem as with the version number. The page token returned immediately after uploading the file changes again within a second or two. The new page token shows the uploaded file having been changed.
Again, there is no change to the content of the file. It hasn't been opened, updated, downloaded anywhere else. It isn't shared with anyone else.
Yet, a few seconds after uploading, the file reappears in the changes list.
As a result, the local code redownloads the file from Drive, assuming remote changes.
Possible workaround
As a hacky hook, I could wait a few seconds after the file upload before getting the new file-version/changes-page-token. This may take care of the delayed version increment issue.
However, there is no documentation of what is causing this phantom change in version number (or changes.list). So, I have no sure way of knowing:
How long a wait is safe enough to get a 'settled' version number without losing possible changes by other users/apps?
Whether the new (delayed) version number will be stable, or may change again at any time for no reason?
Is there a reliable way, short of comparing full contents, of checking if a file was updated/change in Drive?
You can try using the md5Checksum property of the File resource object, if your file is not a Google Doc file (ie. binary). You should be able to use that to track changes to the contents of your binary files.
You might also be able to use the Revisions API.
The Revisions resource object also has a md5Checksum property.
As a workaround, how about using Drive Activity API? I think that there are several answers for your situation. So please think of this as just one of them.
When Drive Activity API is used, the activity information about the target file can be retrieved. For example, from ActionDetail, you can see whether the target file was edited, renamed, deleted and so on.
The sample endpoint and request body are as follows.
Endpoint:
POST https://driveactivity.googleapis.com/v2/activity:query?fields=activities%2CnextPageToken
Request body:
{"itemName": "items/### fileId of target file ###"}
Response:
Sample response is as follows. You can see the information from this. The file with the fileId and filename was edited at the timestamp.
{
"activities": [
{
"primaryActionDetail": {
"edit": {} <--- If the target file was edited, this property is added.
},
"actors": [
{
"user": {
"knownUser": {
"personName": "people/### userId who edited the target file ###",
"isCurrentUser": true
}
}
}
],
"actions": [
{
"detail": {
"edit": {}
}
}
],
"targets": [
{
"driveItem": {
"name": "items/### fileId of target file ###",
"title": "### filename of target file ###",
"file": {},
"mimeType": "### mimeType of target file ###",
"owner": {
"user": {
"knownUser": {
"personName": "people/### owner's userId ###",
"isCurrentUser": true
}
}
}
}
}
],
"timestamp": "2000-01-01T00:00:0.000Z"
},
],
"nextPageToken": "###"
}
Note:
When you use this API in my environment, please enable Drive Activity API at API console and include https://www.googleapis.com/auth/drive.activity.readonly in the scopes.
Although when I used this API, I felt that the response was fast, if the response was slow when you use this, I apologize.
References:
Google Drive Activity API
ActionDetail
If this was not what you want, I apologize.
What you are seeing is the eventual consistency feature of the Google Drive filesystem. If you think about search, it doesn't matter how quickly a search index is updated, only that it is eventually updated and is very efficient for reading. Google Drive works on the same premise.
Drive acknowledges your updates as quickly as possible. Long before those updates have propagated to all worldwide copies of your file. Derived data (eg. timestamps and I think I recall, md5sums) are also calculated after the update has "completed".
The solution largely depends on how problematic the redundant syncs are to your app.
The delay of a few seconds is enough to deal with the vast majority of phantom updates.
You could switch to the v2 API and use etags.
You could implement your own version number using custom properties. So every time you sync up, you increment your own version number. You only sync down if the application version number has changed.

Getting all application extensions, and just applicaiton extensions for an object from MS Graph

Assume I know the extension names I am looking for I could get a users extensions like so:
GET https://graph.microsoft.com/v1.0/users/{{OBJECT_ID}}?$select=extension_{{APP_ID_WITHOUT_GUIDS}}_SomeId,extension_{{APP_ID_WITHOUT_GUIDS}}_SomeValue
Or I could get the attributes from his member groups like so:
GET https://graph.microsoft.com/v1.0/users/{{OBJECT_ID}}/memberOf?$select=extension_{{APP_ID_WITHOUT_GUIDS}}_SomeId,extension_{{APP_ID_WITHOUT_GUIDS}}_SomeValue
However, what If I wanted to see all extension the token had paticular access to. $select=extension_* does not work I get the following:
{
"error": {
"code": "BadRequest",
"message": "Term 'extension_*' is not valid in a $select or $expand expression.",
"innerError": {
"request-id": "3b4e14d6-3bbc-429b-8c45-b0fea629f4a6",
"date": "2018-04-06T13:35:40"
}
}
}
Is there syntax to make this possible?
No, this isn't possible with Microsoft Graph (using v1 Directory Schema Extensions). With Azure AD Graph API there is a function - getAvailableExtensionProperties - that should return all the available v1 directory schema extensions available in the tenant; this doesn't exist in Microsoft Graph. If you use Microsoft Graph schema extensions, you can query /schemaExtensions to find all public schema extension definitions available for use in any tenant (although your app also needs to have been granted access to the underlying extended object - like user).
Hope this helps,

AccessDenied: Required claim values are not provided when accessing education/users endpoint

I'm unable to access the education/users endpoint but I am able to access other endpoints (education/classes, education/schools).
Whenever I try to get a list of all users, I get the following error:
{
"error": {
"code": "AccessDenied",
"message": "Required claim values are not provided.",
"innerError": {
"request-id": "58c42204-440a-482c-b1e9-4c65bb413ed1",
"date": "2018-03-21T20:23:24"
}
}
}
When I try to make the call using the Graph Explorer, I'm given the following notice:
Failure - Status Code - Looks like you may not have the permissions for this call. Please modify your permissions.
Unfortunately, I get the same error after modifying my permissions.
If anyone has any idea why this might be happening, I would be very grateful for the help.
For app+user (delegate) permissions, the only supported scope for the /education/users collection on MSGraph is EduRoster.ReadBasic.
This supports getting an individual user's information, or information on lists of users within classes of which you are a member, but does NOT support browsing the entire set of users in a tenant, as it is deliberately a restricted scope.
If you need more than this, you would need to use app-only permissions, and sync the users into your own data store with EduRoster.Read.All, which would allow you to get all of the users.

Transfer ownership of a file fails - even as Super Administrator (Google Drive API, Java)

I am trying to transfer ownership of files to Super Administrator. The essential part of the code is shown below. The same code works if I transfer ownership of a document that I own. But in this case the original owner is another user in the same domain. [EDIT] I know there is a "transfer-ownership-of-files-from-1-user-to-another" in admin panel, but this is needed for a case when multiple files/folders, from multiple owners needs to be transferred programmatically. [/EDIT]
So the simple scenario is:
user#domain.com owns a file
the ownership needs to be transferred to the admin#domain.com (Super Administrator). The code is running in AppEngine in Java Servlet. And the Super Administrator is authenticated with OAuth.
However it throws (500 OK) exception always in line update.execute(); (showed in the end).
Is this operation impossible even for a Super Admin?
Thanks for any tips!
try {
Drive service = getDriveService();
Permission newPerm = new Permission();
newPerm.setValue("admin#domain.com");
newPerm.setType("user");
newPerm.setRole("writer");
newPerm = service.permissions().insert(fileId, newPerm).execute();
newPerm.setRole("owner");
Update update = service.permissions().update(fileId, newPerm.getId(), newPerm);
update.setTransferOwnership(true);
update.execute();
} catch (IOException e) {
e.printStackTrace();
log.severe(e.getMessage());
}
The exception thrown looks like:
SEVERE: 500 OK
{
"code" : 500,
"errors" : [ {
"domain" : "global",
"message" : "Internal Error",
"reason" : "internalError"
} ],
"message" : "Internal Error"
}
I finally got this working at least partly. Thanks #ZigMandel for the "impersonation" hint! Now I followed this Domain-wide Delegation of Authority carefully. And used the GoogleCredential created using "Service account"-key. With this credential I can impersonate the Drive API operations like adding permissions and transferring ownership to Admin, for example.
The problem that still remains is that with current Drive API it is impossible to programmatically determine the owner email address, which is needed for impersonated credential creation. Now I need to find a workaround for this. Anyway the fundamental idea works now. Thanks!
You wont be able to do it from apps script.
Can be done from appengine. Ive done it but its beyond of the scope to explain here. Involves using the drive api on behalf of the file owner and adding the oauth permissions at the domain level.