How to post Logger.log content into Spreadsheet cell? [closed] - google-apps-script

Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 3 years ago.
Improve this question
I have a script that was provided by someone on here that is intended to be used to retrieve the URL of the latest file in a drive folder. However, the script only works up to having the link in the logger, and not actually posting it into a cell.
Therefore, how can I have it post to a spreadsheet? This is the script I got, and I actually want it to post the URL in Column5 based on a value of Column4. If Column4 value is "YES" the link will be posted but if it is "NO" in column4 the it will simply be empty.
var files = DriveApp.getFolderById(folderId).getFiles();
var fileObj = [];
while (files.hasNext()) {
var file = files.next();
fileObj.push({url: file.getUrl(), date: file.getDateCreated()});
}
fileObj.sort(function(a, b) {return new Date(b.date) - new Date(a.date)});
return fileObj[0].url;
}
function myFunction() {
var folderId = "###";
var lastFileUrl = getLatestFile(folderId);
Logger.log(lastFileUrl)
}

function getLatestFile(folderId) {
var files = DriveApp.getFolderById(folderId).getFiles();
var fileObj = [];
while (files.hasNext()) {
var file = files.next();
fileObj.push({url: file.getUrl(), date: file.getDateCreated()});
}
fileObj.sort(function(a, b) {return new Date(b.date) - new Date(a.date)});
return fileObj[0].url;
}
function putInSS(ssid,sheetname,folderId) {
var ss=SpreadsheetApp.openById(ssid);
var sh=ss.getSheetByName('sheetname');
var rg=sh.getDataRange();
var rg5=sh.getRange(1,5,sh.getLastRow(),1);
var v5=rg5.getValues();
var v=rg.getValues();
var url=getLastestFile(folderId);
v.forEach(function(r,i){
if(r[3]=='YES') {
v5[i]=url;
}
if(r[3]=='NO') {
v5[i]='';
}
});
rg5.setValues(v5)
}
enter code here

Related

List Google drive folder contents to google sheets with only new files

