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 # Hack country_data to allow B&T fake ISBNs LP#1559281
13 $Business::ISBN::country_data{630} = ['B&T' => ['0000000' => '9999999']];
14 $Business::ISBN::country_data{631} = ['B&T' => ['0000000' => '9999999']];
16 my $AC = 'OpenILS::WWW::AddedContent';
18 my $post_url = 'http://contentcafe2.btol.com/ContentCafe/ContentCafe.asmx/XmlPost';
21 my( $class, $args ) = @_;
22 $class = ref $class || $class;
23 return bless($args, $class);
28 return $self->{ContentCafe}->{userid};
33 return $self->{ContentCafe}->{password};
36 sub identifier_order {
38 if ($self->{ContentCafe}->{identifier_order}) {
39 my $order = [ split(',',$self->{ContentCafe}->{identifier_order}) ];
42 return ['isbn','upc'];
46 # we expect a keyhash as opposed to a simple scalar containing an ISBN
50 # --------------------------------------------------------------------------
52 # This function fetches everything and returns:
53 # 0 if we had no usable keys
54 # 0 if we had a lookup failure
55 # A hash of format_type => result if you called that directly
57 my( $self, $keyhash ) = @_;
58 my $doc = $self->fetch_xmldoc([
60 'BiographyDetail', #anotes_*
61 'ExcerptDetail', #excerpt_*
62 'ReviewDetail', #reviews_*
63 'AnnotationDetail', #summary_*
64 {name => 'JacketDetail', attributes => [['Type','S'],['Encoding','HEX']]}, # jacket_small
65 {name => 'JacketDetail', attributes => [['Type','M'],['Encoding','HEX']]}, # jacket_medium
66 {name => 'JacketDetail', attributes => [['Type','L'],['Encoding','HEX']]}, # jacket_large
68 return 0 unless defined $doc;
70 toc_html => $self->parse_toc_html($doc),
71 toc_json => $self->send_json($doc, 'TocItems'),
72 toc_xml => $self->send_xml($doc, 'TocItems'),
73 anotes_html => $self->parse_anotes_html($doc),
74 anotes_json => $self->send_json($doc, 'BiographyItems'),
75 anotes_xml => $self->send_xml($doc, 'BiographyItems'),
76 excerpt_html => $self->parse_excerpt_html($doc),
77 excerpt_json => $self->send_json($doc, 'ExcerptItems'),
78 excerpt_xml => $self->send_xml($doc, 'ExcerptItems'),
79 reviews_html => $self->parse_reviews_html($doc),
80 reviews_json => $self->send_json($doc, 'ReviewItems'),
81 reviews_xml => $self->send_xml($doc, 'ReviewItems'),
82 summary_html => $self->parse_summary_html($doc),
83 summary_json => $self->send_json($doc, 'AnnotationItems'),
84 summary_xml => $self->send_xml($doc, 'AnnotationItems'),
85 jacket_small => $self->parse_jacket($doc, 'S'),
86 jacket_medium => $self->parse_jacket($doc, 'M'),
87 jacket_large => $self->parse_jacket($doc, 'L')
92 # --------------------------------------------------------------------------
94 my( $self, $keyhash ) = @_;
95 return $self->send_jacket( $keyhash, 'S' );
99 my( $self, $keyhash ) = @_;
100 return $self->send_jacket( $keyhash, 'M' );
104 my( $self, $keyhash ) = @_;
105 return $self->send_jacket( $keyhash, 'L' );
108 # --------------------------------------------------------------------------
111 my( $self, $keyhash ) = @_;
112 my $doc = $self->fetch_xmldoc('TocDetail', $keyhash);
113 return 0 unless defined $doc;
114 return $self->parse_toc_html($doc);
118 my( $self, $doc ) = @_;
120 my @nodes = $doc->findnodes('//cc:TocItems[*]');
121 return 0 if (scalar(@nodes) < 1);
122 @nodes = $nodes[0]->findnodes('.//cc:Toc');
123 return 0 if (scalar(@nodes) < 1);
124 foreach my $node ( @nodes ) {
125 $html .= $node->textContent . '</P></P>';
127 return $self->send_html($html);
131 my( $self, $keyhash ) = @_;
132 return $self->send_xml(
133 $self->fetch_xmldoc('TocDetail', $keyhash),
138 my( $self, $keyhash ) = @_;
139 return $self->send_json(
140 $self->fetch_xmldoc('TocDetail', $keyhash),
144 # --------------------------------------------------------------------------
147 my( $self, $keyhash ) = @_;
148 my $doc = $self->fetch_xmldoc('BiographyDetail', $keyhash);
149 return 0 unless defined $doc;
150 return $self->parse_anotes_html($doc);
153 sub parse_anotes_html {
154 my( $self, $doc ) = @_;
156 my @nodes = $doc->findnodes('//cc:BiographyItems[*]');
157 return 0 if (scalar(@nodes) < 1);
158 @nodes = $nodes[0]->findnodes('.//cc:Biography');
159 return 0 if (scalar(@nodes) < 1);
160 foreach my $node ( @nodes ) {
161 $html .= '<P class="biography">' . $node->textContent . '</P>';
163 return $self->send_html($html);
167 my( $self, $keyhash ) = @_;
168 return $self->send_xml(
169 $self->fetch_xmldoc('BiographyDetail', $keyhash),
174 my( $self, $keyhash ) = @_;
175 return $self->send_json(
176 $self->fetch_xmldoc('BiographyDetail', $keyhash),
181 # --------------------------------------------------------------------------
184 my( $self, $keyhash ) = @_;
185 my $doc = $self->fetch_xmldoc('ExcerptDetail', $keyhash);
186 return 0 unless defined $doc;
187 return $self->parse_excerpt_html($doc);
190 sub parse_excerpt_html {
191 my( $self, $doc ) = @_;
193 my @nodes = $doc->findnodes('//cc:ExcerptItems[*]');
194 return 0 if (scalar(@nodes) < 1);
195 @nodes = $nodes[0]->findnodes('.//cc:Excerpt');
196 return 0 if (scalar(@nodes) < 1);
197 foreach my $node ( @nodes ) {
198 $html .= $node->textContent;
200 return $self->send_html($html);
204 my( $self, $keyhash ) = @_;
205 return $self->send_xml(
206 $self->fetch_xmldoc('ExcerptDetail', $keyhash),
211 my( $self, $keyhash ) = @_;
212 return $self->send_json(
213 $self->fetch_xmldoc('ExcerptDetail', $keyhash),
217 # --------------------------------------------------------------------------
220 my( $self, $keyhash ) = @_;
221 my $doc = $self->fetch_xmldoc('ReviewDetail', $keyhash);
222 return 0 unless defined $doc;
223 return $self->parse_reviews_html($doc);
226 sub parse_reviews_html {
227 my( $self, $doc ) = @_;
229 my @nodes = $doc->findnodes('//cc:ReviewItems[*]');
230 return 0 if (scalar(@nodes) < 1);
231 @nodes = $nodes[0]->findnodes('.//cc:ReviewItem');
232 return 0 if (scalar(@nodes) < 1);
233 foreach my $node ( @nodes ) {
234 my @s_nodes = $node->findnodes('./cc:Supplier');
235 my @p_nodes = $node->findnodes('./cc:Publication');
236 my @i_nodes = $node->findnodes('./cc:Issue');
237 my @r_nodes = $node->findnodes('./cc:Review');
238 $html .= '<li><b>' . (scalar(@p_nodes) ? $p_nodes[0]->textContent : '') . '</b>';
239 if (scalar(@i_nodes) && scalar(@p_nodes)) { $html .= ' : '; }
240 $html .= (scalar(@i_nodes) ? $i_nodes[0]->textContent : '') . '<br/>';
241 $html .= (scalar(@r_nodes) ? $r_nodes[0]->textContent : '') . '</li>';
244 return $self->send_html($html);
248 my( $self, $keyhash ) = @_;
249 return $self->send_xml(
250 $self->fetch_xmldoc('ReviewDetail', $keyhash),
255 my( $self, $keyhash ) = @_;
256 return $self->send_json(
257 $self->fetch_xmldoc('ReviewDetail', $keyhash),
261 # --------------------------------------------------------------------------
264 my( $self, $keyhash ) = @_;
265 my $doc = $self->fetch_xmldoc('AnnotationDetail', $keyhash);
266 return 0 unless defined $doc;
267 return $self->parse_summary_html($doc);
270 sub parse_summary_html {
271 my( $self, $doc ) = @_;
273 my @nodes = $doc->findnodes('//cc:AnnotationItems[*]');
274 return 0 if (scalar(@nodes) < 1);
275 @nodes = $nodes[0]->findnodes('.//cc:AnnotationItem');
276 return 0 if (scalar(@nodes) < 1);
277 foreach my $node ( @nodes ) {
278 my @s_nodes = $node->findnodes('./cc:Supplier');
279 my @a_nodes = $node->findnodes('./cc:Annotation');
280 $html .= '<li><b>' . (scalar(@s_nodes) ? $s_nodes[0]->textContent : '') . '</b><br/>';
281 $html .= (scalar(@a_nodes) ? $a_nodes[0]->textContent : '') . '</li>';
284 return $self->send_html($html);
288 my( $self, $keyhash ) = @_;
289 return $self->send_xml(
290 $self->fetch_xmldoc('AnnotationDetail', $keyhash),
295 my( $self, $keyhash ) = @_;
296 return $self->send_json(
297 $self->fetch_xmldoc('AnnotationDetail', $keyhash),
301 # --------------------------------------------------------------------------
304 my ( $self, $keyhash ) = @_;
305 my $keys = []; # Start with an empty array
306 foreach my $identifier (@{$self->identifier_order}) {
307 foreach my $key (@{$keyhash->{$identifier}}) {
315 my( $self, $doc, $contentNode ) = @_;
316 return 0 unless defined $doc;
317 my @nodes = $doc->findnodes('//cc:' . $contentNode . '[*]');
318 return 0 if (scalar(@nodes) < 1);
319 my $perl = OpenSRF::Utils::SettingsParser::XML2perl($nodes[0]);
320 my $json = OpenSRF::Utils::JSON->perl2JSON($perl);
321 return { content_type => 'text/plain', content => $json };
325 my( $self, $doc, $contentNode ) = @_;
326 return 0 unless defined $doc;
327 my @nodes = $doc->findnodes('//cc:' . $contentNode . '[*]');
328 return 0 if (scalar(@nodes) < 1);
329 my $newdoc = XML::LibXML::Document->new( '1.0', 'utf-8' );
330 my $clonenode = $nodes[0]->cloneNode(1);
331 $newdoc->adoptNode($clonenode);
332 $newdoc->setDocumentElement($clonenode);
333 return { content_type => 'application/xml', content => $newdoc->toString() };
337 my( $self, $content ) = @_;
339 # Hide anything that might contain a link since it will be broken
340 my $HTML = <<" HTML";
342 <style type='text/css'>
343 div.ac input, div.ac a[href],div.ac img, div.ac button { display: none; visibility: hidden }
351 return { content_type => 'text/html', content => $HTML };
355 my( $self, $keyhash, $size ) = @_;
357 my $doc = $self->fetch_xmldoc({name => 'JacketDetail', attributes => [['Type',$size],['Encoding','HEX']]}, $keyhash);
358 return 0 unless defined $doc;
360 return $self->parse_jacket($doc, $size);
364 my( $self, $doc, $size ) = @_;
365 my @nodes = $doc->findnodes("//cc:JacketItem[cc:Type/\@Code = '$size']");
366 return 0 if (scalar(@nodes) < 1);
368 my $jacketItem = shift(@nodes); # We only care about the first jacket
369 my @formatNodes = $jacketItem->findnodes('./cc:Format');
370 my $format = $formatNodes[0]->textContent;
371 my @jacketNodes = $jacketItem->findnodes('./cc:Jacket');
372 my $imageData = pack('H*',$jacketNodes[0]->textContent);
375 content_type => 'image/' . lc($format),
376 content => $imageData,
381 # returns an XML document ready for parsing if $keyhash contained usable keys
382 # otherwise returns undef
384 my( $self, $contentTypes, $keyhash ) = @_;
386 my $keys = $self->build_keylist($keyhash);
387 return undef unless @{$keys};
389 my $content = $self->fetch_response($contentTypes, $keys)->content;
390 my $doc = XML::LibXML->new->parse_string($content);
391 $doc->documentElement->setNamespace('http://ContentCafe2.btol.com', 'cc');
395 # returns the HTTP response object from the URL fetch
397 my( $self, $contentTypes, $keys ) = @_;
399 if (ref($contentTypes) ne 'ARRAY') {
400 $contentTypes = [ $contentTypes ];
403 my $xmlRequest = XML::LibXML::Document->new( '1.0', 'utf-8' );
404 my $root = $xmlRequest->createElementNS('http://ContentCafe2.btol.com','ContentCafe');
405 $root->addChild($xmlRequest->createAttribute('DateTime', DateTime->now()->datetime));
406 $xmlRequest->setDocumentElement($root);
407 my $requestItems = $xmlRequest->createElement('RequestItems');
408 $requestItems->addChild($xmlRequest->createAttribute('UserID', $self->userid));
409 $requestItems->addChild($xmlRequest->createAttribute('Password', $self->password));
410 $root->addChild($requestItems);
412 foreach my $key (@{$keys}) {
413 my $requestItem = $xmlRequest->createElement('RequestItem');
414 my $keyNode = $xmlRequest->createElement('Key');
415 $keyNode->addChild($xmlRequest->createTextNode($key));
416 $requestItem->addChild($keyNode);
418 foreach my $contentType (@{$contentTypes}) {
419 my $contentNode = $xmlRequest->createElement('Content');
420 if (ref($contentType) eq 'HASH') {
421 $contentNode->addChild($xmlRequest->createTextNode($contentType->{name}));
422 foreach my $contentAttribute (@{$contentType->{attributes}}) {
423 $contentNode->addChild($xmlRequest->createAttribute($contentAttribute->[0], $contentAttribute->[1]));
426 $contentNode->addChild($xmlRequest->createTextNode($contentType));
428 $requestItem->addChild($contentNode);
431 $requestItems->addChild($requestItem);
433 my $response = $AC->post_url($post_url, $xmlRequest->toString);