[Edited]
I'm using Apps Script in Sheets to use info from a form to, when the form is submitted, populate a template, create a PDF file, and then automatically email the PDF to an email address created from information on the form. The form, the spreadsheet, and the template in a folder on a shared drive.
I get the following error: "Exception: Cannot use this operation on a shared drive item" at tempFolder.removeFile(tempFile). When I deactivate that line of code the script works perfectly. I assume it has something to do with permissions on a shared drive, but am not sure how to set it up to allow me to delete that temporary file. I'm very new to coding, so forgive me if this is a stupid question.
Here is my script:
const info = e.namedValues;
const pdfFile = createPDF(info);
const entryRow = e.range.getRow();
var caseEmail = e.namedValues['LegalServer Case Number']+"#fls.legalserver.org";
const ws = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("With Links");
ws.getRange(entryRow,8).setValue(pdfFile.getUrl());
ws.getRange(entryRow,7).setValue(pdfFile.getName());
sendEmail(caseEmail, pdfFile);
}
function sendEmail(email,pdfFile){
GmailApp.sendEmail(email, "Screening Form","Screening Form Attached",{
attachments: [pdfFile],
name: 'Info'
});
}
function createPDF(info){
const pdfFolder = DriveApp.getFolderById("idforpdffolder");
const tempFolder = DriveApp.getFolderById("idfortempdocfolder");
const templateDoc = DriveApp.getFileById("idfortemplate");
var caseEmail = info['CaseNumber'][0]+"#email.org";
const newTempFile = templateDoc.makeCopy(tempFolder);
const openDoc = DocumentApp.openById(newTempFile.getId());
const body = openDoc.getBody();
body.replaceText("{casenumber}", info['CaseNumber'][0]);
body.replaceText("{name}", info['Name'][0]);
body.replaceText("{timestamp}", info['Timestamp'][0]);
body.replaceText("{casemail}", caseEmail);
//(others deleted for space)
openDoc.saveAndClose();
const blobPDF = newTempFile.getAs(MimeType.PDF);
const pdfFile = pdfFolder.createFile(blobPDF).setName(info['Name'][0]+" - " +info['Timestamp'][0]);
**tempFolder.removeFile(newTempFile);**
return pdfFile;
}
From It's happening at the second-to-last line (remove newTempFile). I updated the code. Thanks for looking at it. and your updated question, if you want to remove the file of newTempFile, how about the following modification?
From:
tempFolder.removeFile(newTempFile);
To:
newTempFile.setTrashed(true);
By this, the file of newTempFile is moved into the trash box.
If you want to completely delete it, it is required to use Drive API as follows. But, in this case, it is required to enable Drive API at Advanced Google services. Ref And, if you have no permission for writing in the shared Drive, an error occurs. Please be careful about this.
Drive.Files.remove(newTempFile.getId(), {supportsAllDrives: true})
Reference:
setTrashed(trashed)
Related
Im creating a simple code in scripts thats on a google sheets. is meant to open a template and change values from the template to the value from the google sheets. heres the code extract
`
function Create_PDF() {
const PDF_folder = DriveApp.getFolderById("1slk_E27fP2bLv-sEYTk7kx44iyHCprgk");
const TEMP_FOLDER = DriveApp.getFolderById("1n37Lc4y4yTRnTFnujUYGlyahq70S_N5q");
const PDF_Template = DriveApp.getFileById("1a0knbNWyC0BRrwvoKseMuYsaqKvEwQULcrZ3Yb18nIk");
const newTempFile = PDF_Template.makeCopy(TEMP_FOLDER);
const OpenDoc = DocumentApp.openById(newTempFile.getId());
const body = OpenDoc.getBody();
body.replaceText("[name]", ['Name'][0])
body.replaceText("[dob]", ['Date of Birth'][0]);
body.replaceText("[email]", ['Email'][0]);
body.replaceText("[phone]", ['Phone number'][0]);
body.replaceText("[uni]", ['University, major and year of study Your answer'][0]);
body.replaceText("[school]", ['High school'][0]);
body.replaceText("[schooldeg]", ['High school degree'][0])
body.replaceText("[language]", ['Languages'][0]);
body.replaceText("[exp]", ['Ushering past experience'][0]);
body.replaceText("[position]", ['Which of these positions fit with your past experience? '][0]);
body.replaceText("[nightlife]", ['Are you open for nightlife work?'][0]);
OpenDoc.saveAndClose();
const BLOBPDF = newTempFile.getAs(MimeType.PDF);
const pdfFile = PDF_folder.createFile(BLOBPDF).setName(['Name'][0]);
console.log("The file has been created ");
return pdfFile;
}
`
this is just timing out. it produces the copy in the temp folder but doesnt create a pdf in the pdf folder
I put the command console.log("working") between each body.replaceText function. it starts to slow down at schooldeg and timesout at language how can i fix this
I have a Google docs template document in a Google Drive file that I would like to duplicate so that it fits in another folder in my Google Drive while including variable field replacement.
My problem is that my .makeCopy function is not working.I want this function copy a template model on Google Sheet, replaces variables fields.
And I am getting this type of comment on my execution log
Here is the script I am using.
Would you have a solution to solve this problem?
function createPDF(){
const info = {
'Nom': ['Jane'],
'Prénom': ['Marcus'],
'Nom de l’entreprise': ['Doe'],
'Adresse': ['123 Avenue Morne-à-lo']
};
const pdfFolder = DriveApp.getFolderById('1S0cWh_hXl-VtyxkrJEOdPcxeiR8Yakkh');
const tempFolder = DriveApp.getFolderById('1dYMbvwVCexrcQJKVuLcnaDpT2Ipjy8WA');
const templateDoc = DriveApp.getFolderById('1xmDYuQyqGCVCSQVWzdckBJUOdqjarhdKhEdfdMnh1og');
const newTempFile = templateDoc.makeCopy(tempFolder);
const openDoc = DocumentApp.openById(newTempFile.getId());
const body = openDoc.getBody();
body.replaceText("{Nom}". info["Nom"][0]);
body.replaceText("{Prénom}". info["Prénom"][0]);
body.replaceText("{Nom de l'entreprise}". info["Nom de l'entreprise"][0]);
body.replaceText("{Adresse}". info["Adresse"][0]);
openDoc.saveAndClose();
const blobPDF= newTempFile.getAs(MimeType.PDF);
const pdfFile = pdfFolder.createFile(blobPDF). setName("My PDF");
}
It's possible that the error is caused by a mistake made few lines above as 1xmDYuQyqGCVCSQVWzdckBJUOdqjarhdKhEdfdMnh1og looks to be too long for a folder id (update: actually it's a document id)
try replacing
const templateDoc = DriveApp.getFolderById('1xmDYuQyqGCVCSQVWzdckBJUOdqjarhdKhEdfdMnh1og');
by
const templateDoc = DriveApp.getFileById('1xmDYuQyqGCVCSQVWzdckBJUOdqjarhdKhEdfdMnh1og');
according to this question, Google Form Upload files to specific new folder based on the value submitted
which lead to this code for google form script editor:
function onFormSubmit(e) {
const folderId = "1HVTDe5YxYDolXrEaGebHOoypYqG38d_fkauOGg5hCAqQfw-amW5aIazflSJEl7THNGTn-nq3"; // Please set top folder ID of the destination folders.
const form = FormApp.getActiveForm();
const formResponses = form.getResponses();
const itemResponses = formResponses[formResponses.length-1].getItemResponses();
Utilities.sleep(3000); // This line might not be required.
// Prepare the folder.
const destFolder = DriveApp.getFolderById(folderId);
const folderName = itemResponses[0].getResponse();
const subFolder = destFolder.getFoldersByName(folderName);
const folder = subFolder.hasNext() ? subFolder : destFolder.createFolder(folderName);
// Move files to the folder.
itemResponses[1].getResponse().forEach(id => DriveApp.getFileById(id).moveTo(folder));
}
i got an error saying: TypeError: itemResponses[1].getResponse(...).forEach is not a function
what should i do to get this code run succesfully?
i am completely new at this stuff, and any kind of help would be really appreciated. Thanks.
edit: Thank You #Tanaike !. It's cleared. Thank you for your help, this case is closed.
Modify
itemResponses[1].getResponse().forEach(id => DriveApp.getFileById(id).moveTo(folder));
to :
itemResponses[2].getResponse().forEach(id => DriveApp.getFileById(id).moveTo(folder));
that is the answer to my question, credit to #Tanaike.
here is the link of the comment to that answer:
Google Form how to upload files and then place it into new folder based on the value submitted
I have a Google Sheet with content in say Col 1. One sentence in each row. I am looking for a script which can save the Col 1 as 'epub' with each sentence (in row) as a new page.
I believe your current situation and your goal as follows.
In your Spreadsheet, there are the sentences in each row of the column "A".
You want to retrieve a value from a cell of column "A" and convert it as a file of EPUB on your Google Drive.
You want to achieve this using Google Apps Script.
In this case, I would like to propose the following flow.
Retrieve the values from the column "A" of the Spreadsheet.
Create Google Document as the temporal file.
Copy the values to Google Document.
Export Google Document as EPUB of application/epub+zip and save it as a file on Google Drive.
Remove the temporal file.
When above flow is reflected to the script, it becomes as follows.
Sample script:
Please copy and paste the following script to the script editor of Google Spreadsheet you want to use. And, please run myFunction. By this, the values are retrieved from the cells "A1:A" and create EPUB files using the values of each row.
function myFunction() {
const sheetName = "Sheet1"; // Please set the sheet name.
const folderId = "root"; // Please set the folder ID you want to export the EPUB files. In the case of "root", the files are created to the root folder.
// 1. Retrieve the values from the column "A" of the Spreadsheet.
const sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName(sheetName);
const startRow = 1;
const endRow = sheet.getLastRow();
const values = sheet.getRange(`A${startRow}:A${endRow}`).getDisplayValues();
// 2. Create Google Document as the temporal file.
const tempDoc = DocumentApp.create("temp");
const id = tempDoc.getId();
const url = "https://docs.google.com/feeds/download/documents/export/Export?exportFormat=epub&id=" + id;
const params = {headers: {authorization: `Bearer ${ScriptApp.getOAuthToken()}`}};
const folder = DriveApp.getFolderById(folderId || "root");
const ids = values.map(([a], i) => {
// 3. Copy the values to Google Document.
const filename = `rowNumber${i + 1}`;
const doc = DocumentApp.openById(id).setName(filename);
doc.getBody().clear().appendParagraph(a);
doc.saveAndClose();
// 4. Export Google Document as EPUB of `application/epub+zip` and save it as a file on Google Drive.
const blob = UrlFetchApp.fetch(url, params).getBlob().setName(`${filename}.epub`);
return folder.createFile(blob).getId();
});
console.log(ids); // Here, you can see the file IDs of the created EPUB files at the log.
// 5. Remove the temporal file.
DriveApp.getFileById(id).setTrashed(true);
}
In this sample script, the filename is rowNumber${i + 1}. So, the created filename is like rowNumber1.epub, rowNumber2.epub. If you want to change this, please modify above script.
The endpoint of const url = "https://docs.google.com/feeds/download/documents/export/Export?exportFormat=epub&id=" + id; is from exportLinks of the method of "Files: get" of Drive API. Ref
Note:
In this case, when a lot of rows are existing in your Spreadsheet, the process time might be over the maximum execution time of 6 minutes. Please be careful this. If the process time is over the maximum execution time, please modify the values of startRow and endRow.
If an error related to Drive API occurs, please enable Drive API at Advanced Google servicves.
If you want to convert the values of the column "A" as one EPUB file, you can also use the following script.
function myFunction2() {
const sheetName = "Sheet1";
const folderId = "root"; // Please set the folder ID you want to export the EPUB files. In the case of "root", the files are created to the root folder.
const filename = `sampleFile`; // Please set the output filename.
// 1. Retrieve the values from the column "A" of the Spreadsheet.
const sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName(sheetName);
const startRow = 1;
const endRow = sheet.getLastRow();
const values = sheet.getRange(`A${startRow}:A${endRow}`).getDisplayValues();
// 2. Create Google Document as the temporal file.
const tempDoc = DocumentApp.create(filename);
// 3. Copy the values to Google Document.
tempDoc.getBody().clear().appendParagraph(values.flat().join("\n"));
tempDoc.saveAndClose();
const id = tempDoc.getId();
// 4. Export Google Document as EPUB of `application/epub+zip` and save it as a file on Google Drive.
const url = "https://docs.google.com/feeds/download/documents/export/Export?exportFormat=epub&id=" + id;
const params = {headers: {authorization: `Bearer ${ScriptApp.getOAuthToken()}`}};
const folder = DriveApp.getFolderById(folderId || "root");
const blob = UrlFetchApp.fetch(url, params).getBlob().setName(`${filename}.epub`);
const createdFileId = folder.createFile(blob).getId();
console.log(createdFileId); // Here, you can see the file ID of the created EPUB file at the log.
// 5. Remove the temporal file.
DriveApp.getFileById(id).setTrashed(true);
}
References:
Spreadsheet Service
Class UrlFetchApp
Drive Service
You need to enable Advanced Drive API
function makeEPUB() {
const ss = SpreadsheetApp.getActive();
const sh = ss.getSheetByName('Sheet1');
const rg = sh.getRange(1,1,sh.getLastRow(),1);
const vs = rg.getDisplayValues().flat();//get rows
const document = DocumentApp.create('mydoc');//creat doc
let body = document.getBody();
vs.forEach(s =>{body.appendParagraph(s);body.appendPageBreak();});//append sentences and page breaks
document.saveAndClose();
let exportLink = Drive.Files.get(document.getId()).exportLinks["application/epub+zip"];
let response = UrlFetchApp.fetch(exportLink, {headers: {Authorization: "Bearer " + ScriptApp.getOAuthToken()}});
let file = DriveApp.createFile(response.getBlob());
file.setName(document.getName() + ".epub");
}
Mostly Copied from Amit Agarwal
Don't know if it works. Have no way that I know of to test it.
is there a way to create an image (e.g. a png) from a google document?
I really mean an image, not just a pdf. GetAS only creates pdf, but returns an error if contentType is set to image/png or other equivalent formats.
My (actually trivial) code is
function convertFile() {
var SOURCE_TEMPLATE = "1HvqYidpUpihzo_HDAQ3zE5ScMVsHG9NNlwPkN80GHK0";
var TARGET_FOLDER = "1Eue-3tJpE8sBML0qo6Z25G0D_uuXZjHZ";
var source = DriveApp.getFileById(SOURCE_TEMPLATE);
var targetFolder = DriveApp.getFolderById(TARGET_FOLDER);
var target = source.makeCopy(source,targetFolder);
var newFile = DriveApp.createFile(target.getAs('image/png'));
}
When I run this code, I get the following error (my translation):
The conversion from application/vnd.google-apps.document to image/png is not supported.
Ty
How about this answer?
Reason of error:
makeCopy() returns File object. getAs() cannot be used for this. By this, the error occurs.
Workaround:
Unfortunately, in the current stage, Google Document cannot be directly exported as PNG images. So it is required to think of workarounds. Google Document can be converted to PDF. This answer uses this. As a workaround, I would like to propose to use an external API which is ConvertAPI. I thought that using the external API, the script becomes simple. This a method (PDF to PNG API) of API can be converted from PDF data to PNG data.
When you try this, for example, you can also test this using "Free Package". When you try using "Free Package", please Sign Up at "Free Package" and retrieve your Secret key.
Sample script:
Before you run this script, please retrieve your Secret key and set it.
var secretkey = "###"; // Please set your secret key.
var SOURCE_TEMPLATE = "1HvqYidpUpihzo_HDAQ3zE5ScMVsHG9NNlwPkN80GHK0";
var TARGET_FOLDER = "1Eue-3tJpE8sBML0qo6Z25G0D_uuXZjHZ";
var url = "https://v2.convertapi.com/convert/pdf/to/png?Secret=" + secretkey;
var options = {
method: "post",
payload: {File: DriveApp.getFileById(SOURCE_TEMPLATE).getBlob()},
}
var res = UrlFetchApp.fetch(url, options);
res = JSON.parse(res.getContentText());
res.Files.forEach(function(e) {
var blob = Utilities.newBlob(Utilities.base64Decode(e.FileData), "image/png", e.FileName);
DriveApp.getFolderById(TARGET_FOLDER).createFile(blob);
});
References:
makeCopy()
getAs()
ConvertAPI
PDF to PNG API of ConvertAPI
Updated on January 11, 2023:
In the current stage, Google Apps Script can use V8 runtime. By this, there are some Javascript libraries that can be used with Google Apps Script. Ref1, Ref2 In this question, in the current stage, by using pdf-lib, all pages in a PDF file can be converted to PNG images using Google Apps Script. The sample script is as follows.
Sample script:
This method uses Drive API. Please enable Drive API at Advanced Google services.
Please set SOURCE_TEMPLATE and TARGET_FOLDER, and run main().
/**
* This is a method for converting all pages in a PDF file to PNG images.
* PNG images are returned as BlobSource[].
* IMPORTANT: This method uses Drive API. Please enable Drive API at Advanced Google services.
*
* #param {Blob} blob Blob of PDF file.
* #return {BlobSource[]} PNG blobs.
*/
async function convertPDFToPNG_(blob) {
// Convert PDF to PNG images.
const cdnjs = "https://cdn.jsdelivr.net/npm/pdf-lib/dist/pdf-lib.min.js";
eval(UrlFetchApp.fetch(cdnjs).getContentText()); // Load pdf-lib
const setTimeout = function (f, t) { // Overwrite setTimeout with Google Apps Script.
Utilities.sleep(t);
return f();
}
const data = new Uint8Array(blob.getBytes());
const pdfData = await PDFLib.PDFDocument.load(data);
const pageLength = pdfData.getPageCount();
console.log(`Total pages: ${pageLength}`);
const obj = { imageBlobs: [], fileIds: [] };
for (let i = 0; i < pageLength; i++) {
console.log(`Processing page: ${i + 1}`);
const pdfDoc = await PDFLib.PDFDocument.create();
const [page] = await pdfDoc.copyPages(pdfData, [i]);
pdfDoc.addPage(page);
const bytes = await pdfDoc.save();
const blob = Utilities.newBlob([...new Int8Array(bytes)], MimeType.PDF, `sample${i + 1}.pdf`);
const id = DriveApp.createFile(blob).getId();
Utilities.sleep(3000); // This is used for preparing the thumbnail of the created file.
const link = Drive.Files.get(id, { fields: "thumbnailLink" }).thumbnailLink;
if (!link) {
throw new Error("In this case, please increase the value of 3000 in Utilities.sleep(3000), and test it again.");
}
const imageBlob = UrlFetchApp.fetch(link.replace(/\=s\d*/, "=s1000")).getBlob().setName(`page${i + 1}.png`);
obj.imageBlobs.push(imageBlob);
obj.fileIds.push(id);
}
obj.fileIds.forEach(id => DriveApp.getFileById(id).setTrashed(true));
return obj.imageBlobs;
}
// Please run this function.
async function myFunction() {
const SOURCE_TEMPLATE = "1HvqYidpUpihzo_HDAQ3zE5ScMVsHG9NNlwPkN80GHK0";
const TARGET_FOLDER = "1Eue-3tJpE8sBML0qo6Z25G0D_uuXZjHZ";
// Use a method for converting all pages in a PDF file to PNG images.
const blob = DriveApp.getFileById(SOURCE_TEMPLATE).getBlob();
const imageBlobs = await convertPDFToPNG_(blob);
// As a sample, create PNG images as PNG files.
const folder = DriveApp.getFolderById(TARGET_FOLDER);
imageBlobs.forEach(b => folder.createFile(b));
}
When this script is run, all pages of the inputted PDF file are converted to PNG images, and those images are created in the destination folder.
Note:
I think that the above script works. But, in this case, when you directly copy and paste the Javascript retrieved from https://cdn.jsdelivr.net/npm/pdf-lib/dist/pdf-lib.min.js to your Google Apps Script project, the process cost for loading it can be reduced.
References:
pdf-lib
copyPages of pdf-lib
addPage of pdf-lib
I know this is an older question, but I thought I'd answer, since I believe I've found a solution that doesn't involve paying for a third-party subscription.
This can be accomplished by accessing the thumbnail of the Doc and creating a new PNG file from that thumbnail. Try this:
function convertFile() {
var SOURCE_TEMPLATE = "1HvqYidpUpihzo_HDAQ3zE5ScMVsHG9NNlwPkN80GHK0";
var TARGET_FOLDER = "1Eue-3tJpE8sBML0qo6Z25G0D_uuXZjHZ";
var source = DriveApp.getFileById(SOURCE_TEMPLATE).getThumbnail().getAs('image/png');
var targetFolder = DriveApp.getFolderById(TARGET_FOLDER);
TARGET_FOLDER.createFile(source);
}
However, I've found that getting the thumbnail of the Doc is not as high quality as getting the thumbnail of a PDF created from the Doc. You can try the code below to compare which version of the new PNG you prefer.
To do this, you will also need to enable Advanced Services on your project, specifically the Drive API service. To do this, follow these instructions to add a new Service to your Google Apps Script project:
Open the Apps Script project.
At the left, click Editor < >.
At the left, next to Services, click Add a service +.
Select Drive API and click Add.
Once you do that, you'll be able to use the Drive command in your script, which is different than DriveApp. Note also the update to source.makeCopy() to only include the TARGET_FOLDER:
function convertFile() {
var SOURCE_TEMPLATE = "1HvqYidpUpihzo_HDAQ3zE5ScMVsHG9NNlwPkN80GHK0";
var TARGET_FOLDER = "1Eue-3tJpE8sBML0qo6Z25G0D_uuXZjHZ";
var source = DriveApp.getFileById(SOURCE_TEMPLATE);
var targetFolder = DriveApp.getFolderById(TARGET_FOLDER);
var target = source.makeCopy(targetFolder);
var pdfBlob = target.getAs(MimeType.PDF);
var newPDF = TARGET_FOLDER.createFile(pdfBlob).setName('Some Name.pdf');
var newId = newPDF.getId();
Drive.Files.update({
title: newPDF.getName(), mimeType: MimeType.PDF
}, newId, pdfBlob);
var newFile = DriveApp.getFileById(newId).getThumbnail().getAs('image/png');
TARGET_FOLDER.createFile(newFile);
target.setTrashed(true);
newPDF.setTrashed(true);
}
This code will create a copy of your Google Doc file, convert it to a PDF, then grab the thumbnail of the PDF as a PNG, and then delete the copy of the Doc file and the PDF that were created.
The Drive.Files.update() function is the critical part of this code, as it finalizes the creation of the PDF file in your Drive. Trying to run the code without that portion will just return the new PDF file as null since the new PDF hasn't completely finished being created at that point.
Hope this helps!