Backport RSS feed fixes from trunk (c9950)
authordbs <dbs@dcc99617-32d9-48b4-a31d-7c20da2025e4>
Sat, 5 Jul 2008 17:59:06 +0000 (17:59 +0000)
committerdbs <dbs@dcc99617-32d9-48b4-a31d-7c20da2025e4>
Sat, 5 Jul 2008 17:59:06 +0000 (17:59 +0000)
git-svn-id: svn://svn.open-ils.org/ILS/branches/rel_1_2@9967 dcc99617-32d9-48b4-a31d-7c20da2025e4

Open-ILS/src/extras/Makefile.install
Open-ILS/src/perlmods/OpenILS/WWW/SuperCat.pm
Open-ILS/src/perlmods/OpenILS/WWW/SuperCat/Feed.pm
Open-ILS/xsl/MARC21slim2ATOM.xsl
Open-ILS/xsl/MARC21slim2RSS2.xsl

index 5c6dbca..a5122b4 100644 (file)
@@ -97,6 +97,7 @@ DEBS =  \
     libclass-dbi-abstractsearch-perl\
     libtemplate-perl\
     libtext-aspell-perl\
+    libdatetime-format-mail-perl\
     libdatetime-timezone-perl\
     libdatetime-perl\
     libunix-syslog-perl\
