Como convertir número a texto con Google Apps Script


Necesitas usar un número como si fuera un string cuando estas trabajando con Google Apps Script?. En muchas ocasiones nos puede resultar útil convertir un dato de tipo numérico a tipo string con Google Apps Script. Generalmente se usa este tipo de conversiones para obtener un identificador de forma automática o un código de producto por ejemplo , de forma que también nos puede resultar útil si aseguramos que el string va a tener un tamaño mínimo (rellanado con ceros por la izquierda, por ejemplo).

El código que os presentaré hoy hace justamente eso, convierte un número a un string usando Google Apps Script y opcionalmente permite rellenar con ceros a la izquierda si es necesario hasta el tamaño de string que tu le digas. 

function NumberToText(number,min_size) 
{
  var text = "";
  
  while(number > 0)
  {
     var char = Math.floor(number%10);
     text = String(char) + text;
     number -= char;   
     number = Math.floor(number/10);
  }

  while ( text.length < min_size )
  {
    text = "0" + text;
  }

  return text;
}


La gracia de este código es que tanto se puede usar en nuestros programas Google Apps Script como usarlo directamente como una fórmula en nuestras hojas de Google Spreadsheets:


Como podéis ver el código es extremadamente sencillo y fácil de usar. Lo podéis adaptar como querías a vuestras necesidades con muy pocos cambios.

Cualquier cosa, no dudéis en hacérmelo saber.

Nos vemos

Como obtener el nombre de un fichero con Google Apps Script


 

Hay ocasiones en las que nos puede resultar útil obtener el nombre de un fichero de Drive del cual solo tenemos el id. La forma de solucionar este problema es extremadamente fácil, obtendremos el fichero gracias al id y la funcionalidad de DriveApp y entonces le preguntaremos el nombre.

Dado que esto tiene utilidad en listas grandes de ids, ya he preparado el código para que lea los ids de la primera columna y escriba el nombre en la segunda columna tal y como se ve en esta imagen:

Nombre de archivo de Drive con Google Apps Script

 Es fácil de adaptar a lo que necesitéis. Os adjunto el código, ya viereis que más sencillo no puede ser. Si tenéis cualquier duda, hacédmela llegar sin problemas.

function onOpen()
{
  SpreadsheetApp.getUi().createMenu("SCRIPT").addItem("Get Name","GetName").addToUi();
}

function GetNameFromId(id)
{
  var result = "NOT FOUND";
  var file = DriveApp.getFileById(id);

  if(file != null)
  {
    result = file.getName();
  }
  
  return result;
}

function GetName() 
{
  var sheet = SpreadsheetApp.getActiveSpreadsheet().getActiveSheet();
  var values = sheet.getDataRange().getDisplayValues();
  
  for( var i = 1 ; i < values.length ; ++i )
  {
    var str = values[i][0];
    if(str != "")
    {
      sheet.getRange(i+1,2).setValue(GetNameFromId(str));
    }
  }
}

Solo como nota final, os comento que no es factible usar esta funcionalidad dentro de una formula ( como quería hacer al principio de redactar este post ) dado que las formulas se ejecutan sin permisos y esta funcionalidad necesita si o si de acceso a DriveApp ( como es lógico ). Es por ello que lo he montado en forma de ejecución batch de toda la lista.

Cualquier sugerencia siempre es bien recibida.

Nos vemos

P.D: Tal vez te interesa saber el paso contrario, como obtener el id de un  fichero con Google Apps Script








Como cambiar permisos de forma recursiva con Google Apps Script


 En muchas ocasiones nos puede resultar útil cambiar los permisos de un árbol de directorios de Drive , de forma que con una sola llamada a un script nos aseguremos que todos los ficheros y carpetas que cuelgan de la carpeta origen tienen los permisos que nosotros queremos.

Hace un tiempo ya hice un artículo sobre como cambiar permisos de una carpeta de Drive con Google Apps Script, así que tomando ese código de base, ya veréis que es muy fácil implementarlo para que sea recursivo en todo el árbol de carpetas.

Todo lo que hemos de hacer para conseguir recursividad  es llamar a la misma función que estamos creando para cada una de las subcarpetas de la carpeta actual. Dicho así, parece complejo, pero viendo el código Google Apps Script lo tendréis clarísimo:

