Apps Script Advanced Drive API Service - newFile() Method not Creating a File - javascript

The newFile() method of the Advanced Drive API Service seems to return an object, but not create a file in my Google Drive. I can't find any documentation for this. Here is code that I tried, and the results I got.
function makeNewDoc() {
var file = Drive.newFile();
Logger.log('file ' + file);
file = {one: "value One"};
Logger.log('file ' + file);
Logger.log("file['one'] " + file['one']);
};
The LOGS print this:
file {}
file [object Object]
file['one'] value One
I tried adding a string inside the newFile() parenthesis:
function makeNewDoc() {
var file = Drive.newFile("some text");
Logger.log('file ' + file);
file = {one: "value One"};
Logger.log('file ' + file);
Logger.log("file['one'] " + file['one']);
for (var key in file) {
Logger.log('key: ' + key);
Logger.log('value: ' + file[key]);
};
};
That didn't produce an error, but it doesn't do anything either. Or I don't know what it's doing.
I've checked my Google drive many times after running the code many times, and there is never a new file in my Drive.
The newFile() method returns an object, that I can put new properties into, and then enumerate. But other than that, I have no idea what it does, or what use it has.
So, if anyone can tell me what the newFile() method, of the Drive API does, I would really like to know.

Below is an example how to make a new document with advanced Drive service
function createNewDoc(title,content,folderId){
var content = content || "";
// neither kind or mimeType properties seem to be necessary
// for Doc to be created, but are being included anyhow
var resource = {
title: title,
parents: [
{
"id": folderId,
"kind": "drive#fileLink"
}
],
mimeType: 'application/vnd.google-apps.document'
};
var blob = Utilities.newBlob(content);
var newfile = Drive.Files.insert(resource, blob, {"convert":"true"});
return newFile;
}

I used the answer code and there was a problem when creating the blob as HTML. The below code converts HTML as a string to a blob to be inserted into a document.
var content = '<!DOCTYPE html><html><body><b>Hello</b></body><html>'
var blob = Utilities.newBlob("").setDataFromString(content,'UTF-8').setContentType("text/html")
var newfile = Drive.Files.insert(resource, blob, {"convert":"true"});

Related

download pdf from URL into gDrive

I need to download a PDF from a link in the following format
fileURL = "https://docs.google.com/feeds/download/documents/export/Export?id=<...DOCID...>&revision=3970&exportFormat=pdf"
and add it to gDrive folder.
I have this code, but the generated file just contain "Blob" rather than the actual content
function dFile(fileName,fileURL) {
var response = UrlFetchApp.fetch(fileURL);
var fileBlob = response.getBlob().getAs('application/pdf');
var folder = DriveApp.getFolderById('..folderID..');
var result = folder.createFile(fileName,fileBlob,MimeType.PDF);
Logger.log("file created");
}
How to I download the actual PDF?
Update:
I have updated my code and now I get this as generated PDF. Which makes me think I need to auth, but not sure how to do it, I set up all auth in manifest already
function dFile(fileName,fileURL) {
var response = UrlFetchApp.fetch(fileURL);
var fileBlob = response.getBlob().getAs('application/pdf');
var folder = DriveApp.getFolderById('..folderID..');
var result = folder.createFile(fileBlob).setName(fileName);
Logger.log("file created");
}
In your script, how about the following modification?
From:
var response = UrlFetchApp.fetch(fileURL);
var fileBlob = response.getBlob().getAs('application/pdf');
To:
var response = UrlFetchApp.fetch(fileURL, { headers: { authorization: "Bearer " + ScriptApp.getOAuthToken() } });
var fileBlob = response.getBlob();
I thought that in your endpoint, getBlob() returns the PDF format.
In your script, createFile is used. By this, the required scope has already been included. But, if an error is related to Drive API, please enable Drive API at Advanced Google services.
Note:
In your endpoint, if revision=3970 is not existing, an error occurs. Please be careful about this.
Reference:
getOAuthToken()

google appscript DocumentApp invalid argument error

Very simple use of the API, just like the example at https://developers.google.com/apps-script/reference/document/document-app#openbyurlurl but I'm getting this error and can't understand why. I get the same error if I try openById() instead.
After some further testing, I believe this error is because the mimetype of the file is not a native google drive document (doc, sheet, slide) but instead a pdf file. I was able to get this working when declaring the mimetype.
var srcfolderId = "1vaAInpB8ACPiYi12A7F2yuOEU7EwNzbI"; // <--- Please input folder ID.
var files = DriveApp.getFolderById(srcfolderId).getFilesByType(MimeType.PDF);
while (files.hasNext()) {
var file = files.next();
var fileBlob = file.getBlob();
var resource = {
title: fileBlob.getName(),
mimeType: fileBlob.getContentType()
};
var options = {
ocr: true
};
//Enable Drive API under advanced api's
var docFile = Drive.Files.insert(resource, fileBlob, options);
Logger.log(docFile.title+" " + docFile.alternateLink);
// Extract Text from PDF file
var doc = DocumentApp.openById(docFile.id);
var text = doc.getBody().getText();
}

