Subir archivo a mi unidad de Google con Google Apps Script (SIN FORMULARIO EN GOOGLE)

18 minutos de lectura

avatar de usuario
Marcel Dz

así que básicamente la tarea es bastante simple, pero no encontré ninguna solución viable para mi problema. Tengo un gran script de carga en mi sitio web (en este momento localhost), pero reduzcamos toda la complejidad a lo único necesario.

Entonces, solo quiero cargar un solo archivo en Google Drive con Google App Script y recibir la URL para guardarlo en una var, para trabajar con esa información en un punto posterior de mi función.

Ahora el problema es que ya tengo el formulario en mi sitio web, no quiero el formulario dentro de script.google.com como html adicional, quiero transferir mi entrada de usuario a Google App Script, luego subirlo a Google Drive y devolver la URL volver a mi sitio web donde puedo guardarlo en una var.

Mi problema ahora es que no puedo poner todas las cosas juntas.

Este es el formulario en mi sitio web (simplificado):

<form name="myForm" method="post">
            <!-- <form name="first-form"> -->

  <input type="text" placeholder="Name" id="myName">
  <input type="file" name="myFile" id="myFile">
  <button onclick="UploadFile()" type="submit">submit</button>

</form>

Entonces, ¿cómo puedo cargar mi información dentro de Google Drive y obtener un resultado? ¿Cómo puedo enviar los datos en Google App Script sin usar iFrame ni nada más?

¡GRACIAS!

**** Ejemplo de trabajo si html está en scripts.google.com ****

gs

function doGet(e) {
  return HtmlService.createHtmlOutputFromFile('forms.html').setTitle("Google File Upload by CTRLQ.org");
}


function uploadFileToGoogleDrive(data, file, name, email) {
  
  try {
    
    var dropbox = "Received Files";
    var folder, folders = DriveApp.getFoldersByName(dropbox);
    
    if (folders.hasNext()) {
      folder = folders.next();
    } else {
      folder = DriveApp.createFolder(dropbox);
    }
    
    /* Credit: www.labnol.org/awesome */
    
    var contentType = data.substring(5,data.indexOf(';')),
        bytes = Utilities.base64Decode(data.substr(data.indexOf('base64,')+7)),
        blob = Utilities.newBlob(bytes, contentType, file),
        file = folder.createFolder([name, email].join(" ")).createFile(blob);
    
    return "OK";
    
  } catch (f) {
    return f.toString();
  }
  
}

html en aplicaciones.googlescript

