Commit c2b3e710 authored by Jorge Aguilera's avatar Jorge Aguilera

opendatamadrid

parent 0d4eb8ad
Pipeline #47870941 passed with stage
in 4 minutes and 40 seconds
......@@ -321,4 +321,4 @@ task contributors{
}.join('\n'))
file('src/jbake/content/about-en.adoc').text = aboutTemplate
}
}
\ No newline at end of file
}
......@@ -44,7 +44,7 @@ void scanDir( File dir ){
}
scanDir(new File("src/jbake/content/"))
files.sort{it.key}.values().flatten().each{ f->
files.values().flatten().each{ f->
println """<<<<
include::../../jbake/content/${f.parentFile.name}/${f.name}[]"""
}
......
......@@ -47,7 +47,7 @@ void scanDir( File dir ){
}
scanDir(new File("src/jbake/content/"))
files.sort{it.key}.values().flatten().each{ f->
files.values().flatten().each{ f->
String text = f.text.split('\n').find{
it.startsWith(":jbake-script:")
} ?: ''
......
......@@ -22,20 +22,14 @@ include::../../jbake/content/index.adoc[]
<<<<
include::../../jbake/content/content/about_template.adoc[]
<<<<
include::../../jbake/content/basico/instalacion.adoc[]
include::../../jbake/content/asciidoctor/catalogo.adoc[]
<<<<
include::../../jbake/content/office/mail.adoc[]
include::../../jbake/content/asciidoctor/commitconf.adoc[]
<<<<
include::../../jbake/content/office/mail_adjunto.adoc[]
include::../../jbake/content/asciidoctor/to_revaljs.adoc[]
<<<<
include::../../jbake/content/basico/basico.adoc[]
<<<<
include::../../jbake/content/file/find_bigger_file.adoc[]
<<<<
include::../../jbake/content/file/read_and_filter.adoc[]
<<<<
include::../../jbake/content/bbdd/count_caidos.adoc[]
<<<<
include::../../jbake/content/basico/clibuilder.adoc[]
<<<<
include::../../jbake/content/basico/command_local.adoc[]
......@@ -44,84 +38,94 @@ include::../../jbake/content/basico/llamada_script_groovy.adoc[]
<<<<
include::../../jbake/content/bbdd/withBatch.adoc[]
<<<<
include::../../jbake/content/file/scan_execute.adoc[]
<<<<
include::../../jbake/content/office/excel_to_table.adoc[]
include::../../jbake/content/basico/config_script.adoc[]
<<<<
include::../../jbake/content/office/table_excel.adoc[]
include::../../jbake/content/basico/dsl_performance.adoc[]
<<<<
include::../../jbake/content/docker/basico.adoc[]
include::../../jbake/content/basico/empaquetar.adoc[]
<<<<
include::../../jbake/content/network/sshoogr_getFile.adoc[]
include::../../jbake/content/basico/htmltable2csv.adoc[]
<<<<
include::../../jbake/content/network/change_properties.adoc[]
include::../../jbake/content/basico/instalacion.adoc[]
<<<<
include::../../jbake/content/docker/image.adoc[]
include::../../jbake/content/basico/listas.adoc[]
<<<<
include::../../jbake/content/javafx/ping_delay.adoc[]
include::../../jbake/content/bbdd/count_caidos.adoc[]
<<<<
include::../../jbake/content/ws/consulta_nif.adoc[]
include::../../jbake/content/bbdd/simple_gorm.adoc[]
<<<<
include::../../jbake/content/office/contacts2qrcode.adoc[]
include::../../jbake/content/docker/basico.adoc[]
<<<<
include::../../jbake/content/office/extractpdf.adoc[]
include::../../jbake/content/docker/chronable.adoc[]
<<<<
include::../../jbake/content/basico/empaquetar.adoc[]
include::../../jbake/content/docker/clean_docker_registry.adoc[]
<<<<
include::../../jbake/content/javafx/tweetsales.adoc[]
include::../../jbake/content/docker/docudocker.adoc[]
<<<<
include::../../jbake/content/basico/listas.adoc[]
include::../../jbake/content/docker/image.adoc[]
<<<<
include::../../jbake/content/office/tweet_report.adoc[]
include::../../jbake/content/file/excel_i18n.adoc[]
<<<<
include::../../jbake/content/google/calendar.adoc[]
include::../../jbake/content/file/find_bigger_file.adoc[]
<<<<
include::../../jbake/content/google/importexport.adoc[]
include::../../jbake/content/file/read_and_filter.adoc[]
<<<<
include::../../jbake/content/asciidoctor/catalogo.adoc[]
include::../../jbake/content/file/maven_inventory.adoc[]
<<<<
include::../../jbake/content/network/grabbit.adoc[]
include::../../jbake/content/file/organize_pictures.adoc[]
<<<<
include::../../jbake/content/file/remove_lines.adoc[]
<<<<
include::../../jbake/content/docker/clean_docker_registry.adoc[]
include::../../jbake/content/file/scan_execute.adoc[]
<<<<
include::../../jbake/content/network/http_builder_ng_get.adoc[]
include::../../jbake/content/google/calendar.adoc[]
<<<<
include::../../jbake/content/javafx/visual_sheet.adoc[]
include::../../jbake/content/google/importexport.adoc[]
<<<<
include::../../jbake/content/javafx/visualize_extension.adoc[]
include::../../jbake/content/google/permisos.adoc[]
<<<<
include::../../jbake/content/google/sheet2calendar.adoc[]
<<<<
include::../../jbake/content/javafx/build_dsl.adoc[]
<<<<
include::../../jbake/content/file/excel_i18n.adoc[]
include::../../jbake/content/google/xml2calendar.adoc[]
<<<<
include::../../jbake/content/docker/docudocker.adoc[]
include::../../jbake/content/gradle/opendatamadrid.adoc[]
<<<<
include::../../jbake/content/basico/config_script.adoc[]
include::../../jbake/content/javafx/ping_delay.adoc[]
<<<<
include::../../jbake/content/ws/bitbucket_ssh.adoc[]
include::../../jbake/content/javafx/tweetsales.adoc[]
<<<<
include::../../jbake/content/docker/chronable.adoc[]
include::../../jbake/content/javafx/visual_sheet.adoc[]
<<<<
include::../../jbake/content/bbdd/simple_gorm.adoc[]
include::../../jbake/content/javafx/visualize_extension.adoc[]
<<<<
include::../../jbake/content/network/change_properties.adoc[]
<<<<
include::../../jbake/content/network/grabbit.adoc[]
<<<<
include::../../jbake/content/network/http_builder_ng_get.adoc[]
<<<<
include::../../jbake/content/network/server-in-a-file.adoc[]
<<<<
include::../../jbake/content/asciidoctor/to_revaljs.adoc[]
include::../../jbake/content/network/sshoogr_getFile.adoc[]
<<<<
include::../../jbake/content/google/xml2calendar.adoc[]
include::../../jbake/content/office/contacts2qrcode.adoc[]
<<<<
include::../../jbake/content/basico/htmltable2csv.adoc[]
include::../../jbake/content/office/extractpdf.adoc[]
<<<<
include::../../jbake/content/file/organize_pictures.adoc[]
include::../../jbake/content/office/excel_to_table.adoc[]
<<<<
include::../../jbake/content/asciidoctor/commitconf.adoc[]
include::../../jbake/content/office/table_excel.adoc[]
<<<<
include::../../jbake/content/basico/dsl_performance.adoc[]
include::../../jbake/content/office/mail.adoc[]
<<<<
include::../../jbake/content/google/permisos.adoc[]
include::../../jbake/content/office/mail_adjunto.adoc[]
<<<<
include::../../jbake/content/office/memoized_tae.adoc[]
<<<<
include::../../jbake/content/office/tweet_report.adoc[]
<<<<
include::../../jbake/content/ws/bitbucket_ssh.adoc[]
<<<<
include::../../jbake/content/ws/consulta_nif.adoc[]
......@@ -115,4 +115,4 @@ options = OptionsBuilder.options().
get()
asciidoctor.convertFile(new File("commit2018.adoc"), options)
//tag::asciidoctor[]
\ No newline at end of file
//end::asciidoctor[]
//tag::dependencies[]
plugins {
id 'com.puravida.gradle.socialnetwork' version '0.1.1'
}
import groovy.json.JsonSlurper
//end::dependencies[]
//tag::parse[]
task eventosBibliotecas(){
def msg = file("$buildDir/telegram.txt")
outputs.files msg
doLast{
def arr = []
def today = Calendar.instance.time
arr.add "-".multiply(10)
arr.add "\n"
arr.add "*Hoy es ${today.format( 'dd/MM/yyyy' )}*"
arr.add "\n"
arr.add "\n"
def json = new JsonSlurper().parseText('https://datos.madrid.es/egob/catalogo/206717-0-agenda-eventos-bibliotecas.json'.toURL().text)
json."@graph".each{ evt->
use(groovy.time.TimeCategory) {
def strstart = Date.parse('yyyy-MM-dd HH:mm:ss',evt.dtstart)
def strend = Date.parse('yyyy-MM-dd HH:mm:ss',evt.dtend)
def duration = strend - today
switch( duration.days ){
case 2:
arr.add "🎟️*${strstart.format( 'dd/MM/yyyy' )} al ${strend.format( 'dd/MM/yyyy' )}*"
arr.add "Dentro de *${duration.days}* días en ${evt.'event-location'}"
arr.add "$evt.title"
arr.add "\n"
}
}
}
if( arr.size() )
msg.text = arr.join('\n')
}
}
//end::parse[]
//tag::telegram[]
telegram{
credentials {
token project.findProperty('telegram_token')
channel project.findProperty('telegram_channel')
}
message file('build/telegram.txt')
sendAsMarkdown
}
telegram.onlyIf{
file("$buildDir/telegram.txt").exists()
}
telegram.dependsOn eventosBibliotecas
//end::telegram[]
build.dependsOn telegram
\ No newline at end of file
= OpenDataMadrid
Jorge Aguilera <jorge.aguilera@puravida-software.com>
2018-2-17
ifndef::backend-pdf[]
:username: jorge-aguilera
:jbake-type: post
:jbake-status: published
:jbake-tags: blog, gradle
:jbake-category: gradle
:jbake-script: /scripts/gradle/OpenDataMadrid.gradle
:idprefix:
:imagesdir: ../images
:jbake-english: opendatamadrid-en
endif::[]
:icons: font
NOTE: En este post vamos a utilizar Gradle como entorno de ejecución de nuestro script, en lugar del propio Groovy, y su
ecosistema de plugins, para consumir una URL con datos abiertos sobre la ciudad de Madrid y enviar una notificación
diaria a un canal de Telegram con un resumen de los próximos eventos que van a ocurrir en la ciudad
{set:icons!:}
[quote, Wikipedia, https://es.wikipedia.org/wiki/Gradle]
____
Gradle es un sistema de automatización de construcción de código abierto que construye sobre los conceptos de
Apache Ant y Apache Maven e introduce un lenguaje especifico del dominio (DSL) basado en Groovy
en vez de la forma XML utilizada por Apache Maven para declarar la configuración de proyecto.
____
== Preparación
En primer lugar deberemos preparar nuestro entorno de desarrollo con Gradle. Para ello disponemos de varios métodos:
- descargarlo, descomprimirlo y ajustar las variables de entorno indicadas
- usar *sdkman* e instalarlo con `sdkman install gradle`
- descargar este proyecto semilla https://gitlab.com/groovy-lang/gradle-seed y trabajar sobre él
Con los dos primeros métodos deberemos ejecutar en el directorio donde queramos trabajar el comando `gradle init` para
que nos cree los ficheros necesarios. Si optamos por clonar el repo indicado en el tercer método esto ya se ha hecho
y simplemente deberemos trabajar sobre el directorio donde hayamos descargado el repo
== Scripts vs Task
Gradle es una herramienta para automatizar la construcción de artefactos basada en el concepto de `task`, los cuales
los podemos ver como pequeños scripts, y que nos permite definir dependencias entre ellas. Así mismo proporciona
en su DSL la capacidad de definir dependencias a los típicos artefactos externos (librerías) para incluir en la ejecución
del build.
De esta forma podemos usar Gradle como un entorno donde utilizar multitud de librerías existentes y mediante scripts
interaccionar con el sistema no sólo para construir artefactos sino para ejecutar acciones variopintas como apagar
un servidor, enviar un correo electrónico con el contenido de un fichero, etc
== OpenDataMadrid
La ciudad de Madrid, España, cuenta con un amplio catálogo de datos abiertos fácilmente accesible vía `http` en diferentes
formatos como pueden ser `xml`, `json`, `excel` e incluso un API REST (https://datos.madrid.es/portal/site/egob)
En este post vamos a ver cómo interpretar el catálogo de actividades programadas de las bibliotecas que se encuentran
en la url https://datos.madrid.es/egob/catalogo/206717-0-agenda-eventos-bibliotecas.json
Si inspeccionamos este recurso veremos que las actividades están organizadas en un elemento `@graph` y cada uno de ellas
indica la fecha de inicio y de fín así como el título, lugar, entre otros:
[source,json]
----
"@graph": [
{
"@id": "https://datos.madrid.es/egob/catalogo/tipo/evento/10847853-bestia-volvoreta.json",
"@type": "https://datos.madrid.es/egob/kos/actividades/CuentacuentosTiteresMarionetas",
"id": "10847853",
"title": "A lo bestia con Volvoreta",
"description": "El miedo, como el amor, es un sentimiento inherente al ser humano, y los cuentos consiguen ponerles cara y ojos a todas esas angustias que nos configuran. Ayudándonos a exorcizar todas las inquietudes que durante una narración en grupo se comparten y en el mejor de los casos, se superan. Por eso, esta sesión es un homenaje a algunos cuentos que ya son clásicos, pero también a aquellas historias que acaban de nacer porque para no tener pesadillas por la noche, nada como soñar despierto durante una hora de cuentos. A partir de 4 años.",
"price": 1,
"dtstart": "2019-04-11 18:00:00.0",
"dtend": "2019-04-11 23:59:00.0",
"excluded-days": "",
"audience": "Niños,Familias",
"uid": "10847853",
"link": "http://www.madrid.es/sites/v/index.jsp?vgnextchannel=ca9671ee4a9eb410VgnVCM100000171f5a0aRCRD&vgnextoid=3762de882dba7610VgnVCM2000001f4a900aRCRD",
"event-location": "Biblioteca Pública Municipal Aluche (Latina)",
"references": {
"@id": "http://www.madrid.es/sites/v/index.jsp?vgnextchannel=ca9671ee4a9eb410VgnVCM100000171f5a0aRCRD&vgnextoid=4224a209a1c71510VgnVCM2000000c205a0aRCRD"
},
"relation": {
"@id": "https://datos.madrid.es/egob/catalogo/tipo/entidadesyorganismos/1757-biblioteca-publica-municipal-aluche-latina-.json"
},
"address": {
"district": {
"@id": "https://datos.madrid.es/egob/kos/Provincia/Madrid/Municipio/Madrid/Distrito/Latina"
}
},
"location": {
"latitude": 40.39597072367931,
"longitude": -3.7562716852987847
}
},
----
La idea de nuestro script es parsear este JSON cada día y buscar qué actividades se van a realizar a dos (2) días vista
y enviar un mensaje a un canal de Telegram con un resumen de las mismas (en caso de que haya actividades)
:icons: font
NOTE: Para el envío de Telegram usaremos un plugin de Gradle que nos permite enviar a diferentes redes sociales
como Twitter, Telegram o Slack, (https://puravida-gradle.gitlab.io/social-network/)
lo cual nos servirá para demostrar la potencia de Gradle.
{set:icons!:}
== Dependencias
Mientras que en un típico script usabamos `@Grab` para resolver las dependencias, con `Gradle` usaremos su DSL `buildSrc`
Así mismo `Gradle` nos permite añadir otro tipo de dependencias no existentes con `@Grab` como son los plugins. Básicamente
son artefactos orientados a implementar tareas que se pueden integrar en nuestro build tanto para ser ejecutadas
directamente como para extenderlas. *En nuestro caso vamos a utilizar el plugin social-network y su tarea telegram*
[source,groovy]
----
include::{sourcedir}{jbake-script}[tag=dependencies]
----
== Parse
Nuestra tarea de parseo va a ser una tarea básica que no extiende de ninguna previa y que va a generar, en caso de
que haya eventos, un fichero `build/telegram.txt` con el texto a enviar en formato Markdown.
Utilizando la sintáxis de Gradle, nuestro script se ejecutará dentro de la closure `doLast` , en la cual descargamos
el JSON y recorremos los elementos comentados anteriormente. Para cada elemento de interés iremos añadiendo a un
array las líneas que queremos volcar al fichero (nótese que podíamos ir escribiendo directamente en el fichero,
simplemente estamos mostrando otras formas de actualizar un fichero de texto).
[source,groovy]
----
include::{sourcedir}{jbake-script}[tag=parse]
----
== Telegram
Como hemos comentado usaremos un plugin de Gradle para el envío a un canal de Telegram al cual sólo le tenemos
que configurar con las credenciales necesarias así como el id del canal al que enviar el mensaje, mediante
las propiedades `telegram_token` y `telegram_channel` (consultar documentación del plugin)
Como _bola extra_ podemos ver las funcionalidades de Gradle para hacer depender unas tareas de otras (telegram de parse
en nuestro caso), así como decidir si una tarea debe ser ejecutada o no en función de las condiciones que necesitemos
[source,groovy]
----
include::{sourcedir}{jbake-script}[tag=telegram]
----
== Ejecución manual (y programada)
Para ejecutar nuestro "script/tarea" simplemente ejecutaremos desde el directorio principal del proyecto:
[source,console]
----
./gradlew -b OpenDataMadrid.gradle build
----
o si usamos windows
[source,console]
----
gradlew.bat -b OpenDataMadrid.gradle build
----
......@@ -12,6 +12,7 @@
javafx:[title:'JavaFX',desc:'Capturar imagen, generar graficos'],
google:[title:'Google',desc:'Sheet, Drive, Calendar'],
asciidoctor:[title:'Documentar',desc:'Groovy y Asciidoctor'],
gradle:[title:'Gradle',desc:'Scripts vs Tasks'],
]
%>
<%include "menu.gsp"%>
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment