Replace attachment when uploading a new attachment - file-upload

I have a simple form and body field. when user upload an attachment I want to remove any attachment already in the body field of the document. how can I do this in my save button.
I have tried to set the properites on the fileUpload control to always change the filename to tha same name but this does not replace the file, instead it adds a new file and add a new sequential number to it
<xp:fileUpload id="fileUpload1" value="#{userdoc.Body}" filename="profile" seUploadname="false"></xp:fileUpload>
I have also tried to loop all embedded attachments in body field before before save, and all attachments are then removed, but my new attachment is not added.

A little late, but in case anyone gets here just as I did through Google...
There's also another option: a NotesXSPDocument.getAttachmentList("rtitem") returns a list of attachments in the document. Each entry is of type DominoDocument.AttachmentValueHolder which has a getState() property that returns if a file was already in the document or just added. To remove the file that was already in the document you could add this SSJS code to a save button (assuming "files" is the name of the richtext item holding the files):
var attList = docFile.getAttachmentList("files");
for(var i=0; i<attList.size(); i++) {
var att = attList.get(i);
if (att.getState()==0) { //STATE_INDOCUMENT: this is the 'old' file: remove it
docFile.removeAttachment("files", att.getName() );
} else if (att.getState()==1) { //STATE_ADDED: this is the new file
//leave it
}
}

This can be done by removing all attachments first (use the removeAllAttachments function from NotesXSPDocument object) and then attach the uploaded file manually to the richtext item.
This SSJS code has to be added to beforeRenderResponse-event of your XPage / Custom Control:
var con = facesContext.getExternalContext();
var request:com.sun.faces.context.MyHttpServletRequestWrapper = con.getRequest();
var map:java.util.Map = request.getParameterMap();
var fileDataName = getClientId('fileUpload1') ;
var fileData:com.ibm.xsp.http.UploadedFile = map.get( fileDataName );
if( fileData == null ){
return;
}
var tempFile:java.io.File = fileData.getServerFile();
var correctedFile = new java.io.File( tempFile.getParentFile().getAbsolutePath() +
java.io.File.separator + fileData.getClientFileName() );
var success = tempFile.renameTo(correctedFile);
try{
document1.removeAllAttachments("Body");
}catch(e){}
var rtFiles:NotesRichTextItem = null;
if(!(document1.getDocument().hasItem("Body"))){
rtFiles = document1.getDocument().createRichTextItem("Body")
}else{
rtFiles = document1.getDocument().getFirstItem("Body");
}
rtFiles.embedObject(lotus.domino.local.EmbeddedObject.EMBED_ATTACHMENT, "",
correctedFile.getAbsolutePath(), null);
correctedFile.renameTo(tempFile);
document1.save();
The richtext item where the files are stored is "Body", the name of the datasource is "document1". The Fileupload control is "fileUpload1".
There are two limitations:
You cannot use this with a save button, you have to use a normal button / link which makes a full refresh (see what Serdar Basegmez wrote above)
You have to refresh the page after a upload once again, otherwise you will not see the uploaded file in a file download conrol (maybe a partial refresh to this control may work).
EDIT:
Sorry, my fault: You can use this code above in a submit button that saves the document. Then you don't have to refresh the page manually!

Related

Extract Text from Multipage Attachment PDF Using Google Apps Script

I have a Gmail attachment PDF with multiple scanned pages. When I use Google Apps Script to save the blob from the attachment to a Drive file, open the PDF manually from Google Drive, then select Open With Google Docs, all of the text from the PDF is displayed as a Google Doc. However, when I save the blob as a Google Doc with OCR, only the text from the image on the first page is saved to a Doc, accessed either manually or by code.
The code to get the blob and process it is:
function getAttachments(desiredLabel, processedLabel, emailQuery){
// Find emails
var threads = GmailApp.search(emailQuery);
if(threads.length > 0){
// Iterate through the emails
for(var i in threads){
var mesgs = threads[i].getMessages();
for(var j in mesgs){
var processingMesg = mesgs[j];
var attachments = processingMesg.getAttachments();
var processedAttachments = 0;
// Iterate through attachments
for(var k in attachments){
var attachment = attachments[k];
var attachmentName = attachment.getName();
var attachmentType = attachment.getContentType();
// Process PDFs
if (attachmentType.includes('pdf')) {
processedAttachments += 1;
var pdfBlob = attachment.copyBlob();
var filename = attachmentName + " " + processedAttachments;
processPDF(pdfBlob, filename);
}
}
}
}
}
}
function processPDF(pdfBlob, filename){
// Saves the blob as a PDF.
// All pages are displayed if I click on it from Google Drive after running this script.
let pdfFile = DriveApp.createFile(pdfBlob);
pdfFile.setName(filename);
// Saves the blob as an OCRed Doc.
let resources = {
title: filename,
mimeType: "application/pdf"
};
let options = {
ocr: true,
ocrLanguage: "en"
};
let file = Drive.Files.insert(resources, pdfBlob, options);
let fileID = file.getId();
// Open the file to get the text.
// Only the text of the image on the first page is available in the Doc.
let doc = DocumentApp.openById(fileID);
let docText = doc.getBody().getText();
}
If I try to use Google Docs to read the PDF without OCR directly, I get Exception: Invalid argument, for example:
DocumentApp.openById(pdfFile.getId());
How do I get the text from all of the pages of the PDF?
DocumentApp.openById is a method that can only be used for Google Docs documents
pdfFile can only be "opened" with the DriveApp - DriveApp.getFileById(pdfFile.getId());
Opening a file with DriveApp allows you to use the following methods on the file
When it comes to OCR conversion, your code works for me correctly to convert all pages of a PDF document to Google Docs, so you error source is likely come from the attachment itself / the way you retrieve the blob
Mind that OCR conversion is not good at preserving formatting, so a two page PDF might be collapsed into a one-page Docs - depneding on the formatting of the PDF

