Multiple bulk import entries using Google Apps Script - javascript

I know there are existing codes to build a form that can upload multiple files (bulk import) such as this Uploading Multiple Files to Google Drive with Google App Script, but I was just wondering if it's possible to do one that asks for bulk import (or big sized file) multiple times? The existing scripts seem to pass the id of one input in the upload function using document.getFileByID(), and I can't pass multiple id's in it.
Here are the codes that I was referring to (copied from Uploading Multiple Files to Google Drive with Google App Script):
function doGet() {
return HtmlService.createHtmlOutputFromFile('form')
.setSandboxMode(HtmlService.SandboxMode.IFRAME);
}
function uploadFileToDrive(base64Data, fileName) {
try{
var splitBase = base64Data.split(','),
type = splitBase[0].split(';')[0].replace('data:','');
var byteCharacters = Utilities.base64Decode(splitBase[1]);
var ss = Utilities.newBlob(byteCharacters, type);
ss.setName(fileName);
var dropbox = "Something"; // Folder Name
var folder, folders = DriveApp.getFoldersByName(dropbox);
if (folders.hasNext()) {
folder = folders.next();
} else {
folder = DriveApp.createFolder(dropbox);
}
var file = folder.createFile(ss);
return file.getName();
}catch(e){
return 'Error: ' + e.toString();
}
}
<body>
<div id="formcontainer">
<label for="myForm">Facilities Project Database Attachment Uploader:</label>
<br><br>
<form id="myForm">
<label for="myForm">Project Details:</label>
<div>
<input type="text" name="zone" placeholder="Zone:">
</div>
<div>
<input type="text" name="building" placeholder="Building(s):">
</div>
<div>
<input type="text" name="propertyAddress" placeholder="Property Address:">
</div>
<div>
<label for="fileText">Project Description:</label>
<TEXTAREA name="projectDescription"
placeholder="Describe your attachment(s) here:"
style ="width:400px; height:200px;"
></TEXTAREA>
</div>
<br>
<label for="attachType">Choose Attachment Type:</label>
<br>
<select name="attachType">
<option value="Pictures Only">Picture(s)</option>
<option value="Proposals Only">Proposal(s)</option>
<option value="Pictures & Proposals">All</option>
</select>
<br>
<label for="myFile">Upload Attachment(s):</label>
<br>
<input type="file" name="filename" id="myFile" multiple>
<input type="button" value="Submit" onclick="iteratorFileUpload()">
</form>
</div>
<div id="output"></div>
<div id="progressbar">
<div class="progress-label"></div>
</div>
<script src="//ajax.googleapis.com/ajax/libs/jquery/1.11.2/jquery.min.js"></script>
<link rel="stylesheet" href="https://ajax.googleapis.com/ajax/libs/jqueryui/1.11.4/themes/smoothness/jquery-ui.css">
<script src="https://ajax.googleapis.com/ajax/libs/jqueryui/1.11.4/jquery-ui.min.js"></script>
<script>
var numUploads = {};
numUploads.done = 0;
numUploads.total = 0;
// Upload the files into a folder in drive
// This is set to send them all to one folder (specificed in the .gs file)
function iteratorFileUpload() {
var allFiles = document.getElementById('myFile').files;
if (allFiles.length == 0) {
alert('No file selected!');
} else {
//Show Progress Bar
numUploads.total = allFiles.length;
$('#progressbar').progressbar({
value : false
});//.append("<div class='caption'>37%</div>");
$(".progress-label").html('Preparing files for upload');
// Send each file at a time
for (var i = 0; i < allFiles.length; i++) {
console.log(i);
sendFileToDrive(allFiles[i]);
}
}
}
function sendFileToDrive(file) {
var reader = new FileReader();
reader.onload = function (e) {
var content = reader.result;
console.log('Sending ' + file.name);
var currFolder = 'Something';
google.script.run.withSuccessHandler(updateProgressbar).uploadFileToDrive(content, file.name, currFolder);
}
reader.readAsDataURL(file);
}
function updateProgressbar( idUpdate ){
console.log('Received: ' + idUpdate);
numUploads.done++;
var porc = Math.ceil((numUploads.done / numUploads.total)*100);
$("#progressbar").progressbar({value: porc });
$(".progress-label").text(numUploads.done +'/'+ numUploads.total);
if( numUploads.done == numUploads.total ){
//uploadsFinished();
numUploads.done = 0;
};
}
</script>
<script>
function fileUploaded(status) {
document.getElementById('myForm').style.display = 'none';
document.getElementById('output').innerHTML = status;
}
</script>
<style>
body {
max-width: 400px;
padding: 20px;
margin: auto;
}
input {
display: inline-block;
width: 100%;
padding: 5px 0px 5px 5px;
margin-bottom: 10px;
-webkit-box-sizing: border-box;
‌​ -moz-box-sizing: border-box;
box-sizing: border-box;
}
select {
margin: 5px 0px 15px 0px;
}
input[type="submit"] {
width: auto !important;
display: block !important;
}
input[type="file"] {
padding: 5px 0px 15px 0px !important;
}
#progressbar{
width: 100%;
text-align: center;
overflow: hidden;
position: relative;
vertical-align: middle;
}
.progress-label {
float: left;
margin-top: 5px;
font-weight: bold;
text-shadow: 1px 1px 0 #fff;
width: 100%;
height: 100%;
position: absolute;
vertical-align: middle;
}
</style>
</body>
Thanks for any advice!