function SetPermisosRecursivos(folder) 
{
    //Seteamos permisos a la carpeta actual
    folder.setSharing(DriveApp.Access.ANYONE_WITH_LINK, DriveApp.Permission.VIEW);

    //Inspeccionamos todas las carpetas hijas
    var folders = folder.getFolders();
    while(folders.hasNext())
    {
       SetPermisosRecursivos(folders.next());
    }

    //Seteamos permisos a todos los ficheros de la carpeta actual
    var files = folder.getFiles();
    while(files.hasNext())  
    {
       files.next().setSharing(DriveApp.Access.ANYONE_WITH_LINK, DriveApp.Permission.VIEW);
    }
}

En este ejemplo todas las carpetas y ficheros que dependan de la carpeta que le pasemos a la función se compartirán con cualquier que tenga el link. Evidentemente podéis cambiar esa linea de código para que los permisos se apliquen como lo necesites en tu caso.

Cualquier duda que tengáis, no vaciléis en hacérmela llegar.

Nos vemos


Cómo saber el usuario actual con Google Apps Script


 Cuando implementamos webs con Google Apps Script o en general cuando queremos comunicar javascript con Google Apps Script siempre podemos tener problemas en saber cual es el usuario real que está usando nuestro servicios.

Generalmente cuando distribuimos una web implementada con Google Apps Script lo hacemos con los permisos de ejecución del desarrollador. Es decir. la web accede a los datos a los que el desarrollador tiene permiso, y el usuario de la web  puede ver el html, pero no puede llegar a los documentos que hay detrás dado que el mismo no tiene permisos. Acostumbra a ser una muy buena manera de recolectar información de diferentes fuentes y poderlas  mostrar a los usuarios de una forma controlada y sin tener que dar permisos para nada a nadie.

Ahora bien, ¿Qué pasaría si necesitáramos saber cual es el usuario que accede a nuestra web? Imaginemos que la web ha de mostrar información diferente en función de que usuario se está conectando (una web con diferentes niveles de permisos, por ejemplo) . Google Apps Script nos permite saber sin lugar a dudas cual es el usuario que se conecta a nuestra web y con que usuario se está ejecutando la web, de forma que podremos mostrar información diferente sin ningún tipo de problemas.

Con este ejemplo veréis facilísimo cual es la diferencia entre usuarios conectados a una web:

function doGet()
{
  var active_user     = Session.getActiveUser().getEmail();
  var effective_user  = Session.getEffectiveUser().getEmail();
  var user            = Session.getUser().getEmail();

  var output = "<p>Active: " + active_user + "</p>";
  output += "<p>Effective: " + effective_user + "</p>";
  output += "<p>User: " + user + "</p>";
  return HtmlService.createHtmlOutput(output);
}

Si ejecutáis la web con vuestro usuario veréis que los 3 campos son iguales:

Usuarios con Google Apps Script
Si habéis habilitado que la web se puede ejecutar sin permisos de ninguno tipo, veréis que solo se llena el campo effective mientras que los otros dos quedan vacíos. 

Si ejecutas la web con otro usuario veras que el campo active y el campo effective difieren.

Conclusión:
- Session.getEffectiveUser() Nos devuelve con que permisos se esta ejecutando la web (generalmente el desarrollador del código que ha publicado la web)
- Session.getActiveUser(): Nos dice que usuario se ha conectado a la web. Este es el que tendremos que usar para saber que usuario esta usando nuestro web.

Con esta información podréis tener controlados que usuarios se conectan a vuestra web, pudiendo denegar servicio, o cambiar lo que vais a mostrar en función del tipo de usuario.

Ya veis que es muy sencillo saber que usuario se conecta a nuestro Google Apps Script y actuar en consecuencia.

No dudéis en hacerme llegar vuestras preguntas.

Nos vemos


Como introducir datos con un popup con Google Apps Script


En ocasiones puede resultar muy útil usar Google Apps Script a fin de simplificar la introducción de datos en nuestros spreadsheets. 

Gracias a Google Apps Scripts podemos generar un popup con los campos que necesitemos que ingresen la información que queramos en las casillas que necesitemos.

