Is it possible to initiate Google Drive File Approval via API? - google-drive-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

Related

Which permissions are needed to upload files with mediawiki api?

I am using the mediawiki api to upload a file. I am sending a mutlipart POST request to
https://commons.wikimedia.org/w/api.php?format=json&action=upload&filename=xxx
In the header I include my Autherzation: Bearer accessToken123 and in the body I include my CSRF token, as well as my multipart file, all as per documentation.
However, the response I get from the server is the following:
{
"error": {
"code": "permissiondenied",
"info": "The action you have requested is limited to users in one of the groups: *, [[Commons:Users|Users]].",
"*": "See https://commons.wikimedia.org/w/api.php for API usage. Subscribe to the mediawiki-api-announce mailing list at <https://lists.wikimedia.org/postorius/lists/mediawiki-api-announce.lists.wikimedia.org/> for notice of API deprecations and breaking changes."
},
"servedby": "mw1448"
}
This would be quite self-explainatory by itself, however when I check my rights/groups with
https://commons.wikimedia.org/w/rest.php/oauth2/resource/profile
I get the following:
{"sub":xxxx,"username":"xxxxx","editcount":7,"confirmed_email":true,"blocked":false,"registered":"xxxx",
"groups":["*","user","autoconfirmed"],
"rights":["read","writeapi","viewmyprivateinfo","abusefilter-view","abusefilter-log","upload","upload_by_url","reupload-own","purge","reupload","autoconfirmed","editsemiprotected","skipcaptcha","abusefilter-log-detail","transcode-reset"],
"grants":["basic","uploadfile","uploadeditmovefile","privateinfo"],"realname":"","email":"xxxx"}
As you can see I am both a part of the required groups and also have the neccessairy upload right. The error message is quite clear, so I don't know what I am missing. It is not the CSRF token or access token, supplying these wrong results in a different error message. Any help is appreciated.
Well I finally figured it out: When requesting the app keys from mediawiki, you can select rights which the app has on behalf of the users. If you want to upload pictures to wikimedia commons, you do not only need the `
Interact with media: Upload new files; Upload, replace, and move
files
right, but also the
Create, edit, and move pages
right, since you are creating a new page with each upload. I hope this helps someone else in the future :`)

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.

/Recent does not return LastAccessedDateTime

https://graph.microsoft.com/v1.0/me/drive/recent
only returns created time and last modified time from fileSystemInfo in the response as below:
"fileSystemInfo": {
"createdDateTime": "2018-05-14T10:15:21Z",
"lastModifiedDateTime": "2018-05-14T10:15:00Z"
}
But not the lastAccessedDateTime as documented.
Does Microsoft Graph Recent API capture and include in its response a read-only file open event? Or is it limited to only the file modified or uploaded events?
I can see that FileSystemInfo class has a property called LastAccessedDateTime. If Recent API does not return this, what is the alternative way to query and retrieve it?
The lastAccessedDateTime property only applies to consumer OneDrive, not SharePoint or OneDrive for Business. From the documentation:
lastAccessedDateTime is not available for items in SharePoint online or OneDrive for Business.

Google Script returning ‘Exception: Empty Response’ when running BigQuery query via API [duplicate]

