Problem:
Files get pulled automatically from my emails to a folder on my Google Drive.
The files are automatically given a name, which was the subject of the email, e.g. "Beach". Multiple files can thus have the same name if emails have the same subject name.
Once the files have landed in Google Drive, I want to move the files, say the ones called "Beach", to another folder called "Beach".
What is the best way to do this? I have tried using scripts, lists of folders/ID/file names etc in spreadsheets, yet can't quite get it.
According to this article, you can use Google Apps Scripts to move files across folders.
function moveFiles(source_folder, dest_folder) {
var files = source_folder.getFiles();
while (files.hasNext()) {
var file = files.next();
dest_folder.addFile(file);
source_folder.removeFile(file);
}
}
Here are some related threads which might help:
Google Drive: Move file to folder
SCRIPT TO MOVE FILES FROM MYDRIVE TO ANOTHER FOLDER IN GOOGLE DRIVE
This is what I use and it works well
The_unique_File_id is the part after drive.google.com/drive/folders/ the letters and numbers
function copyFiles(source_folder, dest_folder) {
var source_folder = DriveApp.getFolderById('The_unique_File_id');
var dest_folder = DriveApp.getFolderById('The_unique_File_id');
var files = source_folder.getFiles();
while (files.hasNext()) {
var file = files.next();
dest_folder.addFile(file);
source_folder.removeFile(file);
}
}
Related
I'm creating a project of a school. I want to show the uploaded stuff by teachers to students.
But I also need to save the file in the folder which is named as faculty name. Student will be able to browse the main directory and after that he can go in the particular faculties folder.
How can I do it? Any suggestions will be appreciated.
For file upload I would start with example like in this answer. Moving files from temporary folder could be easily done by the file uploading action.
For browsing files in your case I would create an action that is able to navigate to the folder where the files are and get a list of files from that folder. Something like this
String file = application.getRealPath("/upload");
File f = new File(file);
String [] fileNames = f.list();
File [] fileObjects= f.listFiles();
for (int i = 0; i < fileObjects.length; i++) {
if(!fileObjects[i].isDirectory()){
String fname = file+fileNames[i];
out.println(fileNames[i]);
}
}
Then map this files to the JSP as links. When that link is clicked you can retrieve the actual path on the server when action is executed. What to do with the data, of course you can return stream result from the action that is used for streaming to the client browser. You can use docs examples from the Struts site or like in this example.
To navigate to the folder use parameters in GET request, that will be used to store current directory in session. You can change it if a user change the current directory from the view layer.
I'm wondering if it's possible to download a file from Google Cloud Storage with a different name than the one that has in the bucket.
For example, in Google Cloud Storage I have stored a file named 123-file.txt but when I download it I would like choose a different name, let's say file.txt
I've noticed that the link for download it is like:
https://storage.cloud.google.com/bucket_name%2F123-file.txt?response-content-disposition=attachment;%20filename=123-file.txt
So I've tried to change it to:
https://storage.cloud.google.com/bucket_name%2F123-file.txt?response-content-disposition=attachment;%20filename=file.txt
But it still keeps downloading as 123-file.txt instead of file.txt
The response-content-disposition parameter can only be used by authorized requests. Anonymous links don't work with it. You have a few options:
The content-disposition of a particular object is part of its metadata and can be permanently set. If you always want a specific file to be downloaded with a specific name, you can just permanently set the content-disposition metadata for the object.
You can also generate signed URLs that include the response-content-disposition query parameter. Then the users will be making authorized requests to download the resource.
example (first option Brandon Yarbrough) with javascript library:
const storage = new Storage()
const fileBucket = storage.bucket('myBucket')
const file = fileBucket.file('MyOriginalFile.txt')
const newName = "NewName.txt"
await file.save(content, {
metadata: {
contentDisposition: `inline; filename="${newName}"`
}
})
the following is a part of a python script i've used to remove the forward slashes - added by google cloud buckets when to represent directories - from multiple objects, it's based on this blog post, please keep in mind the double quotes around the content position "file name"
def update_blob_download_name(bucket_name):
""" update the download name of blobs and remove
the path.
:returns: None
:rtype: None
"""
# Storage client, not added to the code for brevity
client = initialize_google_storage_client()
bucket = client.bucket(bucket_name)
for blob in bucket.list_blobs():
if "/" in blob.name:
remove_path = blob.name[blob.name.rfind("/") + 1:] # rfind gives that last occurence of the char
ext = pathlib.Path(remove_path).suffix
remove_id = remove_path[:remove_path.rfind("_id_")]
new_name = remove_id + ext
blob.content_disposition = f'attachment; filename="{new_name}"'
blob.patch()
I'm trying to replace a PDF file in a Google Drive Folder using a script. Since GAS does not provide a method for adding revisions (versions), I'm trying to replace the content of the file, but all I get is a blank PDF.
I can't use the DriveApp.File class since our Admin has disabled the new API, so I have to use DocsList.File instead.
Input:
OldFile.pdf (8 pages)
NewFile.pdf (20 pages)
Output expected:
OldFile.pdf with the same content as NewFile.pdf
Real Output:
OldFile.pdf with 20 empty pages.
Process:
var old = DocsList.getFileById("####");
var new = DocsList.getFileById("####");
old.replace(new.getContentAsString());
Any ideas, please?
Thanks a lot in advance.
PS.: I also tried calling old.clear() first, but I'd say the problem lies on the getContentAsString method.
The Advanced Drive Service can be used to replace the content of an existing PDF file in Google Drive. This answer also includes an example of how to update a PDF file in a shared Drive.
function overwriteFile(blobOfNewContent,currentFileID) {
var currentFile;
currentFile = DriveApp.getFileById(currentFileID);
if (currentFile) {//If there is a truthy value for the current file
Drive.Files.update({
title: currentFile.getName(), mimeType: currentFile.getMimeType()
}, currentFile.getId(), blobOfNewContent);
}
}
References
https://developers.google.com/apps-script/advanced/drive
https://developers.google.com/drive/api/v3/reference/files/update
An example of using with a shared Drive:
Drive.Files.update({ title: currentFile.getName(), mimeType:
currentFile.getMimeType() }, currentFile.getId(), blobOfNewContent,
{supportsTeamDrives: true});
Try to get it as a blob datatype instead.
How do I write a Google Apps Script that deletes files?
This finds files:
var ExistingFiles = DocsList.find(fileName);
But DocsList.deleteFile does not exist to delete a file.
Is there a way to move those files to another Folder or to Trash?
The other workaround I would consider is to be able to override an existing file with the same name.
Currently when I want to create a file with a name already used in MyDrive then it creates a second file with the same name. I would like to keep 1 file (the new one is kept and the old one is lost).
There are 3 services available to delete a file.
DriveApp - Built-in to Apps Script
Advanced Drive Service - Built-in to Apps Script but must be enabled. Has more capability than DriveApp
Google Drive API - Not built-in to Apps Script, but can be used from Apps Script using the Drive REST API together with UrlFetchApp.fetch(url,options)
The DocsList service is now deprecated.
The Advanced Drive Service can be used to delete a file without sending it to the trash. Seriously consider the risk of not being able to retrieve the deleted file. The Advanced Drive Service has a remove method which removes a file without sending it to the trash folder. Advanced services have many of the same capabilities as the API's, without needing to make an HTTPS GET or POST request, and not needing an OAuth library.
function delteFile(myFileName) {
var allFiles, idToDLET, myFolder, rtrnFromDLET, thisFile;
myFolder = DriveApp.getFolderById('Put_The_Folder_ID_Here');
allFiles = myFolder.getFilesByName(myFileName);
while (allFiles.hasNext()) {//If there is another element in the iterator
thisFile = allFiles.next();
idToDLET = thisFile.getId();
//Logger.log('idToDLET: ' + idToDLET);
rtrnFromDLET = Drive.Files.remove(idToDLET);
};
};
This combines the DriveApp service and the Drive API to delete the file without sending it to the trash. The Drive API method .remove(id) needs the file ID. If the file ID is not available, but the file name is, then the file can first be looked up by name, and then get the file ID.
In order to use DriveAPI, you need to add it through the Resources, Advanced Google Services menu. Set the Drive API to ON. AND make sure that the Drive API is turned on in your Google Cloud Platform. If it's not turned on in BOTH places, it won't be available.
Now you may use the following if the file is as a spreadsheet, doc etc.:
DriveApp.getFileById(spreadsheet.getId()).setTrashed(true);
or if you already have the file instead of a spreadsheet, doc etc. you may use:
file.setTrashed(true);
This code uses the DocsList Class which is now deprecated.
try this :
function test(){
deleteDocByName('Name-of-the-file-to-delete')
}
function deleteDocByName(fileName){
var docs=DocsList.find(fileName)
for(n=0;n<docs.length;++n){
if(docs[n].getName() == fileName){
var ID = docs[n].getId()
DocsList.getFileById(ID).setTrashed(true)
}
}
}
since you can have many docs with the same name I used a for loop to get all the docs in the array of documents and delete them one by one if necessary.
I used a function with the filename as parameter to simplify its use in a script, use test function to try it.
Note : be aware that all files with this name will be trashed (and recoverable ;-)
About the last part of your question about keeping the most recent and deleting the old one, it would be doable (by reading the last accessed date & time) but I think it is a better idea to delete the old file before creating a new one with the same name... far more logical and safe !
Though the The service DocsList is now deprecated, as from the Class Folder references, the settrashed method is still valid:
https://developers.google.com/apps-script/reference/drive/folder#settrashedtrashed
So should work simply this:
ExistingFiles.settrashed(true);
Here is another way to do it without the need of Drive API. (based on Allan response).
function deleteFile(fileName, folderName) {
var myFolder, allFiles, file;
myFolder = DriveApp.getFoldersByName(folderName).next();
allFiles = myFolder.getFilesByName(fileName);
while (allFiles.hasNext()) {
file = allFiles.next();
file.getParents().next().removeFile(file);
}
}
Here is a slightly modified version using the above. This will backup said file to specified folder, also remove any old previous backups with the same name so there are no duplicates.
The idea is here to backup once per day, and will retain 1 month of backups in your backup folder of choice. Remember to set your trigger to daily in your Apps Script.
https://gist.github.com/fmarais/a962a8b54ce3f53f0ed57100112b453c
function archiveCopy() {
var file = DriveApp.getFileById("original_file_id_to_backup");
var destination = DriveApp.getFolderById("backup_folder_name");
var timeZone = Session.getScriptTimeZone();
var formattedDate = Utilities.formatDate(new Date(),timeZone,"dd"); // 1 month backup, one per day
var name = SpreadsheetApp.getActiveSpreadsheet().getName()+"_"+formattedDate;
// remove old backup
var allFiles = destination.getFilesByName(name);
while (allFiles.hasNext()) {
var thisFile = allFiles.next();
thisFile.setTrashed(true);
};
// make new backup
file.makeCopy(name,destination);
}
I am attempting to use Google Picker to upload files to a specific folder in Google Drive. Everything works fine when I am just uploading to the root folder, but even after specifying the parent folder as shown in my code below, the files still go to the root folder, not the folder I am specifying. I am certain the folderID is correct, as I am using the same ID elsewhere to create textiles in my GAE app, and place them in subfolders. My code is below:
function createPicker() {
// Create a view to search images.
var view = new google.picker.View(google.picker.ViewId.DOCS);
view.setMimeTypes('image/png,image/jpeg');
// Use DocsUploadView to upload documents to Google Drive.
var uploadView = new google.picker.DocsUploadView().setParent('THE Parent folder ID');
var picker = new google.picker.PickerBuilder().
addView(view).
addView(uploadView).
setAppId("pressomatic").
setCallback(pickerCallback).
build();
picker.setVisible(true);
}
You have to add:
enableFeature(google.picker.Feature.MULTISELECT_ENABLED)
In your case it becomes:
var picker = new google.picker.PickerBuilder().
enableFeature(google.picker.Feature.MULTISELECT_ENABLED).
addView(view).
addView(uploadView).
setAppId("pressomatic").
setCallback(pickerCallback).
build();
picker.setVisible(true);
}
This is a bug documented in the Picker API Forum: https://groups.google.com/forum/#!topic/Google-Picker-API/xaHcET7JYLw
You have to add:
.enableFeature(google.picker.Feature.MULTISELECT_ENABLED)
In your case it becomes:
var picker = new google.picker.PickerBuilder()
.enableFeature(google.picker.Feature.MULTISELECT_ENABLED)
.addView(view)
.addView(uploadView)
.setAppId("pressomatic")
.setCallback(pickerCallback)
.build();
Hope this helps.