I believe your goal is as follows.
You want to upload only 2 files to your Google Drive using 2 input tags. Each file size is more than 50 MB.
You want to achieve this using Web Apps. The HTML is put in the Google Apps Script project including the script of Web Apps.
Issue and workaround:
In this current stage, when the file size is more than 50 MB, the file content cannot be directly saved as a file using Google Apps Script, because of the current specification at Google side. SO, in this case, it is required to upload the file using the resumable upload with Drive API. Ref In this case, it is required to prepare a script for achieving the resumable upload. But, fortunately, I have already created for achieving this using Javascript library. In this answer, I would like to propose a sample script using this Javascript library.
Usage:
1. Create Google Apps Script for Web Apps.
In order to use Web Apps, please create a new Google Apps Script project.
2. Sample script.
Please copy and paste the following script to the script editor of the created Google Apps Script project.
Google Apps Script side: Code.gs
function main() {
var html = HtmlService.createHtmlOutputFromFile("index");
SpreadsheetApp.getUi().showSidebar(html);
}
function getAuth() {
// DriveApp.createFile() // This is used for adding the scope of "https://www.googleapis.com/auth/drive".
return ScriptApp.getOAuthToken();
}
HTML & Javascript side: index.html
<input type="file" id="file1" />
<input type="file" id="file2" />
<input type="button" onclick="run()" value="Upload" />
<div id="progress"></div>
<script src="https://cdn.jsdelivr.net/gh/tanaikech/ResumableUploadForGoogleDrive_js#master/resumableupload_js.min.js"></script>
<script>
function run() {
google.script.run.withSuccessHandler(accessToken => ResumableUploadForGoogleDrive(accessToken)).getAuth();
}
function ResumableUploadForGoogleDrive(accessToken) {
const f1 = document.getElementById("file1").files[0];
const f2 = document.getElementById("file2").files[0];
[f1, f2].forEach((file, i) => {
if (!file) return;
let fr = new FileReader();
fr.fileName = file.name;
fr.fileSize = file.size;
fr.fileType = file.type;
fr.readAsArrayBuffer(file);
fr.onload = e => {
var id = "p" + ++i;
var div = document.createElement("div");
div.id = id;
document.getElementById("progress").appendChild(div);
document.getElementById(id).innerHTML = "Initializing.";
const f = e.target;
const resource = { fileName: f.fileName, fileSize: f.fileSize, fileType: f.fileType, fileBuffer: f.result, accessToken: accessToken };
const ru = new ResumableUploadToGoogleDrive();
ru.Do(resource, function (res, err) {
if (err) {
console.log(err);
return;
}
console.log(res);
let msg = "";
if (res.status == "Uploading") {
msg = Math.round((res.progressNumber.current / res.progressNumber.end) * 100) + "% (" + f.fileName + ")";
} else {
msg = res.status + " (" + f.fileName + ")";
}
// if (res.status == "Done") google.script.run.putFileInf(res.result);
document.getElementById(id).innerText = msg;
});
};
});
}
</script>
When you want to put the uploaded files to the specific folder, please modify const resource = { fileName: f.fileName, fileSize: f.fileSize, fileType: f.fileType, fileBuffer: f.result, accessToken: accessToken }; as follows.
const resource = { fileName: f.fileName, fileSize: f.fileSize, fileType: f.fileType, fileBuffer: f.result, accessToken: accessToken, folderId: "###folderId###" };
3. Enable Drive API.
Please enable Drive API at Advanced Google services.
4. Deploy Web Apps.
The detailed information can be seen at the official document.
On the script editor, at the top right of the script editor, please click "click Deploy" -> "New deployment".
Please click "Select type" -> "Web App".
Please input the information about the Web App in the fields under "Deployment configuration".
Please select "Me" for "Execute as".
This is the importance of this workaround.
Please select "Anyone" for "Who has access".
For testing this script, I thought that this setting might be suitable.
Please click "Deploy" button.
Copy the URL of the Web App. It's like https://script.google.com/macros/s/###/exec.
When you modified the Google Apps Script, please modify the deployment as a new version. By this, the modified script is reflected in Web Apps. Please be careful this.
You can see the detail of this in the report of "Redeploying Web Apps without Changing URL of Web Apps for new IDE".
5. Testing:
As a simple sample script, when the above HTML and Javascript are run on a sidebar, the following result is obtained. Of course, this result can be obtained using Web Apps. When this script is tested, you can see that the files can be uploaded with the asynchronous process. This demonstration is from here.
Note:
In this case, the access token is retrieved from Google Apps Script side using ScriptApp.getOAuthToken(). For testing this script, you can use the scope of https://www.googleapis.com/auth/drive. But, if you want to keep the security when you use this script in your actual situation, I would like to propose to use https://www.googleapis.com/auth/drive.file as the scope. By this, the access token can access only the files created by this client.
When you modified the Google Apps Script, please modify the deployment as a new version. By this, the modified script is reflected in Web Apps. Please be careful this.
You can see the detail of this in the report of "Redeploying Web Apps without Changing URL of Web Apps for new IDE".
References:
Web Apps
Taking advantage of Web Apps with Google Apps Script
Resumable Upload of Multiple Files with Asynchronous Process for Google Drive

