Fullmenu null

 

03 December 2017

For this post we need the following requirements: a Google account and created events in the calendar. By default we will use the main calendar (but you could use any other one that Google allows us to create). Likewise to be able to access at the Google APIs we must obtain credentials that authorize the application to access at our account.

In this post we are going to use a GroovyScript to connect at Google calendar by reviewing all the events that are created, grouped according to the day of the week and the "theme" that we have assigned.

A calendar event by itself DOES NOT include any field of the "subject" type, so in order to group them we could use, for example, some identifier in the text. In this example what we are going to use is the ability to assign a color to an event, so that if in our calendar we assign the "red" color to the events of type "leisure", the "blue" color to those of "formation", etc. we can, in a very easy way, group disparate events.

Google Console

First we must create an application in the Google console at https://console.developers.google.com

In this application we will enable (at least) the API "Google Calendar API"

Likewise we must create a "Service" credentials obtaining the possibility of downloading them in a JSON file and that we should locate with the script.

Groogle

To facilitate the authentication and creation technical part of services I have created an open source project, Groogle, available at https://gitlab.com/puravida-software/groogle which publishes an artifact in Bintray and that we can use in our scripts simply including its repository.

@GrabResolver(name='puravida', root="https://dl.bintray.com/puravida-software/repo" )
@Grab(group='org.groovyfx',module='groovyfx',version='8.0.0',transitive=false, noExceptions=true)
@Grab(group = 'com.puravida.groogle', module = 'groogle-core', version = '1.0.0')

import com.puravida.groogle.GroogleScript
import com.google.api.services.calendar.CalendarScopes

Groogle will allow us to make the login of our application and save the authorization on our disk in such a way that in subsequent executions it is not necessary to authorize the application again (as long as we do not delete the file with the generated authorization)

InputStream clientSecret = new File('client_secret.json').newInputStream() //(1)

def groogle = new GroogleScript(applicationName:'101-scripts')  //(2)

groogle.login(clientSecret,[CalendarScopes.CALENDAR_READONLY]) //(3)
  1. client-secret.json is the file that we have downloaded from the Google console and that contains the credentials

  2. Groogle do te login and save the authorization in $ HOME/.credentials/${applicationName}

  3. In this post we only require access to Calendar for reading

Customization

Each one should configure his topics according to his preferences. He/She will also create more or less topics according to the degree of detail that need. For this post we are going to use only 3 themes:

def colors = [
        '0':'Generico',
        '10':'Reuniones',  //(1)
        '11':'Ocio'
]
  1. I have not found how to know the color ID a priori so you should run it first and see which it assigns

Business

The business logic of this script will basically consist in covering all the events that Google returns and for each one of them look in a map if there is a sub-map "subject" and if for this sub-map there is another sub-map for the day of the week where add events. In case it does not exist, we will simply initialize it to zero for start to add in it.

def week = ['D','L','M','X','J','V','S']
def stadistics = [:]

groogle.calendarService.events().list(calendarId).execute().items.each{ event ->   //(1)

    def events = !event.recurrentId ? [event] :  //(2)
            groogle.calendarService.events().instances(calendarId, event.id).execute().items

    events.each{ item ->
        String colorId = item.colorId ?: '0'
        if( !stadistics."${colors[colorId]}"){  //(3)
            stadistics."${colors[colorId]}" =[:]
            (java.util.Calendar.SUNDAY..java.util.Calendar.SATURDAY).each{ day ->
                stadistics."${colors[colorId]}"."${week[day-1]}"= 0
            }
        }
        int day = new Date( (event.start.date ?: event.start.dateTime).value)[java.util.Calendar.DAY_OF_WEEK]
        stadistics."${colors[colorId]}"."${week[day-1]}" +=1 //(4)
    }
}
  1. Track all events returned by Google

  2. An event can be punctual or recurrent. In this case we must obtain all instances of it

  3. Search the map for the theme associated with the event and initialization it if no exist

  4. Increase by one for the day of the week of the event

Views