creating a PDF via google apps script but creates the PDF with an additional blank page

I have a apps script bound to a spreadsheet that creates a pdf file from the sheet. this creates one single page pdf and saves it in a folder in drive. Up until recently, this worked perfectly. Now every time I run the code it does what it is supposed to but the file has a second page that is blank. When I create the pdf manually via file/download as/pdf doc, it creates the pdf as it should, with only one page. I have tried this with both the original and copy that the script temporarily creates. Both work when done manually. I am looking for some suggestions on what could have gone wrong and what to change. Here is an example of the code:
function makePDF() {
var sheet1 = SpreadsheetApp.getActive().getSheetByName('eTimesheet');
var sheet2 = SpreadsheetApp.getActive().getSheetByName('Time Sheet');
var sheet3 = SpreadsheetApp.getActive().getSheetByName('Data');
var triggercell3 = sheet1.getRange('M33').getValue();
if (triggercell3 == 'GO'){
var techNumber = sheet3.getRange('B5').getValue();
var date = sheet3.getRange('B3').getValue();
var fileID = sheet3.getRange('B7').getValue();
var pdfName = "TimeSheet- "+ techNumber + " " + date
var ss = SpreadsheetApp.getActive();
var folder = DriveApp.getFolderById(fileID);
sheet2.showSheet();
sheet1.hideSheet();
//Copy whole spreadsheet
var destSpreadsheet = SpreadsheetApp.open(DriveApp.getFileById(ss.getId()).makeCopy("tmp_convert_to_pdf", folder))
//save to pdf
var theBlob = destSpreadsheet.getBlob().getAs('application/pdf').setName(pdfName);
var newFile = folder.createFile(theBlob);
DriveApp.getFileById(destSpreadsheet.getId()).setTrashed(true);
sheet1.showSheet();
sheet2.hideSheet();
sheet1.getRange('M33').clearContent();
}
}
thanks for any assistance...
Without an example, first question I have is... if you delete a few rows from the sheet and run the script, are you back to 1 page?
I am asking in case the issue is just margin settings. If this is the issue, maybe you can adjust rows or use the UrlFetchApp.fetch approach as PDF page formatting can be specified (eg: margin size).

How to Download PDF Links in Column and Save to Common Folder

