This commit is contained in:
Andy Bunce 2012-09-23 17:21:48 +01:00
parent 84579b53c7
commit 49904dabed
8 changed files with 341 additions and 33 deletions

View File

@ -7,12 +7,16 @@
module namespace grxq = 'apb.graphviz.web'; module namespace grxq = 'apb.graphviz.web';
declare default function namespace 'apb.graphviz.web'; declare default function namespace 'apb.graphviz.web';
import module namespace gr = 'apb.graphviz' at "lib/graphviz.xqm";
import module namespace dotui = 'apb.graphxq.dotui' at "dotui.xqm"; import module namespace dotui = 'apb.graphxq.dotui' at "dotui.xqm";
import module namespace txq = 'apb.txq' at "lib/txq.xqm"; import module namespace txq = 'apb.txq' at "lib/txq.xqm";
import module namespace gr = 'apb.graphviz' at "lib/graphviz.xqm";
import module namespace oa="http://basex.org/ns/oauth" at "lib/oauth.xqy";
import module namespace config="apb.config" at "lib/config.xqm";
import module namespace request = "http://exquery.org/ns/request"; import module namespace request = "http://exquery.org/ns/request";
declare namespace rest = 'http://exquery.org/ns/restxq'; declare namespace rest = 'http://exquery.org/ns/restxq';
declare variable $grxq:layout:=fn:resolve-uri("views/layout.xml"); declare variable $grxq:layout:=fn:resolve-uri("views/layout.xml");
declare declare
@ -102,6 +106,14 @@ declare
return render("views/library.xml",$map) return render("views/library.xml",$map)
}; };
declare
%rest:GET %rest:path("graphxq/twitter")
%output:method("html5")
function twitter( ) {
let $d:=$config:config
let $map:=map{"data":=fn:serialize($d) }
return render("views/twitter.xml",$map)
};
(:~ use dot or url :) (:~ use dot or url :)
declare %private function getdot($dot,$url) as xs:string{ declare %private function getdot($dot,$url) as xs:string{
@ -131,7 +143,8 @@ declare function render($template,$locals){
"usermenu":=<div>users</div>, "usermenu":=<div>users</div>,
"title":=request:path(), "title":=request:path(),
"messages":=(), "messages":=(),
"libserver":="//cdnjs.cloudflare.com/ajax/libs"} "libserver":=$config:libserver,
"aceserver":=$config:aceserver}
let $locals:=map:new(($default,$locals)) let $locals:=map:new(($default,$locals))
return txq:render(fn:resolve-uri($template),$locals,$grxq:layout) return txq:render(fn:resolve-uri($template),$locals,$grxq:layout)
}; };

View File

@ -0,0 +1,33 @@
(:~
: configuration access
: looks in WEB-INF/site-config.xml for actual values
:
: @author andy bunce
: @since sept 2012
:)
module namespace config = 'apb.config';
declare default function namespace 'apb.config';
declare variable $config:default:=
<config>
<libserver>//cdnjs.cloudflare.com/ajax/libs</libserver>
<aceserver>http://d1n0x3qji82z53.cloudfront.net</aceserver>
<twitter>
<CONSUMER-KEY>CONSUMER-KEY</CONSUMER-KEY>
<CONSUMER-SECRET>CONSUMER-SECRET</CONSUMER-SECRET>
<access-token>your token</access-token>
<access-token-secret>your secret</access-token-secret>
</twitter>
</config>
;
declare variable $config:config:=
fn:doc(fn:resolve-uri("../../WEB-INF/site-config.xml"))/config
;
(:
: /twitter-bootstrap/2.1.1/..
: /jquery/1.8.1/jquery.min.js
:)
declare variable $config:libserver as xs:string:=$config:config/libserver/fn:string();
declare variable $config:aceserver as xs:string:=$config:config/aceserver/fn:string();

238
src/graphxq/lib/oauth.xqy Normal file
View File

