When does the files get deleted from Google Drive Service account? - google-drive-api

I wanted to know how long does a file in google drive service account stay?
I couldn't find its default expiration time. As I don't have control over the account, how can I know the file is deleted or if no way, Do I have to delete the files from service account myself?

since you don't have control over the account, I don't see how you can actually delete the files owned by that account. the file will stay there as long as the owner not deleting it.
https://support.google.com/drive/answer/2375102
Put a file in trash
To remove a file from your Drive, you can put it
in your trash. Your file will stay there until you empty your trash.
If you're the owner of the file, others can view it until you
permanently delete the file. If you're not the owner, others can see
the file even if you empty your trash.

It is the same how a user creates a file (no expiration date). To know any changes like if it is deleted, you can check the Change Feed to retrieve the changes.
Changes: list
Lists the changes for a user.
Detect Changes
For Google Drive apps that need to keep track of changes to files, the Changes collection provides an efficient way to detect changes to all files, including those that have been shared with a user. The collection works by providing the current state of each file, if and only if the file has changed since a given point in time.
You can delete the files using the Service Account given that it is the owner of the file. You can also check this SO question regarding how to check if a file/folder is deleted.

The files are there to stay until you delete them yourself.
You can always get the file list from the google drive API (I use V3) and get the files list with their ID and delete whichever you want. You can't yet do it via web interface.
Below is an example is c# on how to get the files list:
public List<Google.Apis.Drive.v3.Data.File> GetFilesList(string SearchQ = null)
{
List<Google.Apis.Drive.v3.Data.File> ListOfFiles = new List<Google.Apis.Drive.v3.Data.File>();
FilesResource.ListRequest listRequest = _CurrentDriveService.Files.List();
listRequest.PageSize = 1000;
if (SearchQ != null)
{
listRequest.Q = SearchQ; //("'PARENT_ID' in parents");
}
listRequest.Fields = "nextPageToken, files(id, name,parents,mimeType,size,capabilities,modifiedTime,webViewLink,webContentLink)";
FileList fileFeedList = listRequest.Execute();
while (fileFeedList != null)
{
foreach (File file in fileFeedList.Files)
{
ListOfFiles.Add(file);
}
if (fileFeedList.NextPageToken == null)
{
break;
}
listRequest.PageToken = fileFeedList.NextPageToken;
fileFeedList = listRequest.Execute();
}
return ListOfFiles;
}
and how to delete a particular file:
public bool DeleteFileFromDrive(string FileID) // only to be used when you are the owner of the file. Otherwise it will have no effect.
{
try
{
FilesResource.GetRequest gr = new FilesResource.GetRequest(_CurrentDriveService, FileID);
var FileData = gr.Execute();
if (FileData.MimeType == GoogleDriveMimeTypes.GetFolderMimeTypeString())
{
var filesInFolder = GetFilesList("'" + FileID + "' in parents");
if (filesInFolder.Count > 0)
{
// directory is not empty
return false;
}
}
var requestD = _CurrentDriveService.Files.Delete(FileID);
requestD.Execute();
return true;
}
catch (Exception e)
{
System.Diagnostics.Debug.WriteLine(e.Message);
return false;
}
}

What I figured out was that if you delete the file from service account using API(and because service account is the owner of that file), it will be deleted from all the Shared Drive Sections of the users who access the file. Thanks #some1, #MrRebot and #Hadar Ben David for helping me come up with this conclusion.

Related

Why do I get an empty 200 OK response when uploading a file to a shared Google Drive folder when using a service account?

