use strict;
use HTTP::Request;
use LWP::UserAgent;
use JSON;
use Data::Dumper;
use EPrints;
my $maximumResults = 20;
my $maxPublications = 3;
my $session = EPrints::Session->new();
my $family = $session->param( "_name_family" );
my $given = $session->param( "_name_given" );
my $id = $session->param( "_id" );
# Names API search set up
my $query = 'http://names.mimas.ac.uk/individual/search.json?outputFields=nameComponents%20and%20assigned%20and%20fieldsOfInterest%20and%20affiliations%20and%20resultPublications%20and%20collaborativeRelationships&orderBy=names&maximumRecords=' . $maximumResults;
# EPrints db search set up
my $database = $session->get_database;
my $dataset = $session->get_repository->get_dataset( "eprint" );
my $name_field = $dataset->get_field( "creators_name" );
my $id_field = $dataset->get_field( "creators_id" );
my @fields = ($name_field->get_sql_names, $id_field->get_sql_names);
my $Q_table = $database->quote_identifier($dataset->get_sql_table_name);
my $Q_name_table = $database->quote_identifier($dataset->get_sql_sub_table_name($name_field));
my $Q_id_table = $database->quote_identifier($dataset->get_sql_sub_table_name($id_field));
my $Q_eprintid = $database->quote_identifier( "eprintid" );
my $Q_pos = $database->quote_identifier( "pos" );
my $Q_num_matches = $database->quote_identifier( "num_matches" );
my $Q_eprint_status = $database->quote_identifier( "eprint_status" );
my $sql = "SELECT COUNT($Q_table.$Q_eprintid) ".$database->sql_AS." $Q_num_matches," .
join(",", map { $database->quote_identifier($_) } @fields) .
" FROM $Q_table" .
" LEFT JOIN $Q_name_table" .
" ON $Q_table.$Q_eprintid=$Q_name_table.$Q_eprintid" .
" LEFT JOIN $Q_id_table" .
" ON $Q_name_table.$Q_eprintid=$Q_id_table.$Q_eprintid " .
" AND $Q_name_table.$Q_pos=$Q_id_table.$Q_pos " .
" WHERE " .
" $Q_table.$Q_eprint_status=".$database->quote_value( "archive" );
if ( EPrints::Utils::is_set( $family ) )
{
# Just work with this for now
if (length($family) < 3) {
print ("
");
return;
}
# Add to Names API query
$query .= "&familyName=$family";
# Add to EPrints query
$sql .= " AND ".$database->quote_identifier("creators_name_family").$database->sql_LIKE().$database->quote_value(EPrints::Database::prep_like_value($family).'%');
}
if( EPrints::Utils::is_set( $given ) )
{
# Add to Names API query
$query .= '&givenName=';
foreach my $component ( split /\s+/, $given ) {
$query .= $component . '%20AND%20';
}
$query =~ s/%20AND%20$//;
# Add to EPrints query
$sql .= " AND ".$database->quote_identifier("creators_name_given").$database->sql_LIKE().$database->quote_value(EPrints::Database::prep_like_value($given).'%');
}
#if( EPrints::Utils::is_set( $id ) )
#{
# Do nothing for now
#}
# EPrints query wrap-up
$sql .= " GROUP BY ".join(",",map { $database->quote_identifier($_) } @fields) .
" ORDER BY $Q_num_matches DESC," .
$database->quote_identifier("creators_name_family").",".
$database->quote_identifier("creators_name_given");
# Search across both Names API and internal EPrints db
# Consecutively to start with
# Search for names via local EPrints db search
my @eprints_rows = searchEPrints( $sql );
# Search for names via Names API
my @names_rows = searchNamesAPI( $query) ;
# Combine results
push @eprints_rows, @names_rows;
# Order two sets of data by family name, given name
my @ordered_rows = sort by_name @eprints_rows;
# Output lookup dropdown list
my $ul = render_lookup_list( $session, \@ordered_rows );
$session->send_http_header( content_type => "text/xml; charset=UTF-8" );
binmode(STDOUT,":utf8");
print <
END
print EPrints::XML::to_string( $ul, "utf-8", 1 );
EPrints::XML::dispose( $ul );
$session->terminate;
1;
sub searchNamesAPI {
my $q = shift;
my @rows;
my $request = HTTP::Request->new( GET => "$q" );
my $ua = LWP::UserAgent->new();
my $response = $ua->request($request);
my $content = $response->content();
my $names_hash = decode_json $content; # assumes utf8 input
# Get results from query
foreach my $result_hash ( @{ $names_hash->{results} } )
{
my $item = {};
my $names_uri = $result_hash->{namesID};
$names_uri =~ /\/([^\/]*)$/;
$item->{names_id} = $1;
my $name_chars = $result_hash->{names}->[0]->{characters};
my ($family_name, $given_name) = split /,/, $name_chars;
# Get Fields of Interest
foreach my $foi_hash ( @{$result_hash->{fieldsOfInterest}} ) {
push @{ $item->{foi} }, $foi_hash->{fieldOfInterest};
}
# Get authored articles
foreach my $publication_hash ( @{$result_hash->{resultPublications}} ) {
push @{ $item->{publications} }, $publication_hash->{title};
}
# Get affiliations
foreach my $affiliation_hash ( @{$result_hash->{affiliations}} ) {
push @{ $item->{affiliations} }, $affiliation_hash->{name};
}
my $frag = $session->make_doc_fragment;
$frag->appendChild( $session->make_text("$family_name, $given_name") );
$frag->appendChild( $session->make_text( " " ) );
$frag->appendChild( $session->make_text("[$names_uri]") );
my $small = $session->make_element("span", style=>"font-size:small;color:red" );
$frag->appendChild( $small );
$small->appendChild( $session->make_text( " (from the Names authority service)" ) );
$item->{xhtml} = $frag;
$item->{values} = [
"for:value:relative:_name_family" => $family_name,
"for:value:relative:_name_given" => $given_name,
"for:value:relative:_id" => $names_uri,
];
push @rows, $item;
}
return @rows;
}
sub searchEPrints {
my $q = shift;
my @rows;
my $sth = $session->get_database->prepare_select( $q, 'limit' => $maximumResults );
$session->get_database->execute( $sth , $q );
while( my @row = $sth->fetchrow_array )
{
my $cnt = shift @row;
my $name = $name_field->value_from_sql_row( $session, \@row );
my $id = $id_field->value_from_sql_row( $session, \@row );
my $item = {};
my $frag = $session->make_doc_fragment;
$frag->appendChild( $name_field->render_single_value( $session, $name ) );
if( EPrints::Utils::is_set( $id ) )
{
$frag->appendChild( $session->make_text( " " ) );
$frag->appendChild( $id_field->render_single_value( $session, $id ) );
}
my $small = $session->make_element("span", style=>"font-size:small;color:red" );
$frag->appendChild( $small );
$small->appendChild( $session->make_text( " (author of ".$cnt." item".($cnt>1?"s":"")." in the repository)" ) );
$item->{xhtml} = $frag;
$item->{values} = [
"for:value:relative:_name_family" => $name->{family},
"for:value:relative:_name_given" => $name->{given},
"for:value:relative:_name_honourific" => $name->{honourific},
"for:value:relative:_name_lineage" => $name->{lineage},
"for:value:relative:_id" => $id,
];
push @rows, $item;
}
$sth->finish();
return @rows;
}
sub by_name {
lc $a->{values}->[1] cmp lc $b->{values}->[1]
||
lc $a->{values}->[3] cmp lc $b->{values}->[3]
}
sub render_lookup_list
{
my( $session, $rows ) = @_;
my $ul = $session->make_element( "ul" );
my $first = 1;
foreach my $row (@$rows)
{
# Need to generate a random id for the div otherwise the element
# postion gets cached at the client - a scriptaculous issue?
my $time = time;
$time =~ /(.{4})$/;
my $item_id = $1 . '_' . $row->{names_id};
my $li = $session->make_element(
'li',
id => "names_item_$item_id",
);
if ( $row->{foi} ) {
# This is a Names record
$li->setAttribute( "onMouseOver", "names_show_disambiguation_info('names_item_$item_id')" );
$li->setAttribute( "onMouseOut", "names_hide_disambiguation_info('names_item_$item_id')" );
}
$ul->appendChild( $li );
if( $first )
{
$li->setAttribute( "class", "ep_first" );
$first = 0;
}
if( defined($row->{xhtml}) )
{
$li->appendChild( $row->{xhtml} );
}
elsif( defined($row->{desc}) )
{
$li->appendChild( $session->make_text( $row->{desc} ) );
}
my @values = @{$row->{values}};
my $ul = $session->make_element( "ul" );
$li->appendChild( $ul );
for(my $i = 0; $i < @values; $i+=2)
{
my( $name, $value ) = @values[$i,$i+1];
my $li = $session->make_element( "li", id => $name );
$ul->appendChild( $li );
$li->appendChild( $session->make_text( $value ) );
}
# Add disambiguation information for Names data
if ( $row->{foi} || $row->{publications} ) {
my $div = $session->make_element( "div" );
$li->appendChild( $div );
# Fields of interest
if ( $row->{foi} )
{
my $ul = $session->make_element( "ul");
$div->appendChild( $ul );
foreach my $foi ( @{$row->{foi}} )
{
my $li = $session->make_element( "li", name => "names_foi" );
$ul->appendChild( $li );
$li->appendChild( $session->make_text( $foi ) );
}
}
# Publications
if ( $row->{publications} )
{
my $ul = $session->make_element( "ul");
$div->appendChild( $ul );
my $pub_count = 0;
foreach my $publication ( @{$row->{publications}} )
{
$pub_count++;
my $li = $session->make_element( "li", name => "names_publication" );
$ul->appendChild( $li );
$li->appendChild( $session->make_text( $publication ) );
last if ( $pub_count >= $maxPublications );
}
}
# Affiliations
if ( $row->{affiliations} )
{
my $ul = $session->make_element( "ul");
$div->appendChild( $ul );
foreach my $affiliation ( @{$row->{affiliations}} )
{
my $li = $session->make_element( "li", name => "names_affiliation" );
$ul->appendChild( $li );
$li->appendChild( $session->make_text( $affiliation ) );
}
}
}
}
return $ul;
}