index aee47e3..86d25a3 100644 (file)
@@ -408,7 +408,7 @@ sub unapi {
 
                $feed->root($root);
                $feed->creator($host);
-               $feed->update_ts(gmtime_ISO8601());
+               $feed->update_ts();
                $feed->link( unapi => $base) if ($flesh_feed);
 
                print "Content-type: ". $feed->type ."; charset=utf-8\n\n";
@@ -610,7 +610,9 @@ sub supercat {
 
                $feed->root($root);
                $feed->creator($host);
-               $feed->update_ts(gmtime_ISO8601());
+
+               $feed->update_ts();
+
                $feed->link( unapi => $base) if ($flesh_feed);
 
                print "Content-type: ". $feed->type ."; charset=utf-8\n\n";
@@ -679,7 +681,6 @@ sub bookbag_feed {
        return Apache2::Const::NOT_FOUND unless($bucket);
 
        my $bucket_tag = "tag:$host,$year:record_bucket/$id";
-       $feed->id($bucket_tag);
        if ($type eq 'opac') {
                print "Location: $root/../../en-US/skin/default/xml/rresult.xml?rt=list&" .
                        join('&', map { "rl=" . $_->target_biblio_record_entry } @{ $bucket->items }) .
@@ -696,10 +697,11 @@ sub bookbag_feed {
                $flesh_feed
        );
        $feed->root($root);
+       $feed->id($bucket_tag);
 
        $feed->title("Items in Book Bag [".$bucket->name."]");
        $feed->creator($host);
-       $feed->update_ts(gmtime_ISO8601());
+       $feed->update_ts();
 
        $feed->link(alternate => $base . "/rss2-full/$id" => 'application/rss+xml');
        $feed->link(atom => $base . "/atom-full/$id" => 'application/atom+xml');
@@ -708,7 +710,7 @@ sub bookbag_feed {
 
        $feed->link(
                OPAC =>
-               '/opac/en-US/skin/default/xml/rresult.xml?rt=list&' .
+               $host . '/opac/en-US/skin/default/xml/rresult.xml?rt=list&' .
                        join('&', map { 'rl=' . $_->target_biblio_record_entry } @{$bucket->items} ),
                'text/html'
        );
@@ -768,7 +770,7 @@ sub changes_feed {
        }
 
        $feed->creator($host);
-       $feed->update_ts(gmtime_ISO8601());
+       $feed->update_ts();
 
        $feed->link(alternate => $base . "/rss2-full/$rtype/$axis/$limit/$date" => 'application/rss+xml');
        $feed->link(atom => $base . "/atom-full/$rtype/$axis/$limit/$date" => 'application/atom+xml');
@@ -777,7 +779,7 @@ sub changes_feed {
 
        $feed->link(
                OPAC =>
-               '/opac/en-US/skin/default/xml/rresult.xml?rt=list&' .
+               $host . '/opac/en-US/skin/default/xml/rresult.xml?rt=list&' .
                        join('&', map { 'rl=' . $_} @$list ),
                'text/html'
        );
@@ -993,14 +995,14 @@ sub opensearch_feed {
 
     my $recs = $search->request(
         'open-ils.search.biblio.multiclass.query' => {
-                               org_unit        => $org_unit->[0]->id,
+                       org_unit        => $org_unit->[0]->id,
                        offset          => $offset,
                        limit           => $limit,
                        sort            => $sort,
                        sort_dir        => $sortdir,
-                               ($lang ?    ( 'language' => $lang    ) : ()),
+                       ($lang ?    ( 'language' => $lang    ) : ()),
                } => $terms => 1
-               )->gather(1);
+       )->gather(1);
 
        $log->debug("Hits for [$terms]: $recs->{count}");
 
@@ -1020,10 +1022,10 @@ sub opensearch_feed {
        $feed->search($terms);
        $feed->class($class);
 
-               $feed->title("Search results for [$terms] at ".$org_unit->[0]->name);
+       $feed->title("Search results for [$terms] at ".$org_unit->[0]->name);
 
        $feed->creator($host);
-       $feed->update_ts(gmtime_ISO8601());
+       $feed->update_ts();
 
        $feed->_create_node(
                $feed->{item_xpath},
index ba9d3cc..bce56dd 100644 (file)
@@ -6,6 +6,9 @@ use XML::LibXML;
 use XML::LibXSLT;
 use OpenSRF::Utils::SettingsClient;
 use CGI;
+use DateTime;
+use DateTime::Format::Mail;
+
 
 sub exists {
        my $class = shift;
@@ -225,6 +228,7 @@ sub creator {};
 
 package OpenILS::WWW::SuperCat::Feed::atom;
 use base 'OpenILS::WWW::SuperCat::Feed';
+use OpenSRF::Utils qw/:datetime/;
 
 sub new {
        my $class = shift;
@@ -244,7 +248,8 @@ sub title {
 
 sub update_ts {
        my $self = shift;
-       my $text = shift;
+       # ATOM demands RFC-3339 compliant datetime formats
+       my $text = shift || gmtime_ISO8601();
        $self->_create_node($self->{item_xpath},'http://www.w3.org/2005/Atom','updated', $text);
 }
 
@@ -317,11 +322,15 @@ sub title {
        my $self = shift;
        my $text = shift;
        $self->_create_node('/rss/channel',undef,'title', $text);
+       # RSS2 demands a /channel/description element; just dupe title until we give
+       # users the ability to provide a description for their bookbags
+       $self->_create_node('/rss/channel',undef,'description', $text);
 }
 
 sub update_ts {
        my $self = shift;
-       my $text = shift;
+       # RSS2 demands RFC-822 compliant datetime formats
+       my $text = shift || DateTime::Format::Mail->format_datetime(DateTime->now());
        $self->_create_node($self->{item_xpath},undef,'lastBuildDate', $text);
 }
 
@@ -337,17 +346,27 @@ sub link {
        my $id = shift;
        my $mime = shift || "application/x-$type+xml";
 
-       $type = 'self' if ($type eq 'rss2');
-
-       $self->_create_node(
-               $self->{item_xpath},
-               undef,
-               'link',
-               $id,
-               { rel => $type,
-                 type => $mime,
-               }
-       );
+       if ($type eq 'rss2' or $type eq 'alternate') {
+               # Just link to ourself using standard RSS2 link element
+               $self->_create_node(
+                       $self->{item_xpath},
+                       undef,
+                       'link',
+                       $id,
+                       undef
+               );
+       } else {
+               # Alternate link: use XHTML link element
+               $self->_create_node(
+                       $self->{item_xpath},
+                       'http://www.w3.org/1999/xhtml',
+                       'xhtml:link',
+                       $id,
+                       { rel => $type,
+                         type => $mime,
+                       }
+               );
+       }
 }
 
 sub id {
@@ -372,11 +391,33 @@ sub new {
 
 sub update_ts {
        my $self = shift;
+       # RSS2 demands RFC-822 compliant datetime formats
        my $text = shift;
+       if (!$text) {
+               # No date passed in, default to now
+               $text = DateTime::Format::Mail->format_datetime(DateTime->now());
+       } elsif ($text =~ m/^\s*(\d{4})\.?\s*$/o) {
+               # Publication date is just a year, convert accordingly
+               my $year = DateTime->new(year=>$1);
+               $text = DateTime::Format::Mail->format_datetime($year);
+       }
        $self->_create_node($self->{item_xpath},undef,'pubDate', $text);
 }
 
+sub id {
+       my $self = shift;
+       my $id = shift;
 
+       $self->_create_node(
+               $self->{item_xpath},
+               undef,
+               'guid',
+               $id,
+               {
+                       isPermaLink=>"false"
+               }
+       );
+}
 
 #----------------------------------------------------------
 
index e706763..dd0c7e1 100644 (file)
@@ -24,6 +24,7 @@
                                </id>
                        </xsl:for-each>
 
+                       <!-- Spec wants RFC 3339 format - fix it outside of XSL? -->
                        <xsl:for-each select="marc:controlfield[@tag=005]">
                                <updated>
                                        <xsl:value-of select="."/>
                                </rights>
                        </xsl:for-each>
 
+                       <!-- Spec wants RFC 3339 format - fix it outside of XSL? -->
                        <xsl:for-each select="marc:datafield[@tag=260]/marc:subfield[@code='c']">
                                <published>
                                        <xsl:value-of select="."/>
                                </published>                            
                        </xsl:for-each>
 
-                       <xsl:for-each select="marc:datafield[500&lt;@tag][@tag&lt;=599][not(@tag=506 or @tag=530 or @tag=540 or @tag=546)]">
-                               <summary>
-                                       <xsl:value-of select="marc:subfield[@code='a']"/>
-                               </summary>
-                       </xsl:for-each>
+                       <!--
+                       Spec wants zero or one summary elements per item; best option
+                       would be to test for one of these elements and only create
+                       if one exists, but for now we simply merge all candidates
+                       -->
+                       <summary>
+                               <xsl:for-each select="marc:datafield[500&lt;@tag][@tag&lt;=599][not(@tag=506 or @tag=530 or @tag=540 or @tag=546)]">
+                                               <xsl:value-of select="marc:subfield[@code='a']"/>
+                               </xsl:for-each>
+                       </summary>
 
                        <xsl:for-each select="marc:datafield[@tag=600 or @tag=610 or @tag=611 or @tag=630 or @tag=650 or @tag=653]">
                                <category>
index 8461557..bb8f852 100644 (file)
@@ -78,6 +78,7 @@
                                </dc:publisher>
                        </xsl:for-each>
 
+                       <!-- this is supposed to be RFC-822 compliant -->
                        <xsl:for-each select="marc:datafield[@tag=260]/marc:subfield[@code='c']">
                                <pubDate>
                                        <xsl:value-of select="."/>
                                </dc:format>
                        </xsl:for-each>
 
-                       <xsl:for-each select="marc:datafield[500&lt;@tag][@tag&lt;=599][not(@tag=506 or @tag=530 or @tag=540 or @tag=546)]">
-                               <description>
-                                       <xsl:value-of select="marc:subfield[@code='a']"/>
-                               </description>
-                       </xsl:for-each>
+                       <!-- specification only allows one description element per item -->
+                       <description>
+                               <xsl:for-each select="marc:datafield[500&lt;@tag][@tag&lt;=599][not(@tag=506 or @tag=530 or @tag=540 or @tag=546)]">
+                                               <xsl:value-of select="marc:subfield[@code='a']"/>
+                               </xsl:for-each>
+                       </description>
 
                        <xsl:for-each select="marc:datafield[@tag=600]">
                                <dc:subject>