I am trying to use a Service Account to upload a file into a shared Google Drive folder, using Google Drive API v3 and the .Net client. The service account is added to the folder and "Can organise, add and edit". And if I do a list request I get the folder back (so I know the service account authentication works and that it at least has access to the shared folder).
If I try to upload a file though, I get a 200 response (so no error) but with an empty ResponseBody. And if I list again, the file isn't there. I don't understand what this means or why it is happening and can't find any information about this situation anywhere.
Here's my upload code. [PARENT_ID] is the ID of the shared folder and I've got the content of the CSV file I'm uploading and converted into bytes to put into the stream I've then sent.
using (var driveService = new DriveService(new BaseClientService.Initializer()
{
HttpClientInitializer = googleCredential.CreateScoped(DriveService.Scope.Drive),
ApplicationName = "FunctionApp"
}))
{
File fileMetadata = new File()
{
Name = "FileName",
MimeType = "application/vnd.google-apps.spreadsheet",
Parents = new List<string>() { "[PARENT_ID]" }
};
FilesResource.CreateMediaUpload request;
using (var csvStream = new MemoryStream())
{
csvStream.Write(csvBytes);
request = driveService.Files.Create(
fileMetadata, csvStream, "text/csv");
}
request.Fields = "id";
request.Upload();
var file = request.ResponseBody;
Console.WriteLine("File ID: " + file.Id);
}
The file variable is always null so obviously file.Id throws a NullReferenceException.
I've been staring at this for hours but have not been able to work out what is wrong. Any ideas?
I've tried saving the csv string to a file a then reading it in a file stream (closer to the example at the bottom of https://developers.google.com/drive/api/v3/manage-uploads#import_to_google_docs_types_) but this yields the same result.
Note: I've been able to create a file in the same folder using the "Try this API" tool on https://developers.google.com/drive/api/v3/reference/files/create using the parameters the same as what I pass in the metadata here, but of course that doesn't use a service account and doesn't pass any actual data to the file.
Thanks to #JonSkeet for the solution on GitHub (https://github.com/googleapis/google-api-dotnet-client/issues/1490)
The problem was that the stream was being disposed before the upload (ie after the using). The code change was to not use a using at all.
var csvStream = new MemoryStream(csvBytes);
request = driveService.Files.Create(fileMetadata, csvStream, "text/csv");
var result = request.Upload();
This did a successful upload as expected.
This also didn't use the request.Fields although this could maybe have been left in.

Google Drive API V3 - Some folders with Root Parents show under a different folder in Google Drive UI

In C# (Visual Studio 2015), the code, below, lists the folders with 'root' as the parents id. However, when I go to the Google Drive UI (drive.google.com), some of the folders listed, appear within other, non-root, folders. I've looked at the properties of those folders in C# and see nothing to indicate the discrepancy. I'm obviously missing something. Any ideas?
It's possible that I originally created the folders in question in the root and then moved them to the sub-folder, so it's maintaining its original Parents. Even so, how is the UI positioning them properly, but the API doesn't give me any indication that it should be elsewhere?
FilesResource.ListRequest listRequest = service.Files.List();
listRequest.PageSize = 100;
listRequest.Fields = "nextPageToken, files(*)";
listRequest.Q = " ('root' in parents) and mimeType = 'application/vnd.google-apps.folder' ";
listRequest.OrderBy = "name";
listRequest.Spaces = "drive";
// List files.
IList<Google.Apis.Drive.v3.Data.File> files = listRequest.Execute().Files;
Console.WriteLine("Files:");
if (files != null && files.Count > 0)
{
foreach (var file in files)
{
Console.WriteLine("{0} ({1})", file.Name, file.Id);
}
}
else
{
Console.WriteLine("No files found.");
}
Console.Read();
It occurred to me to look at the value of the "WebViewLink" property for these folders. When I used the link to navigate to them, I discovered they were in "Trash". Then I noticed that the "Trashed" property is True. There are two non-Trashed folders with the same name and I assumed those were the ones it was pointed at. Wrong assumption.
Changed the query value to:
listRequest.Q = " ('root' in parents) and mimeType = 'application/vnd.google-apps.folder' and trashed=false";

Accessing Files and Folders in Team Drive