Looking to learn how to improve my use of loops. Currently I need to list the names and URLS from a google drive Folder to a sheet and this is the code that I have:
Existing Code
function wthFolderContents() {
var folder_id = 'myFolderID';
var folders = DriveApp.getFolderById(folder_id)
var contents = folders.getFiles();
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getSheetByName("SheetName");
sheet.clearContents()
sheet.appendRow( ['name', 'link'] );
var file;
var name;
var link;
var row;
while(contents.hasNext()) {
file = contents.next();
name = file.getName();
link = file.getUrl();
sheet.appendRow ( [name, link] );
with this code everytime the script is run the contents are cleared and then relisted. I am looking at a way of doing this dynamically / only update the new files so the script runs more effeciently.
Ive tried the following
New Code
function wthFolderContents2() {
var folder_id = '1vBzucZsb0SMOoHSWGtkUF-5QLQr5Fh1C';
var folders = DriveApp.getFolderById(folder_id)
var contents = folders.getFiles();
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getSheetByName("WHTCert");
var lastRow = sheet.getLastRow()
var existing = sheet.getRange(1,1,lastRow,1).getValues()
for(i=1;i<lastRow;i++) {
var existingFilename = existing [i][0]
Logger.log(existingFilename)
while(contents.hasNext()) {
var file;
var name;
var link;
file = contents.next();
name = file.getName();
link = file.getUrl();
if (!name == existingFilename) {
sheet.appendRow ( [name, link] );
}
}
}
I cant get this to work, not sure what exactly where I have gone wrong. Hope someone can point me int he right direction!
Cheers
I believe your goal is as follows.
You want to reduce the process cost of your script.
Modification points:
In your script, appendRow is used. In this case, the process cost will become high. Ref
The search for files is run in a loop. In this case, the process cost will become high.
In your situation, it seems that you want to retrieve the file list just under the specific folder. In this case, I thought that when Drive API is used, the process cost can be reduced. In this answer, I would like to propose using Drive API in your script. When this is reflected in your script, it becomes as follows.
When Drive API is used, all values can be retrieved. So, I thought that your 1st process might be able to be used.
Modified script:
Before you use this script, please enable Drive API at Advanced Google services.
function wthFolderContents2() {
var folder_id = '1vBzucZsb0SMOoHSWGtkUF-5QLQr5Fh1C';
// Retrieve file list.
var q = `'${folder_id}' in parents and trashed = false and mimeType != '${MimeType.FOLDER}'`;
var fileList = [['name', 'link']];
var pageToken = "";
do {
var obj = Drive.Files.list({ q, maxResults: 1000, pageToken, fields: "nextPageToken,items(id,title)", corpora: "allDrives", supportsAllDrives: true, includeItemsFromAllDrives: true });
if (obj.items.length > 0) {
fileList = [...fileList, ...obj.items.map(({ id, title }) => [title, `https://docs.google.com/presentation/d/${id}/edit?usp=drivesdk`])];
}
pageToken = obj.nextPageToken;
} while (pageToken);
// Put the values to Spreadsheet.
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getSheetByName("WHTCert");
sheet.clearContents();
sheet.getRange(1, 1, fileList.length, fileList[0].length).setValues(fileList);
}
When this script is run, the file list (filename and URL) is retrieved from the specific folder. And, the retrieved values to the "WHTCert" sheet.
Reference:
Files: list
Please convert this 2 script for scan folder only one subfolder and file, show folder name and link.
function wthFolderContents()
function wthFolderContents2()

Google Apps Script Filter Output Before Moving

Good Morning All,
I should filter the output by the name (must contain a specific word) of the file before it is moved... How can I do this? With this script it moves all the files it finds indiscriminately, but that is not what I want
function moveFiles(sourceFileId, targetFolderId) {
var file = DriveApp.getFileById(sourceFileId);
var folder = DriveApp.getFolderById(targetFolderId);
file.moveTo(folder);
}
function searchDrive() {
var inputMe = 'MYDRIVEID';
var inputFolder = DriveApp.getFolderById(inputMe);
var files = inputFolder.getFiles();
while (files.hasNext()) {
var destinationFolderId = "MYDRIVEID";
var file = files.next();
var moveMe = file.getId();
var moveMeName = file.getName();
Logger.log(moveMeName);
moveFiles(moveMe,destinationFolderId);
}
}
As a quick fix you can just replace:
moveFiles(moveMe,destinationFolderId);
with:
if (moveMeName.contains('specific word')) moveFiles(moveMe,destinationFolderId);
or (for case insensitive mode):
if (moveMeName.toLowerCase().contains('specific word')) moveFiles(moveMe,destinationFolderId);
In your situation, how about the following modification?
Modified script:
In this modification, your searchDrive is modified. Please set the filter texts to filterTexts.
function searchDrive() {
var filterTexts = ["sample1", "sample2",,,]; // Please set the filter text you want to use.
var inputMe = 'MYDRIVEID';
var inputFolder = DriveApp.getFolderById(inputMe);
var files = inputFolder.getFiles();
while (files.hasNext()) {
var destinationFolderId = "MYDRIVEID";
var file = files.next();
var moveMe = file.getId();
var moveMeName = file.getName();
if (!filterTexts.some(e => moveMeName.toUpperCase().includes(e.toUpperCase()))) {
moveFiles(moveMe, destinationFolderId);
}
}
}
When this script is run, the files with the filename which doesn't include the texts of filterTexts are moved.
If you want to distinguish the uppercase and lowercase of the filename, please remove toUpperCase().
Reference:
some()
Added:
From your following reply,
I only want to move files that contain a certain name within the filename. I suppose I have to remove ! in front of filterTexts.some to do this?
In this case, when you use the above script, please set the value you search like var filterTexts = ["sample1"];. From your question, I couldn't understand whether you wanted to search for only one value. So, in my answer, I proposed the script for searching multiple values by considering the scalability of the function.
If you want to search for only one value, you can also the following script.
But I get an error on the previous part of the script, on the line var file = DriveApp.getFileById(sourceFileId); with error Exception: Invalid argument: id what can it be?
I think that this is not related to my proposed script. From your situation, I'm worried that the files you cannot move might be included. In that case, how about skipping such files as following modification?
Modified script:
function searchDrive() {
var filterTexts = "sample1"; // Please set the filter text you want to use.
var inputMe = 'MYDRIVEID';
var inputFolder = DriveApp.getFolderById(inputMe);
var files = inputFolder.getFiles();
while (files.hasNext()) {
var destinationFolderId = "MYDRIVEID";
var file = files.next();
var moveMe = file.getId();
var moveMeName = file.getName();
if (!moveMeName.toUpperCase().includes(filterTexts.toUpperCase())) {
try {
moveFiles(moveMe, destinationFolderId);
} catch (e) {
console.log({ errorMessage: e.message, filename: moveMeName, fileId: moveMe });
}
}
}
}
In this sample script, the files with the filename which includes the value of filterTexts are moved using your function of moveFiles. But, if an error occurs at moveFiles, the file is skipped. At that time, the filename and file ID are shown in the log.

Using Logger.Log to log different value

I was wondering: is it even possible to use Logger.Log in Google Apps Script to log different string to be posted to a spreadsheet?
I have the following code:
var ss = SpreadsheetApp.openByUrl("spreadsheet url");
var sheet = ss.getSheetByName("spreadsheet sheet");
var DocNumber = e.parameter.DocNumber;
var folderId = "Folder ID 1";
var lastFileUrl = getLatestFile(folderId); // just a function that retrieves url of latest file in the folder
Logger.log(lastFileUrl);
var addUrl = sheet.getRange(1,2,sheet.getLastRow(),1);
var fileURL = "https://drive.google.com/uc?export=view&id="+lastFileUrl;
var folderId2 = "Folder ID 2";
var lastFileUrl2 = getLatestFile(folderId2); // same as above
Logger.log(lastFileUrl2);
var addUrl2 = sheet.getRange(1,3,sheet.getLastRow(),1);
var fileURL2 = "https://drive.google.com/uc?export=view&id="+lastFileUrl2;
sheet.appendRow([DocNumber,fileURL,fileURL2]);
}
When this get posted to the spreadsheet, it only posts the second url (fileURL2) - I assume because the last value in the log is this. But I was hoping to post both URL into the spreadsheet.
I tried setting it as a var first as well:
var URL2 = Logger.log(lastFileURL2);
but then the posted value will be https://drive.google.com/uc?export=view&id=Logger
I also tried using appendRow before the second URL logging but it still only takes the second url and disregard the first url.
Therefore, I was curios whether this is even possible at all?
And if not, what's the best way to achieve this without using Logger.log?
Spreadsheet output:
URL1 and URL2 is the URL from Google Drive folder.
Also, forgot to mention, I'm using the script as a Web App, used by an android app. Posting files into the Drive folder is okay, the only problem is fetching the links of the files in different folders.
These are the codes I used to get the latest file url from my folders:
function getLatestFile(folderId) {
var files = DriveApp.getFolderById("Folder_1_ID").getFiles();
var fileObj = [];
while (files.hasNext()) {
var file = files.next();
fileObj.push({id: file.getId(), date: file.getDateCreated()});
}
fileObj.sort(function(a, b) {return new Date(b.date) - new Date(a.date)});
return fileObj[0].id;
}
function getLatestFile(folderId2) {
var files2 = DriveApp.getFolderById("Folder_2_ID").getFiles();
var fileObj2 = [];
while (files2.hasNext()) {
var file2 = files2.next();
fileObj2.push({id: file2.getId(), date: file2.getDateCreated()});
}
fileObj2.sort(function(a, b) {return new Date(b.date) - new Date(a.date)});
return fileObj2[0].id;
}
Problem
Having two functions declared under the same name
Solution
Step by step:
Remove one of the functions (they are identical in terms in usage)
Make the remaining one use the parameter passed in it:
function getLatestFile(folderId) {
var files = DriveApp.getFolderById(folderId).getFiles();
var fileObj = [];
while (files.hasNext()) {
var file = files.next();
fileObj.push({id: file.getId(), date: file.getDateCreated()});
}
fileObj.sort(function(a, b) {return new Date(b.date) - new Date(a.date)});
return fileObj[0].id;
}
Change Logger to console - as of recently, all logs are sent to Stackdriver service, and thus there is no benefit in using Logger (besides by using console you make script more portable).
Commentary
What happens when you declare two or more functions under same name? Normally, the last one declared gets executed (basically, second declaration overwrites the first):
function clone(original) {
return `I am the clone of ${original}`;
}
function clone(cloned) {
return `I am a clone of ${cloned}'s clone`;
}
const elem = document.querySelector("#cloned");
elem.textContent = clone("Gary");
<h2 id="cloned"></h2>

Fetching latest file URL in Drive and posting it to Google Spreadsheet based on a criteria

I am wondering whether it's possible or not to retrieve the URL of the latest file in a Drive Folder then have it posted into a cell in Column B of a Spreadsheet.
Then there's the other part where the URL should only be posted if Column A has the word "YES". So if A has "NO" URL isn't necessary.
The full scenario would be like this.
Picture uploaded into Drive Folder.
"YES" is entered into A1.
URL of latest uploaded picture is fetched then pasted into B1.
Then it continues for all the other rows as well.
Theoretically, that's how I want it to work. But I don't know whether it could work or not.
This is the script that I use to upload picture into Drive:
function doGet(e) {
return message("Error: no parameters in doGet");
}
function doPost(e) {
if (!e.parameters.filename || !e.parameters.file || !e.parameters.imageformat) {
return message("Error: Bad parameters in doPost");
} else {
var imgf = e.parameters.imageformat[0].toUpperCase();
var mime =
(imgf == 'BMP') ? MimeType.BMP
: (imgf == 'GIF') ? MimeType.GIF
: (imgf == 'JPEG') ? MimeType.JPEG
: (imgf == 'JPG') ? MimeType.JPEG
: (imgf == 'PNG') ? MimeType.PNG
: (imgf == 'SVG') ? MimeType.SVG
: false;
if (mime) {
var data = Utilities.base64Decode(e.parameters.file, Utilities.Charset.UTF_8);
var blob = Utilities.newBlob(data, mime, e.parameters.filename);
DriveApp.getFolderById('Folder Id').createFile(blob);
return message("Success");
} else {
return message("Error: Bad image format");
}
}
}
function message(msg) {
return ContentService.createTextOutput(JSON.stringify({Result: msg })).setMimeType(ContentService.MimeType.JSON);
}
While this is the script I use to enter "YES" or "NO" into Column A:
function doGet(e) {
var ss = SpreadsheetApp.openByUrl("Sheet_URL");
var sheet = ss.getSheetByName("Sheet_Name");
addRecord(e,sheet);
}
function doPost(e) {
var ss = SpreadsheetApp.openByUrl("Sheet_URL");
var sheet = ss.getSheetByName("Sheet_Name");
addRecord(e,sheet);
}
function addRecord(e,sheet) {
var HvPict = e.parameter.HvPict;
sheet.appendRow([Hv.Pict]);
}
You want to retrieve the URL of the latest uploaded file in the specific folder.
You want to achieve this using Google Apps Script.
I could understand like above. If my understanding is correct, how about this sample script? Please think of this as just one of several possible answers.
In your case, I thought that the method of getDateCreated() in Class File might be able to be used. So how about the following sample script?
Sample script:
function getLatestFile(folderId) {
var files = DriveApp.getFolderById(folderId).getFiles();
var fileObj = [];
while (files.hasNext()) {
var file = files.next();
fileObj.push({url: file.getUrl(), date: file.getDateCreated()});
}
fileObj.sort(function(a, b) {return new Date(b.date) - new Date(a.date)});
return fileObj[0].url;
}
function myFunction() {
var folderId = "###";
var lastFileUrl = getLatestFile(folderId);
Logger.log(lastFileUrl)
}
When you run the script, please set folderId. This script retrieves the files in the folder of folderId.
When you run the function of myFunction(), the URL of the latest created file is retrieved.
Note:
In your case, above function might should be used at the script of the 2nd HTML form.
If in your actual situation, the uploaded file is modified and you want to retrieve the latest modified file, please try to use getLastUpdated() instead of getDateCreated().
In this case, fileObj.sort(function(a, b) {return new Date(b.date) - new Date(a.date)}); might not be required.
References:
getDateCreated()
getLastUpdated()
Added:
function getLatestFile(folderId) {
var files = DriveApp.getFolderById(folderId).getFiles();
var fileObj = [];
while (files.hasNext()) {
var file = files.next();
fileObj.push({url: file.getUrl(), date: file.getDateCreated()});
}
fileObj.sort(function(a, b) {return new Date(b.date) - new Date(a.date)});
return fileObj[0].url;
}
function doGet(e) { // or doPost(e)
var folderId = "###";
var ss = SpreadsheetApp.openByUrl("Sheet_URL");
var sheet = ss.getSheetByName("Sheet_Name");
sheet.appendRow([e.parameter.HvPict, getLatestFile(folderId)]);
}
When you modified the script of Web Apps, please redeploy Web Apps as new version. By this, the latest script is reflected to the Web Apps. Please be careful this.

PDF created from Google Doc template via Apps Script has old values [duplicate]

This question already has answers here:
Created PDF does not reflect changes made to the original document
(2 answers)
Closed 4 years ago.
Basically here is what is happening. A user submits a Google Form (later this will cause a trigger to set this off), the user then gets emailed a receipt from a template. The problem I am currently having is the copied template will update the values, but the pdf does not have the updated valued.
Sorry for the mess, plan on creating arrays and such later.
// to do : refactor or w/e
// make it so it emails the person a pdf of the doc
var docTemplateId = 'templateID';
var headerPosition = 'A1:E1';
var dataRange = 'A2:E2'; //
var sheetId = 'dataSoureID';
var headers = Sheets.Spreadsheets.Values.get(sheetId, headerPosition);
var rowData = Sheets.Spreadsheets.Values.get(sheetId, dataRange);
var email = rowData.values[0][0];
var name = rowData.values[0][1];
var grade = rowData.values[0][2];
var subject = rowData.values[0][3];
var initalMeeting = rowData.values[0][4];
var techCurrentlyUsed = rowData.values[0][5];
var documentName = 'Good Teacher Planning '+ name;
var documentId = DriveApp.getFileById(docTemplateId).makeCopy().getId();
DriveApp.getFileById(documentId).setName(documentName);
var body = DocumentApp.openById(documentId).getBody();
// to do write get email function
function writeToTemplate()
{
body.replaceText('##email##', email);
body.replaceText('##name##', name);
body.replaceText('##grade##', grade);
body.replaceText('##subject##', subject);
body.replaceText('##initalMeeting##', initalMeeting);
body.replaceText('##techCurrentlyUsed##', techCurrentlyUsed);
}
function emailPDF()
{
var file = DriveApp.getFileById(documentId);
var blob = file.getBlob().getAs('application/pdf').setName(documentName);
MailApp.sendEmail(email, 'hello', 'world', {attachments: blob});
Logger.log('end email')
}
function main()
{
writeToTemplate();
emailPDF();
}
Edit: fixed with saveAndClose();
Your blob source advanced parameter must be an array of attachments:
attachments: [blob1,blob2,blob3]
Even if you only have one attachment, you still need to use an array
attachments: [blob]