El ejemplo que aquí os muestro es muy sencillo, solo pide el nombre y el apellido y lo registra en la hoja de cálculo pero con pocas modificaciones podréis tenerlo listo para trabajar como lo necesitáis.

El popup no es más que una pequeña web que se comunica con el Google Apps Script y le da la información que ha de procesar.

Aquí os dejo el código:

index.html
<!DOCTYPE html>
<html>
  <head>
    <base target="_top">
    <script>
      function Register()
      {
        var Nombre    = document.getElementById("Nombre").value;
        var Apellido  = document.getElementById("Apellido").value;
        google.script.run.withSuccessHandler(Done).Register( Nombre, Apellido );
      }

      function Done()
      {
           document.getElementById("container").innerHTML = "<p> PROCESO FINALIZADO </p>";
      }
    </script>  
  </head>
  <body>
     <div id="container">
       <h1>Introducir datos</h1>
       <p><input type="text" id="Nombre"   value="" placeholder="Nombre"></p>
       <p><input type="text" id="Apellido" value="" placeholder="Apellido"></p>
       <button onclick="Register()"> Registrar </button>
     </div>
  </body>
</html>

Code.gs
function onOpen()
{
  SpreadsheetApp.getUi().createMenu("SCRIPT")
          .addItem("ShowPopup","ShowPopup")
          .addToUi();
}

function ShowPopup()
{
  var html = HtmlService.createHtmlOutputFromFile('index').setWidth(300).setHeight(300);
  SpreadsheetApp.getUi().showModalDialog(html,"Entrada de datos");
}

function Register( Nombre, Apellido )
{
  var row = new Array();
  row.push(Nombre);
  row.push(Apellido);

  SpreadsheetApp.getActiveSpreadsheet().getActiveSheet().appendRow(row);
}

Cómo extraer un PDF solo de las hojas no vacías con Google Apps Script


 Hace un tiempo un usuario me pidió en el post de Como crear un PDF de una selección de datos con Google Apps Script como se podía hacer un script que generase un PDF de las hojas que tuvieran datos.

Es decir, como implementar un Google Apps Script que ignorase las hojas vacías de un spreadsheet y generase un PDF con la información.

El código para hacer esto es bastante sencillo, de hecho, me he basado en el código que publiqué en Como generar un PDF y enviarlo por email con Google Apps Script modificando la parte en que se detecta las hojas a convertir.

El proceso para convertir un spreadsheet a PDF desde Google Apps Script, es tan sencillo como llamar a la API de exportación a través de un UrlFetchApp y con eso lo tenemos todo hecho. 

El proceso de conversión a PDF puede tardar un rato ( dependerá del tamaño de los datos ) , generalmente unas decenas de segundos.

Aquí os dejo el código:

function onOpen()
{
  SpreadsheetApp.getUi().createMenu("SCRIPT").addItem("PDF","ExportPDF").addToUi();
}