I'm using Google Apps Script and V2 of the Drive API (I don't think V3 is available in scripts yet) to automate file creation inside of a Team Drive. I'd like to add editors with the script with no success.
I can access the Team Drive and child folders using the FolderIterator in the standard DriveApp methods.
Attempt 1
function addUserToTeam(email, folders) {
// Open the team drive and get all the folders
var teamFolders = DriveApp.getFolderById('TEAMDRIVEIDSTRING').getFolders();
var folders = ["folderIdToMatch"] // This may hold multiple folders
try {
// Loop an array of folder IDs
for(var i=0; i<folders.length; i++) {
// Check the team drive folders for a matching name
while(teamFolders.hasNext()) {
var teamFolder = teamFolders.next();
if(folders[i] == teamFolder.getId()) {
teamFolder.addEditor(email);
}
}
}
} catch(e) {
Logger.log(e);
}
}
This failed with Exception: Cannot use this operation on a Team Drive item.
Attempt 2
I tried the Drive API by substituting teamFolder.addEditor(email) a Permissions resource:
if(folders[i] == teamFolder.getId()) {
var resource = {
"type":"user",
"role":"writer",
"value": email
}
Drive.Permissions.insert(resource, teamFolder.getId());
}
This fails with a File not found error.
I can find the folder (or file) with DriveApp methods. Any attempt at the same with the Drive API fails.
I cannot find any documentation saying Team Drive files are inaccessible with the API. Is there something wrong with my approach?
After more research and digging, here's the solution for people with similar use cases.
You can access files to an entire Team Drive or to files inside the Drive, but not folders. This is done on purpose to prevent accidentally giving access to directories of sensitive information to people who shouldn't have access.
To give access, supportsTeamDrives is an optional argument in the request body that takes a boolean value. Set this to true and pass in the API call. A successful function is below.
The only way to achieve the outcome I described is to use multiple Team Drives and give access to users based on some event. Another option would be to promote a user to Full permissions (from edit or view) for the duration of the project and then revoke when completed.
Add a user to a Team Drive
(This also works for single files in a Drive)
// Using Google Apps Script with v2 of the Drive API enabled
function addToTeamDrive() {
var resource = {
'value': emailString,
'type': 'user',
'role': 'writer'
}
// If you have several Team Drives, loop through and give access
try {
var TeamDrive = Drive.Teamdrives.list();
for(var i = 0; i < TeamDrive.items.length; i++) {
if(TeamDrive.items[i].name === "Team Drive String") {
// This ID may also be a single file inside a Team Drive
var id = TeamDrive.items[i].id;
}
}
// Add user permissions to the matched Drive
Drive.Permissions.insert(resource, id, {"supportsTeamDrives": true});
} catch(e) {
Logger.log(e);
}
}
You can access but there's alot you can't do like removeFile() or getUrl() even when you have full access. You will still get the
{error: "Exception: Cannot use this operation on a Team Drive item."}
Workaround is to use setTrashed() instead of removeFile() on files/folders.

Google apps script to delete old files permanently and keep last 100 files