@ -0,0 +1,238 @@
(:
: an OAuth implementation written in XQuery for BaseX 7.4
: based on http://norman.walsh.name/2010/09/25/oauth
:)
module namespace oa="http://basex.org/ns/oauth";
import module namespace crypto="http://expath.org/ns/crypto";
declare function oa:twitter-service($CONSUMER-KEY as xs:string,
$CONSUMER-SECRET as xs:string){
<oa:service-provider realm="">
<oa:request-token>
<oa:uri>http://twitter.com/oauth/request_token</oa:uri>
<oa:method>GET</oa:method>
</oa:request-token>
<oa:user-authorization>
<oa:uri>http://twitter.com/oauth/authorize</oa:uri>
</oa:user-authorization>
<oa:user-authentication>
<oa:uri>http://twitter.com/oauth/authenticate</oa:uri>
<oa:additional-params>force_login=true</oa:additional-params>
</oa:user-authentication>
<oa:access-token>
<oa:uri>http://twitter.com/oauth/access_token</oa:uri>
<oa:method>POST</oa:method>
</oa:access-token>
<oa:signature-methods>
<oa:method>HMAC-SHA1</oa:method>
</oa:signature-methods>
<oa:oauth-version>1.0</oa:oauth-version>
<oa:authentication>
<oa:consumer-key>{$CONSUMER-KEY}</oa:consumer-key>
<oa:consumer-key-secret>{$CONSUMER-SECRET}</oa:consumer-key-secret>
</oa:authentication>
</oa:service-provider>
};
declare function oa:timestamp() as xs:unsignedLong {
let $epoch := xs:dateTime('1970-01-01T00:00:00Z')
let $now := current-dateTime()
let $d := $now - $epoch
let $seconds
:= 86400 * days-from-duration($d)
+ 3600 * hours-from-duration($d)
+ 60 * minutes-from-duration($d)
+ seconds-from-duration($d)
return
xs:unsignedLong($seconds)
};
declare function oa:sign($key as xs:string, $data as xs:string) as xs:string {
crypto:hmac($data,$key,'SHA1','base64')
};
declare function oa:signature-method(
$service as element(oa:service-provider)
) as xs:string
{
if ($service/oa:signature-methods/oa:method = "HMAC-SHA1")
then "HMAC-SHA1"
else error(xs:QName("oa:BADSIGMETHOD"),
"Service must support 'HMAC-SHA1' signatures.")
};
declare function oa:http-method(
$proposed-method as xs:string
) as xs:string
{
if (upper-case($proposed-method) = "GET")
then "GET"
else if (upper-case($proposed-method) = "POST")
then "POST"
else error(xs:QName("oa:BADHTTPMETHOD"),
"Service must use HTTP GET or POST.")
};
declare function oa:request-token(
$service as element(oa:service-provider),
$callback as xs:string?)
as element(oa:request-token)
{
let $options := if (empty($callback))
then ()
else
<oa:options>
<oauth_callback>{$callback}</oauth_callback>
</oa:options>
let $data
:= oa:signed-request($service,
$service/oa:request-token/oa:method,
$service/oa:request-token/oa:uri,
$options, (), ())
return
<oa:request-token>
{ if ($data/oa:error)
then
$data/*
else
for $pair in tokenize($data, "&amp;")
return
element { concat("oa:", substring-before($pair, '=')) }
{ substring-after($pair, '=') }
}
</oa:request-token>
};
declare function oa:access-token(
$service as element(oa:service-provider),
$request as element(oa:request-token),
$verifier as xs:string)
as element(oa:access-token)
{
let $options := <oa:options><oauth_verifier>{$verifier}</oauth_verifier></oa:options>
let $data
:= oa:signed-request($service,
$service/oa:access-token/oa:method,
$service/oa:access-token/oa:uri,
$options,
$request/oa:oauth_token,
$request/oa:oaauth_token_secret)
return
<oa:access-token>
{ if ($data/oa:error)
then
$data/*
else
for $pair in tokenize($data, "&amp;")
return
element { concat("oa:", substring-before($pair, '=')) }
{ substring-after($pair, '=') }
}
</oa:access-token>
};
declare function oa:signed-request(
$service as element(oa:service-provider),
$method as xs:string,
$serviceuri as xs:string,
$options as element(oa:options)?,
$token as xs:string?,
$secret as xs:string?)
as element(oa:response)
{
let $realm := string($service/@realm)
let $nonce :=convert:integer-to-base(random:integer(),16)
let $stamp := oa:timestamp()
let $key := string($service/oa:authentication/oa:consumer-key)
let $sigkey := concat($service/oa:authentication/oa:consumer-key-secret,
"&amp;", if (empty($secret)) then "" else $secret)
let $version := string($service/oa:oauth-version)
let $sigmethod := oa:signature-method($service)
let $httpmethod := oa:http-method($method)
let $sigstruct
:= <oa:signature-base-string>
<oauth_consumer_key>{$key}</oauth_consumer_key>
<oauth_nonce>{$nonce}</oauth_nonce>
<oauth_signature_method>{$sigmethod}</oauth_signature_method>
<oauth_timestamp>{$stamp}</oauth_timestamp>
<oauth_version>{$version}</oauth_version>
{ if (not(empty($token)))
then <oauth_token>{$token}</oauth_token>
else ()
}
{ if (not(empty($options)))
then $options/*
else ()
}
</oa:signature-base-string>
let $encparams
:= for $field in $sigstruct/*
order by local-name($field)
return
concat(local-name($field), "=", encode-for-uri(string($field)))
let $sigbase := string-join(($httpmethod, encode-for-uri($serviceuri),
encode-for-uri(string-join($encparams,"&amp;"))), "&amp;")
let $signature := encode-for-uri(oa:sign($sigkey, $sigbase))
(: This is a bit of a pragmatic hack, what's the real answer? :)
let $authfields := $sigstruct/*[starts-with(local-name(.), "oauth_")
and not(self::oauth_callback)]
let $authheader := concat("OAuth realm=&quot;", $service/@realm, "&quot;, ",
"oauth_signature=&quot;", $signature, "&quot;, ",
string-join(
for $field in $authfields
return
concat(local-name($field),"=&quot;", encode-for-uri($field), "&quot;"),
", "))
let $uriparam := for $field in $options/*
return
concat(local-name($field),"=",encode-for-uri($field))
(: This strikes me as slightly weird. Twitter wants the parameters passed
encoded in the URI even for a POST. I don't know if that's a Twitter
quirk or the natural way that OAuth apps work. Anyway, if you find
this library isn't working for some other OAuth'd API, you might want
to play with this bit.
let $requri := if ($httpmethod = "GET")
then concat($serviceuri,
if (empty($uriparam)) then ''
else concat("?",string-join($uriparam,"&amp;")))
else $serviceuri
let $data := if ($httpmethod = "POST" and not(empty($uriparam)))
then <xh:data>{string-join($uriparam,"&amp;")}</xh:data>
else ()
:)
let $requri := concat($serviceuri,
if (empty($uriparam)) then ''
else concat("?",string-join($uriparam,"&amp;")))
let $request := <http:request method = "{$httpmethod}">
<http:header name="Authorization" value="{$authheader}"/>
</http:request>
let $tokenreq :=http:send-request($request,$requri)
return
<oa:response>
{ if (string($tokenreq[1]/@status) != "200")
then
(<oa:error>{$tokenreq[1]}</oa:error>,
<oa:error-body>{$tokenreq[2]}</oa:error-body>)
else
$tokenreq[2]
}
</oa:response>
};

View File

@ -48,10 +48,12 @@ jQuery(function($) { $.extend({
$(document).ready(function(){ $(document).ready(function(){
$("#bnup").on("click",getsvg); $("#bnup").on("click",getsvg);
$("#bnsvg").on("click",function(){ $("#dotForm").submit()}); $("#bnsvg").on("click",function(){ submit(false)});
$("#bndn").on("click",function(){getsvg(true)}); $("#bndn").on("click",function(){submit(true)});
$("#dot").on("keyup",getsvg); $("#dot").on("keyup",getsvg);
$('.colorpicker').colorPicker(); $('.colorpicker').colorPicker();
// set height where extend class
var resize=function(){ var resize=function(){
var h=$(window).height(); var h=$(window).height();
$('.extend').each(function(){ $('.extend').each(function(){
@ -64,6 +66,11 @@ $(document).ready(function(){
resize(); resize();
}); });
function submit(dl){
$("#ckdnload").prop("checked",dl);
$("#dotForm").submit()
}
function getsvg(dl){ function getsvg(dl){
var f=$("#dotForm").serializeArray() var f=$("#dotForm").serializeArray()
var d=$("#frm-defaults").serializeArray() var d=$("#frm-defaults").serializeArray()
@ -74,20 +81,21 @@ function getsvg(dl){
url:"svg", url:"svg",
data:f, data:f,
dataType: "text", dataType: "text",
success: function(str){ success: updateSvg,
// console.log(data)
var oParser = new DOMParser();
var data = oParser.parseFromString(str, "text/xml");
// http://stackoverflow.com/questions/3346106/accessing-a-dom-object-defined-in-an-external-svg-file
var n = document.importNode(data.documentElement,true);
$("#cuthere").empty().append(n);
$("#svgsrc").empty().text(str);
},
error:function(jqXHR, textStatus, errorThrown){ error:function(jqXHR, textStatus, errorThrown){
console.log("ajax error: "+textStatus + errorThrown); console.log("ajax error: "+textStatus + errorThrown);
} }
}); });
}; };
function updateSvg(str){
// console.log(data)
var oParser = new DOMParser();
var data = oParser.parseFromString(str, "text/xml");
// http://stackoverflow.com/questions/3346106/accessing-a-dom-object-defined-in-an-external-svg-file
var n = document.importNode(data.documentElement,true);
$("#cuthere").empty().append(n);
$("#svgsrc").empty().text(str);
};
function dotit(){ function dotit(){
// xsvg.innerText=""; // xsvg.innerText="";

View File

@ -37,12 +37,12 @@
--> -->
<li class="follow-btn"><iframe title="Twitter Follow Button" <li class="follow-btn"><iframe title="Twitter Follow Button"
style="width: 237px; height: 20px;" class="twitter-follow-button" style="width: 237px; height: 20px;" class="twitter-follow-button"
src="http://platform.twitter.com/widgets/follow_button.html?id=twitter-widget-2&amp;lang=en&amp;screen_name=apb1704&amp;show_count=true&amp;show_screen_name=true&amp;size=m" src="http://platform.twitter.com/widgets/follow_button.html?id=twitter-widget-2&amp;lang=en&amp;screen_name=apb1704&amp;show_count=false&amp;show_screen_name=true&amp;size=m"
allowtransparency="true" scrolling="no" frameborder="0"></iframe></li> allowtransparency="true" scrolling="no" frameborder="0"></iframe></li>
<li class="tweet-btn"><iframe title="Twitter Tweet Button" <li class="tweet-btn"><iframe title="Twitter Tweet Button"
style="width: 106px; height: 20px;" style="width: 106px; height: 20px;"
class="twitter-share-button twitter-count-horizontal" class="twitter-share-button twitter-count-horizontal"
src="http://platform.twitter.com/widgets/tweet_button.html?count=horizontal&amp;id=twitter-widget-0&amp;lang=en&amp;original_referer=https%3A%2F%2Fgithub.com%2Fapb2006%2Fxqwebdoc%2F&amp;size=m&amp;text=xqwebdoc #xquery&amp;url=https%3A%2F%2Fgithub.com%2Fapb2006%2Fxqwebdoc&amp;via=apb1704" src="http://platform.twitter.com/widgets/tweet_button.html?count=horizontal&amp;id=twitter-widget-0&amp;lang=en&amp;original_referer=https%3A%2F%2Fgithub.com%2Fapb2006%2Fgraphxq%2F&amp;size=m&amp;text=graphxq graphviz #xquery&amp;url=https%3A%2F%2Fgithub.com%2Fapb2006%2Fgraphxq&amp;via=apb1704"
allowtransparency="true" scrolling="no" frameborder="0"></iframe></li> allowtransparency="true" scrolling="no" frameborder="0"></iframe></li>
</ul> </ul>
</div> </div>

View File

@ -4,7 +4,7 @@
<ul class="nav nav-tabs"> <ul class="nav nav-tabs">
<li class="active"><a href="#tab-dot" data-toggle="tab">Dot</a></li> <li class="active"><a href="#tab-dot" data-toggle="tab">Dot</a></li>
<li><a href="#tab-defaults" data-toggle="tab">Defaults</a></li> <li><a href="#tab-defaults" data-toggle="tab">Defaults</a></li>
<li><a href="#tab-xml" data-toggle="tab">Raw XML</a></li> <li><a href="#tab-xml" data-toggle="tab">SVG</a></li>
<li> <div class="btn-group"> <li> <div class="btn-group">
<button id="bnup" class="btn btn-mini" ><i class="icon-refresh"></i>Redraw</button> <button id="bnup" class="btn btn-mini" ><i class="icon-refresh"></i>Redraw</button>
<button id="bnsvg" class="btn btn-mini" ><i class="icon-fullscreen"></i>SVG</button> <button id="bnsvg" class="btn btn-mini" ><i class="icon-fullscreen"></i>SVG</button>
@ -13,19 +13,16 @@
</div> </div>
</li> </li>
</ul> </ul>
<div class="tab-content extend"> <div class="tab-content" style="overflow:hidden">
<div class="tab-pane active " id="tab-dot" > <div class="tab-pane active " id="tab-dot" >
<form id="dotForm" action= "svg" method="post" target="_new" class="well " > <form id="dotForm" action= "svg" method="post" target="_new" >
<label>digraph "
<input type="text" name="title" placeholder="title" class="input-small" />" <textarea id="dot" name="dot" rows="10" class="extend" style="width:90%;overflow:scroll"
</label> >{$dot}</textarea>
<span style="margin-right:-5px;padding-right:2px;">{{</span>
<textarea id="dot" name="dot" rows="100" style="width:90%;height:100%;overflow:scroll" <input id="ckdnload" name="dl" type="checkbox" style="display:none"/>
>{$dot}</textarea><span style="margin-right:-5px;">}}</span>
<label class="checkbox">
<input name="dl" type="checkbox"/> Download
</label>
</form > </form >
</div> </div>
@ -63,13 +60,16 @@
</div> </div>
<div class="span6"> <div class="span6">
<div id="svgdiv" class="extend" style="width:100%;height:30em;border: 1px solid #E3E3E3;min-height:20em;">{$svgwidget}</div> <div id="svgdiv" class="extend well" style="width:95%;height:30em;min-height:20em;">{$svgwidget}</div>
</div> </div>
<script src="http://d1n0x3qji82z53.cloudfront.net/src-min-noconflict/ace.js" type="text/javascript" charset="utf-8"></script> <script src="{$aceserver}/src-min-noconflict/ace.js" type="text/javascript" charset="utf-8"></script>
<script type="text/javascript"> <script type="text/javascript">
$(document).ready(function(){{ $(document).ready(function(){{
getsvg(false) getsvg(false)
$('#color1').change(function(){{
alert("color changed");
}});
}}) }})
</script> </script>
</div> </div>

View File

@ -18,7 +18,7 @@
<link rel="shortcut icon" href="/graphxq/static/graphxq2.png" /> <link rel="shortcut icon" href="/graphxq/static/graphxq2.png" />
<script src="{$libserver}/jquery/1.8.1/jquery.min.js" type="text/javascript"></script> <script src="{$libserver}/jquery/1.8.1/jquery.min.js" type="text/javascript"></script>
<script src="{$libserver}/twitter-bootstrap/2.1.1/bootstrap.min.js" type="text/javascript"></script> <script src="{$libserver}/twitter-bootstrap/2.1.1/js/bootstrap.min.js" type="text/javascript"></script>
<script src="/graphxq/static/jquery.colorPicker.js" type="text/javascript"></script> <script src="/graphxq/static/jquery.colorPicker.js" type="text/javascript"></script>
<link href="/graphxq/static/colorPicker.css" rel="stylesheet" type="text/css" /> <link href="/graphxq/static/colorPicker.css" rel="stylesheet" type="text/css" />
<script src="/graphxq/static/app.js" type="text/javascript"></script> <script src="/graphxq/static/app.js" type="text/javascript"></script>
@ -68,8 +68,19 @@
<li class="nav"> <li class="nav">
<a href="library">Library</a> <a href="library">Library</a>
</li> </li>
<li class="nav"> <li class="dropdown">
<a href="about">About</a> <a href="#" class="dropdown-toggle" data-toggle="dropdown">
About
<b class="caret"></b>
</a>
<ul class="dropdown-menu">
<li>
<a href="about"><i class="icon-info-sign"></i> This application</a>
</li>
<li>
<a href="twitter"><i class="icon-comment"></i> Twitter test</a>
</li>
</ul>
</li> </li>
</ul> </ul>
<form class="pull-right navbar-search" action="search"> <form class="pull-right navbar-search" action="search">

View File

@ -0,0 +1,5 @@
<div>
<!-- q,collection, hits -->
<h1>No twitter yet</h1>
<pre>{$data}</pre>
</div>