We have a column that contains links to PDFs that starts on line 4 (e.g B4:B). I am trying to find a way to automatically download the PDF files that are accessed via the links to a folder on Drive. This is what I have so far:
function savePDFs() {
var sheet = SpreadsheetApp.getActiveSheet();
var data = sheet.getDataRange().getValues();
for (var i = 3; i < data.length; i++) {
Logger.log(data[i][1]);
}
}
Presumably the above code would write the links starting in column B (index value of [1]) on row 4 (i value of 3) (ie., B4) until the bottom of the data set (eg., data.length()).
I'm now confused about how to access and save the PDF link that are written in the logger to a folder.
Would someone be willing to help me out? I'm currently having to go to each link, click Save Link As... and then navigate to the folder that I'd like to save the linked PDF to. My hope is to modify the above process using code.
Update: I found this bit of code here that may help me out. Note, I changed the PDF link to a currently valid PDF link.
var urlOfThePdf = 'http://download.p4c.philips.com/l4b/9/929000277411_eu/929000277411_eu_pss_aenaa.pdf';// an example of online pdf file
var folderName = 'GAS';// an example of folder name
function saveInDriveFolder(){
var folder = DocsList.getFolder(folderName);// get the folder
var file = UrlFetchApp.fetch(urlOfThePdf); // get the file content as blob
folder.createFile(file);//create the file directly in the folder
}
Okay, I'm going to go and noodle with the data that is in the logger to confirm that the data is in properly formatted PDF links, then I'm going to test this new bit of code out. I feel like I'm getting close.
You can't force a download of a file from an apps script, you must try that from an HTMLService and not sure it will work.
For your need I would recommend to create a dedicated folder and you add all the pdf in it and you use the download function of the drive interface to download all files in one clic.
In drive, a file can be put in several folders so the pdf files stay in the original folder but you create a new folder 'PDF for download" for example and you put them in it. To do that from drive interface you have to click on "shift"+Z when file(s) is/are selected.
For you current list of file you just have to add in your loop the add to folder function. You can use this function.
function addFileToFolder(id){
var folderPDF = DriveApp.getFolderById("Id OFFolder to put pdf");
var file = DriveApp.getFileById(id);
folderPDF.addFile(file);
}
EDIT : Function will browse list of url, get the file and make a copy in a dedicated folder on the user drive.
function downloadInDriveFolder(){
var folderID = 'Id of the folder';// put id of the folder
var folder = DriveApp.getFolderById(folderID)// get the folder
var sheet = SpreadsheetApp.getActiveSheet();
var data = sheet.getDataRange().getValues();
for (var i = 3; i < data.length; i++) {
var blob = UrlFetchApp.fetch(data[i][1]).getContent();
var pdf = DriveApp.createFile(blob);
pdf.setName(data[i][0]);//Put as name of the file the value in col A
folder.addFile(pdf);
}
}
Well I figured it out. I was expecting more code, but this does it for me:
function listPDFs() {
var out = new Array();
var row = 3; //row index of 0 = row 1
var column = 4; // column index of 0 = column A
var sheet = SpreadsheetApp.getActiveSheet();
var data = sheet.getDataRange().getValues();
var folder = DriveApp.getFolderById("this is where you paste your folder id"); // destination folder (this is the 0978SDFSDFKJHSDF078Y98hkyo looking value when you right click your folder and select "Get Link")
for (var i=row ; i<data.length ; i++) {
if(data[i][column] !== "") {
var file = UrlFetchApp.fetch(data[i][column]);
folder.createFile(file);
}
}
return
}
As you can see, I included a row and column variable so that I could easily change these.
I haven't figured out how to assemble them into a merged PDF, but I did figure out that I could sort them by date (which places the top most item first) and then right click and select "Open With...PDF Mergy", which then moves the PDFs into PDF Mergy and merges them up in the correct order. You can find PDF Mergy in the Chrome App Store. If I figure out how to automatically call PDF Mergy from GAS, I'll post that up--but for the time being the above code has saved us a ton of time...so I'm calling it good enough for the time being.

How can I map a Google form submission to a template and email to specific individuals as a PDF?

I am trying to have users submit information through Google forms and have the information inserted into a Google Doc as a template. The completed document would then be converted to a PDF and emailed out to the individual. The issue that I am having is that nothing seems to be produced upon form submission. Help would be appreciated!
Here is the code that I am using:
//Get template from Google Docs and name it
var docTemplate = "1ebZTRMRJTxEkNQl1Y2XTSCmIMhmThSMk3BDEQrJbOBE";
var docName = "Unit Overview Template";
//When Form Gets Submitted
function onFormSubmit(e){
//Get information from form and set as variables
var email_address = "e.values[5]";
var teacher_name = e.values[2];
var unit_name = e.values[6];
var unit_length = e.values[7];
var unit_start = e.values[3];
var course_period = e.values[4];
//Get document template, copy it as a new temp doc, and save the Doc's id
var copyId = DocsList.getFilebyId(docTemplate)
.makeCopy(docName+' for ' +teacher_name)
.getId();
//Open the temporary document
var copyDoc = DocumentApp.openById(copyId);
//Get the document's body section
var copyBody = copyDoc.getActiveSection();
//Replace place holder keys, in our google doc template
copyBody.replaceText('keyFullName', teacher_name);
copyBody.replaceText('keyUnitName', unit_name);
copyBody.replaceText('keyUnitDays', unit_length);
copyBody.replaceText('keyUnitPeriod', course_period);
copyBody.replaceText('keyUnitStart', unit_start);
//Save and close the temporary document
copyDoc.saveAndClose();
//Convert temporary document to PDF
var pdf = DocsList.getFilebyId(copyID).getAs("application/pdf");
//Attach PDF and send the email
var subject = "Unit Lesson Overview";
var body = "Here is your completed Unit Overview for " + unit_name + "";
MailApp.sendEmail(email_address, subject, body, {htmlBody: body, attachments: pdf});
//Delete temp file
DocsList.getFilebyId(copyId).setTrashed(true);
}
Use DriveApp instead of DocsList as the latter is deprecated. Also make sure you have a trigger setup for onFormSubmit under Resources - current project triggers inside the Script Editor.