Copying Files based on a custom column value between document libraries in SharePoint using javascript

I am new to Javascript and currently working on a task where I need to copy files based on a custom column name "PID" from One Document Library to the other.
I was able to get the below code to work which copies all the files
$scope.copyFiles=function()
{
var sourceLib = '/sites/Protocol/ProtocolDocument';
var destLib = '/sites/Protocol/FinalProtocolDocuments';
var context = new SP.ClientContext.get_current();
var web = context.get_web().get_lists();
var folderSrc = web.getFolderByServerRelativeUrl(sourceLib);
//var cq = "<Query><Where><Eq><FieldRef Name="ProtocolID" LookupId="TRUE"/><Value Type="Text">' + 466 + '</Value></Eq></Where></Query>"
context.load(folderSrc,'Files');
context.executeQueryAsync(
function() {
console.log("Got the source folder right here!");
var files = folderSrc.get_files();
var e = files.getEnumerator();
var dest = [];
while (e.moveNext()) {
var file = e.get_current();
var destLibUrl = destLib + "/" + file.get_name();
dest.push(destLibUrl); //delete this when we're happy we got the file paths right
file.copyTo(destLibUrl, true);
}
console.log(dest); //delete this when we're happy we got the file paths right
context.executeQueryAsync(function() { console.log("Files moved successfully!");}, function(sender, args) {console.log("error: ") + args.get_message()});
},
function(sender, args){console.log("Sorry, something messed up: " + args.get_message());}
);
}
I did some research online to get the Filenames based on a custom column value with no luck
Also tried to use CAML , however not sure how to use it in the code.
Would appreciate if anyone could help me get the filenames from a Document Library based on custom column name "PID" so that only selected/filtered files are moved to the destination Library.
UPDATED CODE
$scope.copyFiles=function()
{
var sourceLib = '/sites/Protocol/ProtocolDocument';
var destLib = '/sites/Protocol/FinalProtocolDocuments';
PID='466'
var context = new SP.ClientContext();
var list = context.get_web().get_lists().getByTitle("ProtocolDocument");
var cq = new SP.CamlQuery();
cq.set_viewXml("<View><Query>" +
"<Where>" +
"<Eq><FieldRef Name=\"ProtocolID\"/><Value Type=\"Text\">PID</Value></Eq>" +
"</Where>" +
"</Query>" +
"</View>");
var items = list.getItems(cq);
context.load(items);
context.executeQueryAsync(
function() {
var e = items.getEnumerator();
var dest = [];
while (e.moveNext())
{
var file = e.get_current();
var destLibUrl = destLib + "/" + file.get_name();
dest.push(destLibUrl); //delete this when we're happy we got the file paths right
file.copyTo(destLibUrl, true);
}
console.log(dest); //delete this when we're happy we got the file paths right
context.executeQueryAsync(function() { console.log("Files moved successfully!");}, function(sender, args) {console.log("error: ") + args.get_message()});
},
function(sender, args){console.log("Sorry, something messed up: " + args.get_message());}
);
}
});
Here is my attempt. I tested it successfully on SharePoint 2013, and it copies files from one document library to another, but only the files with a lookup field set to a specific value. I have included a short summary, but if you only want the code then jump down to Now to the actual code.
Please note that I have used syntax not supported by Internet Explorer, so let me know if you need to support that browser. I also believe that a function or method should only do one thing, so I split the functionality into three separate functions. This also helps keep the code clean and easier to read.
To summarize: The first function, findAndCopyFiles(), will run once and find all the files with the lookup field value you set. It will then send each file to the loadAndCopyFile() function to load the file object. This function will run once for every file that should be copied. When the file object is loaded, it is sent to the third and final function, copyFileTo(), that will actually copy the file to the destination document library. This function will also run once per file.
Now to the actual code
First you need to set these configuration variables according to your setup:
const destinationLibraryPath = 'The path to your destination document library';
const sourceLibraryName = 'The name (not path) of your source document library';
const lookupField = 'The name of your lookup field';
const lookupValue = 'The value your lookup field should equal for files to be copied';
findAndCopyFiles()
This function is responsible for finding all the files in the source document library with the lookup field set to the value of lookupValue. We use what is known as a CAML query to filter the files. You can filter on all available fields and columns, not only lookup fields.
const findAndCopyFiles = () => {
const clientContext = SP.ClientContext.get_current();
const sourceList = clientContext.get_web().get_lists().getByTitle(sourceLibraryName);
const camlQuery = new SP.CamlQuery();
const whereQuery = `<Eq><FieldRef Name="${lookupField}"/><Value Type="Text">${lookupValue}</Value></Eq>`;
camlQuery.set_viewXml(`<View><Query><Where>${whereQuery}</Where></Query></View>`);
const sourceListItems = sourceList.getItems(camlQuery);
clientContext.load(sourceListItems);
clientContext.executeQueryAsync(
() => {
const filesEnumerator = sourceListItems.getEnumerator();
while (filesEnumerator.moveNext()) {
loadAndCopyFile(filesEnumerator.get_current(), clientContext);
}
},
(_sender, args) => {
console.log(args.get_message());
}
);
}
When the query executes, we use the getEnumerator() method to iterate through all the files returned by the query, in other words all the files that will be copied.
loadAndCopyFile()
After finding all the relevant files, we send each file to the next function to continue our process. This function will load the file object (as in the actual file) and construct the destination URL using the path to the destination document library and the filename of the file.
const loadAndCopyFile = (file, clientContext) => {
const fileRef = file.get_file();
clientContext.load(fileRef);
clientContext.executeQueryAsync(
() => {
const destinationUrl = `${destinationLibraryPath}/${fileRef.get_name()}`;
copyFileTo(fileRef, destinationUrl, clientContext);
},
(_sender, args) => {
console.log(args.get_message());
}
);
}
copyFileTo()
The final function is responsible for actually copying the file to the destination document library. It is quite simple, and looks like this:
const copyFileTo = (file, destinationUrl, clientContext) => {
file.copyTo(destinationUrl, true);
clientContext.executeQueryAsync(
() => {
console.log(`File copied to ${destinationUrl}!`);
},
(_sender, args) => {
console.log(args.get_message());
}
);
}
Putting it all together
And finally, we execute the findAndCopyFiles() function when all the required libraries are ready:
SP.SOD.executeFunc('sp.js', 'SP.ClientContext', () => {
findAndCopyFiles();
});
Disclaimer: I wrote this post on another computer than the one where I tested the code, so if something does not work it may be because of a simple syntax error. In that case, add a comment and let me know!