<!DOCTYPE html>
<html>
  <head>
    <base target="_blank">
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Google File Upload by CTRLQ.org</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">
    <style>
      .disclaimer{width: 480px; color:#646464;margin:20px auto;padding:0 16px;text-align:center;font:400 12px Roboto,Helvetica,Arial,sans-serif}.disclaimer a{color:#009688}#credit{display:none}
    </style>
  </head>
  <body>

    <!-- Written by Amit Agarwal amit@labnol.org --> 

    <form class="main" id="form" novalidate="novalidate" style="max-width: 480px;margin: 40px auto;">
      <div id="forminner">
        <div class="row">
          <div class="col s12">
            <h5 class="center-align teal-text">Upload Files to my Google Drive</h5>
            <p class="disclaimer">This <a href="http://www.labnol.org/internet/file-upload-google-forms/29170/">File Upload Form</a> (<a href="https://youtu.be/C_YBBupebvE">tutorial</a>) is powered by <a href="https://ctrlq.org/code/19747-google-forms-upload-files" target="_blank">Google Scripts</a></p>
          </div>
        </div>
        <div class="row">
          <div class="input-field col s12">
            <input id="name" type="text" name="Name" class="validate" required="" aria-required="true">
            <label for="name">Name</label>
          </div>
        </div>
        <div class="row">
          <div class="input-field col s12">
            <input id="email" type="email" name="Email" class="validate" required="" aria-required="true">
            <label for="email">Email Address</label>
          </div>
        </div>

        <div class="row">
          <div class="file-field input-field col s12">
            <div class="btn">
              <span>File</span>
              <input id="files" type="file">
            </div>
            <div class="file-path-wrapper">
              <input class="file-path validate" type="text" placeholder="Select a file on your computer">
            </div>
          </div>
        </div>

        <div class="row">
          <div class="input-field col s6">
            <button 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" id = "progress">
          </div>
        </div>
      </div>
      <div id="success" style="display:none">
        <h5 class="left-align teal-text">File Uploaded</h5>
        <p>Your file has been successfully uploaded.</p>
        <p>The <a href="http://www.labnol.org/internet/file-upload-google-forms/29170/">pro version</a> (see <a href="">demo form</a>) includes a visual drag-n-drop form builder, CAPTCHAs, the form responses are saved in a Google Spreadsheet and respondents can upload multiple files of any size.</p>    
        <p class="center-align"><a  class="btn btn-large" href="https://gum.co/GA14?wanted=true" target="_blank">Upgrade to Pro</a></p>
      </div>
    </form>

    <div class="fixed-action-btn horizontal" style="bottom: 45px; right: 24px;">
      <a class="btn-floating btn-large red">
        <i class="large material-icons">menu</i>
      </a>
      <ul>
        <li><a class="btn-floating red"  href="https://gum.co/GA14" target="_blank" title="Buy License - File Upload Form"><i class="material-icons">monetization_on</i></a></li>
        <li><a class="btn-floating blue"  href="https://youtu.be/C_YBBupebvE" target="_blank" title="Video Tutorial"><i class="material-icons">video_library</i></a></li>
        <li><a class="btn-floating green" href="http://www.labnol.org/internet/file-upload-google-forms/29170/" target="_blank" title="How to Create File Upload Forms"><i class="material-icons">help</i></a></li>
      </ul>
    </div>

    <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 file, 
          reader = new FileReader();

      reader.onloadend = function(e) {
        if (e.target.error != null) {
          showError("File " + file.name + " could not be read.");
          return;
        } else {
          google.script.run
            .withSuccessHandler(showSuccess)
            .uploadFileToGoogleDrive(e.target.result, file.name, $('input#name').val(), $('input#email').val());
        }
      };

      function showSuccess(e) {
        if (e === "OK") { 
          $('#forminner').hide();
          $('#success').show();
        } else {
          showError(e);
        }
      }

      function submitForm() {

        var files = $('#files')[0].files;

        if (files.length === 0) {
          showError("Please select a file to upload");
          return;
        }

        file = files[0];

        if (file.size > 1024 * 1024 * 5) {
          showError("The file size should be < 5 MB. Please <a href="http://www.labnol.org/internet/file-upload-google-forms/29170/" target="_blank">upgrade to premium</a> for receiving larger files in Google Drive");
          return;
        }

        showMessage("Uploading file..");

        reader.readAsDataURL(file);

      }

      function showError(e) {
        $('#progress').addClass('red-text').html(e);
      }

      function showMessage(e) {
        $('#progress').removeClass('red-text').html(e);
      }


    </script>

  </body>

</html>

Como se recomienda, voy a describir el proceso aquí.

Así que estamos en el sitio web: www.ejemplo.com , hay un formulario con campo de entrada de texto y campo de archivo. Digamos que ponemos una imagen y la llamamos ejemplo. Ahora, si presionamos enviar, quiero cargar la imagen en Google Drive sin ningún oAuth (es por eso que necesitamos usar el script de la aplicación de Google aquí) y nombrarlo según lo que escribimos en el campo de texto. Cuando finalice la carga, quiero que la URL de la imagen de Google Drive regrese al sitio web, para que el formulario pueda continuar trabajando con la información. Quiero guardar la url devuelta en una var luego, para luego guardarla en una base de datos. Es por eso que necesito el resultado de vuelta a mi sitio web.

Así que el esquema se parece a lo siguiente:

Ingrese la información para formar en el sitio web -> Redirigido a la secuencia de comandos de la aplicación de Google: tome la información del campo de formulario del sitio web y cargue el archivo en Google Drive y asígnele el nombre de entrada de texto -> tomar la URL de Google Drive como resultado final -> redirigir el resultado final de la URL al sitio web -> guardar el resultado de la URL en var y continuar haciendo cosas desde la función en el sitio web -> al final guardar la información de var en una base de datos -> finalizar

———————————————— EDITAR: ——————

Gracias a @Tanaike, estoy mucho más cerca del objetivo de mi desafío aquí, así que para ver dónde me quedé atascado, estoy replicando mi problema ahora:

Tomé el formulario con el script de tu ejemplo:

<form id="form">
  <input name="file" id="uploadfile" type="file">
  <input name="filename" id="filename" type="text">
  <input id="submit" type="submit">
</form>
<script>
const form = document.getElementById('form');
form.addEventListener('submit', e => {
  e.preventDefault();
  const file = form.file.files[0];
  const fr = new FileReader();
  fr.readAsArrayBuffer(file);
  fr.onload = f => {
    
    const url = "https://script.google.com/macros/s/###/exec";  // <--- Please set the URL of Web Apps.
    
    const qs = new URLSearchParams({filename: form.filename.value || file.name, mimeType: file.type});
    fetch(`${url}?${qs}`, {method: "POST", body: JSON.stringify([...new Int8Array(f.target.result)])})
    .then(res => res.json())
    .then(e => console.log(e))  // <--- You can retrieve the returned value here.
    .catch(err => console.log(err));
  }
});
</script>

y para el script de Google:

function doPost(e) {
  // const folderId = "###";  // Folder ID which is used for putting the file, if you need.

  const blob = Utilities.newBlob(JSON.parse(e.postData.contents), e.parameter.mimeType, e.parameter.filename);
  const file = DriveApp.getFolderById(folderId || "root").createFile(blob);
  const responseObj = {filename: file.getName(), fileId: file.getId(), fileUrl: file.getUrl()};
  return ContentService.createTextOutput(JSON.stringify(responseObj)).setMimeType(ContentService.MimeType.JSON);
}

Ahora, cuando intenté cargar algo, tuve el siguiente error: la política CORS no se pudo obtener. Así que cambié esta parte a la siguiente y agregué el modo no cors:

const qs = new URLSearchParams({filename: form.filename.value || file.name, mimeType: file.type});
        fetch(`${url}?${qs}`, {method: "POST", mode: "no-cors", body: JSON.stringify([...new Int8Array(f.target.result)])})

Esto funcionó. Segundo intente cargar el archivo causado en el siguiente error: dice: syntax error: unexpected end of input

Así que cambié esta línea y eliminé los corchetes de res.json

JSON.stringify([...new Int8Array(f.target.result)])})
        .then(res => res.json)

