| blib/lib/SeeAlso/Source/BeaconAggregator/Publisher.pm | |||
|---|---|---|---|
| Criterion | Covered | Total | % |
| statement | 116 | 465 | 24.9 |
| branch | 47 | 352 | 13.3 |
| condition | 23 | 186 | 12.3 |
| subroutine | 9 | 11 | 81.8 |
| pod | 7 | 7 | 100.0 |
| total | 202 | 1021 | 19.7 |
| line | stmt | bran | cond | sub | pod | time | code |
|---|---|---|---|---|---|---|---|
| 1 | package SeeAlso::Source::BeaconAggregator::Publisher; | ||||||
| 2 | 3 | 3 | 87348 | use strict; | |||
| 3 | 3 | ||||||
| 3 | 68 | ||||||
| 3 | 3 | 3 | 10 | use warnings; | |||
| 3 | 3 | ||||||
| 3 | 180 | ||||||
| 4 | |||||||
| 5 | our $VERSION = "0.2_92"; | ||||||
| 6 | |||||||
| 7 | =head1 NAME | ||||||
| 8 | |||||||
| 9 | SeeAlso::Source::BeaconAggregator::Publisher - additional methods for SeeAlso::Source::BeaconAggregator | ||||||
| 10 | |||||||
| 11 | =head1 SYNOPSIS | ||||||
| 12 | |||||||
| 13 | $source = SeeAlso::Source::BeaconAggregator::Publisher->new(...); | ||||||
| 14 | |||||||
| 15 | =head1 DESCRIPTION | ||||||
| 16 | |||||||
| 17 | This package provides the functionallity to export a BEACON file from the | ||||||
| 18 | data connected with an SeeAlso::Source::BeaconAggregator instance and | ||||||
| 19 | also the additional formats "redirect" and "sources" which universally | ||||||
| 20 | can be used as callbacks for SeeAlso::Server (replacing the default | ||||||
| 21 | "seealso" method yielding JSON data). | ||||||
| 22 | |||||||
| 23 | =cut | ||||||
| 24 | |||||||
| 25 | our %Defaults = ( | ||||||
| 26 | # "REVISIT" => 86400, # one day | ||||||
| 27 | "REVISIT" => undef, # no default (leave empty unless otherwise set) | ||||||
| 28 | "uAformatname" => "sources", | ||||||
| 29 | "beaconformatname" => "beacon", | ||||||
| 30 | "FORMAT" => "BEACON", | ||||||
| 31 | "VERSION" => "0.1", # no other exist | ||||||
| 32 | ); | ||||||
| 33 | |||||||
| 34 | 3 | 3 | 792 | use SeeAlso::Source::BeaconAggregator; | |||
| 3 | 5 | ||||||
| 3 | 109 | ||||||
| 35 | 3 | 3 | 12 | use Carp; | |||
| 3 | 5 | ||||||
| 3 | 15250 | ||||||
| 36 | |||||||
| 37 | =head2 new ( ... ) | ||||||
| 38 | |||||||
| 39 | Creates an SeeAlso::Source::BeaconAggregator object with additional methods from | ||||||
| 40 | this package enabled | ||||||
| 41 | |||||||
| 42 | =cut | ||||||
| 43 | |||||||
| 44 | sub new { # directly create BeaconAggregator instance with extended features... | ||||||
| 45 | 4 | 4 | 1 | 3586 | my $class = shift @_; | ||
| 46 | 4 | 41 | push(@SeeAlso::Source::BeaconAggregator::ISA, $class); | ||||
| 47 | 4 | 19 | return SeeAlso::Source::BeaconAggregator->new(@_); | ||||
| 48 | } | ||||||
| 49 | |||||||
| 50 | |||||||
| 51 | =head2 activate () | ||||||
| 52 | |||||||
| 53 | Makes SeeAlso::Source::BeaconAggregator objects member of this class, | ||||||
| 54 | globally enabling the additional methods | ||||||
| 55 | |||||||
| 56 | Usage: | ||||||
| 57 | |||||||
| 58 | $db = SeeAlso::Source::BeaconAggregator::Maintenance->new(...); | ||||||
| 59 | ... | ||||||
| 60 | do stuff | ||||||
| 61 | ... | ||||||
| 62 | require SeeAlso::Source::BeaconAggregator::Publisher | ||||||
| 63 | or die "could not require Publisher extension"; | ||||||
| 64 | SeeAlso::Source::BeaconAggregator::Publisher->activate(); # "recast" all objects | ||||||
| 65 | ... | ||||||
| 66 | do more stuff | ||||||
| 67 | |||||||
| 68 | =cut | ||||||
| 69 | sub activate { # enrich SeeAlso::Source and derived classes with our methods | ||||||
| 70 | 1 | 1 | 1 | 414 | my $class = shift @_; | ||
| 71 | 1 | 10 | push(@SeeAlso::Source::BeaconAggregator::ISA, $class); | ||||
| 72 | 1 | 3 | return 1; | ||||
| 73 | } | ||||||
| 74 | |||||||
| 75 | |||||||
| 76 | ### Produktion der Beacon-Datei | ||||||
| 77 | |||||||
| 78 | =head2 beacon ( [dumpmeta arguments] ) | ||||||
| 79 | |||||||
| 80 | produces a BEACON file (however, $cgibase is mandatory) | ||||||
| 81 | |||||||
| 82 | =head2 dumpmeta ( [$cgibase, [$uAformatname, [$headersonly]]] [, $preset]) | ||||||
| 83 | |||||||
| 84 | produces only the meta fields of a BEACON file | ||||||
| 85 | |||||||
| 86 | Meta fields are generated from the $preset Hashref, falling back to | ||||||
| 87 | values stored in the database, falling back to reasonable default | ||||||
| 88 | values. | ||||||
| 89 | |||||||
| 90 | Arguments: | ||||||
| 91 | |||||||
| 92 | =over 8 | ||||||
| 93 | |||||||
| 94 | =item $cgibase | ||||||
| 95 | |||||||
| 96 | URL of the SeeAlso service the BEACON file is provided for | ||||||
| 97 | |||||||
| 98 | =item $uAformatname | ||||||
| 99 | |||||||
| 100 | unAPI format name to be used as target (Default: "sources") | ||||||
| 101 | |||||||
| 102 | =item $headersonly | ||||||
| 103 | |||||||
| 104 | currently unused | ||||||
| 105 | |||||||
| 106 | =item $preset | ||||||
| 107 | |||||||
| 108 | Hashref of Beacon header fields overriding the contents of the database | ||||||
| 109 | |||||||
| 110 | =back | ||||||
| 111 | |||||||
| 112 | Regular Usage: | ||||||
| 113 | |||||||
| 114 | $db = SeeAlso::Source::BeaconAggregator::Publisher->new(...); | ||||||
| 115 | binmode(STDOUT, ":utf8"); | ||||||
| 116 | my $cgibase = "http://address/of/service"; | ||||||
| 117 | my ( $error, $headerref) = $db->beacon($cgibase, @ARGV, {'FORMAT' => 'PND-BEACON'}); | ||||||
| 118 | |||||||
| 119 | |||||||
| 120 | CGI Usage: | ||||||
| 121 | |||||||
| 122 | $format = $CGI->param('format') || ""; | ||||||
| 123 | if ( $format eq "beacon" ) { # bypass SeeAlso::Server->query() b/c performance / interim storage | ||||||
| 124 | insert access restrictions here... | ||||||
| 125 | do_beacon($source, $CGI); | ||||||
| 126 | } | ||||||
| 127 | ... | ||||||
| 128 | |||||||
| 129 | sub do_beacon { | ||||||
| 130 | my ($self, $cgi) = @_; # Of type SeeAlso::Source::BeaconAggregator | ||||||
| 131 | unless ( $self->can("beacon") ) { | ||||||
| 132 | croak "On the fly generation of beacon Files not supported by this service";} | ||||||
| 133 | my $cgibase = $cgi->url(-path_info=>1); | ||||||
| 134 | |||||||
| 135 | print $cgi->header( -status => 200, | ||||||
| 136 | -expires => '+1d', | ||||||
| 137 | -type => 'text/plain', | ||||||
| 138 | -charset => 'utf-8', | ||||||
| 139 | ); | ||||||
| 140 | return $self->beacon($cgibase, "sources", {}); # prints directly to stdout..., returns $error, $headerref | ||||||
| 141 | } | ||||||
| 142 | |||||||
| 143 | =cut | ||||||
| 144 | |||||||
| 145 | sub beacon { | ||||||
| 146 | 1 | 50 | 1 | 1 | 10600 | my ($self) = shift @_ or croak("beacon is a method!"); # Of type SeeAlso::Source::BeaconAggregator | |
| 147 | 1 | 3 | my ($error, $headerref) = $self->dumpmeta(@_); | ||||
| 148 | 1 | 50 | 3 | croak("Error generating Header, will not proceed") if $error; | |||
| 149 | |||||||
| 150 | 1 | 41 | print @$headerref; | ||||
| 151 | |||||||
| 152 | 1 | 50 | 6 | my $c = (defined $self->{identifierClass}) ? $self->{identifierClass} : $self->autoIdentifier(); | |||
| 153 | |||||||
| 154 | 1 | 3 | my ($sth, $sthexpl) = $self->stmtHdl(<<"XxX"); | ||||
| 155 | SELECT hash, COUNT(DISTINCT seqno) FROM beacons GROUP BY hash ORDER BY hash; | ||||||
| 156 | XxX | ||||||
| 157 | 1 | 50 | 3 | $self->stmtExplain($sthexpl) if $ENV{'DBI_PROFILE'}; | |||
| 158 | 1 | 50 | 138 | $sth->execute() or croak("Could not execute >".$sth->{Statement}."<: ".$sth->errstr); | |||
| 159 | 1 | 3 | my $rows = 0; | ||||
| 160 | 1 | 40 | while ( my $row = $sth->fetchrow_arrayref ) { | ||||
| 161 | 7 | 6 | $rows++; | ||||
| 162 | 7 | 6 | my $expanded = $row->[0]; | ||||
| 163 | 7 | 50 | 13 | if ( defined $c ) { | |||
| 164 | # compat: hash might not take an argument, must resort to value, has to be cleared before... | ||||||
| 165 | 0 | 0 | $c->value(""); | ||||
| 166 | 0 | 0 | 0 | my $did = $c->hash($row->[0]) || $c->value($row->[0]); | |||
| 167 | 0 | 0 | 0 | $expanded = $c->can("pretty") ? $c->pretty() : $c->value(); | |||
| 168 | # illegal identifier b/c different classes for loading and exporting? | ||||||
| 169 | 0 | 0 | 0 | 0 | next unless defined $expanded && ($expanded ne ""); | ||
| 170 | } | ||||||
| 171 | 7 | 100 | 142 | print $expanded.(($row->[1] > 1) ? "|".$row->[1] : "")."\n"; | |||
| 172 | } | ||||||
| 173 | |||||||
| 174 | 1 | 3 | return $rows, $headerref; | ||||
| 175 | } | ||||||
| 176 | |||||||
| 177 | sub dumpmeta { # cgibase unAPIformatname headers_only {preset} | ||||||
| 178 | 2 | 50 | 2 | 1 | 2266 | my ($self) = shift @_ or croak("dumpmeta is a method!"); # Of type SeeAlso::Source::BeaconAggregator | |
| 179 | 2 | 3 | my ($error, @result) = (0, ()); | ||||
| 180 | |||||||
| 181 | 2 | 50 | 33 | 10 | my $cgibase = shift @_ if @_ && !ref($_[0]); | ||
| 182 | 2 | 50 | 33 | 8 | my $uAformatname = shift @_ if @_ && !ref($_[0]); | ||
| 183 | 2 | 33 | 8 | $uAformatname ||= $Defaults{'uAformatname'}; | |||
| 184 | 2 | 50 | 33 | 7 | my $headersonly = shift @_ if @_ && !ref($_[0]); | ||
| 185 | 2 | 50 | 33 | 12 | my $preset = (@_ && ref($_[0])) ? (shift @_) : {}; | ||
| 186 | |||||||
| 187 | 2 | 6 | my ($metasth, $metasthexpl) = $self->stmtHdl(<<"XxX"); | ||||
| 188 | SELECT key, val FROM osd; | ||||||
| 189 | XxX | ||||||
| 190 | 2 | 50 | 5 | $self->stmtExplain($metasthexpl) if $ENV{'DBI_PROFILE'}; | |||
| 191 | 2 | 50 | 85 | $metasth->execute() or croak("Could not execute >".$metasth->{Statement}."<: ".$metasth->errstr); | |||
| 192 | |||||||
| 193 | 2 | 3 | my (%osd, %beaconmeta); | ||||
| 194 | 2 | 23 | while ( my $aryref = $metasth->fetchrow_arrayref ) { | ||||
| 195 | 18 | 15 | my ($key, $val) = @$aryref; | ||||
| 196 | 18 | 50 | 24 | next unless $val; | |||
| 197 | 18 | 100 | 40 | if ($key =~ s/^bc// ) { # BeaconMeta Fields | |||
| 100 | |||||||
| 198 | 4 | 29 | $beaconmeta{$key} = $val} | ||||
| 199 | elsif ( exists $osd{$key} ) { | ||||||
| 200 | 12 | 100 | 16 | if ( ref($osd{$key}) ) { | |||
| 201 | 10 | 5 | push(@{$osd{$key}}, $val)} | ||||
| 10 | 42 | ||||||
| 202 | else { | ||||||
| 203 | 2 | 11 | $osd{$key} = [$osd{$key}, $val]}; | ||||
| 204 | } | ||||||
| 205 | else { | ||||||
| 206 | 2 | 11 | $osd{$key} = $val}; | ||||
| 207 | }; | ||||||
| 208 | 2 | 6 | my @osdexamples; | ||||
| 209 | 2 | 50 | 33 | 7 | if ( $osd{'Examples'} && ref($osd{'Examples'}) ) { | ||
| 50 | |||||||
| 210 | 0 | 0 | foreach my $expl ( @{$osd{'Examples'}} ) { | ||||
| 0 | 0 | ||||||
| 211 | 0 | 0 | $expl =~ s/\s*\|.*$//; | ||||
| 212 | 0 | 0 | push(@osdexamples, $expl); | ||||
| 213 | } | ||||||
| 214 | } | ||||||
| 215 | elsif ( my $expl = $osd{'Examples'} ) { | ||||||
| 216 | 0 | 0 | $expl =~ s/\s*\|.*$//; | ||||
| 217 | 0 | 0 | push(@osdexamples, $expl); | ||||
| 218 | }; | ||||||
| 219 | |||||||
| 220 | 2 | 13 | foreach ( grep /^[A-Z]+$/, keys %$preset ) { | ||||
| 221 | 3 | 6 | $beaconmeta{$_} = $preset->{$_}} | ||||
| 222 | # Mandatory fields | ||||||
| 223 | 2 | 33 | 8 | push(@result, "#FORMAT: ".($beaconmeta{'FORMAT'} || $Defaults{'FORMAT'})."\n"); | |||
| 224 | 2 | 33 | 6 | push(@result, "#VERSION: ".($beaconmeta{'VERSION'} || $Defaults{'VERSION'})."\n"); | |||
| 225 | 2 | 50 | 4 | if ( $beaconmeta{'TARGET'} ) { | |||
| 50 | |||||||
| 226 | 0 | 0 | $beaconmeta{'TARGET'} =~ s/^\{BASE\}/$cgibase/; | ||||
| 227 | 0 | 0 | push(@result, "#TARGET: $beaconmeta{'TARGET'}\n"); | ||||
| 228 | } | ||||||
| 229 | elsif ( $cgibase ) { | ||||||
| 230 | 2 | 6 | push(@result, "#TARGET: $cgibase?format=$uAformatname&id={ID}\n")} | ||||
| 231 | else { | ||||||
| 232 | 0 | 0 | carp "Don't know how to construct the mandatory #TARGET field!"; | ||||
| 233 | 0 | 0 | $error ++; | ||||
| 234 | } | ||||||
| 235 | |||||||
| 236 | 2 | 33 | 8 | my $timestamp = $preset->{'TIMESTAMP'} || $osd{DateModified} || $^T; | |||
| 237 | 2 | 50 | 9 | push(@result, "#TIMESTAMP: ".SeeAlso::Source::BeaconAggregator::tToISO($timestamp)."\n") if $timestamp > 0; | |||
| 238 | 2 | 50 | 12 | my $revisit = ($beaconmeta{'REVISIT'} || $Defaults{'REVISIT'}) || ""; | |||
| 239 | 2 | 2 | $revisit =~ tr/ //d; | ||||
| 240 | 2 | 3 | $revisit =~ s/(\d+)mo\w*/($1*30)."d"/ei; | ||||
| 0 | 0 | ||||||
| 241 | 2 | 2 | $revisit =~ s/(\d+)M\w*/($1*30)."d"/e; | ||||
| 0 | 0 | ||||||
| 242 | 2 | 3 | $revisit =~ s/(\d+)w\w*/($1*7)."d"/ei; | ||||
| 0 | 0 | ||||||
| 243 | 2 | 4 | $revisit =~ s/(\d+)d\w*/($1*24)."h"/ei; | ||||
| 1 | 6 | ||||||
| 244 | 2 | 3 | $revisit =~ s/(\d+)h\w*/($1*60)."m"/ei; | ||||
| 1 | 3 | ||||||
| 245 | 2 | 3 | $revisit =~ s/(\d+)m\w*/($1*60)."s"/ei; | ||||
| 1 | 2 | ||||||
| 246 | 2 | 4 | $revisit =~ s/(\d+)s\w*/$1/i; | ||||
| 247 | 2 | 50 | 66 | 13 | push(@result, "#REVISIT: ".SeeAlso::Source::BeaconAggregator::tToISO($timestamp + $revisit)."\n") if $revisit && ($revisit =~ /^[+-]?\d+$/) && ($revisit > 0);; | ||
| 66 | |||||||
| 248 | |||||||
| 249 | # $beaconmeta{'UPDATE'} ||= "daily"; | ||||||
| 250 | 2 | 50 | 33 | 10 | $beaconmeta{'FEED'} ||= "$cgibase?format=".$Defaults{'beaconformatname'} if $cgibase; | ||
| 251 | 2 | 33 | 16 | $beaconmeta{'EXAMPLES'} ||= join("|", @osdexamples); | |||
| 252 | 2 | 33 | 8 | $beaconmeta{'CONTACT'} ||= $self->{Contact} || $osd{'Contact'}; | |||
| 33 | |||||||
| 253 | 2 | 33 | 8 | $beaconmeta{'DESCRIPTION'} ||= $self->{Description} || $osd{'Description'}; | |||
| 33 | |||||||
| 254 | 2 | 33 | 9 | $beaconmeta{'NAME'} ||= $self->{ShortName} || $osd{'ShortName'}; | |||
| 33 | |||||||
| 255 | 2 | 10 | foreach ( grep !/^(FORMAT|REVISIT|TARGET|TIMESTAMP|VERSION)$/, SeeAlso::Source::BeaconAggregator->beaconfields() ) { | ||||
| 256 | 32 | 100 | 44 | next unless my $val = $beaconmeta{$_}; | |||
| 257 | 6 | 50 | 10 | next if $val =~ /^-/; | |||
| 258 | 6 | 17 | $val =~ s/\s+/ /g; $val =~ s/^\s+//; $val =~ s/\s+$//; | ||||
| 6 | 9 | ||||||
| 6 | 7 | ||||||
| 259 | 6 | 13 | push(@result, "#$_: $val\n"); | ||||
| 260 | } | ||||||
| 261 | |||||||
| 262 | # extract admin info of last transaction (i.e. last possible modification of underlying data) | ||||||
| 263 | # alternatively: SELECT seqno, utime FROM repos WHERE seqno=(SELECT MAX(seqno) FROM repos); | ||||||
| 264 | 2 | 6 | my ($laststh, $laststhexpl) = $self->stmtHdl(<<"XxX"); | ||||
| 265 | SELECT MAX(seqno), MAX(mtime) FROM repos; | ||||||
| 266 | XxX | ||||||
| 267 | 2 | 50 | 3 | $self->stmtExplain($laststhexpl) if $ENV{'DBI_PROFILE'}; | |||
| 268 | 2 | 50 | 88 | $laststh->execute() or croak("Could not execute >".$laststh->{Statement}."<: ".$laststh->errstr); | |||
| 269 | 2 | 50 | 20 | if ( my $aryref = $laststh->fetchrow_arrayref ) { | |||
| 270 | 2 | 2 | my ($sq, $ut) = @$aryref; | ||||
| 271 | 2 | 50 | 13 | push(@result, "#X-REVISION: $sq [".SeeAlso::Source::BeaconAggregator::tToISO($ut)."]\n") if $sq; | |||
| 272 | }; | ||||||
| 273 | 2 | 6 | my $admref = $self->admhash(); | ||||
| 274 | 2 | 50 | 6 | if ( my $cu = $admref->{'gcountu'} ) { | |||
| 275 | 2 | 50 | 6 | my $type = $admref->{'IDENTIFIER_CLASS'} || ""; | |||
| 276 | 2 | 50 | 10 | push(@result, "#X-EXTENT: $cu unique identifiers".($type ? " of type $type" : "")."\n"); | |||
| 277 | }; | ||||||
| 278 | |||||||
| 279 | |||||||
| 280 | ## PND-BEACON | ||||||
| 281 | # CONTACT => ['VARCHAR(63)'], | ||||||
| 282 | # INSTITUTION => ['VARCHAR(255)'], | ||||||
| 283 | # ISIL => ['VARCHAR(63)'], | ||||||
| 284 | # DESCRIPTION => ['VARCHAR(255)'], | ||||||
| 285 | ## BEACON | ||||||
| 286 | # MESSAGE => ['VARCHAR(255)'], # enthaelt {hits} | ||||||
| 287 | # ONEMESSAGE => ['VARCHAR(255)'], | ||||||
| 288 | # SOMEMESSAGE => ['VARCHAR(255)'], | ||||||
| 289 | # PREFIX => ['VARCHAR(255)'], | ||||||
| 290 | ## WInofficial | ||||||
| 291 | # NAME => ['VARCHAR(255)'], | ||||||
| 292 | |||||||
| 293 | 2 | 11 | return $error, \@result; | ||||
| 294 | } | ||||||
| 295 | |||||||
| 296 | |||||||
| 297 | =head2 redirect ( $server, $format, $extra, $query ) | ||||||
| 298 | |||||||
| 299 | Produces an HTTP redirect page, HTML content contains very terse details in case | ||||||
| 300 | of multiple results. | ||||||
| 301 | |||||||
| 302 | This subroutine may be used as callback method in SeeAlso::Server | ||||||
| 303 | |||||||
| 304 | Usage is a bit cludgy due to author's lack of understanding of SeeAlso::Server | ||||||
| 305 | |||||||
| 306 | $source = SeeAlso::Sources::BeaconAggregator::Publisher->new(...); | ||||||
| 307 | $CGI = CGI->new(); | ||||||
| 308 | |||||||
| 309 | $formats = { | ||||||
| 310 | ... | ||||||
| 311 | redirect => { | ||||||
| 312 | type => "text/html", | ||||||
| 313 | docs => "http://www.endofthe.net/", | ||||||
| 314 | # method => \&SeeAlso::Source::BeaconAggregator::Publisher::redirect, | ||||||
| 315 | #redirect_300 => 'sources', | ||||||
| 316 | } | ||||||
| 317 | }; | ||||||
| 318 | |||||||
| 319 | $server = SeeAlso::Server->new ( | ||||||
| 320 | 'cgi' => $CGI, | ||||||
| 321 | 'formats' => $formats, | ||||||
| 322 | ... | ||||||
| 323 | ); | ||||||
| 324 | |||||||
| 325 | # Closure as fix: Server.pm does not expose self, $source and the CGI object to the format methods | ||||||
| 326 | my $oref = \&SeeAlso::Source::BeaconAggregator::Publisher::redirect; | ||||||
| 327 | $server->{'formats'}->{'redirect'}->{method} | ||||||
| 328 | = sub {return &$oref($source, $server, $method, $formats->{$method}, @_)}; | ||||||
| 329 | |||||||
| 330 | my $result = $server->query($source); | ||||||
| 331 | |||||||
| 332 | Arguments: | ||||||
| 333 | |||||||
| 334 | =over 8 | ||||||
| 335 | |||||||
| 336 | =item $server | ||||||
| 337 | |||||||
| 338 | SeeAlso::Server object. Must contain a CGI object | ||||||
| 339 | |||||||
| 340 | =item $format | ||||||
| 341 | |||||||
| 342 | Name of a format registered with the $server object () | ||||||
| 343 | |||||||
| 344 | =item $extra | ||||||
| 345 | |||||||
| 346 | Hashref with the following configuration directives | ||||||
| 347 | |||||||
| 348 | redirect_300 => CGI 'format' parameter to be used in HTML content (eg. format=sources) | ||||||
| 349 | |||||||
| 350 | force_single => Only regard the first hit (thus always redirect) | ||||||
| 351 | |||||||
| 352 | =item $query | ||||||
| 353 | |||||||
| 354 | Identifier to be queried | ||||||
| 355 | |||||||
| 356 | =back | ||||||
| 357 | |||||||
| 358 | =cut | ||||||
| 359 | |||||||
| 360 | sub redirect { # Liste der Beacon-Header fuer Treffer oder einfaches redirect | ||||||
| 361 | 0 | 0 | 1 | 0 | my ($self, $server, $format, $extra, $query) = @_; | ||
| 362 | 0 | 0 | 0 | my $formatprops = $server->{'formats'}->{$format} || {}; | |||
| 363 | 0 | 0 | 0 | my $cgi = $server->{'cgi'} or croak("I rely on a prepared CGI.pm object"); | |||
| 364 | |||||||
| 365 | my %headerdefaults = ( -type => ($formatprops->{'type'} || 'text/html'), | ||||||
| 366 | # ($formatprops->{'charset'} ? (-charset => $formatprops->{'charset'}) : ()), | ||||||
| 367 | -charset => ($formatprops->{'charset'} || 'UTF-8'), | ||||||
| 368 | 0 | 0 | 0 | -expires => ($server->{'expires'} || '+1h'), | |||
| 0 | |||||||
| 0 | |||||||
| 369 | ); | ||||||
| 370 | |||||||
| 371 | 0 | 0 | my ($hash, $pretty, $canon) = $self->prepare_query($query); | ||||
| 372 | 0 | 0 | 0 | unless ( $hash ) { | |||
| 373 | 0 | 0 | print $cgi->header(-status => "400 Bad Request (Identifier '$query' not valid)", | ||||
| 374 | -expires => "+1y", | ||||||
| 375 | -type => 'text/html', | ||||||
| 376 | ), | ||||||
| 377 | $cgi->start_html (-dtd => "-//W3C//DTD HTML 3.2 Final//EN", | ||||||
| 378 | -title => "No valid identifier", | ||||||
| 379 | ), | ||||||
| 380 | $cgi->p("Malformed identifier '$query'"), | ||||||
| 381 | $cgi->end_html; | ||||||
| 382 | 0 | 0 | return ""; | ||||
| 383 | }; | ||||||
| 384 | |||||||
| 385 | 0 | 0 | my $clusterid; | ||||
| 386 | 0 | 0 | 0 | if ( $self->{cluster} ) { | |||
| 387 | 0 | 0 | my ($clusterh, $clusterexpl) = $self->stmtHdl("SELECT beacons.altid FROM cluster.beacons WHERE beacons.hash=? OR beacons.altid=? LIMIT 1;"); | ||||
| 388 | 0 | 0 | 0 | $self->stmtExplain($clusterexpl, $hash, $hash) if $ENV{'DBI_PROFILE'}; | |||
| 389 | 0 | 0 | $clusterh->execute($hash, $hash); | ||||
| 390 | 0 | 0 | while ( my $onerow = $clusterh->fetchrow_arrayref() ) { | ||||
| 391 | 0 | 0 | $clusterid = $onerow->[0];} | ||||
| 392 | } | ||||||
| 393 | |||||||
| 394 | 0 | 0 | 0 | my $clause = $extra->{force_single} ? "LIMIT 1" : "ORDER BY repos.sort, repos.alias"; | |||
| 395 | 0 | 0 | my ( $tfield,$afield, $gfield, $mfield,$nfield,$ifield) = map{ scalar $self->beaconfields($_) } | ||||
| 0 | 0 | ||||||
| 396 | qw(TARGET ALTTARGET IMGTARGET MESSAGE NAME INSTITUTION); | ||||||
| 397 | # above 5 6 7 8 9 10 | ||||||
| 398 | # below 0 1 2 3 4 | ||||||
| 399 | # 11 | ||||||
| 400 | 0 | 0 | my ($sth, $sthexpl); | ||||
| 401 | 0 | 0 | 0 | if ( $clusterid ) { # query IN cluster | |||
| 402 | 0 | 0 | ($sth, $sthexpl) = $self->stmtHdl(<<"XxX"); | ||||
| 403 | SELECT beacons.hash, beacons.altid, beacons.hits, beacons.info, beacons.link, | ||||||
| 404 | repos.$tfield, repos.$afield, repos.$gfield, repos.$mfield, repos.$nfield, repos.$ifield, | ||||||
| 405 | repos.alias | ||||||
| 406 | FROM beacons NATURAL LEFT JOIN repos | ||||||
| 407 | WHERE ( (beacons.hash=?) | ||||||
| 408 | OR (beacons.hash IN (SELECT cluster.beacons.hash FROM cluster.beacons WHERE cluster.beacons.altid=?)) ) | ||||||
| 409 | $clause; | ||||||
| 410 | XxX | ||||||
| 411 | 0 | 0 | 0 | $self->stmtExplain($sthexpl, $clusterid, $clusterid) if $ENV{'DBI_PROFILE'}; | |||
| 412 | 0 | 0 | 0 | $sth->execute($clusterid, $clusterid) or croak("Could not execute >".$sth->{Statement}."<: ".$sth->errstr); | |||
| 413 | } | ||||||
| 414 | else { | ||||||
| 415 | 0 | 0 | ($sth, $sthexpl) = $self->stmtHdl(<<"XxX"); | ||||
| 416 | SELECT beacons.hash, beacons.altid, beacons.hits, beacons.info, beacons.link, | ||||||
| 417 | repos.$tfield, repos.$afield, repos.$gfield, repos.$mfield, repos.$nfield, repos.$ifield, | ||||||
| 418 | repos.alias | ||||||
| 419 | FROM beacons NATURAL LEFT JOIN repos | ||||||
| 420 | WHERE beacons.hash=? | ||||||
| 421 | $clause; | ||||||
| 422 | XxX | ||||||
| 423 | 0 | 0 | 0 | $self->stmtExplain($sthexpl, $hash) if $ENV{'DBI_PROFILE'}; | |||
| 424 | 0 | 0 | 0 | $sth->execute($hash) or croak("Could not execute >".$sth->{Statement}."<: ".$sth->errstr); | |||
| 425 | } | ||||||
| 426 | |||||||
| 427 | 0 | 0 | 0 | my $c = $self->{identifierClass} || undef; | |||
| 428 | 0 | 0 | my @rawres; | ||||
| 429 | my %didalready; | ||||||
| 430 | 0 | 0 | while ( my $onerow = $sth->fetchrow_arrayref ) { | ||||
| 431 | 0 | 0 | 0 | 0 | next if $onerow->[11] && exists $self->{'aliasfilter'}->{$onerow->[11]}; | ||
| 432 | 0 | 0 | my $uri = $onerow->[4]; # Evtl. Expliziter Link | ||||
| 433 | 0 | 0 | my $guri = ""; | ||||
| 434 | |||||||
| 435 | 0 | 0 | my $h = $onerow->[0]; | ||||
| 436 | 0 | 0 | my $p; | ||||
| 437 | 0 | 0 | 0 | 0 | if ( $h eq $hash ) { | ||
| 0 | |||||||
| 438 | 0 | 0 | $p = $pretty} | ||||
| 439 | elsif ( $clusterid && ref($c) ) { | ||||||
| 440 | 0 | 0 | $c->value(""); | ||||
| 441 | 0 | 0 | 0 | my $did = $c->hash($h) || $c->value($h) || $h; | |||
| 442 | 0 | 0 | 0 | $p = $c->can("pretty") ? $c->pretty() : $c->value(); | |||
| 443 | }; | ||||||
| 444 | 0 | 0 | 0 | $p = ($clusterid ? $h : $pretty) unless defined $p; | |||
| 0 | |||||||
| 445 | |||||||
| 446 | 0 | 0 | 0 | if ( $onerow->[1] ) { # Konkordanzformat | |||
| 0 | |||||||
| 447 | 0 | 0 | 0 | $uri ||= sprintf($onerow->[6] || $onerow->[5], $p, SeeAlso::Source::BeaconAggregator::urlpseudoescape($onerow->[1])); | |||
| 0 | |||||||
| 448 | 0 | 0 | 0 | $guri = sprintf($onerow->[7], $p, SeeAlso::Source::BeaconAggregator::urlpseudoescape($onerow->[1])) if $onerow->[7]; | |||
| 449 | } | ||||||
| 450 | elsif ( $onerow->[5] ) { # normales Beacon-Format | ||||||
| 451 | 0 | 0 | 0 | $uri ||= sprintf($onerow->[5], $p); | |||
| 452 | 0 | 0 | 0 | $guri = sprintf($onerow->[7], $p) if $onerow->[7]; | |||
| 453 | }; | ||||||
| 454 | 0 | 0 | 0 | next unless $uri; | |||
| 455 | |||||||
| 456 | # #NAME #INSTITUTION _alias | ||||||
| 457 | 0 | 0 | my $label; | ||||
| 458 | 0 | 0 | 0 | 0 | if ( $label = $onerow->[8] ) { #MESSAGE | ||
| 0 | |||||||
| 459 | 0 | 0 | 0 | $label = sprintf($label, $onerow->[2] || "...")} | |||
| 460 | elsif ( $label = $onerow->[9] || $onerow->[10] || $onerow->[11] || "???" ) { | ||||||
| 461 | 0 | 0 | 0 | $label .= " (".$onerow->[1].")" if $onerow->[1]} | |||
| 462 | |||||||
| 463 | 0 | 0 | 0 | push(@rawres, [$uri, $guri, $label, $onerow->[11], $onerow->[3]]) unless $didalready{join("\x7f", $label, $uri)}++;; | |||
| 464 | }; | ||||||
| 465 | 0 | 0 | my $hits = scalar @rawres; | ||||
| 466 | |||||||
| 467 | 0 | 0 | 0 | if ( ! $hits ) { | |||
| 0 | |||||||
| 468 | 0 | 0 | print $cgi->header(-status => "404 Not Found (identifier '$canon')", | ||||
| 469 | %headerdefaults), | ||||||
| 470 | $cgi->start_html (-dtd => "-//W3C//DTD HTML 3.2 Final//EN", | ||||||
| 471 | -title => "No References for $pretty", | ||||||
| 472 | ), | ||||||
| 473 | $cgi->p("No References found for ", $cgi->a({href=>"$canon"}, $pretty)), | ||||||
| 474 | $cgi->end_html; | ||||||
| 475 | 0 | 0 | return ""; | ||||
| 476 | } | ||||||
| 477 | elsif ( $hits == 1 ) { | ||||||
| 478 | 0 | 0 | return $cgi->redirect(-status => "302 Found (Redirecting for identifier '$canon')", | ||||
| 479 | -uri => $rawres[0]->[0], | ||||||
| 480 | %headerdefaults); | ||||||
| 481 | } | ||||||
| 482 | |||||||
| 483 | 0 | 0 | my $sources = new CGI($cgi); | ||||
| 484 | 0 | 0 | $sources->param(-name => 'id', -value=>"$canon"); | ||||
| 485 | 0 | 0 | 0 | unless ( $canon =~ /:\/\// ) { | |||
| 486 | 0 | 0 | my ($osd, $beaconmeta) = $self->get_meta; | ||||
| 487 | 0 | 0 | 0 | my $prefix = $beaconmeta->{'PREFIX'} || ""; | |||
| 488 | 0 | 0 | 0 | $canon = "$prefix$pretty" if $prefix; | |||
| 489 | }; | ||||||
| 490 | 0 | 0 | 0 | if ( my $multired = $extra->{redirect_300} ) { | |||
| 491 | 0 | 0 | $sources->param(-name => 'format', -value=>$multired); | ||||
| 492 | 0 | 0 | print $cgi->redirect(-status => "300 Multiple Choices for identifier '$canon'", | ||||
| 493 | -uri => $sources->url(-path_info=>1, -query=>1), | ||||||
| 494 | %headerdefaults); | ||||||
| 495 | } | ||||||
| 496 | else { | ||||||
| 497 | 0 | 0 | print $cgi->header(-status => "300 Multiple Choices for identifier '$canon'", | ||||
| 498 | # -nph => 1, # for older CGI/mod_perl??? | ||||||
| 499 | %headerdefaults); | ||||||
| 500 | # mod_perl overrides the header and adds a custom document at the end of everything | ||||||
| 501 | # therefore we force the header out (a simple print "" does not suffice) and then can | ||||||
| 502 | # safely reset the status to OK via CGI.pm leaking the Apache2::Request object | ||||||
| 503 | 0 | 0 | 0 | if ( my $r = $sources->r ) { | |||
| 504 | 0 | 0 | local($|) = 1; | ||||
| 505 | 0 | 0 | print "\n"; | ||||
| 506 | 0 | 0 | $r->status(200); | ||||
| 507 | }; | ||||||
| 508 | }; | ||||||
| 509 | 0 | 0 | my @result; | ||||
| 510 | 0 | 0 | push(@result, $cgi->start_html ( -title => "$hits References for $pretty", | ||||
| 511 | -dtd => "-//W3C//DTD HTML 3.2 Final//EN"), | ||||||
| 512 | $cgi->h1("$hits References for ", $cgi->a({href=>"$canon"}, $pretty)), | ||||||
| 513 | '
|
||||||
| 514 | |||||||
| 515 | 0 | 0 | my $rowcnt = 0; | ||||
| 516 | 0 | 0 | foreach ( @rawres ) { # uri, guri, label, alias, info | ||||
| 517 | 0 | 0 | 0 | if ( $_->[1] ) { | |||
| 518 | 0 | 0 | 0 | my $tooltip = $_->[4] ? ($_->[4]." [".$_->[2]."]") : $_->[2]; | |||
| 519 | 0 | 0 | 0 | my $img = $cgi->a({href=>$_->[0], title=>$tooltip}, $cgi->img({src=>$_->[1], alt=>$_->[4]||$_->[2], style=>"width: 5em; border: 0pt;"})); | |||
| 520 | 0 | 0 | 0 | push(@result, $cgi->li({id=>"$_->[3]".++$rowcnt}, $img, $cgi->a({href=>$_->[0]}, $_->[2]), ($_->[4] ? " [".$_->[4]."]" : ""))); | |||
| 521 | } | ||||||
| 522 | else { | ||||||
| 523 | 0 | 0 | 0 | push(@result, $cgi->li({id=>"$_->[3]".++$rowcnt}, $cgi->a({href=>$_->[0]}, $_->[2]), $_->[4] ? " [".$_->[4]."]" : ""))}; | |||
| 524 | }; | ||||||
| 525 | |||||||
| 526 | 0 | 0 | push(@result, ''); | ||||
| 527 | |||||||
| 528 | 0 | 0 | 0 | if ( $server->{'formats'}->{'sources'} ) { | |||
| 529 | 0 | 0 | $sources->param(-name => 'format', -value=>"sources"); | ||||
| 530 | 0 | 0 | push(@result, $cgi->p("[", $cgi->a({href=>($sources->url(-path_info=>1, -query=>1))}, "Details"), "]")); | ||||
| 531 | }; | ||||||
| 532 | |||||||
| 533 | 0 | 0 | my($tu, $ts, $tcu, $tcs) = times(); | ||||
| 534 | 0 | 0 | push(@result, sprintf("", $tu, $ts, $tu+$ts), $cgi->end_html()); | ||||
| 535 | 0 | 0 | return join("\n", @result); | ||||
| 536 | } | ||||||
| 537 | |||||||
| 538 | =head2 sources ( $server, $format, $extra, $query ) | ||||||
| 539 | |||||||
| 540 | Produces an HTML page with details to the queried identifier (description of sources) | ||||||
| 541 | |||||||
| 542 | This subroutine may be used as callback method in SeeAlso::Server (cf. description | ||||||
| 543 | of redirect above | ||||||
| 544 | |||||||
| 545 | =over 8 | ||||||
| 546 | |||||||
| 547 | =item $server | ||||||
| 548 | |||||||
| 549 | SeeAlso::Server object | ||||||
| 550 | |||||||
| 551 | |||||||
| 552 | =item $format | ||||||
| 553 | |||||||
| 554 | Format selected for $server | ||||||
| 555 | |||||||
| 556 | |||||||
| 557 | =item $extra | ||||||
| 558 | |||||||
| 559 | Hashref with the following configuration directives | ||||||
| 560 | |||||||
| 561 | css => URL of css file to be referenced | ||||||
| 562 | |||||||
| 563 | =item $query | ||||||
| 564 | |||||||
| 565 | Identifier to be queried | ||||||
| 566 | |||||||
| 567 | =back | ||||||
| 568 | |||||||
| 569 | =cut | ||||||
| 570 | |||||||
| 571 | sub sources { # Liste der Beacon-Header fuer Treffer | ||||||
| 572 | # We escape all characters except US-ASCII, because older CGI.pm's set an xml declaration | ||||||
| 573 | # which somehow interferes with IE8's adherence to the character set... | ||||||
| 574 | 0 | 0 | 1 | 0 | my ($self, $server, $format, $extra, $query) = @_; | ||
| 575 | 0 | 0 | 0 | my $formatprops = $server->{'formats'}->{$format} || {}; | |||
| 576 | 0 | 0 | 0 | my $cgi = $server->{'cgi'} || CGI->new(); | |||
| 577 | |||||||
| 578 | 0 | 0 | my ($hash, $pretty, $canon) = $self->prepare_query($query); | ||||
| 579 | 0 | 0 | 0 | unless ( $hash ) { | |||
| 580 | 0 | 0 | print $cgi->header(-status => "400 Bad Request (Identifier '$query' not valid)", | ||||
| 581 | -expires => "+1y", | ||||||
| 582 | -type => 'text/html', | ||||||
| 583 | ), | ||||||
| 584 | $cgi->start_html (-dtd => "-//W3C//DTD HTML 3.2 Final//EN", | ||||||
| 585 | -title => "No valid identifier", | ||||||
| 586 | ), | ||||||
| 587 | $cgi->p("Malformed identifier '$query'"), | ||||||
| 588 | $cgi->end_html; | ||||||
| 589 | 0 | 0 | return ""; | ||||
| 590 | }; | ||||||
| 591 | |||||||
| 592 | 0 | 0 | my ($clusterid, %idlist); | ||||
| 593 | 0 | 0 | 0 | my $c = $self->{identifierClass} || undef; | |||
| 594 | 0 | 0 | 0 | if ( $self->{cluster} ) { | |||
| 595 | 0 | 0 | my ($clusterh, $clusterexpl) = $self->stmtHdl("SELECT beacons.hash, beacons.altid FROM cluster.beacons WHERE beacons.hash=? OR beacons.altid=? LIMIT 1;"); | ||||
| 596 | 0 | 0 | 0 | $self->stmtExplain($clusterexpl, $hash, $hash) if $ENV{'DBI_PROFILE'}; | |||
| 597 | 0 | 0 | 0 | $clusterh->execute($hash, $hash) or croak("Could not execute >".$clusterh->{Statement}."<: ".$clusterh->errstr); | |||
| 598 | 0 | 0 | while ( my $onerow = $clusterh->fetchrow_arrayref() ) { | ||||
| 599 | 0 | 0 | $clusterid = $onerow->[1]; | ||||
| 600 | 0 | 0 | my $h = $onerow->[0]; | ||||
| 601 | 0 | 0 | 0 | if ( $c ) { | |||
| 602 | 0 | 0 | $c->value(""); | ||||
| 603 | 0 | 0 | 0 | my $did = $c->hash($h) || $c->value($h); | |||
| 604 | 0 | 0 | 0 | my $p = $c->can("pretty") ? $c->pretty() : $c->value(); | |||
| 605 | 0 | 0 | $idlist{$p} = ""; | ||||
| 606 | } | ||||||
| 607 | else { | ||||||
| 608 | 0 | 0 | $idlist{$h} = ""; | ||||
| 609 | } | ||||||
| 610 | }; | ||||||
| 611 | 0 | 0 | $idlist{$pretty} = "queriedid"; | ||||
| 612 | 0 | 0 | 0 | if ( $clusterid ) { | |||
| 613 | 0 | 0 | 0 | if ( $clusterid eq $hash ) { | |||
| 0 | |||||||
| 614 | 0 | 0 | $idlist{$pretty} .= " preferredid"} | ||||
| 615 | elsif ( $c ) { | ||||||
| 616 | 0 | 0 | $c->value(""); | ||||
| 617 | 0 | 0 | 0 | my $did = $c->hash($clusterid) || $c->value($clusterid); | |||
| 618 | 0 | 0 | 0 | my $p = $c->can("pretty") ? $c->pretty() : $c->value(); | |||
| 619 | 0 | 0 | $idlist{$p} = "variantid preferredid"; | ||||
| 620 | } | ||||||
| 621 | else { | ||||||
| 622 | 0 | 0 | $idlist{$clusterid} = "variantid preferredid"; | ||||
| 623 | }; | ||||||
| 624 | 0 | 0 | my ($varianth, $variantexpl) = $self->stmtHdl("SELECT beacons.hash FROM cluster.beacons WHERE beacons.altid=?;"); | ||||
| 625 | 0 | 0 | 0 | $self->stmtExplain($variantexpl, $clusterid) if $ENV{'DBI_PROFILE'}; | |||
| 626 | 0 | 0 | 0 | $varianth->execute($clusterid) or croak("Could not execute >".$varianth->{Statement}."<: ".$varianth->errstr); | |||
| 627 | 0 | 0 | while ( my $onerow = $varianth->fetchrow_arrayref() ) { | ||||
| 628 | 0 | 0 | my $v = $onerow->[0]; | ||||
| 629 | 0 | 0 | 0 | if ( $c ) { | |||
| 630 | 0 | 0 | $c->value(""); | ||||
| 631 | 0 | 0 | 0 | my $did = $c->hash($v) || $c->value($v); | |||
| 632 | 0 | 0 | 0 | my $p = $c->can("pretty") ? $c->pretty() : $c->value(); | |||
| 633 | 0 | 0 | 0 | (exists $idlist{$p}) || ($idlist{$p} = "variantid"); | |||
| 634 | } | ||||||
| 635 | else { | ||||||
| 636 | 0 | 0 | 0 | (exists $idlist{$v}) || ($idlist{$v} = "variantid"); | |||
| 637 | } | ||||||
| 638 | } | ||||||
| 639 | } | ||||||
| 640 | } | ||||||
| 641 | |||||||
| 642 | 0 | 0 | my ($countsth, $countexpl); | ||||
| 643 | 0 | 0 | 0 | if ( $clusterid ) { | |||
| 644 | 0 | 0 | ($countsth, $countexpl) = $self->stmtHdl(<<"XxX"); | ||||
| 645 | SELECT COUNT(DISTINCT seqno) FROM beacons | ||||||
| 646 | WHERE ( (hash=?) OR (hash IN (SELECT beacons.hash FROM cluster.beacons WHERE cluster.beacons.altid=?)) ); | ||||||
| 647 | XxX | ||||||
| 648 | 0 | 0 | 0 | $self->stmtExplain($countexpl, $clusterid, $clusterid) if $ENV{'DBI_PROFILE'}; | |||
| 649 | 0 | 0 | 0 | $countsth->execute($clusterid, $clusterid) or croak("Could not execute >".$countsth->{Statement}."<: ".$countsth->errstr); | |||
| 650 | } | ||||||
| 651 | else { | ||||||
| 652 | 0 | 0 | ($countsth, $countexpl) = $self->stmtHdl(<<"XxX"); | ||||
| 653 | SELECT COUNT(DISTINCT seqno) FROM beacons WHERE hash=?; | ||||||
| 654 | XxX | ||||||
| 655 | 0 | 0 | 0 | $self->stmtExplain($countexpl, $hash) if $ENV{'DBI_PROFILE'}; | |||
| 656 | 0 | 0 | 0 | $countsth->execute($hash) or croak("Could not execute >".$countsth->{Statement}."<: ".$countsth->errstr); | |||
| 657 | }; | ||||||
| 658 | 0 | 0 | my $hitsref = $countsth->fetchrow_arrayref; | ||||
| 659 | 0 | 0 | 0 | my $hits = $hitsref->[0] || 0; | |||
| 660 | |||||||
| 661 | 0 | 0 | my ($osd, $beaconmeta) = $self->get_meta; | ||||
| 662 | 0 | 0 | 0 | my $prefix = $beaconmeta->{'PREFIX'} || ""; | |||
| 663 | 0 | 0 | 0 | (my $servicename = $beaconmeta->{'NAME'} || $osd->{'ShortName'} || "") =~ s/([<>&"]|[^\x00-\x7f])/''.ord($1).';'/ge; | |||
| 0 | 0 | ||||||
| 664 | |||||||
| 665 | 0 | 0 | my $target = $cgi->url(-path=>1); | ||||
| 666 | |||||||
| 667 | 0 | 0 | my @result; | ||||
| 668 | push(@result, $cgi->start_html( | ||||||
| 669 | -encoding => "UTF-8", | ||||||
| 670 | -title => "$servicename referring ".$query->as_string(), | ||||||
| 671 | -meta => {'robots'=>'noindex'}, | ||||||
| 672 | 0 | 0 | 0 | ($extra->{'css'} ? (-style => {'src'=>$extra->{'css'}}) : ()), | |||
| 673 | -head => [$cgi->Link({-rel=>'unapi-server', | ||||||
| 674 | -type=>'application/xml', | ||||||
| 675 | title=>'unAPI', | ||||||
| 676 | -href=>$target}), | ||||||
| 677 | $cgi->Link({-rel=>'start', | ||||||
| 678 | -href=>$target}), | ||||||
| 679 | ], | ||||||
| 680 | )); | ||||||
| 681 | |||||||
| 682 | 0 | 0 | push(@result, ''); | ||||
| 683 | 0 | 0 | push(@result, ''); | ||||
| 684 | |||||||
| 685 | 0 | 0 | push(@result, $cgi->h1("$hits References for ".$cgi->abbr({class=>"unapi-id", title=>"$canon"}, $query))); | ||||
| 686 | |||||||
| 687 | 0 | 0 | push(@result, ' '); |
||||
| 688 | 0 | 0 | 0 | push(@result, $cgi->p($cgi->span("Identifier:"), $cgi->a({href=>"$prefix$pretty"}, "$prefix$pretty"))) if $prefix; | |||
| 689 | # delete $idlist{$pretty} if $prefix; | ||||||
| 690 | 0 | 0 | 0 | 0 | push(@result, $cgi->p($cgi->span("Variant Identifiers:"), map {$cgi->span({class=>($idlist{$_} || "variantid")}, $_)} sort keys %idlist)) if %idlist; | ||
| 0 | 0 | ||||||
| 691 | 0 | 0 | push(@result, ''); | ||||
| 692 | |||||||
| 693 | 0 | 0 | my ($srcsth, $srcexpl); | ||||
| 694 | 0 | 0 | 0 | if ( $clusterid ) { | |||
| 695 | 0 | 0 | ($srcsth, $srcexpl) = $self->stmtHdl(<<"XxX"); | ||||
| 696 | SELECT beacons.*, repos.* | ||||||
| 697 | FROM beacons NATURAL LEFT JOIN repos | ||||||
| 698 | WHERE ( (beacons.hash=?) | ||||||
| 699 | OR (beacons.hash IN (SELECT beacons.hash FROM cluster.beacons WHERE cluster.beacons.altid=?)) ) | ||||||
| 700 | ORDER BY repos.sort, repos.alias; | ||||||
| 701 | XxX | ||||||
| 702 | 0 | 0 | 0 | $self->stmtExplain($srcexpl, $clusterid, $clusterid) if $ENV{'DBI_PROFILE'}; | |||
| 703 | 0 | 0 | 0 | $srcsth->execute($clusterid, $clusterid) or croak("Could not execute >".$srcsth->{Statement}."<: ".$srcsth->errstr); | |||
| 704 | } | ||||||
| 705 | else { | ||||||
| 706 | 0 | 0 | ($srcsth, $srcexpl) = $self->stmtHdl(<<"XxX"); | ||||
| 707 | SELECT beacons.*, repos.* | ||||||
| 708 | FROM beacons NATURAL LEFT JOIN repos | ||||||
| 709 | WHERE beacons.hash=? | ||||||
| 710 | ORDER BY repos.sort, repos.alias; | ||||||
| 711 | XxX | ||||||
| 712 | 0 | 0 | 0 | $self->stmtExplain($srcexpl, $hash) if $ENV{'DBI_PROFILE'}; | |||
| 713 | 0 | 0 | 0 | $srcsth->execute($hash) or croak("Could not execute >".$srcsth->{Statement}."<: ".$srcsth->errstr); | |||
| 714 | } | ||||||
| 715 | |||||||
| 716 | 0 | 0 | my $rows = 0; | ||||
| 717 | 0 | 0 | push(@result, ' '); |
||||
| 718 | 0 | 0 | my ($lastseq, @groups) = (0, ()); | ||||
| 719 | 0 | 0 | while ( my $onerow = $srcsth->fetchrow_hashref ) { | ||||
| 720 | 0 | 0 | $rows ++; | ||||
| 721 | 0 | 0 | 0 | 0 | if ( $lastseq and $onerow->{'seqno'} == $lastseq ) { | ||
| 722 | 0 | 0 | my %vary; | ||||
| 723 | 0 | 0 | foreach my $key ( grep /^(hash|altid|hits|info|link)$/, keys %$onerow ) { | ||||
| 724 | 0 | 0 | my $pval = $onerow->{$key}; | ||||
| 725 | 0 | 0 | 0 | next unless defined $pval; | |||
| 726 | 0 | 0 | 0 | $pval =~ s/([<>&"]|[^\x00-\x7f])/''.ord($1).';'/ge if $key eq "link"; | |||
| 0 | 0 | ||||||
| 727 | 0 | 0 | $vary{$key} = $pval; | ||||
| 728 | } | ||||||
| 729 | 0 | 0 | push(@{$groups[$#groups]}, \%vary); | ||||
| 0 | 0 | ||||||
| 730 | } | ||||||
| 731 | else { | ||||||
| 732 | 0 | 0 | my (%vary, %repos, %meta); | ||||
| 733 | 0 | 0 | while ( my($key, $val) = each %$onerow ) { | ||||
| 734 | 0 | 0 | my $pval = $val; | ||||
| 735 | 0 | 0 | 0 | unless ( $key =~ /altid|feed|target|uri|link/i ) { | |||
| 736 | 0 | 0 | 0 | $pval =~ s/([<>&"]|[^\x00-\x7f])/''.ord($1).';'/ge if defined $pval}; | |||
| 0 | 0 | ||||||
| 737 | 0 | 0 | 0 | if ( $key =~ /time|revisit/i ) { | |||
| 738 | 0 | 0 | 0 | next unless $val; | |||
| 739 | 0 | 0 | $pval = HTTP::Date::time2str($val); | ||||
| 740 | }; | ||||||
| 741 | 0 | 0 | 0 | if ( $key =~ /^bc(\w+)$/ ) { | |||
| 0 | |||||||
| 742 | 0 | 0 | 0 | $repos{$1} = $pval if $pval} | |||
| 743 | elsif ( $key =~ /^(hash|altid|hits|info|link)$/ ) { | ||||||
| 744 | 0 | 0 | $vary{$key} = $pval} | ||||
| 745 | else { | ||||||
| 746 | 0 | 0 | 0 | $meta{"_$key"} = $pval if $pval} | |||
| 747 | }; | ||||||
| 748 | 0 | 0 | push(@groups, [\%repos, \%meta, \%vary]); | ||||
| 749 | }; | ||||||
| 750 | 0 | 0 | $lastseq = $onerow->{'seqno'}; | ||||
| 751 | }; | ||||||
| 752 | # Grouping done, now display... | ||||||
| 753 | |||||||
| 754 | 0 | 0 | my %didalreadysee; | ||||
| 755 | 0 | 0 | foreach my $groupref ( @groups ) { | ||||
| 756 | 0 | 0 | my ($repos, $meta, @vary) = @$groupref; | ||||
| 757 | |||||||
| 758 | 0 | 0 | 0 | my $aos = $meta->{'_alias'} || $meta->{'_seqno'}; | |||
| 759 | |||||||
| 760 | 0 | 0 | 0 | my $multi = (scalar @vary > 1) ? "multi" : "single"; | |||
| 761 | 0 | 0 | push(@result, qq! !); |
||||
| 762 | 0 | 0 | push(@result, $cgi->h3({class=>"aggregator", onClick=>"toggle('ag$aos')"}, "Administrative Details")); | ||||
| 763 | |||||||
| 764 | 0 | 0 | push(@result, $cgi->h3({class=>"beacon", onClick=>"toggle('bc$aos')"}, "Repository Details")); | ||||
| 765 | |||||||
| 766 | 0 | 0 | 0 | if ( $multi eq "single" ) { | |||
| 767 | 0 | 0 | push(@result, $cgi->h3({class=>"hit", onClick=>"toggle('ht$aos')"}, "Result Details")); | ||||
| 768 | |||||||
| 769 | 0 | 0 | my $vary = $vary[0]; | ||||
| 770 | |||||||
| 771 | 0 | 0 | my $hits = $vary->{'hits'}; | ||||
| 772 | 0 | 0 | my $description = $hits; | ||||
| 773 | |||||||
| 774 | 0 | 0 | my $h = $vary->{'hash'}; | ||||
| 775 | 0 | 0 | 0 | my $variantid = ($h eq $hash) ? "" : "variantid"; | |||
| 776 | 0 | 0 | my $p; | ||||
| 777 | 0 | 0 | 0 | 0 | if ( $h eq $hash ) { | ||
| 0 | |||||||
| 778 | 0 | 0 | $p = $pretty} | ||||
| 779 | elsif ( $clusterid && ref($c) ) { | ||||||
| 780 | 0 | 0 | $c->value(""); | ||||
| 781 | 0 | 0 | 0 | my $did = $c->hash($h) || $c->value($h) || $h; | |||
| 782 | 0 | 0 | 0 | $p = $c->can("pretty") ? $c->pretty() : $c->value(); | |||
| 783 | }; | ||||||
| 784 | 0 | 0 | 0 | $p = ($clusterid ? $h : $pretty) unless defined $p; | |||
| 0 | |||||||
| 785 | |||||||
| 786 | 0 | 0 | my $uri = "???"; | ||||
| 787 | 0 | 0 | 0 | 0 | if ( $uri = $vary->{'link'} ) { # o.k. | ||
| 0 | |||||||
| 0 | |||||||
| 0 | |||||||
| 788 | } | ||||||
| 789 | elsif ( $repos->{'ALTTARGET'} && $vary->{'altid'} ) { | ||||||
| 790 | 0 | 0 | $uri = sprintf($repos->{'ALTTARGET'}, $p, SeeAlso::Source::BeaconAggregator::urlpseudoescape($vary->{'altid'}))} | ||||
| 791 | elsif ( $repos->{'TARGET'} ) { | ||||||
| 792 | 0 | 0 | $uri = sprintf($repos->{'TARGET'}, $p)} | ||||
| 793 | elsif ( $repos->{'ALTTARGET'} ) { | ||||||
| 794 | 0 | 0 | $uri = sprintf($repos->{'ALTTARGET'}, $p, SeeAlso::Source::BeaconAggregator::urlpseudoescape($p))}; | ||||
| 795 | |||||||
| 796 | 0 | 0 | 0 | my $redundant = ($didalreadysee{$uri}++) ? "subsequent" : ""; | |||
| 797 | |||||||
| 798 | 0 | 0 | my $guri = ""; | ||||
| 799 | 0 | 0 | 0 | if ( $repos->{'IMGTARGET'} ) { | |||
| 800 | 0 | 0 | $guri = sprintf($repos->{'IMGTARGET'}, $p, SeeAlso::Source::BeaconAggregator::urlpseudoescape($vary->{'altid'}))} | ||||
| 801 | |||||||
| 802 | 0 | 0 | 0 | my @labels = grep /\S/, $repos->{'NAME'} || "", $repos->{'DESCRIPTION'} || "", $repos->{'INSTITUTION'} || ""; | |||
| 0 | |||||||
| 0 | |||||||
| 803 | 0 | 0 | my $rlabel; | ||||
| 804 | 0 | 0 | 0 | if ( $hits == 1 ) { | |||
| 0 | |||||||
| 805 | 0 | 0 | 0 | $rlabel = $repos->{'ONEMESSAGE'} if $repos->{'ONEMESSAGE'}} | |||
| 806 | elsif ( $hits == 0 ) { | ||||||
| 807 | 0 | 0 | 0 | $rlabel = $repos->{'SOMEMESSAGE'} if $repos->{'SOMEMESSAGE'}}; | |||
| 808 | 0 | 0 | 0 | unless ( $rlabel ) { | |||
| 809 | 0 | 0 | 0 | $rlabel = $repos->{'MESSAGE'} || shift @labels || "???"}; | |||
| 810 | 0 | 0 | my $label = sprintf($rlabel, $hits); | ||||
| 811 | |||||||
| 812 | 0 | 0 | 0 | my $ttip = pop @labels || ""; | |||
| 813 | 0 | 0 | $ttip =~ s/(\d+);/chr($1)/ge; | ||||
| 0 | 0 | ||||||
| 814 | |||||||
| 815 | 0 | 0 | 0 | 0 | push(@result, $cgi->a({style=>"float: right; clear: right;", href=>$uri}, $cgi->img({alt=>$vary->{'info'}||$label,src=>$guri}))) if $guri; | ||
| 816 | |||||||
| 817 | 0 | 0 | push(@result, $cgi->h2({class=>"label $redundant $variantid ident_$p", id=>"head$aos"}, $cgi->a({href=>$uri, title=>$ttip}, $label))); | ||||
| 818 | |||||||
| 819 | 0 | 0 | push(@result, qq! !); |
||||
| 820 | 0 | 0 | 0 | push(@result, $cgi->span($vary->{'info'})) if $vary->{'info'}; | |||
| 821 | 0 | 0 | 0 | 0 | push(@result, $cgi->span("($hits Treffer)")) if $hits && ($rlabel !~ /%s/); | ||
| 822 | 0 | 0 | push(@result, ''); | ||||
| 823 | |||||||
| 824 | 0 | 0 | push(@result, qq! | ||||
| 825 | 0 | 0 | push(@result, $cgi->p({class=>"ht_uri"}, $cgi->span("Target URL:"), $cgi->a({href=>$uri}, CGI::escapeHTML($uri)))); | ||||
| 826 | 0 | 0 | 0 | push(@result, $cgi->p({class=>"ht_guri"}, $cgi->span("Preview URL:"), $cgi->a({href=>$guri}, $guri))) if $guri; | |||
| 827 | 0 | 0 | 0 | push(@result, $cgi->p({class=>"ht_hits"}, $cgi->span("Hits:"), $hits)) if $hits; | |||
| 828 | 0 | 0 | 0 | push(@result, $cgi->p({class=>"ht_info"}, $cgi->span("Additional Info:"), $vary->{'info'})) if $vary->{'info'}; | |||
| 829 | 0 | 0 | 0 | push(@result, $cgi->p({class=>"ht_idnote"}, $cgi->span("Variant Identifier:"), $p)) if $variantid; | |||
| 830 | 0 | 0 | push(@result, ''); | ||||
| 831 | } | ||||||
| 832 | else { | ||||||
| 833 | 0 | 0 | push(@result, $cgi->h3({class=>"hit", onClick=>"mtoggle('res$aos', 'hit')"}, "Result Details")); | ||||
| 834 | 0 | 0 | my $hits = scalar @vary; | ||||
| 835 | |||||||
| 836 | 0 | 0 | 0 | my @labels = grep /\S/, $repos->{'NAME'} || "", $repos->{'DESCRIPTION'} || "", $repos->{'INSTITUTION'} || ""; | |||
| 0 | |||||||
| 0 | |||||||
| 837 | 0 | 0 | 0 | my $rlabel = $repos->{'MESSAGE'} || shift @labels || "???"; | |||
| 838 | 0 | 0 | 0 | my $ttip = pop @labels || ""; | |||
| 839 | 0 | 0 | $ttip =~ s/(\d+);/chr($1)/ge; | ||||
| 0 | 0 | ||||||
| 840 | |||||||
| 841 | # my $rlabel = $repos->{'SOMEMESSAGE'} || $repos->{'MESSAGE'} || $repos->{'DESCRIPTION'} || $repos->{'NAME'} || $repos->{'INSTITUTION'} || "???"; | ||||||
| 842 | |||||||
| 843 | # my $ttip = $repos->{'MESSAGE'} ? $repos->{'DESCRIPTION'} || $repos->{'NAME'} || $repos->{'INSTITUTION'} || "" | ||||||
| 844 | |||||||
| 845 | # : $repos->{'INSTITUTION'} || $repos->{'NAME'} || ""; | ||||||
| 846 | |||||||
| 847 | # $ttip = "" if $ttip eq $rlabel; | ||||||
| 848 | 0 | 0 | $ttip =~ s/(\d+);/chr($1)/ge; | ||||
| 0 | 0 | ||||||
| 849 | |||||||
| 850 | 0 | 0 | my $label = sprintf($rlabel, $hits); | ||||
| 851 | 0 | 0 | push(@result, $cgi->h2({class=>"label", id=>"head$aos"}, $label)); | ||||
| 852 | |||||||
| 853 | 0 | 0 | push(@result, qq!
|
||||
| 854 | 0 | 0 | my $cnt = 0; | ||||
| 855 | 0 | 0 | foreach my $vary ( @vary ) { | ||||
| 856 | 0 | 0 | $cnt ++; | ||||
| 857 | |||||||
| 858 | 0 | 0 | my $h = $vary->{'hash'}; | ||||
| 859 | 0 | 0 | 0 | my $variantid = ($h eq $hash) ? "" : "variantid"; | |||
| 860 | 0 | 0 | my $p; | ||||
| 861 | 0 | 0 | 0 | 0 | if ( $h eq $hash ) { | ||
| 0 | |||||||
| 862 | 0 | 0 | $p = $pretty} | ||||
| 863 | elsif ( $clusterid && ref($c) ) { | ||||||
| 864 | 0 | 0 | $c->value(""); | ||||
| 865 | 0 | 0 | 0 | my $did = $c->hash($h) || $c->value($h) || $h; | |||
| 866 | 0 | 0 | 0 | $p = $c->can("pretty") ? $c->pretty() : $c->value(); | |||
| 867 | }; | ||||||
| 868 | 0 | 0 | 0 | $p = ($clusterid ? $h : $pretty) unless defined $p; | |||
| 0 | |||||||
| 869 | |||||||
| 870 | 0 | 0 | my $uri = "???"; | ||||
| 871 | 0 | 0 | 0 | 0 | if ( $uri = $vary->{'link'} ) { # o.k. | ||
| 0 | |||||||
| 0 | |||||||
| 0 | |||||||
| 872 | } | ||||||
| 873 | elsif ( $repos->{'ALTTARGET'} && $vary->{'altid'} ) { | ||||||
| 874 | 0 | 0 | $uri = sprintf($repos->{'ALTTARGET'}, $p, SeeAlso::Source::BeaconAggregator::urlpseudoescape($vary->{'altid'}))} | ||||
| 875 | elsif ( $repos->{'TARGET'} ) { | ||||||
| 876 | 0 | 0 | $uri = sprintf($repos->{'TARGET'}, $p)} | ||||
| 877 | elsif ( $repos->{'ALTTARGET'} ) { | ||||||
| 878 | 0 | 0 | $uri = sprintf($repos->{'ALTTARGET'}, $p, SeeAlso::Source::BeaconAggregator::urlpseudoescape($p))}; | ||||
| 879 | |||||||
| 880 | 0 | 0 | 0 | my $redundant = ($didalreadysee{$uri}++) ? "subsequent" : ""; | |||
| 881 | |||||||
| 882 | 0 | 0 | my $guri = ""; | ||||
| 883 | 0 | 0 | 0 | if ( $repos->{'IMGTARGET'} ) { | |||
| 884 | 0 | 0 | $guri = sprintf($repos->{'IMGTARGET'}, $p, SeeAlso::Source::BeaconAggregator::urlpseudoescape($vary->{'altid'}))} | ||||
| 885 | |||||||
| 886 | 0 | 0 | 0 | 0 | my $hits = $vary->{hits} if $vary->{hits} and $vary->{hits} != 1; | ||
| 887 | |||||||
| 888 | 0 | 0 | push(@result, qq! |
||||
| 889 | 0 | 0 | 0 | push(@result, $cgi->div({style=>"float: right;"}, $cgi->a({href=>$uri}, $cgi->img({src=>$guri})))) if $guri; | |||
| 890 | 0 | 0 | 0 | push(@result, $cgi->a({href=>$uri}, $cgi->span($vary->{'info'} || "[$cnt.]"))); | |||
| 891 | 0 | 0 | 0 | push(@result, $cgi->span("($hits Treffer)")) if $hits; | |||
| 892 | 0 | 0 | push(@result, ''); | ||||
| 893 | |||||||
| 894 | 0 | 0 | push(@result, qq! | ||||
| 895 | 0 | 0 | push(@result, $cgi->p({class=>"ht_uri"}, $cgi->span("Target URL:"), $cgi->a({href=>$uri}, $uri))); | ||||
| 896 | 0 | 0 | 0 | push(@result, $cgi->p({class=>"ht_guri"}, $cgi->span("Preview URL:"), $cgi->a({href=>$guri}, $guri))) if $guri; | |||
| 897 | 0 | 0 | 0 | push(@result, $cgi->p({class=>"ht_hits"}, $cgi->span("Hits:"), $vary->{hits})) if $vary->{hits}; | |||
| 898 | 0 | 0 | 0 | push(@result, $cgi->p({class=>"ht_info"}, $cgi->span("Additional Info:"), $vary->{'info'})) if $vary->{'info'}; | |||
| 899 | 0 | 0 | 0 | push(@result, $cgi->p({class=>"ht_idnote"}, $cgi->span("Variant Identifier:"), $p)) if $variantid; | |||
| 900 | |||||||
| 901 | 0 | 0 | push(@result, ''); | ||||
| 902 | 0 | 0 | push(@result, ''); | ||||
| 903 | }; | ||||||
| 904 | 0 | 0 | push(@result, qq!!); | ||||
| 905 | } | ||||||
| 906 | |||||||
| 907 | 0 | 0 | push(@result, qq! | ||||
| 908 | 0 | 0 | foreach ( sort keys %$repos ) { | ||||
| 909 | 0 | 0 | 0 | next if /(MESSAGE|TARGET)$/; | |||
| 910 | 0 | 0 | 0 | next unless $repos->{$_}; | |||
| 911 | 0 | 0 | $repos->{$_} =~ s!([a-z]+://\S+)!$cgi->a({href=>"$1", target=>"_blank"}, "$1")!ge; # URL | ||||
| 0 | 0 | ||||||
| 912 | 0 | 0 | $repos->{$_} =~ s!(?:\<\s*)?(\w[\w.-]*)\@((?:\w[\w-]*\.)+\w+)(?:\s*\>)?!<$1 (at) $2>!g; # Mail Addr | ||||
| 913 | 0 | 0 | $repos->{$_} =~ s/\s*\|\s*/ | /g; # Examples | ||||
| 914 | 0 | 0 | 0 | next if /^(FORMAT|PREFIX|REVISIT|VERSION)$/; # Postpone to "administrative Details" | |||
| 915 | 0 | 0 | push(@result, $cgi->p({class=>"bc_$_"}, $cgi->span("#$_:"), $repos->{$_})); | ||||
| 916 | }; | ||||||
| 917 | 0 | 0 | 0 | push(@result, $cgi->p({class=>"ag_mtime"}, $cgi->span("Modified:"), $meta->{'_mtime'})) if $meta->{'_mtime'}; | |||
| 918 | 0 | 0 | push(@result, ''); | ||||
| 919 | |||||||
| 920 | 0 | 0 | push(@result, qq! | ||||
| 921 | 0 | 0 | foreach ( sort keys %$repos ) { | ||||
| 922 | 0 | 0 | 0 | next unless /^(FORMAT|PREFIX|REVISIT|VERSION)$/; | |||
| 923 | 0 | 0 | 0 | next unless $repos->{$_}; | |||
| 924 | 0 | 0 | push(@result, $cgi->p({class=>"bc_$_"}, $cgi->span("#$_:"), $repos->{$_})); | ||||
| 925 | }; | ||||||
| 926 | 0 | 0 | 0 | push(@result, $cgi->p({class=>"ag_ftime"}, $cgi->span("Loaded:"), $meta->{'_ftime'})) if $meta->{'_ftime'}; | |||
| 927 | 0 | 0 | 0 | push(@result, $cgi->p({class=>"ag_fstat"}, $cgi->span("Load status:"), $meta->{'_fstat'})) if $meta->{'_fstat'}; | |||
| 928 | 0 | 0 | 0 | push(@result, $cgi->p({class=>"ag_utime"}, $cgi->span("Update attempt:"), $meta->{'_utime'})) if $meta->{'_utime'}; | |||
| 929 | 0 | 0 | 0 | push(@result, $cgi->p({class=>"ag_ustat"}, $cgi->span("Update status:"), $meta->{'_ustat'})) if $meta->{'_ustat'}; | |||
| 930 | 0 | 0 | 0 | push(@result, $cgi->p({class=>"ag_counti"}, $cgi->span("Identifiers:"), $meta->{'_counti'})) if $meta->{'_counti'}; | |||
| 931 | 0 | 0 | 0 | push(@result, $cgi->p({class=>"ag_countu"}, $cgi->span("Distinct Ids:"), $meta->{'_countu'})) if $meta->{'_countu'}; | |||
| 932 | 0 | 0 | 0 | push(@result, $cgi->p({class=>"ag_sort"}, $cgi->span("Sort key:"), $meta->{'_sort'})) if $meta->{'_sort'}; | |||
| 933 | 0 | 0 | 0 | push(@result, $cgi->p({class=>"ag_admin"}, $cgi->span("Remark:"), $meta->{'_admin'})) if $meta->{'_admin'}; | |||
| 934 | 0 | 0 | push(@result, ''); | ||||
| 935 | |||||||
| 936 | 0 | 0 | push(@result, ''); | ||||
| 937 | |||||||
| 938 | 0 | 0 | push(@result, ''); | ||||
| 939 | }; | ||||||
| 940 | 0 | 0 | push(@result, ''); | ||||
| 941 | |||||||
| 942 | 0 | 0 | push(@result, ' '); |
||||
| 943 | # $cgi->span("provided by:"), | ||||||
| 944 | 0 | 0 | push(@result, $cgi->p({class=>"mt_NAME"}, $cgi->a({href=>$target}, $servicename))); | ||||
| 945 | # $cgi->span("Service description:"), | ||||||
| 946 | 0 | 0 | 0 | (my $descr = $beaconmeta->{'DESCRIPTION'} || $osd->{'Description'} || "") =~ s/([<>&"]|[^\x00-\x7f])/''.ord($1).';'/ge; | |||
| 0 | 0 | ||||||
| 947 | 0 | 0 | push(@result, $cgi->p({class=>"mt_DESCRIPTION"}, $descr)); | ||||
| 948 | 0 | 0 | push(@result, ''); | ||||
| 949 | |||||||
| 950 | 0 | 0 | my($tu, $ts, $tcu, $tcs) = times(); | ||||
| 951 | 0 | 0 | push(@result, sprintf("", $tu, $ts, $tu+$ts), $cgi->end_html()); | ||||
| 952 | 0 | 0 | return join("\n", @result); | ||||
| 953 | } | ||||||
| 954 | |||||||
| 955 | |||||||
| 956 | =head2 get_meta () | ||||||
| 957 | |||||||
| 958 | Returns a pair of hash references: | ||||||
| 959 | |||||||
| 960 | =over 8 | ||||||
| 961 | |||||||
| 962 | =item 1 | ||||||
| 963 | |||||||
| 964 | OSD fields | ||||||
| 965 | |||||||
| 966 | =item 2 | ||||||
| 967 | |||||||
| 968 | Beacon header fields | ||||||
| 969 | |||||||
| 970 | =back | ||||||
| 971 | |||||||
| 972 | =cut | ||||||
| 973 | |||||||
| 974 | sub get_meta { | ||||||
| 975 | 1 | 1 | 1 | 1574 | my ($self) = @_; | ||
| 976 | |||||||
| 977 | 1 | 4 | my ($metasth, $metaexpl) = $self->stmtHdl(<<"XxX"); | ||||
| 978 | SELECT key, val FROM osd; | ||||||
| 979 | XxX | ||||||
| 980 | 1 | 50 | 4 | $self->stmtExplain($metaexpl) if $ENV{'DBI_PROFILE'}; | |||
| 981 | 1 | 50 | 42 | $metasth->execute() or croak("Could not execute >".$metasth->{Statement}."<: ".$metasth->errstr); | |||
| 982 | 1 | 2 | my (%osd, %beaconmeta); | ||||
| 983 | 1 | 15 | while ( my $aryref = $metasth->fetchrow_arrayref ) { | ||||
| 984 | 9 | 9 | my ($key, $val) = @$aryref; | ||||
| 985 | 9 | 50 | 10 | next unless $val; | |||
| 986 | 9 | 100 | 24 | if ($key =~ s/^bc// ) { # BeaconMeta Fields | |||
| 100 | |||||||
| 987 | 2 | 16 | $beaconmeta{$key} = $val} | ||||
| 988 | elsif ( exists $osd{$key} ) { | ||||||
| 989 | 6 | 100 | 9 | if ( ref($osd{$key}) ) { | |||
| 990 | 5 | 4 | push(@{$osd{$key}}, $val)} | ||||
| 5 | 21 | ||||||
| 991 | else { | ||||||
| 992 | 1 | 6 | $osd{$key} = [$osd{$key}, $val]}; | ||||
| 993 | } | ||||||
| 994 | else { | ||||||
| 995 | 1 | 7 | $osd{$key} = $val}; | ||||
| 996 | }; | ||||||
| 997 | 1 | 5 | return (\%osd, \%beaconmeta); | ||||
| 998 | } | ||||||
| 999 | |||||||
| 1000 | =head1 AUTHOR | ||||||
| 1001 | |||||||
| 1002 | Thomas Berger | ||||||
| 1003 | CPAN ID: THB | ||||||
| 1004 | gymel.com | ||||||
| 1005 | THB@cpan.org | ||||||
| 1006 | |||||||
| 1007 | =head1 COPYRIGHT | ||||||
| 1008 | |||||||
| 1009 | This program is free software; you can redistribute | ||||||
| 1010 | it and/or modify it under the same terms as Perl itself. | ||||||
| 1011 | |||||||
| 1012 | The full text of the license can be found in the | ||||||
| 1013 | LICENSE file included with this module. | ||||||
| 1014 | |||||||
| 1015 | |||||||
| 1016 | =cut | ||||||
| 1017 | |||||||
| 1018 | 1; | ||||||
| 1019 | # The preceding line will help the module return a true value | ||||||
| 1020 |