This might seem like very basic stuff, but can somebody tell me what the purpose of this [0]; after the ("myfile3") in the code below does? I got it from the Google developers page but there is no explanation as to what it does. I am new to GAS and Javascript and don't have a lot of programming experience but all I am trying to do is copy a file on from my root drive in Google drive and then move it to another folder. Then code below works sometimes, but then after a while I get an error that tells me: "File copyFile must be converted to a Google document first. (line 5, file "copy")".
Any help appreciated. (Sorry if it is a stupid question)
The code is:
function copyFile()
{
var file = DocsList.find("myfile3")[0];
var copy = file.makeCopy("myfile5");
}
from the documentation : find(query) : Returns an array of all the files in the container that contain the given string.
Find() searches the content of all the files, not their names.
That means that you have to choose which element of the array you want to open... using [0] means you take the first result.
It might be the file you're looking for but it is not sure at all...
To narrow your search to the filename you should simply iterate the returned array while testing each file's name and pick up the one you want.
it might be in a for loop like this :
var files = DocsList.find("myfile3");
for(var f=0;f<files.length;++f){if(files[f].getName()==query){var foundDocId=file[f].getId() ; break}
From there use the file ID to access your file as this one is unique (names are not in Google Docs).
as simple as that ;-)
I would suggest testing the DriveApp version of this function for two implicit reasons:
The DocsList service is deprecated and may be discontinued as the
DriveApp functions are fleshed out.
DriveApp is a little more agnostic
when it comes to filetypes, and may bypass your error.
Check out fileMakeCopy() in the Apps Script Documents for details.
Related
I have a Google Docs template which is automatically copied into a folder and replace specific values with values coming from spreadsheet cells.
The template contains values such as <<41>> which are used to be "find-and-replaced" with values coming from a spreadsheet.
The find-and-replace process is fine, and the results of the document looks like this image below
Now, I want this document to be converted into PDF after it has been updated, so I made a function for the convertion and call it at the bottom after all the codes has been executed.
Here's the function:
//convert to PDF
function convertPDF(FileID,newName) {
Utilities.sleep(120000);
docblob = DocumentApp.openById(FileID).getAs('application/pdf');
/* Add the PDF extension */
docblob.setName(newName + ".pdf");
var file = DriveApp.createFile(docblob);
}
The convertion works fine, but the converted document isn't updated. Rather, it is like it was the one freshly copied from the template, before the values were changed.
If you may notice, I have added a "sleep" timer before in the conversion function so as to delay the conversion and give time for the changes to be saved, I've tried 1 and 2 minutes sleep but still it doesn't work.
What can I do to make sure the PDF is created from the updated template?
The function I provided above works fine, we just need to forced the script to save the changes by calling the saveAndClose() method before calling the function that converts the doc into PDF.
I was searching for an answer for this same problem but for Google Sheets. Gave saveAndClose() a shot, but it didn't work for Sheets. Did some more searching and found that the Sheets solution for a similar problem is:
SpreadsheetApp.flush()
Here is the relevant Question/Answer.
Hope this helps someone get to their answer faster.
Let's say there is a file in a Team Drive folder and over 120 users have access to it. Most can edit the file, but some can only view it or comment on it. I wrote a script that logs the number of users who can only view this file, like so:
function t() {
var folder = DriveApp.getFolderById(/* folder ID */);
var file = folder.getFiles().next();
var viewers = file.getViewers();
Logger.log(viewers.length);
}
That should log a number greater than 0, but it turns out it logs exactly 0. This can't be right because I checked the file myself, and indeed it has several users who have view-level access to the file.
Please help me understand what's going on and how I could go about fixing this problem!
Edit: On an unrelated note, why can't I get a commenter from a file the same way I can get an editor or a viewer? For instance, file.getViewers() and file.getEditors() are valid instructions, assuming that file is a File object. But there is no file.getCommenters() instruction, even though there is a file.removeCommenter() instruction.
According to the getViewers():
Gets the list of viewers and commenters for this
File.
If the user who executes the script does not have edit access to the
File, this method returns an empty array.
So you probably don't have edit access.
getEditors() array does not include the file owner. See the getOwner() method.
I'm working on a project in a shared Google Drive folder where we recently learned we need to change some strings, that are found in all the documents, with slightly different strings. There are hundreds of files, and it'd be impossible to go through them all one by one, and after some looking I found a Universal Find and Replace script.
https://ctrlq.org/code/19926-universal-find-replace-in-google-drive
Problem is, I have little to no experience with code and even with the instructions given on the site, I have no clue what I have to do with the script. All of it is gibberish to me, and I'd be unbelievably grateful if someone could walk me through all of it.
Questions:
Where in the script do I specify the Drive folder in question and how do I specify it? The "folder path" thing has me even more confused, so if you can let me know where exactly I can find the needed info, that would be great.
Where do I specify the strings I need to replace? I can obviously tell that doc.replaceText has something to do with it, but the fact that it says "You can use regex too" makes me curious if there's anything else I need to change before that?
How should I make a copy of the script code and where in my Google Drive do I place the file?
If there's any other steps I might be overlooking, please mention those as well.
Also, will it be possible to replace more than one string in a single script? (i.e change all "red" to "blue" and change all "black" to "white")
Thank you all in advance, this might end up being a lifesaver?
You might want to look at Apps Script's Drive Service and Document Service to help you be more familiar about the classes and functions to be used.
Drive Service
This service allows scripts to create, find, and modify files and folders in Google Drive.
Document Service
This service allows scripts to create, access, and modify Google Docs files.
Creating a Folder
Using the sample code :
// Log the name of every folder in the user's Drive.
var folders = DriveApp.getFolders();
while (folders.hasNext()) {
var folder = folders.next();
Logger.log(folder.getName());
}
You can set
var newFolder = DriveApp.createFolder('My New Folder');
//To check if you successfully created a folder
Logger.log(newFolder.getId())
//To set sub folder under "My New Folder"
var id = newFolder.getId()
var subFolder = newFolder.createFolder('New Sub Folder')
2. Where do I specify the strings I need to replace? I can obviously tell that doc.replaceText has something to do with it, but the fact that it says "You can use regex too" makes me curious if there's anything else I need to change before that?
You can use findText(searchPattern, from)
Searches the contents of the element for the specified text pattern, starting from a given search result.
A subset of the JavaScript regular expression features are not fully supported, such as capture groups and mode modifiers.
The provided regular expression pattern is independently matched against each text block contained in the current element.
3. How should I make a copy of the script code and where in my Google Drive do I place the file?
You can use Apps Script Console to create your codes, this will be placed in you drive folder.
Lastly, here is a sample code that will change the color of the text:
var body = DocumentApp.getActiveDocument().getBody();
// Use editAsText to obtain a single text element containing
// all the characters in the document.
var text = body.editAsText();
// Insert text at the beginning of the document.
text.insertText(0, 'Inserted text.\n');
// Insert text at the end of the document.
text.appendText('\nAppended text.');
// Make the first half of the document blue.
text.setForegroundColor(0, text.getText().length / 2, '#00FFFF');
Hope it helps!
As part of a suite of tools I am developing for the company I work for, I have an add-on in development that when first installed generates all the relevant files and folders for the suite.
Due to the complexity of some of the files I discovered that using the following code was the quickest way to generate the files:
function createTemplate(branchId){
var home=DriveApp.getFolderById(branchId)
var master=DriveApp.getFileById(stringId).getBlob();
home.createFile(master);
}
I am presented with the problem, however, that all the files generate as PDFs. I am aware that this is because the default blob content type is the PDF file type and that getAs(contentType) can be used to specify the desired blob content type; but I have struggled to find any documentation specifying how to call the content type as a Spreadsheet, for example.
Is this possible and I've just missed somewhere in Google's documentation how to specify content type as spreadsheet or is it no possible and can blobs only be returned with content types of PDF or image types?
UPDATE: So I discovered accidentally that the content type for spreadsheets would appear to have be specified by application/vnd.google-apps.spreadsheet However, I now get the error Converting from application/pdf to application/vnd.google-apps.spreadsheet is not supported.
FURTHER UPDATE: Potential solution using different route found using the below script:
function createTemplate(branchId){
var home=DriveApp.getFolderById(branchId);
var master=DriveApp.getFileById("fileId").makeCopy("PP Template", home);
}
Although this had around an 8 second run-time so not the quickest thing in the world. Blob related answer still welcome.
As far as I am aware, blob will not do what you want to at this time. There is a reason that DocumentApp.create, etc. exist. They are the function calls that Google wants you to make for what you want to do. They don't want 13 ways to perform the same function.
I am trying to utilize Google Drive as repository for many different types of documents. I have those documents arranged in several different folders.
When I perform a search it seems to search my entire Google Drive account for matching results regardless of the fact that I am currently within a specific folder.
This poses a problem for me as I want to be able to refine my searches to within a given grouping of documents.
If I am searching for documents related to my work, for instance, I don't want documents showing up in my search that are personal, or in my personal directories.
Is there a way to refine my search to only show documents within a specified folder and it's subfolders? I know I can refine the search based on file type and ownership, but that doesn't work for me.
Thanks in advance.
Using the Google Drive SDK, you can perform a search query for <folder_id> in parents.
The code I have included allows me to search the body of files within a specific folder. I am using it to search scanned documents and will have it move the file to another folder based on search criteria I specify.
The great thing about this is that it will search the body of the document and return all documents that meet your search criteria. As you can see I can also specify a date range and you can use other operators to define your search. https://developers.google.com/drive/web/search-parameters.
This was a great find for me and I hope it can help some others.
function searchFolder(){
var parent = DriveApp.getFolderById(‘*******************’); // folder Id
var search = 'modifiedDate >"2014-08-01" and modifiedDate < "2014-12-31" and fullText contains "PUT SEARCH TEXT HERE"';
var specificFolder = parent.searchFiles(search);
while (specificFolder.hasNext()) {
var file = specificFolder.next();
Logger.log(file.getName());
Logger.log(file.getId());
}
}
As far as I know you'd have to do this for each subfolder, but the API (and my app) will search by folder.
I wrote an app that uses the API to search by folder. It is a bit slow so be patient when it is loading.
https://script.google.com/macros/s/AKfycby6G32K-vKCiLmoKvMtG64cYPHEREEx1PY5IoYrEYaR6WAfbXs/exec
// -----------------
var sr = DocsList.getFolder("temp_scripts").find("var");
var i = 0;
for(i=0;i<sr.length;i++)
{
var r = sr[i];
Logger.log('name='+r.getName());
Logger.log('parent=' +r.getParents()[0].getName() );
Logger.log('---');
}
// -----------------
I found a sort of workaround using the description field.
In my particular case, all the files created in the folder i want to search are created programmatically by my own script, but is quite simple to write a script to (re)define the description field into all the files in a specific folder using .setDescription(DESCRIPTION). Once this is done...
The good news is that the standard search in google drive give results based on the description field, including the value set on it into the search field (plus any data you want to find into those files) you will get the results you need.
Of course you need to scarify the description field (or, at least, overcrowd it;-)
As, I think all of you, I'm still waiting for the folder keyword in the standard serch field.
I implemented the function in this Chrome Extension.
https://chrome.google.com/webstore/detail/advanced-drive-search/chomjcpadndbjgkanbaakmjehdoighab
You can check the code here
https://github.com/kissrobber/advanced_google_drive_search_chrome_extension
What that do is
get all the folders
build a query with the folder_id and the descendant folder_ids. Like this (<folder_id> in parents or <folder_id> in parents or ....)
If you have concern with the performance, try the Chrome extension.
There is another workaround that do NOT require any third party app or extension.
Remove your folder (In which you wanna search something)
Search with is:trashed filter. For example: is:trashed query_string
Restore your folder back