el tercer intento de cargar el archivo realmente funcionó con el siguiente resultado de la consola:

ƒ json() { [native code] }

Pero no hay ningún archivo cargado en Google Drive. Me estoy perdiendo algo en alguna parte. Tal vez deberíamos crear una carpeta y colocar los archivos allí.

Ah, y otra información: cuando ejecuto la función doPost en la aplicación de Google, dice:

TypeError: Cannot read property 'postData' of undefined (line 13

EDITAR2 —————————————–

yo añadí https://drive.google.com/uc?export=download&id=###ID de archivo### a su código y todo funciona bien. El archivo se está cargando.

Digamos que cargamos el archivo test.mp3 y lo llamamos testdata. Esto es lo que recibimos:

{
  "filename": "testdata",
  "fileId": "###some id##",
  "fileUrl": "https://drive.google.com/uc?export=download&id=###fileId###"
}

Ahora, cuando abro la URL del archivo, el navegador descarga el archivo pero se llama: testdata, no testdata.mp3. Falta la terminación de tipo de archivo.

Segunda tarea: si hace clic en el enlace, quiero abrir el archivo en el navegador, cuando sea un archivo mp3, por ejemplo, quiero que pueda reproducir el sonido en la vista web, como está aquí: https://files.freemusicarchive.org/storage-freemusicarchive-org/music/Creative_Commons/Dead_Combo/CC_Affiliates_Mixtape_1/Dead_Combo_-_01_-_Povo_Que_Cas_Descalo.mp3

Espero que me puedas orientar!

  • Échale un vistazo: desarrolladores.google.com/picker/docs

    – Cos

    12 de agosto de 2020 a las 12:56

  • Gracias por el enlace, hasta donde yo sé, necesita la autenticación oAuth, necesito una carga pública, por lo que este enfoque no funciona para mí.

    – Marcel Dz

    12 de agosto de 2020 a las 12:59

  • Prueba una aplicación web y la marco en tu sitio web

    – Cobre

    12 de agosto de 2020 a las 13:04

  • ¿Cómo se vería esto? Necesito un resultado para mi sitio web y luego guardarlo en una var, ¿es posible con un iframe?

    – Marcel Dz

    12 de agosto de 2020 a las 13:06

  • Esto es un poco difícil de seguir. ¿Puede diseñar un proceso paso a paso del flujo de trabajo? Submit form > data gets posted to x > redirect to y ¿etc?

    – Espero que esto te sea útil.

    12 de agosto de 2020 a las 13:07

avatar de usuario
Tanaike

Creo que su objetivo es el siguiente.

  • Su sitio web no está relacionado con la cuenta de Google. es independiente
  • Su sitio web tiene un formulario para cargar un archivo.
  • Cuando los usuarios envían el formulario, desea cargar el archivo en su Google Drive sin la autorización y desea devolver la URL del archivo cargado en Google Drive.
  • Acerca de “Base de datos”, esta es su base de datos. Colocará la URL recuperada del archivo en “Base de datos” en el lado del cliente.

En este caso, creo que su objetivo se puede lograr utilizando las aplicaciones web creadas por Google Apps Script.

Uso:

Por favor, haga el siguiente flujo.

1. Cree un nuevo proyecto de Google Apps Script.

El script de muestra de Web Apps es un script de Google Apps. Por lo tanto, cree un proyecto de Google Apps Script.

Si desea crearlo directamente, acceda a https://script.nuevo/. En este caso, si no ha iniciado sesión en Google, se abre la pantalla de inicio de sesión. Por lo tanto, inicie sesión en Google. Con esto, se abre el editor de secuencias de comandos de Google Apps Script.

2. Preparar guión.

Copie y pegue la siguiente secuencia de comandos (Google Apps Script) en el editor de secuencias de comandos. Este script es para las aplicaciones web.

Lado del servidor: Google Apps Script

Establezca la ID de la carpeta en la que desea colocar el archivo.

function doPost(e) {
  const folderId = "root";  // Or Folder ID which is used for putting the file instead of "root", if you need.

  const blob = Utilities.newBlob(JSON.parse(e.postData.contents), e.parameter.mimeType, e.parameter.filename);
  const file = DriveApp.getFolderById(folderId).createFile(blob);
  const responseObj = {filename: file.getName(), fileId: file.getId(), fileUrl: file.getUrl()};
  return ContentService.createTextOutput(JSON.stringify(responseObj)).setMimeType(ContentService.MimeType.JSON);
}

3. Implementar aplicaciones web.

  1. En el editor de secuencias de comandos, abra un cuadro de diálogo mediante “Publicar” -> “Implementar como aplicación web”.
  2. Seleccione “Me” por “Ejecutar la aplicación como:”.
    • Con esto, el script se ejecuta como propietario.
  3. Seleccione “Cualquiera, incluso anónimo” por “Quién tiene acceso a la aplicación:”.
  4. Haga clic en el botón “Implementar” como nueva “Versión del proyecto”.
  5. Abre automáticamente un cuadro de diálogo de “Se requiere autorización”.
    1. Haga clic en “Revisar permisos”.
    2. Seleccionar cuenta propia.
    3. Haga clic en “Avanzado” en “Esta aplicación no está verificada”.
    4. Haga clic en “Ir al nombre del proyecto ### ### (inseguro)”
    5. Haga clic en el botón “Permitir”.
  6. Haga clic en Aceptar”.
  7. Copie la URL de las aplicaciones web. Es como https://script.google.com/macros/s/###/exec.
    • Cuando modificó Google Apps Script, vuelva a implementarlo como una nueva versión. Con esto, el script modificado se refleja en Web Apps. Por favor tenga cuidado con esto.

4. Cargue un archivo del lado del cliente al lado del servidor.

Lado del cliente: HTML y Javascript

Establezca la URL de sus aplicaciones web en el siguiente script.

<form id="form">
  <input name="file" id="uploadfile" type="file">
  <input name="filename" id="filename" type="text">
  <input id="submit" type="submit">
</form>
<script>
const form = document.getElementById('form');
form.addEventListener('submit', e => {
  e.preventDefault();
  const file = form.file.files[0];
  const fr = new FileReader();
  fr.readAsArrayBuffer(file);
  fr.onload = f => {
    
    const url = "https://script.google.com/macros/s/###/exec";  // <--- Please set the URL of Web Apps.
    
    const qs = new URLSearchParams({filename: form.filename.value || file.name, mimeType: file.type});
    fetch(`${url}?${qs}`, {method: "POST", body: JSON.stringify([...new Int8Array(f.target.result)])})
    .then(res => res.json())
    .then(e => console.log(e))  // <--- You can retrieve the returned value here.
    .catch(err => console.log(err));
  }
});
</script>
  • En el lado del cliente, cuando selecciona un archivo de su PC local y presiona el botón, el archivo se carga en su Google Drive recuperando los datos en las aplicaciones web (lado del servidor).

Resultado:

Cuando se ejecuta el script anterior, se devuelve el siguiente valor. A partir de aquí, puede recuperar la URL del archivo.

{
  "filename": "### inputted filename ###",
  "fileId": "###",
  "fileUrl": "https://drive.google.com/file/d/###/view?usp=drivesdk"
}

Nota:

  • Cuando modificó la secuencia de comandos de las aplicaciones web, vuelva a implementar las aplicaciones web como una nueva versión. Con esto, el último script se refleja en Web Apps. Por favor tenga cuidado con esto.
  • En el script anterior, el tamaño máximo de archivo es de 50 MB. Porque en la etapa actual, el tamaño máximo de blob es de 50 MB en Google Apps Script.

Referencias:

  • ¡¡Esto es increíble!! ¡mil gracias por esta guía informativa paso a paso! Lo intentaré cuando haya terminado con el trabajo, pero lo que vi hasta ahora al desplazarme rápidamente, hay mucha información relevante que me proporcionó y parece que ESTA es la solución perfecta para mi desafío. Solo puedo decir de nuevo, ¡¡MILES DE GRACIAS A TI!!

    – Marcel Dz

    13 de agosto de 2020 a las 10:51


  • Buenos días, quería que le diera algunos comentarios. Entonces, antes que nada, obtuve un error de política de cors, pero lo descubrí agregando el modo: ‘no-cors’ a la línea después de buscar la publicación. Ahora, en este momento, recibo un error de sintaxis en esta línea: .then(res => res.json()), dice final inesperado de entrada

    – Marcel Dz

    14 de agosto de 2020 a las 6:18


  • @Marcel Dz Gracias por responder. Pido disculpas por las molestias. Desafortunadamente, no puedo replicar su situación. Porque cuando lo probé, pude confirmar que no ocurre ningún error. Así que propuse arriba. Me disculpo profundamente por esto. Para comprender correctamente su situación y replicar correctamente su situación, ¿puede proporcionar la información detallada para replicar su problema actual? Por esto, me gustaría confirmarlo. Si puede cooperar para resolver su problema, me alegro. ¿Puede cooperar para resolver su problema? Si puede hacerlo, agregue el flujo de detalles en su pregunta.

    – Tanaike

    14 de agosto de 2020 a las 6:22


  • Gracias por responder rápidamente, lo acabo de recibir cambiando .then(res => res.json() a .then(res=> res.json) sin los corchetes, funciona. Ahora, cuando subo un archivo, recibo algo así: ƒ json() { [native code] } pero el archivo aún no está cargado en la unidad

    – Marcel Dz

    14 de agosto de 2020 a las 6:24

  • @Marcel Dz Gracias por responder. Pido disculpas por las molestias. Desafortunadamente, no puedo replicar su situación. Porque cuando lo probé, pude confirmar que no ocurre ningún error. Así que propuse arriba. Me disculpo profundamente por esto. Para comprender correctamente su situación y replicar correctamente su situación, ¿puede proporcionar la información detallada para replicar su problema actual? Por esto, me gustaría confirmarlo. Si puede cooperar para resolver su problema, me alegro. ¿Puede cooperar para resolver su problema? Si puede hacerlo, agregue el flujo de detalles en su pregunta.

    – Tanaike

    14 de agosto de 2020 a las 6:25

¡Muchos consejos útiles en https://stackoverflow.com/a/63391363/1585523 respuesta! Gracias por compartir. En lugar de publicar el archivo, también podríamos usar

En el cliente: index.html

google.script.run.withSuccessHandler(fileName => {}).withFailureHandler(error => {}).saveInDrive(fileAsByteArray);

En el servidor: Code.gs

function saveInDrive(f) {
  const blob = Utilities.newBlob(f, "image/jpeg", "some-name");
  const file = DriveApp.getFolderById("root").createFile(blob);
  return file.getName()
}

Incluso puede intercambiar tipos complicados como objetos JS con información binaria como valores también en este enfoque.

  • ¿podría explicar cómo se define fileAsByteArray?

    – PriyankaJ

    22 de febrero a las 15:14

  • Depende de cómo obtenga el archivo original. En la fuente se puede buscar API: por ejemplo const fileAsByteArray = new File([Uint8Array.from(await fetchResp)], "myfile.bin"). desarrollador.mozilla.org/en-US/docs/Web/JavaScript/Reference/… toma inp de muchas maneras

    – Nitina

    23 de febrero a las 7:43


¿Ha sido útil esta solución?

Esta web utiliza cookies propias y de terceros para su correcto funcionamiento y para fines analíticos y para mostrarte publicidad relacionada con sus preferencias en base a un perfil elaborado a partir de tus hábitos de navegación. Al hacer clic en el botón Aceptar, acepta el uso de estas tecnologías y el procesamiento de tus datos para estos propósitos. Configurar y más información
Privacidad