Related

Google Scripts/HTML/JavaScript Upload File to Folder Error Argument cannot be null: blob

I am creating an online HTML form that gives people the option to upload a file. I am using google sheets to collect the data so I am using their google scripts feature. When I run my code everything works, meaning I get data inserted into cells, but not the file upload. Here is my Google Scripts code for the file upload:
function doGet(request) {
return HtmlService.createTemplateFromFile('Index')
.evaluate();
}
/* #Include JavaScript and CSS Files */
function include(filename) {
return HtmlService.createHtmlOutputFromFile(filename)
.getContent();
}
function uploadFiles(data){
var folder = DriveApp.getFolderById('1pp1ELzGa2fZqU4IHAasZMHsmYx19pnYv');
var createFile = folder.createFile(data.image);
return createFile.getUrl();
}
From what I can tell the problem is at the data.image. This is where I am trying to retrieve my image so I can upload it into the folder. It must be that uploadFiles(data) is not properly bringing in data.
Here is the HTML and JavaScript:
<form id="myForm" onsubmit="handleFormSubmit(this)">
<h1 class="h4 mb-4 text-center" style="text-align:center"> <center>File Upload Testing</center></h1>
<table>
<tr>
<td colspan="11"><input type="file" id="image"></td>
</tr>
<input type="hidden" id="fileURL" name="fileURL">
</table>
<button type="submit" class="button button1" id="submitBtn">Submit</button>
</form>
<script>
document.getElementById('submitBtn').addEventListener('click',
function(e){
google.script.run.withSuccessHandler(onSuccess).uploadFiles(this.parentNode);;}
)
function onSuccess(data){
document.getElementById("fileURL").value = data;
}
</script>
I have a feeling that the e parameter is not retrieving the data above, however I don't really understand how it works. It could also be this.parentNode that's not grabbing the fike.
I am using the onSuccess function to retrieve the link so I can put it into my google sheet for quick access.
This is the error I receive;
Here is a link to the google sheet. To reach google scripts go to 'Tools -> Script Editor'.
https://docs.google.com/spreadsheets/d/16w8uB4OZHCeD7cvlrUv5GHP72CWxQhO1AAkF9MMSpoE/edit?usp=sharing
Here is another technique I attempted to use:
Javascript:
function uploadthis(fileForm){
const file = fileForm.image.files[0];
const fr = new FileReader();
fr.onload = function(e) {
const obj = {
// filename: file.name
mimeType: file.type,
bytes: [...new Int8Array(e.target.result)]
};
google.script.run.withSuccessHandler((e) => console.log(e)).uploadFiles(obj);
};
fr.readAsArrayBuffer(file);
}
Google Script:
function uploadFiles(data){
var file = Utilities.newBlob(data.bytes, data.mimeType); // Modified
var folder = DriveApp.getFolderById('1pp1ELzGa2fZqU4IHAasZMHsmYx19pnYv');
var createFile = folder.createFile(file);
return createFile.getId(); // Added
}
Thank you!