function ExportPDF() 
{
   var timestamp = Math.floor((new Date()).getTime() / 1000);
   
   var spreadsheet = SpreadsheetApp.getActiveSpreadsheet();
   var sheets      = spreadsheet.getSheets();

   var values = new Array();
   for(var s = 0 ; s < sheets.length ; s++)
   {
     //Asumimos que la hoja esta "escrita" si tiene más de una fila de datos
     if ( sheets[s].getDataRange().getValues().length > 1 )
     {
        values.push(sheets[s].getName());
     }
   }
   var out         = SpreadsheetApp.create(spreadsheet.getName() + "-ToPrint-" + timestamp);
   var folder      = DriveApp.getFolderById("tu_nombre_de_Carpeta");
   
   SpreadsheetApp.flush();
   for(var i = 0 ; i < values.length ; ++i)
   {
      var sheet = spreadsheet.getSheetByName(values[i]);
      sheet.copyTo(out).setName(values[i]);
   }
   var first_sheet = out.getSheets()[0];
   out.deleteSheet(first_sheet);
   SpreadsheetApp.flush();
   
   var exportUrl = 'https://docs.google.com/spreadsheets/d/' + out.getId()
      + '/export?exportFormat=pdf&format=pdf'
      + '&size=FOLIO'                  //Tamaño del papel: 0-LETTER,1-TABLOID,2-LEGAL,3-STATEMENT,4-EXECUTIVE,5-FOLIO,6-A3,7-A4,8-A5,9-B4,10-B5
      + '&portrait=false'              //Orientación: False - Horizontal / True - Vertical
      + '&fitw=true'                   //Forzamos que quepa correctamente en el ancho de la hoja
      + '&scale=4'                     // Fit to Page?
      + '&top_margin=1.75'             //Margen Superior          
      + '&bottom_margin=1.75'          //Margen inferior         
      + '&left_margin=1.5'             //Margen Izquierdo          
      + '&right_margin=1.5'            //Margen Derecho        
      + '&sheetnames=false'            //Marcamos si se ha de poner el nombre de las hojas o no
      + '&printtitle=false'            //Marcamos si se ha imprimir el titulo del documento o no
      + '&pagenum=false'               //Indicamos si se de pintar el número de página
      + '&gridlines=true'              //Marcamos si queremos que se vean las lineas de las celdas o no   
      + '&fzr=FALSE'                   //Frozen: marcamos si las cabeceras se han de ir imprimiendo o no en las consecutivas hojas
      + '&id=' + out.getId();          //Identificador del tab
            
  var response = UrlFetchApp.fetch(exportUrl, {  muteHttpExceptions: true, headers: { Authorization: 'Bearer ' +  ScriptApp.getOAuthToken()  } } );
  
  var blob = response.getBlob();
  blob = blob.setName(out.getName());
  var pdfFile = DriveApp.createFile(blob);
  pdfFile.moveTo(folder);
  SpreadsheetApp.getUi().alert(pdfFile.getUrl());

  DriveApp.getFileById(out.getId()).setTrashed(true);
}

 No vaciléis en hacerme llegar vuestras dudas ( tardaré más o menos pero siempre acabaré respondiendo )

Nos vemos

 

 

Como obtener el tamaño de imágenes con Google Apps Script

Puede haber ocasiones en que obtener el tamaño de imágenes usando Google Apps Script puede ser extremadamente útil para automatizar tareas, el problema es que esto es bastante difícil de conseguir (te reto a que lo encuentres :) ).  Aunque me ha costado bastante he conseguido desarrollar un manera de hacerlo y que me permite ahorra bastante tiempo diario al calcular los tamaños de grupos de imágenes.

He montado un spreadsheet con esta estructura, donde puedes poner la lista de url a las imagenes y al ejecutar el script se rellenan el height y el width de la imagen gracias a la magia de Google Apps Script.
como calcular tamaño de una imagen con Google Apps Script


Como conseguirlo?
En este caso concreto, el gran problema no es saber programar, sino encontrar la manera de poder obtener la información que queremos. Desde Google Apps Script es IMPOSIBLE conseguirlo directamente, no hay herramienta que te lo permita, pero, desde JavaScript si que es factible saber el tamaño de una imagen.

El código para saber el tamaño de una imagen con JavaScript seria tal que así:
function GetImagesize()
{
	var img = new Image();
	img.addEventListener("load", function()
            {
               var url = this.currentSrc;
               var width  = this.naturalWidth;
               var height = this.naturalHeight; 
		//Aqui hacemos lo queramos con ese tamaño	
            });
	img.src = url_de_tu_imagen;
}

Básicamente, creamos un objeto de tipo imagen (una de las pocas cosas de JavaScript que no podemos hacer en Google Apps Script), le marcamos que cuando la imagen este cargada obtenga el tamaño de la imagen correspondiente y le damos la url de la imagen a cargar.

Tal como hemos dicho esto no puede hacerse en Google Apps Script, pero... desde Google Apps Script si que podemos servir una web que use JavaScript. Es más, podemos hacer que esta web esta embedida dentro de un popup en un spreadsheet, de forma que cuando llamemos a este popup desde nuestro spreadsheet se realice todo el proceso de obtención de tamaños de imágenes. 

