1 package OpenILS::WWW::AddedContent::ContentCafe;
2 use strict; use warnings;
3 use OpenSRF::Utils::Logger qw/$logger/;
4 use OpenSRF::Utils::SettingsParser;
5 use OpenSRF::Utils::JSON;
6 use OpenSRF::EX qw/:try/;
7 use OpenILS::WWW::AddedContent;
12 my $AC = 'OpenILS::WWW::AddedContent';
14 my $post_url = 'http://contentcafe2.btol.com/ContentCafe/ContentCafe.asmx/XmlPost';
17 my( $class, $args ) = @_;
18 $class = ref $class || $class;
19 return bless($args, $class);
24 return $self->{ContentCafe}->{userid};
29 return $self->{ContentCafe}->{password};
32 sub identifier_order {
34 if ($self->{ContentCafe}->{identifier_order}) {
35 my $order = [ split(',',$self->{ContentCafe}->{identifier_order}) ];
38 return ['isbn','upc'];
42 # we expect a keyhash as opposed to a simple scalar containing an ISBN
46 # --------------------------------------------------------------------------
48 # This function fetches everything and returns:
49 # 0 if we had no usable keys
50 # 0 if we had a lookup failure
51 # A hash of format_type => result if you called that directly
53 my( $self, $keyhash ) = @_;
54 my $doc = $self->fetch_xmldoc([
56 'BiographyDetail', #anotes_*
57 'ExcerptDetail', #excerpt_*
58 'ReviewDetail', #reviews_*
59 'AnnotationDetail', #summary_*
60 {name => 'JacketDetail', attributes => [['Type','S'],['Encoding','HEX']]}, # jacket_small
61 {name => 'JacketDetail', attributes => [['Type','M'],['Encoding','HEX']]}, # jacket_medium
62 {name => 'JacketDetail', attributes => [['Type','L'],['Encoding','HEX']]}, # jacket_large
64 return 0 unless defined $doc;
66 toc_html => $self->parse_toc_html($doc),
67 toc_json => $self->send_json($doc, 'TocItems'),
68 toc_xml => $self->send_xml($doc, 'TocItems'),
69 anotes_html => $self->parse_anotes_html($doc),
70 anotes_json => $self->send_json($doc, 'BiographyItems'),
71 anotes_xml => $self->send_xml($doc, 'BiographyItems'),
72 excerpt_html => $self->parse_excerpt_html($doc),
73 excerpt_json => $self->send_json($doc, 'ExcerptItems'),
74 excerpt_xml => $self->send_xml($doc, 'ExcerptItems'),
75 reviews_html => $self->parse_reviews_html($doc),
76 reviews_json => $self->send_json($doc, 'ReviewItems'),
77 reviews_xml => $self->send_xml($doc, 'ReviewItems'),
78 summary_html => $self->parse_summary_html($doc),
79 summary_json => $self->send_json($doc, 'AnnotationItems'),
80 summary_xml => $self->send_xml($doc, 'AnnotationItems'),
81 jacket_small => $self->parse_jacket($doc, 'S'),
82 jacket_medium => $self->parse_jacket($doc, 'M'),
83 jacket_large => $self->parse_jacket($doc, 'L')
88 # --------------------------------------------------------------------------
90 my( $self, $keyhash ) = @_;
91 return $self->send_jacket( $keyhash, 'S' );
95 my( $self, $keyhash ) = @_;
96 return $self->send_jacket( $keyhash, 'M' );
100 my( $self, $keyhash ) = @_;
101 return $self->send_jacket( $keyhash, 'L' );
104 # --------------------------------------------------------------------------
107 my( $self, $keyhash ) = @_;
108 my $doc = $self->fetch_xmldoc('TocDetail', $keyhash);
109 return 0 unless defined $doc;
110 return $self->parse_toc_html($doc);
114 my( $self, $doc ) = @_;
116 my @nodes = $doc->findnodes('//cc:TocItems[*]');
117 return 0 if (scalar(@nodes) < 1);
118 @nodes = $nodes[0]->findnodes('.//cc:Toc');
119 return 0 if (scalar(@nodes) < 1);
120 foreach my $node ( @nodes ) {
121 $html .= $node->textContent . '</P></P>';
123 return $self->send_html($html);
127 my( $self, $keyhash ) = @_;
128 return $self->send_xml(
129 $self->fetch_xmldoc('TocDetail', $keyhash),
134 my( $self, $keyhash ) = @_;
135 return $self->send_json(
136 $self->fetch_xmldoc('TocDetail', $keyhash),
140 # --------------------------------------------------------------------------
143 my( $self, $keyhash ) = @_;
144 my $doc = $self->fetch_xmldoc('BiographyDetail', $keyhash);
145 return 0 unless defined $doc;
146 return $self->parse_anotes_html($doc);
149 sub parse_anotes_html {
150 my( $self, $doc ) = @_;
152 my @nodes = $doc->findnodes('//cc:BiographyItems[*]');
153 return 0 if (scalar(@nodes) < 1);
154 @nodes = $nodes[0]->findnodes('.//cc:Biography');
155 return 0 if (scalar(@nodes) < 1);
156 foreach my $node ( @nodes ) {
157 $html .= '<P class="biography">' . $node->textContent . '</P>';
159 return $self->send_html($html);
163 my( $self, $keyhash ) = @_;
164 return $self->send_xml(
165 $self->fetch_xmldoc('BiographyDetail', $keyhash),
170 my( $self, $keyhash ) = @_;
171 return $self->send_json(
172 $self->fetch_xmldoc('BiographyDetail', $keyhash),
177 # --------------------------------------------------------------------------
180 my( $self, $keyhash ) = @_;
181 my $doc = $self->fetch_xmldoc('ExcerptDetail', $keyhash);
182 return 0 unless defined $doc;
183 return $self->parse_excerpt_html($doc);
186 sub parse_excerpt_html {
187 my( $self, $doc ) = @_;
189 my @nodes = $doc->findnodes('//cc:ExcerptItems[*]');
190 return 0 if (scalar(@nodes) < 1);
191 @nodes = $nodes[0]->findnodes('.//cc:Excerpt');
192 return 0 if (scalar(@nodes) < 1);
193 foreach my $node ( @nodes ) {
194 $html .= $node->textContent;
196 return $self->send_html($html);
200 my( $self, $keyhash ) = @_;
201 return $self->send_xml(
202 $self->fetch_xmldoc('ExcerptDetail', $keyhash),
207 my( $self, $keyhash ) = @_;
208 return $self->send_json(
209 $self->fetch_xmldoc('ExcerptDetail', $keyhash),
213 # --------------------------------------------------------------------------
216 my( $self, $keyhash ) = @_;
217 my $doc = $self->fetch_xmldoc('ReviewDetail', $keyhash);
218 return 0 unless defined $doc;
219 return $self->parse_reviews_html($doc);
222 sub parse_reviews_html {
223 my( $self, $doc ) = @_;
225 my @nodes = $doc->findnodes('//cc:ReviewItems[*]');
226 return 0 if (scalar(@nodes) < 1);
227 @nodes = $nodes[0]->findnodes('.//cc:ReviewItem');
228 return 0 if (scalar(@nodes) < 1);
229 foreach my $node ( @nodes ) {
230 my @s_nodes = $node->findnodes('./cc:Supplier');
231 my @p_nodes = $node->findnodes('./cc:Publication');
232 my @i_nodes = $node->findnodes('./cc:Issue');
233 my @r_nodes = $node->findnodes('./cc:Review');
234 $html .= '<li><b>' . (scalar(@p_nodes) ? $p_nodes[0]->textContent : '') . '</b>';
235 if (scalar(@i_nodes) && scalar(@p_nodes)) { $html .= ' : '; }
236 $html .= (scalar(@i_nodes) ? $i_nodes[0]->textContent : '') . '<br/>';
237 $html .= (scalar(@r_nodes) ? $r_nodes[0]->textContent : '') . '</li>';
240 return $self->send_html($html);
244 my( $self, $keyhash ) = @_;
245 return $self->send_xml(
246 $self->fetch_xmldoc('ReviewDetail', $keyhash),
251 my( $self, $keyhash ) = @_;
252 return $self->send_json(
253 $self->fetch_xmldoc('ReviewDetail', $keyhash),
257 # --------------------------------------------------------------------------
260 my( $self, $keyhash ) = @_;
261 my $doc = $self->fetch_xmldoc('AnnotationDetail', $keyhash);
262 return 0 unless defined $doc;
263 return $self->parse_summary_html($doc);
266 sub parse_summary_html {
267 my( $self, $doc ) = @_;
269 my @nodes = $doc->findnodes('//cc:AnnotationItems[*]');
270 return 0 if (scalar(@nodes) < 1);
271 @nodes = $nodes[0]->findnodes('.//cc:AnnotationItem');
272 return 0 if (scalar(@nodes) < 1);
273 foreach my $node ( @nodes ) {
274 my @s_nodes = $node->findnodes('./cc:Supplier');
275 my @a_nodes = $node->findnodes('./cc:Annotation');
276 $html .= '<li><b>' . (scalar(@s_nodes) ? $s_nodes[0]->textContent : '') . '</b><br/>';
277 $html .= (scalar(@a_nodes) ? $a_nodes[0]->textContent : '') . '</li>';
280 return $self->send_html($html);
284 my( $self, $keyhash ) = @_;
285 return $self->send_xml(
286 $self->fetch_xmldoc('AnnotationDetail', $keyhash),
291 my( $self, $keyhash ) = @_;
292 return $self->send_json(
293 $self->fetch_xmldoc('AnnotationDetail', $keyhash),
297 # --------------------------------------------------------------------------
300 my ( $self, $keyhash ) = @_;
301 my $keys = []; # Start with an empty array
302 foreach my $identifier (@{$self->identifier_order}) {
303 foreach my $key (@{$keyhash->{$identifier}}) {
311 my( $self, $doc, $contentNode ) = @_;
312 return 0 unless defined $doc;
313 my @nodes = $doc->findnodes('//cc:' . $contentNode . '[*]');
314 return 0 if (scalar(@nodes) < 1);
315 my $perl = OpenSRF::Utils::SettingsParser::XML2perl($nodes[0]);
316 my $json = OpenSRF::Utils::JSON->perl2JSON($perl);
317 return { content_type => 'text/plain', content => $json };
321 my( $self, $doc, $contentNode ) = @_;
322 return 0 unless defined $doc;
323 my @nodes = $doc->findnodes('//cc:' . $contentNode . '[*]');
324 return 0 if (scalar(@nodes) < 1);
325 my $newdoc = XML::LibXML::Document->new( '1.0', 'utf-8' );
326 my $clonenode = $nodes[0]->cloneNode(1);
327 $newdoc->adoptNode($clonenode);
328 $newdoc->setDocumentElement($clonenode);
329 return { content_type => 'application/xml', content => $newdoc->toString() };
333 my( $self, $content ) = @_;
335 # Hide anything that might contain a link since it will be broken
336 my $HTML = <<" HTML";
338 <style type='text/css'>
339 div.ac input, div.ac a[href],div.ac img, div.ac button { display: none; visibility: hidden }
347 return { content_type => 'text/html', content => $HTML };
351 my( $self, $keyhash, $size ) = @_;
353 my $doc = $self->fetch_xmldoc({name => 'JacketDetail', attributes => [['Type',$size],['Encoding','HEX']]}, $keyhash);
354 return 0 unless defined $doc;
356 return $self->parse_jacket($doc, $size);
360 my( $self, $doc, $size ) = @_;
361 my @nodes = $doc->findnodes("//cc:JacketItem[cc:Type/\@Code = '$size']");
362 return 0 if (scalar(@nodes) < 1);
364 my $jacketItem = shift(@nodes); # We only care about the first jacket
365 my @formatNodes = $jacketItem->findnodes('./cc:Format');
366 my $format = $formatNodes[0]->textContent;
367 my @jacketNodes = $jacketItem->findnodes('./cc:Jacket');
368 my $imageData = pack('H*',$jacketNodes[0]->textContent);
371 content_type => 'image/' . lc($format),
372 content => $imageData,
377 # returns an XML document ready for parsing if $keyhash contained usable keys
378 # otherwise returns undef
380 my( $self, $contentTypes, $keyhash ) = @_;
382 my $keys = $self->build_keylist($keyhash);
383 return undef unless @{$keys};
385 my $content = $self->fetch_response($contentTypes, $keys)->content;
386 my $doc = XML::LibXML->new->parse_string($content);
387 $doc->documentElement->setNamespace('http://ContentCafe2.btol.com', 'cc');
391 # returns the HTTP response object from the URL fetch
393 my( $self, $contentTypes, $keys ) = @_;
395 if (ref($contentTypes) ne 'ARRAY') {
396 $contentTypes = [ $contentTypes ];
399 my $xmlRequest = XML::LibXML::Document->new( '1.0', 'utf-8' );
400 my $root = $xmlRequest->createElementNS('http://ContentCafe2.btol.com','ContentCafe');
401 $root->addChild($xmlRequest->createAttribute('DateTime', DateTime->now()->datetime));
402 $xmlRequest->setDocumentElement($root);
403 my $requestItems = $xmlRequest->createElement('RequestItems');
404 $requestItems->addChild($xmlRequest->createAttribute('UserID', $self->userid));
405 $requestItems->addChild($xmlRequest->createAttribute('Password', $self->password));
406 $root->addChild($requestItems);
408 foreach my $key (@{$keys}) {
409 my $requestItem = $xmlRequest->createElement('RequestItem');
410 my $keyNode = $xmlRequest->createElement('Key');
411 $keyNode->addChild($xmlRequest->createTextNode($key));
412 $requestItem->addChild($keyNode);
414 foreach my $contentType (@{$contentTypes}) {
415 my $contentNode = $xmlRequest->createElement('Content');
416 if (ref($contentType) eq 'HASH') {
417 $contentNode->addChild($xmlRequest->createTextNode($contentType->{name}));
418 foreach my $contentAttribute (@{$contentType->{attributes}}) {
419 $contentNode->addChild($xmlRequest->createAttribute($contentAttribute->[0], $contentAttribute->[1]));
422 $contentNode->addChild($xmlRequest->createTextNode($contentType));
424 $requestItem->addChild($contentNode);
427 $requestItems->addChild($requestItem);
429 my $response = $AC->post_url($post_url, $xmlRequest->toString);