I have read/write permissions to a shared folder with another Google user.
I want to list all the files (in all the folders) in that shared folder link using drive V3 API.
What is the best way to do this?
The solution currently employed is pretty slow in performance if the number of folders inside shared folders is large.
My Current solution:
1 - Finding all the folders in shared link
2 - Finding all files whose parent is folder
private void getFolderHierarchy(File Res, DriveService driveService, string localPath, string editorName, string projectName)
{
if (Res.MimeType == "application/vnd.google-apps.folder")
{
m_parent += Res.Name + #"\";
foreach (var res in ResourceFromFolder(driveService, Res.Id).ToList())
getFolderHierarchy(res, driveService, localPath, editorName, projectName);
m_parent = m_parent.Remove(m_parent.Length - Res.Name.Length - 1);
}
else if (Res.MimeType == "image/jpeg" || Res.MimeType == "image/png")
{
{
if (!m_DownloadedFromEditorFileId.Contains(Res.Id))
{
m_DownloadedGoogleFileId.Add(Res.Name);
m_parent = m_parent.Remove(m_parent.Length - Res.Name.Length);
}
}
}
}
public List<File> ResourceFromFolder(DriveService service, string folderId)
{
var request = service.Files.List();
request.PageSize = 100;
request.Q = "'" + folderId + "'" + " in parents and trashed=false";
request.Fields = "files(modifiedTime,id,parents,name,webContentLink,mimeType)";
List<File> TList = new List<File>();
do
{
var children = request.Execute();
foreach (var child in children.Files)
{
System.Threading.Thread.Sleep(10);
TList.Add(service.Files.Get(child.Id).Execute());
}
request.PageToken = children.NextPageToken;
} while (!String.IsNullOrEmpty(request.PageToken));
return TList;
}
The second option would be the best way to get the files from a shared folder. As stated in this related SO post use files/list with a parent query.
GET https://www.googleapis.com/drive/v2/files?q='FOLDERID'+in+parents&key={YOUR_API_KEY}
The speed will depend of how large/many the files under the that shared folder.
Hope this helps.
Related
path should be like shareddrive/folder/abcd.csv "folder" is a common folder in all the shared drives, if possible I want path of files in that specific folder
Path for files of All Drives from file Id
function getPathAllDrivesFromId(fileid) {
var ids = [{id:fileid,name:DriveApp.getFileById(fileid).getName()}];
let r;
do {
r = Drive.Files.get(fileid,{supportsAllDrives:true,supportsTeamDrives:true});
if(r.parents.length > 0) {
//Logger.log(JSON.stringify(r.parents[0]));
ids.push({id:r.parents[0].id,name:DriveApp.getFolderById(r.parents[0].id).getName()});
fileid = r.parents[0].id
}
}while (r.parents.length > 0);
if(ids[ids.length - 1].name == "Drive") {
ids[ids.length - 1].name = Drive.Drives.get(ids[ids.length - 1].id).name;
}
//Logger.log(JSON.stringify(ids));
let path = ids.map(obj => obj.name).flat().reverse().join(' / ')
Logger.log(path);
return path;
}
I'm trying to create a list of files stored in my Google Drive and also a list of their current and previous permissions. Specifically, I want to create a list of files in my Google Drive which at any point in the past have had the 'Anyone with a link can view/edit (etc)' permission set.
I have created a Google Apps Script to do this and I can iterate through all the files OK and I can get files which currently have that permission set, but I can't see a way to get the history of the file's permissions.
I have found and activated the revisions list API: https://developers.google.com/drive/api/v2/reference/revisions/list
This gets revisions but I can't see anywhere that it lists the sharing history of a revision.
Is what I'm attempting to do possible?
It's definitely possible using the Drive Activity API. You can use the Quickstart for Google Apps Script to view all the activity of an item (file or folder) or done by a User. In this case I modified the Quickstart to show the Permissions changes of a given Drive Id.
function listDriveActivity() {
var request = {
itemName: "items/1bFQvSJ8pMdss4jInrrg7bxdae3dKgu-tJqC1A2TktMs", //Id of the file
pageSize: 10};
var response = DriveActivity.Activity.query(request);
var activities = response.activities;
if (activities && activities.length > 0) {
Logger.log('Recent activity:');
for (var i = 0; i < activities.length; i++) {
var activity = activities[i];
var time = getTimeInfo(activity);
var action = getActionInfo(activity.primaryActionDetail);
var actors = activity.actors.map(getActorInfo);
var targets = activity.targets.map(getTargetInfo);
if (action == "permissionChange"){ //Only show permissionChange activity
Logger.log(
'%s: %s, %s, %s', time, truncated(actors), action,
truncated(targets));
}
}
} else {
Logger.log('No activity.');
}
}
/** Returns a string representation of the first elements in a list. */
function truncated(array, opt_limit) {
var limit = opt_limit || 2;
var contents = array.slice(0, limit).join(', ');
var more = array.length > limit ? ', ...' : '';
return '[' + contents + more + ']';
}
/** Returns the name of a set property in an object, or else "unknown". */
function getOneOf(object) {
for (var key in object) {
return key;
}
return 'unknown';
}
/** Returns a time associated with an activity. */
function getTimeInfo(activity) {
if ('timestamp' in activity) {
return activity.timestamp;
}
if ('timeRange' in activity) {
return activity.timeRange.endTime;
}
return 'unknown';
}
/** Returns the type of action. */
function getActionInfo(actionDetail) {
return getOneOf(actionDetail);
}
/** Returns user information, or the type of user if not a known user. */
function getUserInfo(user) {
if ('knownUser' in user) {
var knownUser = user.knownUser;
var isMe = knownUser.isCurrentUser || false;
return isMe ? 'people/me' : knownUser.personName;
}
return getOneOf(user);
}
/** Returns actor information, or the type of actor if not a user. */
function getActorInfo(actor) {
if ('user' in actor) {
return getUserInfo(actor.user)
}
return getOneOf(actor);
}
/** Returns the type of a target and an associated title. */
function getTargetInfo(target) {
if ('driveItem' in target) {
var title = target.driveItem.title || 'unknown';
return 'driveItem:"' + title + '"';
}
if ('drive' in target) {
var title = target.drive.title || 'unknown';
return 'drive:"' + title + '"';
}
if ('fileComment' in target) {
var parent = target.fileComment.parent || {};
var title = parent.title || 'unknown';
return 'fileComment:"' + title + '"';
}
return getOneOf(target) + ':unknown';
}
Remember to enable the Drive Activity API in Resources > Advanced Google Services
In my example this returns the logs:
You can also look deeper into the Permissions by using the permissionChange Parameters in the query.
If you have a business/enterprise/edu account the admin audit logs will tell you this for 6 months of data. Or it will at least tell you when a permission was changed from x to y.
Can't think of a method for personal.
I am making a feature in my Java backend to create a Google Sheet.
Now in that backend, it already has a function to create Google Docs and it is working well. Following is the function to create a Google Doc.
public String createFileFromHtml(Project project, String html) throws DocumentGatewayException {
// Determine the google drive ID for the given areaId
String areaId =
Strings.isNullOrEmpty(project.getAreaId()) ? Constants.TEST_AREA : project.getAreaId();
String areaGoogleDriveId = null;
try {
if (areaIdToGoogleDriveIdMap.isEmpty() || !areaIdToGoogleDriveIdMap.containsKey(areaId)) {
String pageToken = null;
do {
String query = "'" + ERD_GOOGLE_DRIVE_ID + "' in parents";
query += " and mimeType = '" + FOLDER_MIME_TYPE + "'";
query += "and trashed = false";
FileList result =
drive
.files()
.list()
.setQ(query)
.setPageToken(pageToken)
.setFields("nextPageToken, files(id, name)")
.execute();
for (File file : result.getFiles()) {
areaIdToGoogleDriveIdMap.put(file.getName(), file.getId());
}
pageToken = result.getNextPageToken();
} while (pageToken != null);
}
} catch (IOException e) {
throw new DocumentGatewayException(e);
}
areaGoogleDriveId = areaIdToGoogleDriveIdMap.get(areaId);
Preconditions.checkArgument(
!Strings.isNullOrEmpty(areaGoogleDriveId), areaId + " needs to have a google drive folder");
// Generate metadata to be used to create the file using the google drive ID above.
File fileMetadata = new File();
fileMetadata.setName(project.getTitle());
fileMetadata.setMimeType("application/vnd.google-apps.document");
fileMetadata.setParents(Collections.singletonList(areaGoogleDriveId));
try {
// Create file.
File file =
drive
.files()
.create(
fileMetadata,
new ByteArrayContent("text/html", html.getBytes(StandardCharsets.UTF_8)))
.setFields("id")
.execute();
// Make all authors writers
if (!project.getAuthorIds().isEmpty()) {
for (String authorId : project.getAuthorIds()) {
processor.setWritter(project.getUuid(), file.getId(), authorId, 0);
}
// Set owner
String authorId = EmailUtils.AuthorNameToEmail(project.getAuthorIds().get(0));
processor.setOwner(project.getUuid(), file.getId(), authorId, 0);
}
// Set commenter
processor.setCommenter(project.getUuid(), file.getId(), 0);
return file.getId();
} catch (IOException e) {
logger.error(
"Error creating document", KeyValue.string("project_uuid", project.getUuid()), e);
throw new DocumentGatewayException(e);
}
}
I wanted to create a Google Sheet instead. So I tried changing application/vnd.google-apps.document to application/vnd.google-apps.spreadsheet. But after this change, it was still creating Google Doc instead of Google Sheet.
So anyones knows why? I just need to create a Google Sheet.
Google Drive API version: google-api-services-drive-v3-rev130-1.25.0
Thanks.
How can retrieve only shared calendar using Exchange EWS API.
How can i know which calendar is shared using Exchange EWS API.
You can just specify the calendar, which you want to acces in your FolderId.
FolderId folderIdFromCalendar = new FolderId(WellKnownFolderName.Calendar, "sharedInbox#example.com");
You can then use the folderIdFromCalendar for retrieving the calendar items, you want, e.g.:
FindItemsResults<Item> appointments = ExchangeServive.FindItems(folderIdFromCalendar, ItemView);
Remember that the program has to be run in the context of a user, which the mailbox is shared with.
Update:
If you happen to know the FolderId, you can just check, if the current user has access to this calendar by performing this code:
As above, you will need to initialize a FolderId:
FolderId folderIdFromCalendar = new FolderId("AQMkADAwATM3ZmYAZS1kNjE0LWU1ZmQtMDACLTAwCgAuAAADJRMtiupYBUGDcKdcqUrr3AEA1/sqwbrwUEeFM0Mc+UBFoQAAABzkm1sAAAA=");
After that, try the following code:
if (folderIdFromCalendar != null)
{
try
{
ItemView cView = new ItemView(1000);
FindItemsResults<Item> appointments = service.FindItems(folderIdFromCalendar, cView);
int count = appointments.TotalCount; //just an example of some random action on the folder calendar
}
catch (ServiceResponseException ex)
{
Console.WriteLine("The specified calendar was not shared with you. \n" + ex);
}
}
else
{
Console.WriteLine("The specified calendar ID could not be linked to a calendar folder.");
}
Another Update:
if (folderIdFromCalendar != null)
{
if (folderIdFromCalendar.Mailbox.ToString().ToLower() == "your-Mailadress".ToLower())
{
Console.WriteLine("The folder you specified is your own");
}
else
{
try
{
ItemView cView = new ItemView(1000);
FindItemsResults<Item> appointments = service.FindItems(folderIdFromCalendar, cView);
int count = appointments.TotalCount; //just an example of some random action on the folder calendar
Console.WriteLine("You have been given access to this mailbox. Its owner is: " + folderIdFromCalendar.Mailbox.ToString()); //if you need to know, whos mailbox you are accessing right now
}
catch (ServiceResponseException ex)
{
Console.WriteLine("The specified calendar was not shared with you. \n" + ex);
}
}
}
else
{
Console.WriteLine("The specified calendar ID could not be linked to a calendar folder.");
}
Last Update:
I have googled quite a bit now and found something that worked for me. But to be perfectly honest, I don't understand everything, which is going on in the following code:
FolderId folderIdFromCalendar = new FolderId("AQMkADAwATM3ZmYAZS1kNjE0LWU1ZmQtMDACLTAwCgAuAAADJRMtiupYBUGDcKdcqUrr3AEA1/sqwbrwUEeFM0Mc+UBFoQAAABzkm1sAAAA=");
Folder folderFromCalendar = Folder.Bind(service, folderIdFromCalendar);
AlternateId aiAlternateid = new AlternateId(IdFormat.EwsId, folderFromCalendar.Id.UniqueId, "random#mailadress.com");
AlternateIdBase aiResponse = service.ConvertId(aiAlternateid, IdFormat.EwsId);
var mailbox = ((AlternateId)aiResponse).Mailbox;
if (folderFromCalendar != null)
{
if (mailbox.ToString().ToLower() == "your-Mailadress".ToLower())
{
Console.WriteLine("The folder you specified is your own");
}
else
{
try
{
ItemView cView = new ItemView(1000);
FindItemsResults<Item> appointments = service.FindItems(folderIdFromCalendar, cView);
int count = appointments.TotalCount; //just an example of some random action on the folder calendar
Console.WriteLine("You have been given access to this mailbox. Its owner is: " + mailbox.ToString());
}
catch (ServiceResponseException ex)
{
Console.WriteLine("The specified calendar was not shared with you. \n" + ex);
}
}
}
else
{
Console.WriteLine("The specified calendar ID could not be linked to a calendar folder.");
}
I don't understand, how the string "random#mailadress.com" affects anything in that program, but the syntax needs a string there.
I need to create sub folders in google drive using google drive api added using nuget package in console application.
I can get the folder id of root folder. Can get children of rot folder, can also upload file in root folder. Only problem is creation of sub folders in folders.
for (int i = 1; i < array.Count(); i++)
{
var subfoldername = new Google.Apis.Drive.v2.Data.File { Title = array[i], MimeType = "application/vnd.google-apps.folder" };
ChildrenResource.ListRequest request = service.Children.List(rootfolderid);
ChildList children = request.Execute();
if (children.Items.Count > 0)
{
foreach (ChildReference c in children.Items)
{
Google.Apis.Drive.v2.Data.File file = service.Files.Get(c.Id).Execute();
if (file.MimeType == "application/vnd.google-apps.folder")
{
List<GoogleDriveFile> googledrive = new List<GoogleDriveFile>();
googledrive.Add(new GoogleDriveFile
{
OriginalFilename = file.OriginalFilename
});
}
}
}
else
{
// here need to add sub folder in folder, but this line adds folder at root
var result = service.Files.Insert(foldername).Execute();
}
Here is the way i do, when creating a sub folder in google drive it must need a parents. So before execute the string q, we need to search for the parent root id
string findRootId = "mimeType = 'application/vnd.google-apps.folder' and title ='" + RootFolder + "' and trashed = false";
IList<File> _RootId = GoogleDriveHelper.GetFiles(service, findRootId);
if (_RootId.Count == 0) {
_RootId.Add(GoogleDriveHelper.createDirectory(service, RootFolder, "", "root"));
Console.WriteLine("Root folder {0} was created.", RootFolder);
}
var id = _RootId[0].Id;
string Q = "mimeType = 'application/vnd.google-apps.folder' and '" + id + "' in parents and title ='" + GoogleDriveFolderName + "' and trashed = false";
You must add the property parents while creating a Folder.
parents[]
Collection of parent folders which contain this file.
Setting this field will put the file in all of the provided folders. On insert, if no folders are provided, the file will be placed in the default root folder.
Sample Code:
function createSubFolder() {
var body = new Object();
body.title = 'SubFolder';
body.parents = [{'id':'0B5xvxYkWPFpCUjJtZVZiMWNBQlE'}];
body.mimeType = "application/vnd.google-apps.folder";
console.log(body)
var request = gapi.client.request({
'path': '/drive/v2/files',
'method': 'POST',
'body': JSON.stringify(body)
});
request.execute(function(resp) { console.log(resp); });
}
I'm using Drive v2 in JavaScript
Hope this helps