[英]Create a file with the same name as the folder where a file was uploaded
我在 Web 应用程序中有一个 HTML 表单,是使用 GAS 创建的。
此 HTML 表单是根据此处的文件上传脚本创建的:
这是 HTML 表格:
第一个数字是指在表格上选择的 model ,第二个数字是指使用的插槽。
因此需要创建一个function来识别Model
中选择的input
,根据这个input
判断第一个空文件夹是哪个,然后取那个文件夹的ID
传给客户端上传文件在里面。
在社区一些成员的帮助下,进行了一些改编,最终的 function 是这样的:
/** Modified version of script written by Tanaike */
function createOrGetFolder(folderName, parentFolderId) {
try {
var parentFolder = DriveApp.getFolderById(parentFolderId), folder;
if (parentFolder) {
var foldersIter = parentFolder.getFoldersByName("Video");
if (foldersIter.hasNext()) {
var videoFolder = foldersIter.next();
var nextFolderName = folderName + "-01";
while (!folder) {
video_folder = videoFolder.getFoldersByName(nextFolderName);
if (video_folder.hasNext()) {
folder = video_folder.next();
var files = folder.getFiles();
if (files.hasNext()) {
var [a, b] = nextFolderName.split("-");
nextFolderName = `${a}-${String(Number(b) + 1).padStart(2, "0")}`;
folder = null;
}
} else {
folder = videoFolder.createFolder(nextFolderName);
}
}
} else {
folder = parentFolder.createFolder("Video");
folder = folder.createFolder(folderName);
}
} else {
throw new Error("Parent Folder with id: " + parentFolderId + " not found");
}
return folder.getId();
} catch (error) {
return error;
}
}
它工作得很好,关键是这个表单还有一个 function,在提交表单时生成一个.csv 文件,function 是这个:
.gs
文件:
const saveDataAsCSV = (data, folderId) => DriveApp.getFolderById(folderId).createFile("Sample.csv", data);
HTML
档案:
var name = $('#name01').val();
var description = $('#description').val();
var model = $('#Model').val();
upload_folder = model;
var color = $('#Color').val();
var form_values = [name, description, model, color];
var data = form_values.join(",");
google.script.run.saveDataAsCSV(data, uploadParentFolderId);
我的目标是使 .csv 文件生成与上传文件的文件夹同名,也就是说,如果文件上传到文件夹01-01
,文件名必须是01-01.csv
,如果文件上传到02-02
文件夹,文件名必须是02-02.csv
,依此类推。
我怎样才能做到这一点?
完整的脚本代码可以在这里查看:
.gs
文件:
function doGet(e) {
return HtmlService.createTemplateFromFile('forms0101.html').evaluate();
}
function getOAuthToken() {
return ScriptApp.getOAuthToken();
}
function getParent(){
var ss = SpreadsheetApp.getActiveSpreadsheet();
var id = ss.getId();
var parent = DriveApp.getFileById(id).getParents().next().getId();
return parent
}
function getLimitFolder(){
var ss = SpreadsheetApp.getActiveSpreadsheet();
var pastapai = DriveApp.getFileById(ss.getId()).getParents();
var limitfolder = pastapai.next().getFoldersByName("_").next().getId();
return limitfolder;
}
function getFilesLimit(){
var ss = SpreadsheetApp.getActiveSpreadsheet();
var pastapai = DriveApp.getFileById(ss.getId()).getParents();
var files = [];
Logger.log(pastapai);
//var limitfolder = pastapai.next().getFoldersByName("_").next().getId();
var limitfolder = pastapai.next().getFoldersByName("_").next().getFiles();
while(limitfolder.hasNext()){
var file = limitfolder.next();
files.push([file.getId()]);
}
console.log(files.length);
return files.length;
}
//function testenumeroarquivos(){
//console.log(checkForFiles()); // When you use this line, you can see the filename of the files.
//}
/**
* creates a folder under a parent folder, and returns it's id. If the folder already exists
* then it is not created and it simply returns the id of the existing one
*/
function createOrGetFolder(folderName, parentFolderId) {
try {
var parentFolder = DriveApp.getFolderById(parentFolderId), folder;
if (parentFolder) {
var foldersIter = parentFolder.getFoldersByName("Video");
if (foldersIter.hasNext()) {
var videoFolder = foldersIter.next();
var nextFolderName = folderName + "-01";
while (!folder) {
video_folder = videoFolder.getFoldersByName(nextFolderName);
if (video_folder.hasNext()) {
folder = video_folder.next();
var files = folder.getFiles();
if (files.hasNext()) {
var [a, b] = nextFolderName.split("-");
nextFolderName = `${a}-${String(Number(b) + 1).padStart(2, "0")}`;
folder = null;
}
} else {
folder = videoFolder.createFolder(nextFolderName);
}
}
} else {
folder = parentFolder.createFolder("Video");
folder = folder.createFolder(folderName);
}
} else {
throw new Error("Parent Folder with id: " + parentFolderId + " not found");
}
console.log("Test" + nextFolderName)
return folder.getId();
} catch (error) {
return error;
}
}
const saveDataAsCSV = (data, folderId) => {
const folder = DriveApp.getFolderById(folderId);
folder.createFile(`${nextFolderName.getName()}.csv`, data);
}
const increaseRequest = (data, folderId) => DriveApp.getFolderById(folderId).createFile("IncreaseRequest.csv", data);
// NOTE: always make sure we use DriveApp, even if it's in a comment, for google to import those
// libraries and allow the rest of the app to work. see https://github.com/tanaikech/Resumable_Upload_For_WebApps
HTML
档案:
<!DOCTYPE html>
<html>
<head>
<base target="_blank">
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Drive Multi Large File Upload</title>
<link href="https://fonts.googleapis.com/icon?family=Material+Icons" rel="stylesheet">
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/materialize/0.97.5/css/materialize.min.css">
<!-- Bootstrap CSS -->
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/css/bootstrap.min.css" integrity="sha384-Gn5384xqQ1aoWXA+058RXPxPg6fy4IWvTNh0E263XmFcJlSAwiGgFAW/dAiS6JXm" crossorigin="anonymous">
<style>
@import url('https://fonts.googleapis.com/css2?family=Rubik:wght@400;600;700&display=swap');
.disclaimer{
width: 480px;
color: #646464;
margin: 20px auto;
padding:0 16px;
text-align:center;
font:400 12px Rubik,sans-serif;
}
h5.center-align.teal-text {
font:700 26px Rubik,sans-serif;
color: #00F498!important;
}
.row {
font:600 14px Rubik,sans-serif;
}
.btn {
background-color: black;
}
.btn:hover {
background-color: #00F498;
}
body {
margin-top: -40px;
}
#progress {
color: #00000;
}
.disclaimer a{
color: #00BCAA;
}
#credit{
display:none
}
.btnOpenModal {
font-size: x-large;
padding: 10px;
border: none;
border-radius: 5px;
background-color: blueviolet;
color: white;
cursor: pointer;
}
hr {
border: 0px;
border-top: 1px solid lightgray;
}
.modal-container {
width: 100vw;
position: fixed;
top: 30px;
display: none;
z-index: 999;
justify-content: center;
}
.modal {
display: flex;
flex-direction: column;
padding: 30px;
background-color: white;
border-radius: 10px;
width: 50%;
}
.active {
display: flex;
}
.active .modal {
animation: modal .4s;
}
@keyframes modal {
from {
opacity: 0;
transform: translate3d(0, -60px, 0);
}
to {
opacity: 1;
transform: translate3d(0, 0, 0);
}
}
.btns {
display: flex;
justify-content: space-between;
margin-top: 10px;
}
.btns button {
font-size: medium;
padding: 10px;
border: none;
border-radius: 5px;
color: white;
cursor: pointer;
}
.btnOK {
background-color: blue!important;
}
.btnClose {
background-color: brown!important;
}
</style>
</head>
<body>
<form class="main" id="form" novalidate="novalidate" style="max-width: 480px;margin: 40px auto;">
<div id="forminner">
<div class="modal-container">
<div class="modal">
<h2>Info</h2>
<hr />
<span>
Lorem Ipsum is simply dummy text of the printing and typesetting
industry. Lorem Ipsum has been the industry's standard dummy text
ever since the 1500s, when an unknown printer took a galley of
type and scrambled it to make a type specimen book.
</span>
<hr />
<div class="btns">
<button class="btnOK" onclick="increaseRequest(); closeModal();">OK</button>
<button class="btnClose" onclick="closeModal()">Close</button>
</div>
</div>
</div>
<h5 class="center-align teal-text" style="margin-bottom: -10px; font-size: 20px; font-family: Rubik; ">YOUR NAME</h5>
<div class="row">
<div class="input-field col s12">
<input id="name01" type="text" name="Name" class="validate" required="required" aria-required="true">
<label for="name" class="">Name</label>
</div>
</div>
<h5 class="center-align teal-text" style="margin-bottom: -10px; font-size: 20px; font-family: Rubik; ">SOME DESCRIPTION</h5>
<div class="row">
<div class="input-field col s12">
<input id="description" type="text" name="Description" class="validate" required="required" aria-required="true">
<label for="name">Description</label>
</div>
</div>
<div class="row">
<div class="col-8 col-md-4">
<h6>Model</h6>
<select class="custom-select" id="Model">
<option selected="">Choose...</option>
<option value="01">01</option>
<option value="02">02</option>
<option value="03">03</option>
</select>
<h6>Color</h6>
<select class="custom-select" id="Color">
<option selected="">Choose...</option>
<option value="Red">Red</option>
<option value="Green">Green</option>
</select>
</div>
</div>
<div class="row">
<div class="col s12">
<h5 class="center-align teal-text">Upload the Video File</h5>
</div>
</div>
<div class="row">
<div class="file-field input-field col s12">
<div id="input-btn" class="btn">
<span>File</span>
<input id="files" type="file" single="">
</div>
<div class="file-path-wrapper">
<input class="file-path validate" type="text" placeholder="Select the file">
</div>
</div>
</div>
<div class="row">
<div class="input-field col s6">
<button id="submit-btn" class="waves-effect waves-light btn submit-btn" type="submit" onclick="submitForm(); return false;">Submit</button>
</div>
</div>
<div class="row">
<div class="input-field col s12 hide" id="update">
<hr>
<p>
Por favor, aguarde enquanto seu arquivo está sendo carregado.<br><span style="color: #00000;"><b>Não feche ou atualize a janela durante o upload.</b></span>
</p>
</div>
</div>
<div class="row">
<div class="input-field col s12" id="progress">
</div>
</div>
</div>
</div>
<div id="success" style="display:none">
<h5 class="center-align teal-text">Tudo certo!</h5>
<p>Se você já preencheu todos os campos é só fechar essa janela e clicar em enviar!</p>
<button id="fechar" class="waves-effect waves-light btn submit-btn" style ="transform: translateX(160%);" type="button" onclick="google.script.host.close()">Fechar</button>
</div>
</form>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/2.2.0/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/materialize/0.97.5/js/materialize.min.js"></script>
<script src="https://gumroad.com/js/gumroad.js"></script>
<script>
var upload_folder = "01";
const chunkSize = 5242880;
const uploadParentFolderId = <?=getParent()?>; // creates a folder inside of this folder
const limitfolder = <?=getLimitFolder()?>;
const fileslimit = <?=getFilesLimit()?>;
const modal = document.querySelector('.modal-container');
var name = $('#name01').val();
var description = $('#description').val();
var model = $('#Model').val();
upload_folder = model;
var color = $('#Color').val();
var form_values = [name, description, model, color];
form_values = form_values.map(r => r.replaceAll(",", "#")); // Essa linha substitui todas as "," por "#" antes de gerar o .csv
var data = form_values.join(",");
function submitForm() {
var name = $('#name01').val();
var description = $('#description').val();
var model = $('#Model').val();
upload_folder = model;
var color = $('#Color').val();
var form_values = [name, description, model, color];
form_values = form_values.map(r => r.replaceAll(",", "#")); // Essa linha substitui todas as "," por "#" antes de gerar o .csv
var data = form_values.join(",");
// Added the below script.
if ($('#submit-btn.disabled')[0]) return; // short circuit
var name = upload_folder
var files = [...$('#files')[0].files]; // convert from FileList to array
if (files.length === 0) {
showError("Por favor, selecione um arquivo");
return;
}
google.script.run.saveDataAsCSV(data, uploadParentFolderId);
google.script.run.saveDataAsCSV(data, limitfolder);
disableForm(); // prevent re submission
// the map and reduce are here to ensure that only one file is uploaded at a time. This allows
// the promises to be run sequentially
files.map(file => uploadFilePromiseFactory(file))
.reduce((promiseChain, currentTask) => {
return promiseChain.then(currentTask);
}, Promise.resolve([])).then( () => {
console.log("Completed all files upload");
showSuccess();
});
}
function checkforfiles() {
if (fileslimit <= 2) {
submitForm();
}
if (fileslimit == 3) {
openModal();
}
if (fileslimit >= 4) {
showError("erro");
return;
}
}
function openModal() {
modal.classList.add('active');
}
function closeModal() {
modal.classList.remove('active');
}
function increaseRequest() {
google.script.run.increaseRequest(data, limitfolder);
}
function disableForm() {
$('#submit-btn').addClass('disabled');
$('#input-btn').addClass('disabled');
$('#update').removeClass('hide');
$('#update').removeClass('hide');
}
function closer(){
google.script.host.close();
}
function uploadFilePromiseFactory(file) {
return () => {
console.log("Processing: ", file.name);
return new Promise((resolve, reject) => {
showProgressMessage("Seu arquivo está sendo carregado");
var fr = new FileReader();
fr.fileName = file.name;
fr.fileSize = file.size;
fr.fileType = file.type;
// not sure of a better way of passing the promise functions down
fr.resolve = () => resolve();
fr.reject = (error) => reject(error);
fr.onload = onFileReaderLoad;
fr.readAsArrayBuffer(file);
});
};
}
/**
* Gets called once the browser has loaded a file. The main logic that creates a folder
* and initiates the file upload resides here
*/
function onFileReaderLoad(onLoadEvent) {
var fr = this;
var newFolderName = upload_folder
createOrGetFolder(newFolderName, uploadParentFolderId).then(newFolderId => {
console.log("Found or created guest folder with id: ", newFolderId);
uploadFileToDriveFolder.call(fr, newFolderId).then(() => {
fr.resolve();
}, (error) => {
fr.reject(error);
});
},
(error) => {
if (error) {
showError(error.toString());
}
console.log("onFileReaderLoad Error2: ", error);
});
}
/**
* call to the DriveApp api. Wrapped in a promise in case I want to address timing issues between a
* createFolder and findFolderById
*/
function createOrGetFolder(folderName, parentFolderId) {
return new Promise((resolve, reject) => {
google.script.run.withSuccessHandler(response => {
console.log("createOrGetFolder response: ", response);
if (response && response.length) {
resolve(response);
}
reject(response);
}).createOrGetFolder(folderName, parentFolderId);
});
}
/**
* Helper functions modified from:
* https://github.com/tanaikech/Resumable_Upload_For_WebApps
*/
function uploadFileToDriveFolder(parentFolderId) {
var fr = this;
return new Promise((resolve, reject) => {
var fileName = fr.fileName;
var fileSize = fr.fileSize;
var fileType = fr.fileType;
console.log({fileName: fileName, fileSize: fileSize, fileType: fileType});
var buf = fr.result;
var chunkpot = getChunkpot(chunkSize, fileSize);
var uint8Array = new Uint8Array(buf);
var chunks = chunkpot.chunks.map(function(e) {
return {
data: uint8Array.slice(e.startByte, e.endByte + 1),
length: e.numByte,
range: "bytes " + e.startByte + "-" + e.endByte + "/" + chunkpot.total,
};
});
google.script.run.withSuccessHandler(oAuthToken => {
var xhr = new XMLHttpRequest();
xhr.open("POST", "https://www.googleapis.com/upload/drive/v3/files?uploadType=resumable");
xhr.setRequestHeader('Authorization', "Bearer " + oAuthToken);
xhr.setRequestHeader('Content-Type', "application/json");
xhr.send(JSON.stringify({
mimeType: fileType,
name: fileName,
parents: [parentFolderId]
}));
xhr.onload = () => {
doUpload(fileName, {
location: xhr.getResponseHeader("location"),
chunks: chunks,
}).then(success => {
resolve(success);
console.log("Successfully uploaded: ", fileName);
},
error => {
reject(error);
});
};
xhr.onerror = () => {
console.log("ERROR: ", xhr.response);
reject(xhr.response);
};
}).getOAuthToken();
});
}
function showSuccess() {
$('#forminner').hide();
$('#success').show();
$('#fechar').show();
}
function showError(e) {
$('#progress').addClass('red-text').html(e);
}
function showMessage(e) {
$('#update').html(e);
}
function showProgressMessage(e) {
$('#progress').removeClass('red-text').html(e);
}
/**
* Helper functions modified from:
* https://github.com/tanaikech/Resumable_Upload_For_WebApps
*/
function doUpload(fileName, e) {
return new Promise((resolve, reject) => {
showProgressMessage("Carregando: <span style='color: #00F498 ;'>" + "0%</span>");
var chunks = e.chunks;
var location = e.location;
var cnt = 0;
var end = chunks.length;
var temp = function callback(cnt) {
var e = chunks[cnt];
var xhr = new XMLHttpRequest();
xhr.open("PUT", location, true);
console.log("content range: ", e.range);
xhr.setRequestHeader('Content-Range', e.range);
xhr.send(e.data);
xhr.onloadend = function() {
var status = xhr.status;
cnt += 1;
console.log("Uploading: " + status + " (" + cnt + " / " + end + ")");
showProgressMessage("Carregando: <span style='color: #00F498 ;'>"
+ Math.floor(100 * cnt / end) + "%</span>" );
if (status == 308) {
callback(cnt);
} else if (status == 200) {
$("#progress").text("Done.");
resolve();
} else {
$("#progress").text("Error: " + xhr.response);
reject();
}
};
}(cnt);
});
}
/**
* Helper functions modified from:
* https://github.com/tanaikech/Resumable_Upload_For_WebApps
*/
function getChunkpot(chunkSize, fileSize) {
var chunkPot = {};
chunkPot.total = fileSize;
chunkPot.chunks = [];
if (fileSize > chunkSize) {
var numE = chunkSize;
var endS = function(f, n) {
var c = f % n;
if (c == 0) {
return 0;
} else {
return c;
}
}(fileSize, numE);
var repeat = Math.floor(fileSize / numE);
for (var i = 0; i <= repeat; i++) {
var startAddress = i * numE;
var c = {};
c.startByte = startAddress;
if (i < repeat) {
c.endByte = startAddress + numE - 1;
c.numByte = numE;
chunkPot.chunks.push(c);
} else if (i == repeat && endS > 0) {
c.endByte = startAddress + endS - 1;
c.numByte = endS;
chunkPot.chunks.push(c);
}
}
} else {
var chunk = {
startByte: 0,
endByte: fileSize - 1,
numByte: fileSize,
};
chunkPot.chunks.push(chunk);
}
return chunkPot;
}
</script>
</body>
</html>
也可以通过访问此工作表来查看
虽然我不确定我是否能正确理解你的实际预期结果,但请测试以下修改。
请修改 Google Apps Script 的saveDataAsCSV
如下。
const saveDataAsCSV = (data, folderId1, folderId2 = null) => {
if (folderId2) {
DriveApp.getFolderById(folderId1).createFile(`${DriveApp.getFolderById(folderId2).getName()}.csv`, data);
} else {
DriveApp.getFolderById(folderId1).createFile("sample.csv", data);
}
}
请删除google.script.run.saveDataAsCSV(data, uploadParentFolderId);
在 function submitForm
中。
并且,修改onFileReaderLoad
的onFileReaderLoad如下。
function onFileReaderLoad(onLoadEvent) {
var fr = this;
var newFolderName = upload_folder
createOrGetFolder(newFolderName, uploadParentFolderId).then(newFolderId => {
google.script.run.saveDataAsCSV(data, uploadParentFolderId, newFolderId);
console.log("Found or created guest folder with id: ", newFolderId);
uploadFileToDriveFolder.call(fr, newFolderId).then(() => {
fr.resolve();
}, (error) => {
fr.reject(error);
});
},
(error) => {
if (error) {
showError(error.toString());
}
console.log("onFileReaderLoad Error2: ", error);
});
}
01-01.csv
到uploadParentFolderId
文件夹。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.