Ahora el problema que tendremos es que la obtención de los tamaños de las imágenes se producirá de forma asíncrona (se obtendrá cuando la imagen se haya cargado), de forma que esta información la tendremos que ir guardando hasta que no la podamos recuperar toda. La forma más fácil es usar la cache ( sessionStorage ) de JavaScript.

Finalmente solo necesitaremos transferir toda esta información desde JavaScript a Google Apps Script para poder guardarla en nuestro spreadsheet.

Como podéis ver, el proyecto es bastante más complicado de lo que parece, pero personalmente ha sido todo un orgullo poderlo completar.

Os adjunto todo el código del proyecto para que podáis ponerlo en práctica.

Espero que os sirva! 

No dudéis en hacerme llegar vuestras propuestas!

Code.gs
function onOpen()
{
  SpreadsheetApp.getUi().createMenu("SCRIPT")
          .addItem("CheckSize","CheckSize")
          .addToUi();
}

function AskForList()
{
  var spreadsheet = SpreadsheetApp.getActiveSpreadsheet();
  var sheeturl = spreadsheet.getActiveSheet();
  var images   = sheeturl.getRange(1,1,sheeturl.getLastRow(), 1 ).getValues();

  var elements = new Array();
  for(var i = 1 ; i < images.length ; ++i)
  {
      var url = images[i][0];
      var element = new Object();
      element.url    = url;
      elements.push(element);
  }
  return elements;
}

function ReportSizes(sizes)
{
   var spreadsheet = SpreadsheetApp.getActiveSpreadsheet();
   var sheet = spreadsheet.getActiveSheet();
   for(var i = 0 ; i < sizes.length ; ++i)
   {
     var size = sizes[i];
     sheet.getRange(i+2,2).setValue(size.Height);
     sheet.getRange(i+2,3).setValue(size.Width);
   }
}

function CheckSize()
{
  var html = HtmlService.createHtmlOutputFromFile('index').setWidth(100).setHeight(100);
  SpreadsheetApp.getUi().showModalDialog(html,"Image Size");
}

index.html
<!DOCTYPE html>
<html>
  <head>
    <base target="_top">
    <script>
      function getSize(url)
      {   
        var img = new Image();
        img.addEventListener("load", function()
            {
               var url = this.currentSrc;
               var width  = this.naturalWidth;
               var height = this.naturalHeight; 
               sessionStorage[url+"_width"] = width;
               sessionStorage[url+"_height"]= height;
            });
        img.src = url;
      }
      
      function ReciveDone()
      {
        document.getElementById("button").innerHTML = "<a> PROCESS END </a>";
      }

      function ReciveWaiting(list)
      {
         var errors = new Array();
         
         for(var i = 0 ; i < list.length ; ++i )
         {
            var element = list[i];
            var width  = sessionStorage[element.url+"_width"];
            var height = sessionStorage[element.url+"_height"];
            list[i].Height = height;
            list[i].Width  = width;
         }

         google.script.run.withSuccessHandler(ReciveDone).ReportSizes(list);
      }

      function ReciveList(list)
      {
         sessionStorage.clear();
         for(var i = 0 ; i < list.length ; ++i )
         {
            var element = list[i];
            getSize(element.url);
         }
         google.script.run.withSuccessHandler(ReciveWaiting).AskForList();
      }

      function AskForList()
      {
         document.getElementById("button").innerHTML = "";
         google.script.run.withSuccessHandler(ReciveList).AskForList();
      }
    </script>
  </head>
  <body>
     <div id="button">
        <input type="button" onclick="AskForList()" value="PROCEED">  
     </div>
  </body>
</html>

Cómo poner un popup en un spreadsheet con Google Apps Script


 Hay ocasiones en que nos puede resultar interesante poner un popup en un spreadsheet. Ya sea para mostrar información, para pedirle información al usuario o para permitir mostrar una pequeña web en el spreadsheet, los popups de Google Apps Script pueden ser de gran utilidad.

La forma de poder hacer popups con Google Apps Script se basa en cargar una web en un contexto modal y mostrarlo. Parece complicado pero realmente, es algo trivial.

Lo primero que necesitaremos es un html que es el que mostraremos en nuestro popup dentro del spreadsheet, aquí os dejo un ejemplo, pero en principio podríais poner cualquier web hecha en HTML5 que quisierais:

<!DOCTYPE html>
<html>
  <head>
    <base target="_top">
  </head>
  <body>
     <h1>Ejemplo de web en popup<h1>
      <select>
        <option value="1">Opcion 1</option>
        <option value="2">Opcion B</option>
        <option value="3">Tegucigalpa</option>
      </select>
  </body>
</html>

Esta web se comporta exactamente igual que una web que podamos servir directamente desde un spreadsheet, así que nos permitirá hacer cosas como comunicar desde JavaScript con el Google Apps Script del servidor. Con esto, está claro que la potencia del sistema es extrema.

Como serviremos este html en un popup del spreadsheet con Google Apps Script? Fácil, vamos a usar la función showModalDialog para servir la web que queramos como un popup del tamaño que queramos.

function onOpen()
{
  SpreadsheetApp.getUi().createMenu("SCRIPT")
          .addItem("ShowPopup","ShowPopup")
          .addToUi();
}

function ShowPopup()
{
  var html = HtmlService.createHtmlOutputFromFile('index').setWidth(300).setHeight(300);
  SpreadsheetApp.getUi().showModalDialog(html,"Ejemplo de popup");
}

Si copiáis estos ficheros en vuestro proyecto y ejecutáis veréis algo de este estilo:

Ejemplo de popup


Como ya os habréis imaginado esto da una funcionalidad adicional a nuestros spreadsheets realmente brutal. Nos permite crear con HTML5 interficies de usuario profesionales ya sea para mostrar información o pedirla.

Bajo mi forma de ver, es una de las características más potentes de Google Apps Script, es un tema que no tiene límites ni fin.

Espero que te haya servido, y recuerda, no vaciles en hacerme llegar tus dudas

Nos vemos




Como crear una biblioteca con Google Apps Script

Seguramente habrás oído hablar de las bibliotecas de Google Apps Script y te preguntarás si es algo que te puede servir en tus proyectos. Una biblioteca de Google Apps Script no es más que un proyecto al que le damos acceso al código desde otro proyectos. 

Para verlo claro, nada más sencillo que un ejemplo.

Abriremos un proyecto de código dentro de un spreadsheet (como hacemos en el resto de proyectos) y escribiremos una función que haga algo concreto, en mi caso he hecho una función muy sencilla que se encarga de sumar vectores:

/**
 * Función que se encarga de sumar vectores. No controla tamaños.
 * @param a Primer vector a sumar
 * @param b Segundo vector a sumar
 * @return Suma de los vectores a y b
 */
function VectorSum(a,b) 
{
  var c = new Array();

  for(var i = 0 ; i < a.length ; ++i)
  {
     c.push( a[i]+b[i] );
  }
  return c;
}

Una vez tengamos hecho este código vamos a publicarlo como librería.

Le vamos a a dar a Implementar > Nueva Implementación

Y seleccionaremos que la nueva implementación es una biblioteca


Y pondremos una descripción de para que sirve nuestra biblioteca.

Con ello conseguiremos una ruta de acceso a la biblioteca que es lo que usaremos para distribuirla y usarla en nuestros proyectos.

Para "instalar" la libreria en nuestro proyecto solo debemos crear un nuevo proyecto de código y darle al botón de la izquierda de + Bibliotecas.


Aquí veréis que una vez detecte el id de nuestra librería nos permitirá seleccionar la versión que tendremos que usar y (muy importante) el nombre que usaremos para el workspace, el identificador.

Todas las funciones de la biblioteca se llamarán a través de ese identificador. Una vez hemos "instalado" la librería en el nuevo proyecto podemos llamar a la función de la librería usando el nombre del workspace de esta manera:

function TestSum()
{
   var a = [1.0,2.0,3.0];  
   var b = [3.0,4.0,5.0];
   var c = MathLib.VectorSum(a,b);
   Logger.log(c);
}

Como podéis ver es una funcionalidad muy potente que nos permite organizar y limpiar el código, poderlo distribuir de una forma sencilla y tener un control bastante mayor sobre nuestras implementaciones.

Espero que os haya servido, no vacileis en hacerme llegar vuestras dudas.

Nos vemos!


Tal vez te interese