Need alternative to local or remote goto/destinations with merged documents

BACKGROUND
I have a java program that analyzes data and creates a pdf report using itext 5.
I recently had to add a summary of major problems at the start of the document so a user would not have to read over a hundred pages to find problems. Problems are only discovered when serially looking through the data.
I solved the problem by creating 3 pdf documents and then merging them, a start/title pdf, the summary of problems pdf, and the body or analysis pdf. (Basically splitting the original document at the point I wanted to insert the summary)
I use PdfReader and PdfCopy to combine the documents. I am able to keep the chapter bookmarks OK.
THE PROBLEM
As I encounter a significant problem I add it to the 'summary' document. I want to add a link in the summary to point to the problem in the body.
I tried to use Chunk.setLocalDestination and setLocalGoto but realized why that did not work, so I tried using setLocalDestination and setRemoteGoto (with and without 'file://'), but that did not work either. (Also, I used the final pdf document name in the RemoteGoto, not the temporary pdf document name.)
I do not want to use bookmarks because that seems wrong and would not look right.
I am hoping someone could suggest an alternate method or make a suggestion.
To recap, in my current code a create a Chunk with setLocalDestination and that chunk goes into the 'body' document. At the same time I create a setRemoteGoto which is put into the summary document. I was hoping when they were combined the link would work, but when the link is clicked, you go to the first page of the combined document.
Thanks.....
PS I have both iText in action books
CLARIFICATION 3/5/2014
What I was calling 'bookmarks' are really Chapter class entities that are inserted into sections of the 3 documents as they are being created.
After saving the 3 documents, PdfReader is used to open each and PdfCopy is used to put them into a new, final document.
I get the data from the Chapters, which creates the 'bookmarks' on the left side of the Pdf reader used by the user, e.g. Acrobat Reader.
int thisPdfPages = reader.getNumberOfPages();
reader.consolidateNamedDestinations();
java.util.List<HashMap<String, Object>> bookmarks = SimpleBookmark.getBookmark(reader);
if (bookmarks != null) {
if (pageOffset != 0) {
if (debug3) auditLogger.log("Shifting pages by " + pageOffset );
SimpleBookmark.shiftPageNumbers(bookmarks, pageOffset, null);
}
masterBookmarks.addAll(bookmarks);
}
for (int i = 0; i < thisPdfPages;) {
page = copy.getImportedPage(reader, ++i);
stamp = copy.createPageStamp(page);
// add page numbers
ColumnText.showTextAligned(stamp.getUnderContent(), Element.ALIGN_CENTER, new Phrase(String.format("page %d of %d", start + i, totalPages)), 297.5f, 28, 0);
stamp.alterContents();
copy.addPage(page);
}
PRAcroForm form = reader.getAcroForm();
if (form != null) {
copy.copyAcroForm(reader);
}
When analyzing the data I have 2 documents open, a base document which contains all the details and a summary document which contains notable events over some thresholds.
//NOTE section is part of the 'body' document
//NOTE summaryPhrase is a part of the 'summary' document
String linkName = "summaryPf_" + networkid ;
//create Link target
section.add(new Chunk("CHANGE TO EMPTY STRING WHEN WORKING").setLocalDestination( linkName ));
//create Link
Chunk linkChunk = new Chunk( "[Link] " );
Font linkFont = new Font( regularFont );
linkFont.setColor(BaseColor.BLUE);
linkFont.setStyle( Font.UNDERLINE );
linkChunk.setFont( linkFont );
boolean useLocal = true;
// both local and remote goto's fail
if (useLocal) {
linkChunk.setLocalGoto( linkName);
} else {
// all permutations of setting filename fail,
// but it does bring up a permissions dialog when the link is clicked.
//String remotePdfName = "file://./" + pdfReportName ;
//String remotePdfName = "file://" + pdfReportName ;
//String remotePdfName = "file:" + pdfReportName ;
String remotePdfName = pdfReportName ;
linkChunk.setRemoteGoto( remotePdfName, linkName);
}
// add link to summary document
summaryPhrase.add( linkChunk );
summaryPhrase.add( String.format("There were %d devices with ping failures", summaryCount));
summaryPhrase.add( Chunk.NEWLINE );
}
If I use setLocalGoto, when you click the link in the final document you goto the first page.
If I use setRemoteGoto, a dialog ask permission to go to a document, but the document fails to open, tried several permutations on filename.