Read JSON from from HTML file input

If I have an input:
<input type="file" id="upload" onchange="getFile(this)">
And my user will upload a JSON file (as plaintext, so I will have to use JSON.parse()), how can I take this file and actually get the data via getFile()
In getFile(element), I've tried using element.files[0] but that doesn't seem to contain the actual data. I've also looked here, here, and here, but none of these solve my problem. This resource on MDN seems promising, but I don't really get it.
I would like a solution involving either URL.createObjectURL() or FileReader().
Also, before anyone posts this in the comments, I do understand that these solutions do not work on all browsers, and I would like to do this from the frontend.
You could take advantage of the Response constructor and call .json() on any blob/file.
function getFile (elm) {
new Response(elm.files[0]).json().then(json => {
console.log(json)
}, err => {
// not json
})
}
Alternative method using the new read methods on blob.prototype[...]
new Blob(['1']).text().then(JSON.parse).then(console.log)
I guess for larger files response.json might be faster/better since it can parse the content in background and not block the main UI unlike JSON.parse
I think you need this api:
FileReader Api From MDN
JSON#parse()
View In Stackblitz
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Read Text</title>
<style>
div {
margin-top: 30px;
border: solid 1px black;
padding: 5px;
}
</style>
<script>
function processFiles(files) {
var file = files[0];
var message = document.getElementById("message");
message.innerHTML = "File Name:" + file.name + "<br>";
message.innerHTML += "File Size:" + file.size + "<br>";
message.innerHTML += "File Type:" + file.type + "<br>";
var reader = new FileReader();
reader.onload = function (e) {
var output = document.getElementById("fileOutput");
// parse string to json
output.textContent = JSON.parse(e.target.result);
};
reader.readAsText(file);
}
</script>
</head>
<body>
<input id="fileInput" type="file" size="50" onchange="processFiles(this.files)">
<div id="message"></div>
<div id="fileOutput"></div>
</body>
</html>

How to make a drag and drop HTML file reader

