I was reading about third party shortcuts in Google Drive and able to create a file in Google Drive with the sample payload mentioned in the link.
var fileMetadata = new File()
{
Name = "Project plan",
MimeType = "application/vnd.google-apps.drive-sdk"
};
var request = driveService.Files.Create(fileMetadata);
request.Fields = "id";
var file = request.Execute();
Console.WriteLine("File ID: " + file.Id);
What I am not able to get is where can I set the external file URL here? Or how does it even work?
Answer
It is up to the third-party to handle the redirect to the relevant file for which a shortcut points to. This is done with the Google Drive File ID.
More Information:
Google Drive shortcuts are used to link a file, the contents of which are stored elsewhere than on Drive, such as a third party web app. This isn't done through links, as Drive shortcuts contain no content and are made using the file metadata endpoint.
When you make a Third-party shortcut using the Files.Create method as you show above, the indicative information of the fact it is a shortcut is by the application/vnd.google-apps.drive-sdk mimeType, using the POST URL for inserting file metadata:
POST https://www.googleapis.com/drive/v3/files
Authorization: <AUTHORIZATION HEADER>
{
"title": "File's title",
"description": "File's description",
"mimeType": "application/vnd.google-apps.drive-sdk"
}
When the shortcut is clicked, you will then get redirected to the third party web site from which the file was created - the Google Drive File ID is contained inside the ?state query parameter, as per the documentation on Open Files.
The important thing to know is that it is completely up to the third-party app/website to use Google Drive File ID in the ?state parameter to match the file and content they have stored.
References:
Create a shortcut to an external file
Handle an Open URL
Files: create | Google Drive API | Google Developers
Configure a Drive UI Integration
Related
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.
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"
the scenario is like this. I have a file in Google Drive, then share it to public, but not the direct link to my file. see sample here https://ganool.ag/steve-jobs-2015-bluray-720p-ganool-ag/ | scroll down and find link https://file.rocks/file/jBH0tM97Ne (ignore the pirate movie in the link, it's just sample). When you click the link, the file will be copied to your drive account, save in a folder called File.rocks, than a subfolder with random name.
my question is, what API command used in that script? just the concept, not the complete script.
sorry for my english.
The behavior shown in that website is similar to the Save to Drive button which allows the user to save files to their Drive account from an arbitrary URL via their browser.
The technology used to upload files is similar to that used by the Google Drive web user interface. The file is downloaded to the user's browser in parts and uploaded to Google Drive as data is received.
Authorize your app to get code
exchange code for token
create client-folder-id if not exist
then use copy
for example:
POST https://www.googleapis.com/drive/v3/files/<your-file-id>/copy
Authorization: Bearer token...xxxxxx
{
"parents": [
"<client-folder-id>"
]
}
If you create a non-container bound g-apps script (i.e. not as part of a gDoc or a gSheet), you can download it (however not view as a .json directly in the browser from the link) from gDrive as a .json. If you download a gDoc or gSheet, it converts to xlsx or docx and opening these with a zip viewer shows a number of files (many of type xml) however none contain the Google version's attached scripts.
Is there a way to read script files as a .json from within another Google Apps
Script? perhaps using the Drive-API or with g-a-s. DriveApp class?
Is there a way to download or read through DriveApp, the .jsons of
container bound scripts (which are usually invisible from all but within the original gFile)?
Update
Based on Kriggs, added a Logger.log(link) and this works great for stand-alone scripts.
How about for container-bound?
for stand alone script files:
exportLinks={
application/vnd.google-apps.script+json=
script.google.com/feeds/download/export?id=[scriptId]&format=json
}
for container-bound script files, there are links to csv, sheet and pdf, but no script json.
exportLinks= {
text/csv=docs.google.com/spreadsheets/export?id=[sheetId]&exportFormat=csv,
application/vnd.openxmlformats-officedocument.spreadsheetml.sheet=
docs.google.com/spreadsheets/export?id=[sheetId]exportFormat=xlsx,
application/pdf=
docs.google.com/spreadsheets/export?id=[sheetId]&exportFormat=pdf
}
Update
In Google sheet, go to Tools->script Editor->
URL in address bar looks like:
https://script.google.com/macros/d/
[ProjectKey]/edit?uiv=2&mid=[aVeryLongAlphaNum]
this is the download json:
https://script.google.com/feeds/download/export?id=[ProjectKey]
Question is, can we use the Drive API to find [ProjectKey]
Have there been any feature requests for DriveApp/Drive-API methods to seek Project Keys in your account?
Would there be a way to test if a file has a container bound script? Then the question is, is the script included in the file size (this can be easily tested, however it is unknown to the asker at this point).
Something like this may work although it looks computationally costly:
var SizeOfFile = yourFile.getSize();//
var charsInFile = yourFile.getAsString();
var unicodeSizeReference = [];//get bytes per character array
charsInFile.sort()
//find frequency of characters then multiply from unicoseSizeReference.
//there could be other gotchas as well, however this is just testing for feasibility
var SizeOfTextInFile = [/*#of chars in file name and sheetname*/]+[/*#of chars in all sheets*/];
SizeOfTextInFile *= unicodeBytesPerCharacter;//ranges from 1 to 4
var someThreshold = 10;//bytes
var hasScript=0;
if ([SizeOfFile - SizeOfTextInFile] > someThreshold) hasScript=1
Yes you have to get it trough the Drive API with OAuth2, I used the DriveApp to get the fileId, but you can modify to use Drive api aswell. To enable the Drive API go to Resources -> Advanced Google Services, find the Drive API and turn on.
When you send a get with Drive you get back an object of the file which contains the property exportLinks, using it you fetch the URL with OAuth2 authentication (the ScriptApp.getOAuthToken()), the fetched string will be a JSON, which has the Array fileswith the colection of scripts.
function getAppsScriptAsJson( fileName ) {
var fileDrive = Drive.Files.get( DriveApp.getFilesByName( fileName ).next().getId() );
var link = JSON.parse(fileDrive)[ 'exportLinks' ][ 'application/vnd.google-apps.script+json' ];
var fetched = UrlFetchApp.fetch(link, {headers:{'Accept':'application/vnd.google-apps.script+json', "Authorization":'Bearer '+ScriptApp.getOAuthToken()}, method:'get'});
return JSON.parse(fetched.getContentText());
}
As for container bound:
DriveApp can't get it by name
It doesn't display an ID anywhere, just the project key
Drive API can't lookup by the project id, nor DriveApp
Drive API can't find by the name
There's no reference of the script from the returned object from Drive API nor the DriveApp
I guess it is pretty much incognito, doubt there's any way ATM.
You can always make a Standalone app and set it as a library for the Spreadsheet...
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);
}
}