Google apps script, openByURL returns missing file? - file

I've been trying to figure out why part of my Google App script doesn't work, but I've failed to come up with an answer.
The script is downloading an attachment, CSV, from an email in Gmail and stores in with a specific name in a specific folder - this works perfectly fine.
But then I want to edit the CSV, and this is where I run into problems.
var newFolderIterator = DriveApp.getFoldersByName(destinationFolderName)
var newFolderId, myFileName, myFileId
while(newFolderIterator.hasNext()) {
newFolderId = newFolderIterator.next().getId()
var newFileList = DriveApp.getFolderById(newFolderId).getFiles()
while(newFileList.hasNext()) {
myFileName = newFileList.next()
myFileId = myFileName.getId()
var myFileURL = myFileName.getUrl()
Logger.log(myFileName.getId() + " " + myFileName.getName()) //Logs the ID and Name
Logger.log(myFileURL) //Logs the URL
var ss = SpreadsheetApp.openById(myFileName.getId()) //Error, cannot find the ID (error message: perhaps it's missing?)
}
}
I've tried using the openByURL as well, with the same error message.
Probably really easy to fix, any hints and tips is appreciated.
Thanks

The problem here is you are uploading a CSV but attempting to open it with SpreadsheetApp. SpreadsheetApp can only open Google Sheets documents, and your CSV is not automatically converted.
The CSV must first be converted to a Google Sheets document before you can access it with SpreadsheetApp.
You may be able to do this on upload, but I haven't tried this personally. This question looks relevant:
How to automatically import data from uploaded CSV or XLS file into Google Sheets

Related

Update an XML file in Google Drive via Google API

Let's say I have this minimal XML file on Google Drive.
<?xml version="1.0" encoding="UTF-8"?>
<MyCounter>
<counter>137</counter>
</MyCounter>
Using Google Script, I want to:
parse the XML
add 1 to the counter
update the file.
I'm at step 2 at the moment. I can delete the old file and create a new one with the same name and updated content. I prefer to update the existing one instead, so it will maintain the unique ID, and I can access the file with said ID instead of searching for it via file name.
You want to update a text file in your Google Drive without changing the file ID.
You want to add 1 to 137 of <counter>137</counter> in the file.
You want to achieve above using Google Apps Script.
If my understanding is correct, how about this sample script? I think that there are several answers for your situation. So please think of this as just one of them.
Flow:
Retrieve data from the text file.
Add 1 to number of <counter>{number}</counter> using replace().
Update the file using setContent().
By this flow, the file can be updated without changing file ID.
Sample script:
var fileId = "#####"; // Please set fileId here.
var file = DriveApp.getFileById(fileId);
var str = file.getBlob().getDataAsString();
var r = str.replace(/<counter>(\d+)<\/counter>/, function(_, p) {
return "<counter>" + (Number(p) + 1) + "</counter>";
});
file.setContent(r);
Note:
If you have already prepared the script for adding the counter, please use it.
References:
replace()
setContent()

Download xlsx file passed from nodejs to frontend angularjs

I have a JSON array of objects that is a result of a function in nodejs. I use json2xls to convert that to an excel file, and it downloads to the server (not in a public folder, and is formatted correctly in Excel).
I would like to send a response to the frontend with the json results (to display as a preview) and show a button they can click to download the xlsx file OR display the JSON results and automatically download the file.
But I can't get it, and I've tried so many things I'm going crazy.
My controller code (the part that creates the xls file):
var xls = json2xls(results,{});
var today = (new Date()).toDateString('yyyy-mm-dd');
var str = today.replace(/\s/g, '');
var fileName = "RumbleExport_"+ str +".xlsx";
var file = fs.writeFileSync(fileName,xls,'binary');
res.download('/home/ubuntu/workspace/'+file);
The frontend controller:
vm.exportData = function(day, event, division) {
console.log('Export registrations button pressed.', vm.export);
//send the search parameters to the backend to run checks
$http.post('/api/exportData', vm.export).then(function(response){
vm.results = response.data;
console.log("Results",response);
vm.exportMessage = "Found " + vm.results.length + " registrations.";
})
.catch(function(error){
vm.exportError = error.data;
});
};
The view:
//display a button to download the export file
<a target="_self" file="{{vm.results}}" download="{{vm.results}}">Download Export File</a>
Someone please put me out of my misery. All the classes I've taken and none have covered this.
I FINALLY got it! And since I searched forever trying to make something work, I'll share the answer:
On the backend:
//save the file to the public/exports folder
var file = fs.writeFileSync('./public/exports/'+fileName,xls,'binary');
//send the results to the frontend
res.json(200).json({results:results, fileName: fileName});
On the frontend, use HTML to download a link to the file:
<a href="exports/{{fileName}}" download>Save File</a>