I am trying to import a list of files from Google Drive to YouTube. The meta-data and the URL to the file are in a Google spreadsheet, so I wrote some code using Google Apps Script that does the following
Get the selected rows
Retrieve title, description, Google Drive URL
Load the file from Google Drive via DriveApp.getFileById
Upload the blob to YouTube using the title and description via YouTube.Videos.insert
Update the selected row with the YouTube video id from the response
The upload looks something like this
var blob = DriveApp.getFileById(id).getBlob();
var resource = {
snippet: {
title: 'The title',
description: 'A long description ...',
defaultLanguage: 'de',
categoryId: 17,
tags: [ 'Sport', 'Fitness' ],
},
status: {
privacyStatus: 'unlisted'
}
}
try {
var result = YouTube.Videos.insert(resource, "snippet,status", blob);
return result.id;
} catch (err) {
console.log({message: 'Error ' + err.message, error: err});
}
This code has already worked about a year ago. I have adapted it slightly, but now I do not get a response from the YouTube.Videos.insert call. The following is logged inside the catch:
message: Error Empty response
error: Exception: Empty response
Not very helpful.
Before uploading, I do a YouTube.Channels.list
to get a target channel in case there are multiple channels available. For this request, I have to permit access to my data and I am only asked on the first invocation. I also see the script in the list of applications for my Google account. I assume permissions are ok.
Any suggestions on how I can get more information on the issue, or is there something I should do differently?
Regarding the target channel (and this might be a different question), I cannot really use this, as it seems I can only upload to a specific channel, if I am a YouTube content partner (see parameters onBehalfOfContentOwner and onBehalfOfContentOwnerChannel):
Note: This parameter is intended exclusively for YouTube content partners.
I had same problem in my project and here's what I have figured out: if your video file size is more than 10 Mb, you will get Empty response error.
Probably (can't say officialy because no documentation mentions it) this is happening because Google Apps Script's YouTube.Videos.insert (and all other available built-in services) uses UrlFetchApp under the hood, which have restriction of 10 Mb per call: https://developers.google.com/apps-script/guides/services/quotas#current_limitations. You can check it yourself using your sample code: if file is under 10 Mb, it will be uploaded successfully.
As possible workaround, you can use idea from this answer: https://stackoverflow.com/a/44853845/555121
Basically, you will need to open modal window using SpreadsheetApp.getUi().showModalDialog and then perform upload to YouTube via plain JavaScript inside modal dialog, which have no restrictions on transferred data size. Here's good example of YouTube resumable upload implementation: https://github.com/sangnvus/2015SUMJS01/blob/master/WIP/Sources/FlyAwayPlus/FlyAwayPlus/Scripts/youtube-upload.js

Cannot upload from Drive via YouTube Data API in Google Apps Script: empty response

I am trying to import a list of files from Google Drive to YouTube. The meta-data and the URL to the file are in a Google spreadsheet, so I wrote some code using Google Apps Script that does the following
Get the selected rows
Retrieve title, description, Google Drive URL
Load the file from Google Drive via DriveApp.getFileById
Upload the blob to YouTube using the title and description via YouTube.Videos.insert
Update the selected row with the YouTube video id from the response
The upload looks something like this
var blob = DriveApp.getFileById(id).getBlob();
var resource = {
snippet: {
title: 'The title',
description: 'A long description ...',
defaultLanguage: 'de',
categoryId: 17,
tags: [ 'Sport', 'Fitness' ],
},
status: {
privacyStatus: 'unlisted'
}
}
try {
var result = YouTube.Videos.insert(resource, "snippet,status", blob);
return result.id;
} catch (err) {
console.log({message: 'Error ' + err.message, error: err});
}
This code has already worked about a year ago. I have adapted it slightly, but now I do not get a response from the YouTube.Videos.insert call. The following is logged inside the catch:
message: Error Empty response
error: Exception: Empty response
Not very helpful.
Before uploading, I do a YouTube.Channels.list
to get a target channel in case there are multiple channels available. For this request, I have to permit access to my data and I am only asked on the first invocation. I also see the script in the list of applications for my Google account. I assume permissions are ok.
Any suggestions on how I can get more information on the issue, or is there something I should do differently?
Regarding the target channel (and this might be a different question), I cannot really use this, as it seems I can only upload to a specific channel, if I am a YouTube content partner (see parameters onBehalfOfContentOwner and onBehalfOfContentOwnerChannel):
Note: This parameter is intended exclusively for YouTube content partners.
I had same problem in my project and here's what I have figured out: if your video file size is more than 10 Mb, you will get Empty response error.
Probably (can't say officialy because no documentation mentions it) this is happening because Google Apps Script's YouTube.Videos.insert (and all other available built-in services) uses UrlFetchApp under the hood, which have restriction of 10 Mb per call: https://developers.google.com/apps-script/guides/services/quotas#current_limitations. You can check it yourself using your sample code: if file is under 10 Mb, it will be uploaded successfully.
As possible workaround, you can use idea from this answer: https://stackoverflow.com/a/44853845/555121
Basically, you will need to open modal window using SpreadsheetApp.getUi().showModalDialog and then perform upload to YouTube via plain JavaScript inside modal dialog, which have no restrictions on transferred data size. Here's good example of YouTube resumable upload implementation: https://github.com/sangnvus/2015SUMJS01/blob/master/WIP/Sources/FlyAwayPlus/FlyAwayPlus/Scripts/youtube-upload.js