JavaScript not able to rename file before upload

I am trying to upload file to aws s3. before i upload i want to rename it by adding timestamp to file name. but i am geting an error as 'Cannot assign to read only property 'name' of object '#''
here is the code
let file = e.target.files[0];
let timeStamp = (new Date()).getTime();
let fileExt = file.name.split('.')[file.name.split('.').length-1];
let fileNameWithoutExt = file.name.replace(`.${fileExt}`,'');
let newFileName = fileNameWithoutExt + '_' + timeStamp + '.' + fileExt;
file.name = newFileName;
Yep that sounds like a weird rule to set it as Read-only, but it's what it is...
So the workaround, not so hard, is to create a new File object from your previous one...
var previous_file = new File(['foo'], 'file.txt', {type: 'text/plain'});
try{
previous_file.name = 'hello.txt';
}
catch(e){}
console.log(previous_file.name); // didn't work
// so we just create a new File from it...
var new_file = new File([previous_file], 'hello.txt');
console.log(new_file);
But also note that if you need to support older browsers that don't support the File constructor, then you can override this file name in a FormData that you will send to your sever:
var file = new File(['foo'], 'text.txt', {type:'text/plain'});
var formdata = new FormData();
// this will override the file name
formdata.append('file', file, 'hello.txt');
// and now you can send this formdata through xhr
// for demo, we will just log its content
for(let entry of formdata.entries()) {
console.log(entry);
}
The append() method of FormData accepts a third optional filename parameter.
// new file name as a variable with timestamp
const newName = new Date().getTime() + event.target.files[0].name;
fd.append('file[]', event.target.files[0], newName);
You can't change a name of an already created file.
You can create
new instance of file with new file name, like in a post above.But
File constroctor is not supported by all browsers (is not supported at IE and EDGE supporting table).
You can put new
file name to key property of your amazon upload
https://docs.aws.amazon.com/AmazonS3/latest/API/sigv4-post-example.html
instead of key = "folder1/folder2/${filename}"
you can write key = "folder1/folder2/youfilename.txt"

How to add a File object to a FileList collection in JavaScript?

I am working on a drag and drop file upload field.
I am able to return a FileList object containing the file that has been specified by the user. I have a hidden file input field which I then want to add the file object to so I can then send the form data via AJAX.
The problem I am having is that I can't seem to copy the file object to the file input field. Here is how I am attempting it:
var files = evt.dataTransfer.files; // FileList object.
var fileUploadElem = document.getElementById(fileUploadId);
// trying to copy the first file of files into the file upload field
fileUploadElem.files[0] = files[0];
// this statement returns '0' instead of '1'
console.log('fileUploadElem length: '+fileUploadElem.files.length);
Appreciate any advice or pointers.
This is an example from MDN on how to do it with FormData:
function sendForm() {
var output = document.getElementById("output");
var data = new FormData(document.getElementById("fileinfo"));
data.append("CustomField", "This is some extra data");
var xhr = new XMLHttpRequest();
xhr.open("POST", "stash.pl", false)
xhr.send(data);
if (xhr.status == 200) {
output.innerHTML += "Uploaded!<br />";
} else {
output.innerHTML += "Error " + xhr.status + " occurred uploading your file.<br />";
}
}
The reason it didn't work for me was because one of the JavaScript properties isn't supported in Chrome hence it worked on my colleague's machine who was working within the Firefox browser but not for me.

Categories

Resources