I created a folder in my root google Drive that contains video files (.avi). I need to write a google apps script to delete the old video files permanently when the total numbers of the files are more than 100 files? i.e deleting all video files except last (newer) 100 files.
The name for each file is related to the time that this file were created example: 2013-02-25__20-29-45-01.avi
2013-02-25__20-24-49-09.avi
2013-02-25__18-26-24-08.avi
......
So I think the script should first list these files alphabetical starting with the newer and ended with the old one, then keep first 100 files and delete all others permanently.
I know how to do that in bash script, but not in google drive which I think they use javascript (.gs).
As I said in the comments, the script you referred to was not very far from what you want... but I admit your situation is a bit more complex so let's say this will be another exception to sto politics ;-)
That said, I didn't test this code thoroughly so it will probably need some tuning. I left a couple of commented logs throughout the script to test intermediate results, don't hesitate to use them. Also, think about updating the mail adress and don't forget that setTrashed can be manually reversed ;-) (better so when trying new code)
EDIT : I took some time this morning to test the script, it had a couple of "approximations";-)
here is a "clean" version that works nicely
function DeleteMyOldAvi() {
var pageSize = 200;
var files = null;
var token = null;
var i = null;
var totalFiles = []
var toDelete = []
Logger.clear()
do {
var result = DocsList.getAllFilesForPaging(pageSize, token);
var files = result.getFiles()
var token = result.getToken();
for(n=0;n<files.length;++n){
if(files[n].getName().toLowerCase().match('.avi')=='.avi'){
totalFiles.push([files[n].getName(),files[n].getDateCreated().getTime(),files[n].getId()]);// store name, Date created in mSec, ID in a subarray
// Logger.log(files[n].getName()+' created on '+Utilities.formatDate(files[n].getDateCreated(), 'GMT','MMM-dd-yyyy'))
}
}
} while (files.length == pageSize);// continue until job is done
totalFiles.sort(function(x,y){ // sort array on milliseconds date created (numeric/descending)
var xp = x[1];
var yp = y[1];
return yp-xp ;
});
// Logger.log(totalFiles.length)
if(totalFiles.length>100){
for(nn=totalFiles.length-1;nn>=100;nn--){
toDelete.push(totalFiles[nn]) ;// store the files to delete
}
// Logger.log(toDelete)
for(n=0;n<toDelete.length;++n){
var file = toDelete[n]
DocsList.getFileById(file[2]).setTrashed(true);// move to trash each file that is in the toDelete array
Logger.log(file[0]+' was deleted');// log the file name to create mail message
}
MailApp.sendEmail('myMail#gmail.com', 'Script AUTODELETE report', Logger.getLog());// send yourself a mail
}else{
MailApp.sendEmail('myMail#gmail.com', 'Script AUTODELETE report', 'No file deleted');// send yourself a mail
}
}

How to delete/overwrite CSV file using google apps script?

My google apps script imports a csv file [test.csv] into a new tab, manipulates some values, then saves the manipulated tab as a csv file [test.csv]. When it saves the new version, it simply makes another copy [test(1).csv]. I wish instead to overwrite the previous file (or delete the old one then export/write the new version.) Help please?
I am using reference code from the Interacting With Docs List Tutorial
I know this is an old question, but much of the information in the accepted answer has been deprecated by Google since then. DocsList is gone, as are the clear() and append() methods on a file object.
I use the following function to create or overwrite a file:
// Creates or replaces an existing file
function updateFile (folder, filename, data) {
try {
// filename is unique, so we can get first element of iterator
var file = folder.getFilesByName(filename).next()
file.setContent(data)
} catch(e) {
folder.createFile(filename, data)
}
}
For reference, here's some code for doing the same for a folder. It assumes we're operating in the parent folder of the current sheet and want a folder
object for a new or existing folder there.
// Get folder under current folder. Create it if it does not exist
function getOrCreateFolder(csvFolderName) {
var thisFileId = SpreadsheetApp.getActive().getId();
var thisFile = DriveApp.getFileById(thisFileId);
var parentFolder = thisFile.getParents().next();
try {
// csvFolderName is unique, so we can get first element of iterator
var folder = parentFolder.getFoldersByName(csvFolderName).next();
// asking for the folder's name ensures we get an error if the
// folder doesn't exist. I've found I don't necessarily catch
// an error from getFoldersByName if csvFolderName doesn't exist.
fname = folder.getName()
} catch(e) {
var folder = parentFolder.createFolder(csvFolderName);
}
return folder
}
You could do DocsList.find(fileName) which gives you a list of files that have that name. If file names are unique, then you can just do var file = DocsList.find(fileName)[0].
If you are a Google Apps user, you can use file.clear() to remove all the contents of the old file, and then file.append() to insert all of the new contents.
Otherwise, you will have to file.setTrashed(true) and then DocsList.createFile() to make the new one.