m
xquery version "1.0";
(: -----------------------------------------------------------------------
A simple twitter client. This is the main script which is called from
controller.xql. It retrieves an atom feed from twitter and caches
it in the xmldb. The data is then passed to twitter-view.xql for
formatting and display.
-----------------------------------------------------------------------:)
declare namespace tc="http://exist-db.org/xquery/twitter-client";
declare namespace atom="http://www.w3.org/2005/Atom";
declare namespace html="http://www.w3.org/1999/xhtml";
import module namespace httpclient="http://exist-db.org/xquery/httpclient"
at "java:org.exist.xquery.modules.httpclient.HTTPClientModule";
import module namespace xdb="http://exist-db.org/xquery/xmldb";
(: To access more than just the tweets posted by a single user (e.g. its friends timeline),
you need to authenticate with a valid twitter account. Enter the username/password pair
below. :)
declare variable $tc:login := ( "user", "password" );
declare variable $tc:update-frequency := xs:dayTimeDuration("PT5M");
(: Create the HTTP basic authentication header if user credentials available :)
declare function tc:get-headers($credentials as xs:string*) {
if (empty($credentials)) then
()
else
let $auth := concat('Basic ', util:string-to-binary(concat($credentials[1], ':', $credentials[2])))
return
<headers>
<header name="Authorization" value="{$auth}"/>
</headers>
};
(: Send an HTTP request to twitter to retrieve the timeline in Atom format :)
declare function tc:get-timeline($credentials as xs:string*, $userId as xs:string, $view as xs:string) {
let $uri := xs:anyURI(
concat("http://twitter.com/statuses/", $view, "_timeline/", $userId, ".atom")
)
let $headers := tc:get-headers($credentials)
let $response := httpclient:get($uri, false(), $headers)
return
if ($response/@statusCode eq "200") then
$response/httpclient:body/*
else if ($response/httpclient:body//error) then
$response/httpclient:body//error/string()
else
concat("Twitter reported an error. Code: ", $response/@statusCode)
};
(: Retrieve the timeline and store it into the db :)
declare function tc:update-timeline($credentials as xs:string*, $userId as xs:string, $view as xs:string) {
let $null := xdb:create-collection("/db", "twitter")
let $feed := tc:get-timeline($credentials, $userId, $view)
return
if (empty($feed) or $feed instance of xs:string) then
$feed
else
let $docPath := xdb:store("/db/twitter", concat($userId, "_", $view, ".xml"), $feed)
return
doc($docPath)/atom:feed
};
(: Main function: returns the timeline in atom format. The data is cached within the database
and will be renewed every few minutes. :)
declare function tc:timeline($credentials as xs:string*, $userId as xs:string, $view as xs:string) {
let $feed := doc(concat("/db/twitter/", $userId, "_", $view, ".xml"))/atom:feed
return
if (exists($feed) and
(xs:dateTime($feed/atom:updated) + $tc:update-frequency) > current-dateTime()) then
$feed
else
tc:update-timeline($credentials, $userId, $view)
};
(: This script will just retrieve the feed, then forward it to
twitter-view.xql, using a request attribute. The forwarding is done
through controller.xql :)
let $user := request:get-parameter("user", ())
let $view := request:get-parameter("view", "user")
let $feed :=
if ($user) then
tc:timeline(
if ($tc:login[1] eq 'user') then () else $tc:login,
$user, $view
)
else ()
return
request:set-attribute("twitter.feed", $feed)