jueves, 27 de mayo de 2021

Saltar errores y continuar con el código

Estoy haciendo código para conseguir quitar todos los permisos a un correo concreto en todos los archivos y subcarpetas de una carpeta dada. 

Para conseguir quitar permisos el código necesita una dirección de correo  tal que así: 

archivo.removeEditor(email)

Metiendo esta orden en un bucle que recorra todos los archivos nos permite conseguir nuestro objetivo.

Pero, a veces, resulta que no encuentra dicho correo y el código da error y NO SIGUE ADELANTE, se para.

Un truco para saltar por encima es utilizar este tratamiento de errores de Javascript:

try{archivo.removeEditor(email)} 

catch(e){}


Gracias a envolver nuestro código en try{} y añadir después catch(e){} logramos que el error no nos pare.

Entre las llaves de la segunda parte catch(e){}, podemos poner código que solamente corra cuando se da el error.



jueves, 4 de marzo de 2021

Recorrer carpetas y documentos en DRIVE

Este artículo tiene como objetivo mostrar el código básico para trabajar con Drive, es decir, para recorrer todos los archivos y subcarpetas de drive.

 

Ultimamente he estado trabajando con los permisos que damos a carpetas y documentos drive. 

Nuestra recomendaciones son:

  • No utilizar permisos en carpetas (la herencia es difícil de controlar)
  • No utilizar permisos globales, salvo que haya una razón importante
  • Utilizar google groups para gestionar los permisos

 

Debido a estas recomendaciones, ha habido centros que se han encontrado con la tarea de cambiar un montón de permisos anteriores, como por ejemplo: infinidad de carpetas, subcarpetas y documentos que tienen permiso de "cualquiera de educación con el enlace". Otro ejemplo es tener infinidad de permisos en documentos obsoletos a los que queremos hacer desaparecer, sin tener que meter horas yendo documento por documento y persona por persona quitando estos permisos.

Gracias al código, todas estas necesidades se pueden hacer de forma automática, simplemente dando la dirección de una carpeta y el código se ocupa de limpiar de permisos todo lo que contenga dicha carpeta.

He hecho diferentes funciones, según el objetivo a conseguir, pero en todas se ha repetido el proceso básico de ir recorriendo todos los documentos y subcarpetas incluidas en una carpeta dada. Por eso, me parece interesante hacer una especie de código básico que controle este proceso y, que con diferentes variantes, nos permita hacer infinidad de cosas con drive.

 

Lo vamos a hacer en tres funciones entrelazadas: función inicial, función para archivos y función para subcarpetas. La unión es la siguiente:

Empezamos con la función inicial y de ahí llamamos a la función de los archivos. Desde archivos llamamos a la función de subcarpetas. En esta última, en la función subcarpetas volvemos a llamar a la función archivos (que vuelve a llamar a subcarpetas, que vuelve a llamar a archivos..... hasta que no hay más)

Este recorrido es fundamental para poder recorrer todos los archivos y subcarpetas que haya dentro de una carpeta.

 

Dentro de cada función estas son las líneas básicas:

 

Inicio:

 // Conseguimos la carpeta principal

 var carpeta_global =DriveApp.getFolderById(id_general)

// Llamamos a la función archivos

archivos(carpeta_global)

Archivos:

 // Conseguimos todos los archivos de la carpeta

  var archivos_global = carpeta_global.getFiles() 

// Los recorremos todos con un bucle

  while (archivos_global.hasNext()){

// Apuntamos a cada archivo (dentro del bucle)

var archivo= archivos_global.next();

// Con cada archivo podemos hacer lo que necesitemos, por ejemplo, 

archivo. setSharing(DriveApp.Access.PRIVATE, DriveApp.Permission.NONE) //quitamos todos los permisos globales

}

// Una vez terminado con todos los archivos de esta carpeta llamamos a la función  de subcarpetas, fuera del bucle

   subcarpeta(carpeta_global)

Subcarpetas: 

// Conseguimos todas las subcarpetas que haya dentro

  var sub_carpetas = carpeta_global.getFolders()
// Hacemos el bucle para recorrerlas
     while (sub_carpetas.hasNext()) {

// Apuntamos a cada una de ellas
       var subcarpeta = sub_carpetas.next()

// Con cada subcarpeta podemos hacer muchas cosas, por ejemplo,

subcarpeta.removeEditor(correo) // Eliminamos un editor concreto

 // y dentro del bucle llamamos a la función archivos, PERO, pasando cada subcarpeta, en vez de la carpeta_global

archivos(subcarpeta)

lunes, 4 de enero de 2021

Conseguir fecha legible

En otros artículos anteriores ya he hablado de las fechas y como tratarlas, pero siempre buscando trucos para conseguirlo.

Ahora os traigo, lo que espero que sea, la solución definitiva. Además con alternativas para diferentes idiomas:

Euskaraz egitean, deklinazio arazo txiki bat dugu. Hortaz, bide luzetxoa egin behar dugu:

  var marca_temporal_mes = marca_temporal.toLocaleString('eu-ES',{month:'long'})
  var marca_temporal_ano= marca_temporal.toLocaleString('eu-ES',{year: 'numeric'})
  var marca_temporal_dia= marca_temporal.toLocaleString('eu-ES',{day:'2-digit'})
  Logger.log(marca_temporal_ano+'(e)ko '+marca_temporal_mes+'ren '+marca_temporal_dia)

En  castellano, nos basta con definir cada parte de la fecha en una única orden:

  var mi_marca =marca_temporal.toLocaleString('es-ES',{year: 'numeric',month:'long',day:'2-digit'})
  Logger.log(mi_marca)

En inglés americano, igual que en castellano, lo hacemos en una sola orden:

var my_time = marca_temporal.toLocaleString('en-US',{year: 'numeric',month:'long',day:'2-digit'})

Logger.log(my_time)

En inglés británico, cambiamos simplemente de 'en-US' a 'en-GB'

var my_time = marca_temporal.toLocaleString('en-GB',{year: 'numeric',month:'long',day:'2-digit'})

Logger.log(my_time)

 Referencia:

 toLocaleString

 Artículos antiguos:

Trabajar con fechas

Problemas con la marca temporal

jueves, 17 de diciembre de 2020

Insertar logo en pestaña (código y proceso extraño)

Estoy haciendo una aplicación para crear actas y necesito que en la pestaña de cada acta aparezca como encabezado el logo del centro.

Quiero, además, que la imagen del logo esté en drive.

Como cada pestaña con cada acta se crea por código, no me vale el menú insertar-imagen-en celda, ya que, que yo sepa, no hay forma de hacerlo desde código.

Pero si puedo utilizar la función "image(url;[]) 

Pero la url que nos da drive de una imagen, utilizando "conseguir enlace" no funciona con esta función. 

Me funciona, sin embargo, la combinación de https://drive.google.com/uc?export=view&id= con el id de cada imagen.

Para hacerle la vida más fácil al usuario, le pido la url de "conseguir enlace" y mediante este trozo de código la convierto al tipo de enlace que he descrito en el anterior párrafo:

  

  var herramienta = SpreadsheetApp.getActiveSpreadsheet()

  var imagen_url = herramienta.getRangeByName('imagen').getValue()
  var imagen_primera_parte = "https://drive.google.com/uc?export=view&id="       
  var imagen_id imagen_url.match(/[-\w]{25,}/)
  var imagen = imagen_primera_parte+imagen_id

pestana.getRange('A1').setValue('=image("'+imagen+'";1)')

 

El código funciona perfectamente: desde la url extrae el id de la imagen y después la añade al enlace especial. Con la última fila del código, insertamos la imagen en la celda A1 con la función image.


Pero, me he encontrado con la SORPRESA que hay veces que la imagen aparece y otras que no.

Después de investigar y probar diferentes situaciones, me he encontrado con que aparece siempre la imagen si utilizamos un proceso muy particular.

 El proceso funciona así:

  1. Debemos subir la imagen desde el ordenador
  2. Debemos darle permiso público a la imagen(cualquiera con el enlace)

Sorprendentemente, no me ha funcionado con imágenes que ya estaban de antemano en mi Drive y, por supuesto, ninguna imagen que no tenga dado el permiso público de antemano.

lunes, 30 de noviembre de 2020

Regexmatch (Comportamiento extraño de la fórmula?!)

¡Cuidado con el orden de los datos en la fórmula!

El resultado no es el mismo

La formula regexmatch la traducimos así:  Resultado de(texto donde se busca; texto a buscar)

 Hay que tener claro  que en la primera parte se define "donde" "dentro de" 

Y en la segunda parte el "que"

Os planteo un caso real en la herramienta de reservas del aula de informática en un centro con horario tanto de mañana como de tarde. Esto es importante ya que las horas a reservar van desde las 8:30 a las 20:30

Vamos a ver si ( 18:30; todas las horas) nos da dos resultados: 8:30 y 18:30

En este busca cada hora del día si cabe en "18:30" y encuentra que tanto 8:30 como 18:30 caben

Pero, al revés, ( todas las horas; 18:30) nos da solamente 18:30

En este caso busca la hora 18:30 si cabe en alguna hora del día y solamente encuentra 18:30

En resumen: 

El orden de los parámetros de la fórmula es al revés de como lo formulamos, primero en donde buscamos y, segundo el qué.


jueves, 1 de octubre de 2020

Conseguir el enlace para poder editar una respuesta de formulario (Más sencillo)

   Para conseguir editar una respuesta mandada por formulario, podemos guardar la url en la hoja de cálculo con este pequeño código

 

 var herramienta = SpreadsheetApp.getActiveSpreadsheet() 

  var pestana_datos = herramienta.getRangeByName('datos').getSheet() // Hemos creado un intervalo con nombre en dicha pestaña, llamado datos, evitamos el problema de cambio de nombre a la pestaña

  var ultima_fila = pestana_datos.getRange('A1').setValue('=filter(row(a2:a);a2:a=max(a2:a))').getValue() // Suponemos que en A está la marca temporal

var url_form = SpreadsheetApp.getActiveSpreadsheet().getFormUrl()
  var respuestas = FormApp.openByUrl(url_form).getResponses()
  var cuantas = respuestas.length
pestana_datos.getRange(ultima_fila, columa_donde_guardar_url).setValue(respuestas[cuantas-1].getEditResponseUrl())

miércoles, 9 de septiembre de 2020

Fórmula para unir contenido de varias columnas en una sola (No código)

 En este artículo NO vamos a hablar de código, pero si de una pequeña fórmula que nos soluciona la vida cuando después de hacer un super-formulario con varias páginas condicionales (por ejemplo, una página por cada grupo de alumnos y una pregunta anterior, condicional que según el grupo que se elija el formulario te manda a una página u otra). 

La ingrata sorpresa, después de todo el trabajo hecho en el diseño del formulario, es que cada contestación se refleja en la hoja de respuestas en una columna diferente. 

Y nosotros queremos que solamente estén los datos en una sola columna.

Bueno, aquí va la solución por medio de una fórmula:

=arrayformula(f2:f&g2:g&h2:h) 

Es decir, nos aparecerá los datos de estas tres columnas en una sola.

Crear PDF horizontal

El código que vamos a mostrar aquí no ha sido creado por nosotros, sino que lo hemos encontrado en Internet. Objetivo: Publicar una pesta...