Python 2.7 and blobkeys: how to return the filename instead of the url?

Very new to Python/Google App Engine and just trying to work my way around a pretty massive application. This is what I currently have:
file_keys = self.request.get_all('blobKey').filename
file_links = []
for key in file_keys:
file_links.append('https://www.mysite.com/admin/downloads/%s' % key)
This will return something similar to this:
https://www.mysite.com/admin/downloads/4NLNpXrzZ0vjOZcOPzZpiQVoASeSXlZukbq0AMyFlmGYDhNZrWaRASBxL8TC6gjw
How would I go about returning just the file name? (It's a form where you enter some information and provide a file, and I would like to return that specific file's filename in the email sent out instead of the generated URL).
I would think filename would work as shown here: https://developers.google.com/appengine/docs/python/blobstore/blobinfoclass
But have not had any luck with that.
Any input is appreciated.
This is the solution I came up with:
file_keys = self.request.get_all('blobKey')
blob_info_list = blobstore.BlobInfo.get(file_keys)
file_info_list = []
for blob in blob_info_list:
info = {"file_name":blob.filename, "key":blob.key()}
file_info_list.append(info)
template_dict = { 'file_info_list':file_info_list}

Google Apps Scripts - How to replace a file?

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 to download a pdf file in Composite c1

I'm trying to implement a functionality that enables a user to download a PDF on clicking on a hyper-link. What i've done is, I've created a global datatype Publications which takes values "Description" and "PDF DOC" and I've a user control with a hyper-link which binds the description as its text.
LinkButton1.Text = details.Description;
Composite.Data.DataReference<IMediaFile> i = new Composite.Data.DataReference<IMediaFile>((details as A.DataTypes.Publications).PdfDoc);
string filePath = "/media(" + i.Data.Id + ")";
and on the click on the link button I've...
Response.ContentType = "Application/pdf";
Response.AppendHeader("Content-Disposition", "attachment; filename=Test_PDF.pdf");
Response.TransmitFile(filePath );
Response.End();
this is showing an error saying "could not find file", any idea why?
It looks like you are trying to use the C1 syntax for media files at a place where the C1 page renderer never replaces it with the actual url of the file. So you end up passing something like /media(b5354eba-3f69-4885-9eba-74576dff372d) to the Response.TransmitFile() function, which will not work because that is not a valid file path.
If you use this syntax on a C1 page, the page renderer will replace it with the real url of the file.
My advise would be to build this URL yourself and just link to it, instead of using TransmitFile. A simple redirect will suffice if the file is open for public access. If it is lying acessible on the web server already, there is not much point in using Response.TransmitFile and fetching it and writing it in the outputstream.
Try look at the DownloadFoldersAsZip package (https://bitbucket.org/burningice/compositec1contrib/src/4c31794cd46c/DownloadFoldersAsZip?at=default) which has this functionality. The main issue with your code is that you make the assumption of where the files are stored. You can't do that with the C1 Media Archive, since files can be either local, in a database, in Azure Blob storage or just a random place on the internet.
Instead you should use the GetReadStream() extension method of your IMediaFile instance. This will give you a stream which you can copy unto your Response.ResponseStream
See here for an example: https://bitbucket.org/burningice/compositec1contrib/src/4c31794cd46cb03dd0b0ee830b83204753355b03/DownloadFoldersAsZip/Web/GenerateZipHandler.cs?at=default#cl-145
solved it, just needed to give....string filePath = "~/media({" + i.Data.Id + "})"; instead of string filePath = "/media(" + i.Data.Id + ")";
You can also use this code
Composite.Data.DataReference i = new Composite.Data.DataReference((details as A.DataTypes.Publications).PdfDoc)
This gives the media file reference
string fileName = "/App_Data/Media/" + i.Data.Id.ToString();
this.Response.AddHeader("content-disposition", string.Format(
"attachment;filename=download.pdf", Path.GetFileName(fileName)));
this.Response.ContentType = "application/pdf";
this.Response.WriteFile(this.Server.MapPath(fileName));
This can get the file Downloaded as download.pdf

Resources