Hace un tiempito que estoy jugando con el API de blogger para hacer posts automaticamente. Lo que me parece más complicado es autenticarse vía oauth2 desde una aplicación de línea de comando. Por eso hice un módulo de sandro que lo hace por mi, pidiendo el código de autorización solo cuando es necesario
Se puede usar como módulo de sandro así:
define({
accessToken: './accessToken'
},
function(m) {
var accessToken = m.accessToken(
'refresh_token_fname.txt',
{
clientId: 'CLIENT ID HERE',
clientSecret: 'CLIENT SECRET HERE'
}
)
// Use accessToken here!
})
Abajo les dejo accessToken.js completo (cuidado, son 134 líneas de código):
define({
javaPackages: "javaPackages",
ary: "sandro/nadaMas/array",
json: "sandro/nadaMas/json",
object: "sandro/nadaMas/object"
}, function(m) {
var URL = m.javaPackages.java.net.URL
var String = m.javaPackages.java.lang.String
var URLEncoder = m.javaPackages.java.net.URLEncoder
var StandardCharsets = m.javaPackages.java.nio.charset.StandardCharsets
var InputStreamReader = m.javaPackages.java.io.InputStreamReader
var BufferedReader = m.javaPackages.java.io.BufferedReader
var Scanner = m.javaPackages.java.util.Scanner
var System = m.javaPackages.java.lang.System
var File = java.io.File
var FileOutputStream = java.io.FileOutputStream
var OutputStreamWriter = java.io.OutputStreamWriter
var out = System.out
var in_ = new Scanner(System["in"])
var paramBytes = function(p) {
var s = new String( Object.keys(p).map(function(k) {
return "" + URLEncoder.encode(k, "UTF-8") + "=" + URLEncoder.encode(p[k])
}).join("&") )
return s.getBytes(StandardCharsets.UTF_8)
}
var postJsonResult = function(url, params) {
var parameters = paramBytes(params)
var c = new URL(url).openConnection()
try {
c.requestMethod = "POST"
c.doOutput = true
c.fixedLengthStreamingMode = parameters.length
c.setRequestProperty("Content-Type", "application/x-www-form-urlencoded; charset=UTF-8")
c.connect()
c.outputStream.write(parameters)
if (200 != c.responseCode) {
return null
}
var response = ""
var reader = new BufferedReader( new InputStreamReader( c.inputStream ) )
while( true ) {
var buff = reader.readLine()
if (buff == null) {
break
}
response += buff
}
return m.json.parse( "" + response )
} finally {
c.disconnect()
}
}
var authCode2refreshToken = function(authCode, credentials) {
var rv = postJsonResult(
"https://www.googleapis.com/oauth2/v4/token", {
code: authCode,
redirect_uri: "urn:ietf:wg:oauth:2.0:oob",
client_id: credentials.clientId,
client_secret: credentials.clientSecret,
grant_type: "authorization_code"
}
)
return rv ? rv["refresh_token"] : null
}
var refreshAccessToken = function(refreshToken, credentials) {
var rv = postJsonResult(
"https://www.googleapis.com/oauth2/v4/token", {
refresh_token: refreshToken,
client_id: credentials.clientId,
client_secret: credentials.clientSecret,
grant_type: "refresh_token"
}
)
return rv ? rv["access_token"] : null
}
var readFileLine = function(fname) {
var sc = new Scanner(new File(fname))
try {
return sc.nextLine()
} finally {
sc.close()
}
}
var writeFileLine = function(fname, line) {
try {
var w = new OutputStreamWriter( new FileOutputStream(fname) )
line = "" + line
w.write(line, 0, line.length)
} finally {
w.close()
}
}
var obtainAccessToken = function(refreshTokenFname, credentials) {
var accessToken = null
var refreshToken = null
try {
refreshToken = readFileLine(refreshTokenFname)
} catch (e) {
// ignore
}
while (true) {
if (refreshToken) {
accessToken = refreshAccessToken(refreshToken, credentials)
}
if (accessToken) {
return accessToken
}
var authorizationUrl =
"https://accounts.google.com/o/oauth2/auth?scope=https://www.googleapis.com/auth/blogger&redirect_uri=urn:ietf:wg:oauth:2.0:oob&response_type=code&client_id=" +
credentials.clientId
out.println("Anda a este URL, completa la autorizacion y pega el codigo de autorizacion aca. Despues presiona ENTER")
out.println(authorizationUrl)
var authCode = in_.nextLine()
refreshToken = authCode2refreshToken(authCode, credentials)
writeFileLine(refreshTokenFname, refreshToken)
}
}
return obtainAccessToken
})
Si quieren, es bastante fácil transliterarlo a código Java.
Espero que les sirva,
Aureliano.
2016-01-30
Obteniendo el access token
Sigo en mi cruzada para hacer cosas automáticamente en blogger usando sandro. En este caso, hice el código para obtener un access token a partir de un authorization code. Para eso, primero necesitás registrar una aplicación de línea de comando. Una vez que lo hayas hecho, vas a tener el client id y el client secret. Pero eso no alcanza, para obtener el access token, como el que usamos en el post anterior, hace falta un authorization code. Para obtenerlo, conectate a este URL:
https://accounts.google.com/o/oauth2/auth?scope=https://www.googleapis.com/auth/blogger&redirect_uri=urn:ietf:wg:oauth:2.0:oob&response_type=code&client_id=ACA_VA_TU_CLIENT_ID
Y te va a mostrar el authorization code después de loguearte a google y autorizar a tu aplicación a hacer cosas de blogger en tu nombre.
Una vez que obtuviste tu authorization code, hay que obtener un access token. El access token te sirve para manipular blogger con tu usuario por la próxima hora. Para renovarlo, hay que usar un refresh token, que también obtendremos, pero voy a mostrar cómo usarlo en otro post.
Acá abajo dejo el código de ejemplo para obtener estos tokens.
define({
javaPackages: "javaPackages",
ary: "sandro/nadaMas/array",
json: "sandro/nadaMas/json",
object: "sandro/nadaMas/object"
}, function(m) {
var URL = m.javaPackages.java.net.URL
var out = m.javaPackages.java.lang.System.out
var String = m.javaPackages.java.lang.String
var URLEncoder = m.javaPackages.java.net.URLEncoder
var StandardCharsets = m.javaPackages.java.nio.charset.StandardCharsets
var InputStreamReader = m.javaPackages.java.io.InputStreamReader
var BufferedReader = m.javaPackages.java.io.BufferedReader
var tokenUrl = new URL("https://www.googleapis.com/oauth2/v3/token")
var paramBytes = function(p) {
var s = Object.keys(p).map(function(k) {
return "" + URLEncoder.encode(k, "UTF-8") + "=" + URLEncoder.encode(p[k])
}).join("&")
out.println(s)
s = new String(s)
return s.getBytes(StandardCharsets.UTF_8)
}
return function(code, client_id, client_secret) {
var parameters = paramBytes({
code: code,
redirect_uri: "urn:ietf:wg:oauth:2.0:oob",
client_id: client_id,
client_secret: client_secret,
grant_type: "authorization_code"
})
var c = tokenUrl.openConnection()
c.requestMethod = "POST"
c.doOutput = true
c.fixedLengthStreamingMode = parameters.length
c.setRequestProperty("Content-Type", "application/x-www-form-urlencoded; charset=UTF-8")
c.connect()
c.outputStream.write(parameters)
var response = ""
var reader = new BufferedReader( new InputStreamReader( c.inputStream ) )
while( true ) {
var buff = reader.readLine()
if (buff == null) {
break
}
response += buff
}
var jsonResponse = m.json.parse( "" + response )
out.println("Tokens: " + m.json.stringify(jsonResponse))
}
})
No uso la google-client-api de java porque es un quilombo y no entendí cómo usarla, así que me conecto a los webservices de google directamente.
https://accounts.google.com/o/oauth2/auth?scope=https://www.googleapis.com/auth/blogger&redirect_uri=urn:ietf:wg:oauth:2.0:oob&response_type=code&client_id=ACA_VA_TU_CLIENT_ID
Y te va a mostrar el authorization code después de loguearte a google y autorizar a tu aplicación a hacer cosas de blogger en tu nombre.
Una vez que obtuviste tu authorization code, hay que obtener un access token. El access token te sirve para manipular blogger con tu usuario por la próxima hora. Para renovarlo, hay que usar un refresh token, que también obtendremos, pero voy a mostrar cómo usarlo en otro post.
Acá abajo dejo el código de ejemplo para obtener estos tokens.
define({
javaPackages: "javaPackages",
ary: "sandro/nadaMas/array",
json: "sandro/nadaMas/json",
object: "sandro/nadaMas/object"
}, function(m) {
var URL = m.javaPackages.java.net.URL
var out = m.javaPackages.java.lang.System.out
var String = m.javaPackages.java.lang.String
var URLEncoder = m.javaPackages.java.net.URLEncoder
var StandardCharsets = m.javaPackages.java.nio.charset.StandardCharsets
var InputStreamReader = m.javaPackages.java.io.InputStreamReader
var BufferedReader = m.javaPackages.java.io.BufferedReader
var tokenUrl = new URL("https://www.googleapis.com/oauth2/v3/token")
var paramBytes = function(p) {
var s = Object.keys(p).map(function(k) {
return "" + URLEncoder.encode(k, "UTF-8") + "=" + URLEncoder.encode(p[k])
}).join("&")
out.println(s)
s = new String(s)
return s.getBytes(StandardCharsets.UTF_8)
}
return function(code, client_id, client_secret) {
var parameters = paramBytes({
code: code,
redirect_uri: "urn:ietf:wg:oauth:2.0:oob",
client_id: client_id,
client_secret: client_secret,
grant_type: "authorization_code"
})
var c = tokenUrl.openConnection()
c.requestMethod = "POST"
c.doOutput = true
c.fixedLengthStreamingMode = parameters.length
c.setRequestProperty("Content-Type", "application/x-www-form-urlencoded; charset=UTF-8")
c.connect()
c.outputStream.write(parameters)
var response = ""
var reader = new BufferedReader( new InputStreamReader( c.inputStream ) )
while( true ) {
var buff = reader.readLine()
if (buff == null) {
break
}
response += buff
}
var jsonResponse = m.json.parse( "" + response )
out.println("Tokens: " + m.json.stringify(jsonResponse))
}
})
No uso la google-client-api de java porque es un quilombo y no entendí cómo usarla, así que me conecto a los webservices de google directamente.
2016-01-24
Accediendo al API de blogger desde sandro
Hoy estuve jugando con el API de blogger desde un script que hice usando sandro. Como puedo usar las APIs de java desde el código JavaScript que implementa los módulos de Sandro, decidí usar la biblioteca que google provee para Java.
Lo que más me costó fue toda la parte de oauth2. Como estoy solo probando, no quise armar todo un webserver para hacer todo el camino de oauth. En vez de eso, usé el oauth playground para obtener un access-token y programé desde ahí.
Con todo esto, y afanando bastante de acá hice un scriptcito que obtiene algunos datos de este blog.
define({
javaPackages : "javaPackages",
ary : "sandro/nadaMas/array"
}, function(m) {
var Blogger = m.javaPackages.com.google.api.services.blogger.Blogger
var NetHttpTransport = m.javaPackages.com.google.api.client.http.javanet.NetHttpTransport
var JacksonFactory = com.google.api.client.json.jackson2.JacksonFactory
var GoogleCredential = com.google.api.client.googleapis.auth.oauth2.GoogleCredential
var HTTP_TRANSPORT = new NetHttpTransport();
var JSON_FACTORY = new JacksonFactory();
var CREDENTIAL = GoogleCredential().setAccessToken("HERE GOES THE ACCESS TOKEN")
var buildBlogger = function() {
var bb = new Blogger.Builder(HTTP_TRANSPORT, JSON_FACTORY, CREDENTIAL)
bb.applicationName = "Testing blogger"
return bb.build()
}
return function() {
var out = m.javaPackages.java.lang.System.out
var blogger = buildBlogger()
var action = blogger.blogs().getByUrl("http://aurelianito.blogspot.com")
action.fields = "description,name,posts/totalItems,updated"
var blog = action.execute();
// Now we can navigate the response.
out.println("Name: " + blog.name)
out.println("Description: " + blog.description)
out.println("Post Count: " + blog.posts.totalItems)
out.println("Last Updated: " + blog.updated)
}
})
Si lo corren debería mostrarles algo muy parecido a:
Name: aurelianito
Description: Blog de Aureliano Calvo.
Aureliano Calvo's blog.
Post Count: 318
Last Updated: 2016-01-20T19:49:14.000-03:00
Después tengo que ver cómo hacer para hacer que el flujo del oauth ande bien.
Happy hacking,
Aureliano
Lo que más me costó fue toda la parte de oauth2. Como estoy solo probando, no quise armar todo un webserver para hacer todo el camino de oauth. En vez de eso, usé el oauth playground para obtener un access-token y programé desde ahí.
Con todo esto, y afanando bastante de acá hice un scriptcito que obtiene algunos datos de este blog.
define({
javaPackages : "javaPackages",
ary : "sandro/nadaMas/array"
}, function(m) {
var Blogger = m.javaPackages.com.google.api.services.blogger.Blogger
var NetHttpTransport = m.javaPackages.com.google.api.client.http.javanet.NetHttpTransport
var JacksonFactory = com.google.api.client.json.jackson2.JacksonFactory
var GoogleCredential = com.google.api.client.googleapis.auth.oauth2.GoogleCredential
var HTTP_TRANSPORT = new NetHttpTransport();
var JSON_FACTORY = new JacksonFactory();
var CREDENTIAL = GoogleCredential().setAccessToken("HERE GOES THE ACCESS TOKEN")
var buildBlogger = function() {
var bb = new Blogger.Builder(HTTP_TRANSPORT, JSON_FACTORY, CREDENTIAL)
bb.applicationName = "Testing blogger"
return bb.build()
}
return function() {
var out = m.javaPackages.java.lang.System.out
var blogger = buildBlogger()
var action = blogger.blogs().getByUrl("http://aurelianito.blogspot.com")
action.fields = "description,name,posts/totalItems,updated"
var blog = action.execute();
// Now we can navigate the response.
out.println("Name: " + blog.name)
out.println("Description: " + blog.description)
out.println("Post Count: " + blog.posts.totalItems)
out.println("Last Updated: " + blog.updated)
}
})
Si lo corren debería mostrarles algo muy parecido a:
Name: aurelianito
Description: Blog de Aureliano Calvo.
Aureliano Calvo's blog.
Post Count: 318
Last Updated: 2016-01-20T19:49:14.000-03:00
Después tengo que ver cómo hacer para hacer que el flujo del oauth ande bien.
Happy hacking,
Aureliano