For the view we will use a link: GroovyFX that shows a bar graph barChart that it allows to visualize the different counters of the days of the week grouped by subject. However this component asks us to provide it the data series in a succession of 'key', 'value', 'key', 'value' instead of a map, so that the first thing we will do is transform our map into a more suitable one:

def flatten =[:]
stadistics.each{
    flatten."$it.key" = it.value.collect{ [it.key,it.value]}.flatten() //(1)
}

And now we can build the view, generating the series in a dynamic way.

start {
    stage(visible:true,width:640,height:480) { //(2)
        scene{
            tilePane() {
                barChart(
                        yAxis:new NumberAxis(label:'Ocupacion', tickLabelRotation:90),
                        xAxis:new CategoryAxis(label:'Actividad'),
                        barGap:3,
                        categoryGap:20) {
                    flatten.each{   //(1)
                        series(name: it.key, data:it.value)
                    }
                }
            }
        }
    }
}
  1. We dynamically create the series based on the themes that we have initially.

My calendar would look like this:

calendar

Script
//tag::dependencies[]
@GrabResolver(name='puravida', root="https://dl.bintray.com/puravida-software/repo" )
@Grab(group='org.groovyfx',module='groovyfx',version='8.0.0',transitive=false, noExceptions=true)
@Grab(group = 'com.puravida.groogle', module = 'groogle-core', version = '1.0.0')

import com.puravida.groogle.GroogleScript
import com.google.api.services.calendar.CalendarScopes
//end::dependencies[]

import static groovyx.javafx.GroovyFX.start
import javafx.scene.chart.CategoryAxis;
import javafx.scene.chart.NumberAxis;
import javafx.application.Platform
import javafx.scene.SnapshotParameters
import javax.imageio.ImageIO
import java.awt.image.BufferedImage
//tag::login[]
InputStream clientSecret = new File('client_secret.json').newInputStream() //(1)

def groogle = new GroogleScript(applicationName:'101-scripts')  //(2)

groogle.login(clientSecret,[CalendarScopes.CALENDAR_READONLY]) //(3)
//end::login[]

String calendarId = 'primary'
/*
Si quieres saber todos tus calendarios simplemente ejecuta esta linea
println groogle.calendarService.calendarList().list().execute().items*.id
*/

//tag::temas[]
def colors = [
        '0':'Generico',
        '10':'Reuniones',  //(1)
        '11':'Ocio'
]
//end::temas[]

//tag::business[]
def week = ['D','L','M','X','J','V','S']
def stadistics = [:]

groogle.calendarService.events().list(calendarId).execute().items.each{ event ->   //(1)

    def events = !event.recurrentId ? [event] :  //(2)
            groogle.calendarService.events().instances(calendarId, event.id).execute().items

    events.each{ item ->
        String colorId = item.colorId ?: '0'
        if( !stadistics."${colors[colorId]}"){  //(3)
            stadistics."${colors[colorId]}" =[:]
            (java.util.Calendar.SUNDAY..java.util.Calendar.SATURDAY).each{ day ->
                stadistics."${colors[colorId]}"."${week[day-1]}"= 0
            }
        }
        int day = new Date( (event.start.date ?: event.start.dateTime).value)[java.util.Calendar.DAY_OF_WEEK]
        stadistics."${colors[colorId]}"."${week[day-1]}" +=1 //(4)
    }
}
//end::business[]

//tag::flatten[]
def flatten =[:]
stadistics.each{
    flatten."$it.key" = it.value.collect{ [it.key,it.value]}.flatten() //(1)
}
//end::flatten[]

//tag::vista[]
start {
    stage(visible:true,width:640,height:480) { //(2)
        scene{
            tilePane() {
                barChart(
                        yAxis:new NumberAxis(label:'Ocupacion', tickLabelRotation:90),
                        xAxis:new CategoryAxis(label:'Actividad'),
                        barGap:3,
                        categoryGap:20) {
                    flatten.each{   //(1)
                        series(name: it.key, data:it.value)
                    }
                }
            }
        }
    }
}
//end::vista[]