I am working on a small HTML file API application. This application can support users to drag, drop a file and read the file content. However, I found I either can make the drag, drop and read the file info part or using HTML upload feature to let users upload a file and read the file content.
Please see the example here: https://jsfiddle.net/tqcuor5g/
I just want the user can drop a file into a drop zone and the app can read its content and show in the text area.
My question is how can I make the application support drag, drop and read the file content at the same time? Thank you in advance!
Source code:
<!DOCTYPE html>
<html>
<head>
<style type="text/css">
body
{
font-size:18pt;
}
#filedrop
{
width: 300px;
height: 200px;
color: Gray;
border: 10px dashed #9a9a9a;
}
</style>
<title>Reading a Text File</title>
<script type="text/javascript">
function init() {
var bHaveFileAPI = (window.File && window.FileReader);
if (!bHaveFileAPI) {
alert("This browser doesn't support the File API");
return;
}
document.getElementById("filedrop").addEventListener("drop", onFilesDropped);
document.getElementById("filedrop").addEventListener("dragover", onDragOver);
document.getElementById("fileElem").addEventListener("change", onFileChanged);
}
function onFileChanged(theEvt) {
var thefile = theEvt.target.files[0];
console.log(thefile);
// check to see if it is text
if (thefile.type != "text/plain") {
document.getElementById('filecontents').innerHTML = "No text file chosen";
return;
}
var reader = new FileReader();
reader.onload = function (evt) {
var resultText = evt.target.result;
document.getElementById('filecontents').innerHTML = resultText;
}
reader.readAsText(thefile);
}
function onDragOver(theEvt) {
theEvt.stopPropagation();
theEvt.preventDefault();
}
function onFilesDropped(theEvt) {
theEvt.stopPropagation();
theEvt.preventDefault();
var files = theEvt.target.files;
document.getElementById('filedata').innerHTML = "";
for (var i = 0; i <= files.length; i++) {
var fileInfo = "<p>File name: " + files[i].name + "; size: " + files[i].size + "; type: " + files[i].type + "</p>";
document.getElementById('filedata').innerHTML += fileInfo;
}
}
window.addEventListener("load", init);
</script>
</head>
<body>
<h1>Using Drag and Drop</h1>
<p>Drop files here: </p>
<div id="filedrop"></div>
<p>File Information: </p>
<div id="filedata"></div>
<h1>Reading File Data as Text</h1>
<form action="">
<label>Select a file: </label>
<input type="file" name="files" id="fileElem" />
</form>
<p>File contents: </p>
<textarea cols="80" rows="10" id="filecontents"></textarea>
</body>
</html>

How To Include a google apps script in a html page,that has uploading functionality on google Drive

I just want to collect a files from users (like resume) & store on my google drive. That is working file from google apps script like below.I want to add this form to my html page. Which is provided by google as form URL
https://script.google.com/macros/s/AKfycbx8w-Um_pIWx8A1S_3R2CrSYhQqyLF6tyYJOQuUHdFT5jqBFP0/exec
want to add in shouttoday.com site's page.
i also tried include as js script,or iframe but not working.
There is to files as ---
server.gs
function doGet(e) {
return HtmlService.createHtmlOutputFromFile('form.html');
}
function uploadFiles(form) {
try {
var dropbox = "Student Files";
var folder, folders = DriveApp.getFoldersByName(dropbox);
if (folders.hasNext()) {
folder = folders.next();
} else {
folder = DriveApp.createFolder(dropbox);
}
var blob = form.myFile;
var file = folder.createFile(blob);
file.setDescription("Uploaded by " + form.myName);
return "File uploaded successfully " + file.getUrl();
} catch (error) {
return error.toString();
}
}
form.html
<form id="myForm">
<input type="text" name="myName" placeholder="Your name..">
<input type="file" name="myFile">
<input type="submit" value="Upload Resume"
onclick="this.value='Uploading..';
google.script.run.withSuccessHandler(fileUploaded)
.uploadFiles(this.parentNode);
return false;">
</form>
<div id="output"></div>
<script>
function fileUploaded(status) {
document.getElementById('myForm').style.display = 'none';
document.getElementById('output').innerHTML = status;
}
</script>
<style>
input { display:block; margin: 20px; }
</style>
having url app script url: https://script.google.com/macros/s/AKfycbx8w-Um_pIWx8A1S_3R2CrSYhQqyLF6tyYJOQuUHdFT5jqBFP0/exec
But Don't know how to embedded this app (form) in my html page.
You need to use google developer console for this. It have programming example available for the same. So, that will really help you.

Wordpress can't handle jQuery code

I have requested an API from a website to check availability of an email, and I got a jQuery code to integrate the API to my website.
I use WordPress, and I tried to add the code, but it doesn't work and I don't know why.
I suspected it was a jQuery library problem, so I loaded it in the "function" file, and in the script from google API, but nothing.
Thanks for your help, and here is the code (by the way I also tried changing with 'jQuery.')
<!DOCTYPE html>
<html lang="en" xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta charset="utf-8" />
<title>emailverifyapi.com : License Key Sample.</title>
<style type="text/css">
.statusUnknown {
color: #c1c72c;
}
.statusOk {
color: #009933;
}
.statusBad, .errorMsg {
color: #ff0000;
}
input[type='text'] {
width: 300px;
}
p label {
display: inline-block;
width: 60px;
}
</style>
<script src="//ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
</head>
<body>
<h1>emailverifyapi.com : email verification demo using simple key authentication with jQuery.</h1>
<h2>About</h2>
<p>This example shows how to perform email verification using just client side scripting and invoking a simple key based RESTful endpoint at api.emailverifyapi.com.</p>
<h2>How to run this sample</h2>
<p>This page can be hosted anywhere (i.e. any web host or platform). The only thing needed is a valid license key.</p>
<h2>Key features</h2>
<ul>
<li>Compatible with all modern browsers</li>
<li>Uses jQuery 1.11.1</li>
<li>No server side scripting required</li>
</ul>
<hr />
<h2>Try it</h2>
<p>
<label for="key">Key:</label>
<input type="text" id="key" name="key" tabindex="1" maxlength="20" />
</p>
<p>
<label for="email">Email:</label>
<input type="text" name="email" id="email" tabindex="2" />
<input type="button" name="submit" id="submit" tabindex="3" value="verify" />
</p>
<div id="validationResult"></div>
<!--Result output here-->
<script>
/*nest key logic inside document.ready to ensure functionality only available once document has fully loaded in browser.*/
$(function() {
console.log("ready!");
$('#submit').click(function() {
var emailText = $('#email').val(); // get key from text box entry
var keyText = $('#key').val(); // get email address to be checked from text box
if (keyText.length == 0) {
$('#validationResult').html("<span class='errorMsg'>Please enter key.</span>");
return;
}
if (emailText.length == 0) {
$('#validationResult').html("<span class='errorMsg'>Please enter something for email.</span>");
return;
}
$('#validationResult').html("verifying...");
var emailVerifyApi = '//api.emailverifyapi.com/api/a/v1?email=' + encodeURIComponent(emailText) + '&key=' + keyText;
/*execute remote request to perform email verification. Any errors will appear in the developer console (e.g. viewable using Chrome developer tools)*/
$.getJSON(emailVerifyApi, {})
.done(function(data) {
reportResult(data);
})
.fail(function(jqxhr, textStatus, error) {
var err = textStatus + ", " + error;
console.log("Request failed: " + err);
});;
});
});
/*Output result to the 'validationResult' div element*/
function reportResult(data) {
var status = data['status'].toLowerCase(); // get 'status' from REST response
var additionalStatus = data['additionalStatus']; // get 'additionalStatus' from REST response
var message = data['Message']; // if there is an error (e.g. license issues), a notification will appear in the 'Message" from REST response.
console.log(status);
console.log(additionalStatus);
console.log(message);
var statusHtml;
// if there is an error message, show here
if (message != null && message != '') {
statusHtml = "<span class='errorMsg'>Error. Message='" + message + "' .</span>";
} else {
// map REST response data to presentation messages.
switch (status) {
case 'ok':
statusHtml = "<span class='statusOk'>Email address is ok.</span>";
break;
case 'bad':
statusHtml = "<span class='statusBad'>Email address is not valid.</span>";
break;
default:
statusHtml = "<span class='statusUnknown'>Unable to validate email. Reason=" + additionalStatus + "</span>";
break;
}
}
console.log(statusHtml);
// present the result on screen
$('#validationResult').html(statusHtml);
}
</script>
</body>
</html>
Is that the output of your page as HTML or is that the code of the page itself?
All scripts should be loaded using the wp_enqueue_scripts() function which you use in your functions.php file.
You could use the following code:
function myScriptFunction() {
wp_enqueue_script(
'custom-script',
get_stylesheet_directory_uri() . '/js/script.js',
array( 'jquery', true )
);
}
add_action( 'wp_enqueue_scripts', 'myScriptFunction' );
This tells WordPress to load your custom script, where it is located, that it depends on jQuery, and that it should be loaded in the footer.
WordPress loads jQuery in noconflict mode so it will not recognize "$" so instead use jQuery.

Categories