From f79c1a3b7288c8c74805d3feca026d173ae004f0 Mon Sep 17 00:00:00 2001 From: Owen Leonard Date: Tue, 7 Sep 2010 09:18:50 -0400 Subject: [PATCH] Fix for Bug 4473 - Recent comments view for the OPAC - modifies opac-showreviews.pl to display recent comments for all titles, sorted in descending order by date. - includes RSS feed - includes (thanks to Chris N.): [Enhancement][3.4] Add RFC822 Format to C4::Dates This patch adds RFC822 formatting to C4::Dates. It also updates Dates.t appropriately. Consult the POD for this module for how to use this format. Please note that this module *does not* handle TZ conversion at this point. This means that the TZ portion of a RFC822 time will be truncated and the converted time will be in the same TZ as was passed in. When generating an RFC822 time, the local TZ offset will be included since none of the other supported formats provide a means for including their TZ. This is not a problem introduced by the addition of RFC822 formatting. Rather it is due to this module not having TZ support to begin with. Also note that the dow, moy abbreviations are English as required by RFC822 section 3.3 (thanks to self for pointing that out). --- C4/Dates.pm | 274 ++++++++++++-------- C4/Review.pm | 20 +- koha-tmpl/opac-tmpl/prog/en/css/opac.css | 28 ++- .../prog/en/modules/opac-showreviews-rss.tmpl | 36 +++ .../prog/en/modules/opac-showreviews.tmpl | 100 ++++++-- opac/opac-showreviews.pl | 128 +++++++++- t/Dates.t | 115 ++++---- 7 files changed, 494 insertions(+), 207 deletions(-) create mode 100644 koha-tmpl/opac-tmpl/prog/en/modules/opac-showreviews-rss.tmpl diff --git a/C4/Dates.pm b/C4/Dates.pm index 451e2d3..335de1c 100644 --- a/C4/Dates.pm +++ b/C4/Dates.pm @@ -1,4 +1,5 @@ package C4::Dates; + # This file is part of Koha. # # Koha is free software; you can redistribute it and/or modify it under the @@ -26,154 +27,198 @@ use vars qw($VERSION @ISA @EXPORT @EXPORT_OK %EXPORT_TAGS); use vars qw($debug $cgi_debug); BEGIN { - $VERSION = 0.04; - @ISA = qw(Exporter); - @EXPORT_OK = qw(format_date_in_iso format_date); + $VERSION = 0.04; + @ISA = qw(Exporter); + @EXPORT_OK = qw(format_date_in_iso format_date); } use vars qw($prefformat); + sub _prefformat { - unless (defined $prefformat) { + unless ( defined $prefformat ) { $prefformat = C4::Context->preference('dateformat'); } return $prefformat; } -our %format_map = ( - iso => 'yyyy-mm-dd', # plus " HH:MM:SS" - metric => 'dd/mm/yyyy', # plus " HH:MM:SS" - us => 'mm/dd/yyyy', # plus " HH:MM:SS" - sql => 'yyyymmdd HHMMSS', +our %format_map = ( + iso => 'yyyy-mm-dd', # plus " HH:MM:SS" + metric => 'dd/mm/yyyy', # plus " HH:MM:SS" + us => 'mm/dd/yyyy', # plus " HH:MM:SS" + sql => 'yyyymmdd HHMMSS', + rfc822 => 'a, dd b y HH:MM:SS z ', ); our %posix_map = ( - iso => '%Y-%m-%d', # or %F, "Full Date" - metric => '%d/%m/%Y', - us => '%m/%d/%Y', - sql => '%Y%m%d %H%M%S', + iso => '%Y-%m-%d', # or %F, "Full Date" + metric => '%d/%m/%Y', + us => '%m/%d/%Y', + sql => '%Y%m%d %H%M%S', + rfc822 => '%a, %d %b %Y %H:%M:%S %z', ); -our %dmy_subs = ( # strings to eval (after using regular expression returned by regexp below) - # make arrays for POSIX::strftime() - iso => '[(($6||0),($5||0),($4||0),$3, $2 - 1, $1 - 1900)]', - metric => '[(($6||0),($5||0),($4||0),$1, $2 - 1, $3 - 1900)]', - us => '[(($6||0),($5||0),($4||0),$2, $1 - 1, $3 - 1900)]', - sql => '[(($6||0),($5||0),($4||0),$3, $2 - 1, $1 - 1900)]', +our %dmy_subs = ( # strings to eval (after using regular expression returned by regexp below) + # make arrays for POSIX::strftime() + iso => '[(($6||0),($5||0),($4||0),$3, $2 - 1, $1 - 1900)]', + metric => '[(($6||0),($5||0),($4||0),$1, $2 - 1, $3 - 1900)]', + us => '[(($6||0),($5||0),($4||0),$2, $1 - 1, $3 - 1900)]', + sql => '[(($6||0),($5||0),($4||0),$3, $2 - 1, $1 - 1900)]', + rfc822 => '[($7, $6, $5, $2, $3, $4 - 1900, $8)]', ); +our @months = qw(Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec); + +our @days = qw(Sun Mon Tue Wed Thu Fri Sat); + sub regexp ($;$) { - my $self = shift; - my $delim = qr/:?\:|\/|-/; # "non memory" cluster: no backreference - my $format = (@_) ? _recognize_format(shift) : ($self->{'dateformat'} || _prefformat()); + my $self = shift; + my $delim = qr/:?\:|\/|-/; # "non memory" cluster: no backreference + my $format = (@_) ? _recognize_format(shift) : ( $self->{'dateformat'} || _prefformat() ); # Extra layer of checking $self->{'dateformat'}. # Why? Because it is assumed you might want to check regexp against an *instantiated* Dates object as a # way of saying "does this string match *whatever* format that Dates object is?" - ($format eq 'sql') and - return qr/^(\d{4})(\d{1,2})(\d{1,2})(?:\s{4}(\d{2})(\d{2})(\d{2}))?/; - ($format eq 'iso') and - return qr/^(\d{4})$delim(\d{1,2})$delim(\d{1,2})(?:(?:\s{1}|T)(\d{2})\:?(\d{2})\:?(\d{2}))?Z?/; - return qr/^(\d{1,2})$delim(\d{1,2})$delim(\d{4})(?:\s{1}(\d{1,2})\:?(\d{1,2})\:?(\d{1,2}))?/; # everything else + ( $format eq 'sql' ) + and return qr/^(\d{4})(\d{1,2})(\d{1,2})(?:\s{4}(\d{2})(\d{2})(\d{2}))?/; + ( $format eq 'iso' ) + and return qr/^(\d{4})$delim(\d{1,2})$delim(\d{1,2})(?:(?:\s{1}|T)(\d{2})\:?(\d{2})\:?(\d{2}))?Z?/; + ( $format eq 'rfc822' ) + and return qr/^([a-zA-Z]{3}),\s{1}(\d{1,2})\s{1}([a-zA-Z]{3})\s{1}(\d{4})\s{1}(\d{1,2})\:(\d{1,2})\:(\d{1,2})\s{1}(([\-|\+]\d{4})|([A-Z]{3}))/; + return qr/^(\d{1,2})$delim(\d{1,2})$delim(\d{4})(?:\s{1}(\d{1,2})\:?(\d{1,2})\:?(\d{1,2}))?/; # everything else } sub dmy_map ($$) { - my $self = shift; - my $val = shift or return undef; - my $dformat = $self->{'dateformat'} or return undef; - my $re = $self->regexp(); - my $xsub = $dmy_subs{$dformat}; - $debug and print STDERR "xsub: $xsub \n"; - if ($val =~ /$re/) { - my $aref = eval $xsub; + my $self = shift; + my $val = shift or return undef; + my $dformat = $self->{'dateformat'} or return undef; + my $re = $self->regexp(); + my $xsub = $dmy_subs{$dformat}; + $debug and print STDERR "xsub: $xsub \n"; + if ( $val =~ /$re/ ) { + my $aref = eval $xsub; + if ($dformat eq 'rfc822') { + $aref = _abbr_to_numeric($aref, $dformat); + pop(@{$aref}); #pop off tz offset because we are not setup to handle tz conversions just yet + } _check_date_and_time($aref); - return @{$aref}; - } - # $debug and - carp "Illegal Date '$val' does not match '$dformat' format: " . $self->visual(); - return 0; + push @{$aref}, (-1,-1,1); # for some reason unknown to me, setting isdst to -1 or undef causes strftime to fail to return the tz offset which is required in RFC822 format -chris_n + return @{$aref}; + } + + # $debug and + carp "Illegal Date '$val' does not match '$dformat' format: " . $self->visual(); + return 0; +} + +sub _abbr_to_numeric { + my $aref = shift; + my $dformat = shift; + my ($month_abbr, $day_abbr) = ($aref->[4], $aref->[3]) if $dformat eq 'rfc822'; + + for( my $i = 0; $i < scalar(@months); $i++ ) { + if ( $months[$i] =~ /$month_abbr/ ) { + $aref->[4] = $i-1; + last; + } + }; + + for( my $i = 0; $i < scalar(@days); $i++ ) { + if ( $days[$i] =~ /$day_abbr/ ) { + $aref->[3] = $i; + last; + } + }; + return $aref; } sub _check_date_and_time { my $chron_ref = shift; - my ($year, $month, $day) = _chron_to_ymd($chron_ref); - unless (check_date($year, $month, $day)) { + my ( $year, $month, $day ) = _chron_to_ymd($chron_ref); + unless ( check_date( $year, $month, $day ) ) { carp "Illegal date specified (year = $year, month = $month, day = $day)"; } - my ($hour, $minute, $second) = _chron_to_hms($chron_ref); - unless (check_time($hour, $minute, $second)) { + my ( $hour, $minute, $second ) = _chron_to_hms($chron_ref); + unless ( check_time( $hour, $minute, $second ) ) { carp "Illegal time specified (hour = $hour, minute = $minute, second = $second)"; } } sub _chron_to_ymd { my $chron_ref = shift; - return ($chron_ref->[5] + 1900, $chron_ref->[4] + 1, $chron_ref->[3]); + return ( $chron_ref->[5] + 1900, $chron_ref->[4] + 1, $chron_ref->[3] ); } sub _chron_to_hms { my $chron_ref = shift; - return ($chron_ref->[2], $chron_ref->[1], $chron_ref->[0]); + return ( $chron_ref->[2], $chron_ref->[1], $chron_ref->[0] ); } sub new { - my $this = shift; - my $class = ref($this) || $this; - my $self = {}; - bless $self, $class; - return $self->init(@_); + my $this = shift; + my $class = ref($this) || $this; + my $self = {}; + bless $self, $class; + return $self->init(@_); } + sub init ($;$$) { - my $self = shift; - my $dformat; - $self->{'dateformat'} = $dformat = (scalar(@_) >= 2) ? $_[1] : _prefformat(); - ($format_map{$dformat}) or croak - "Invalid date format '$dformat' from " . ((scalar(@_) >= 2) ? 'argument' : 'system preferences'); - $self->{'dmy_arrayref'} = [((@_) ? $self->dmy_map(shift) : localtime )] ; - $debug and warn "(during init) \@\$self->{'dmy_arrayref'}: " . join(' ',@{$self->{'dmy_arrayref'}}) . "\n"; - return $self; + my $self = shift; + my $dformat; + $self->{'dateformat'} = $dformat = ( scalar(@_) >= 2 ) ? $_[1] : _prefformat(); + ( $format_map{$dformat} ) or croak "Invalid date format '$dformat' from " . ( ( scalar(@_) >= 2 ) ? 'argument' : 'system preferences' ); + $self->{'dmy_arrayref'} = [ ( (@_) ? $self->dmy_map(shift) : localtime ) ]; + $debug and warn "(during init) \@\$self->{'dmy_arrayref'}: " . join( ' ', @{ $self->{'dmy_arrayref'} } ) . "\n"; + return $self; } + sub output ($;$) { - my $self = shift; - my $newformat = (@_) ? _recognize_format(shift) : _prefformat(); - return (eval {POSIX::strftime($posix_map{$newformat}, @{$self->{'dmy_arrayref'}})} || undef); + my $self = shift; + my $newformat = (@_) ? _recognize_format(shift) : _prefformat(); + return ( eval { POSIX::strftime( $posix_map{$newformat}, @{ $self->{'dmy_arrayref'} } ) } || undef ); } -sub today ($;$) { # NOTE: sets date value to today (and returns it in the requested or current format) - my $class = shift; - $class = ref($class) || $class; - my $format = (@_) ? _recognize_format(shift) : _prefformat(); - return $class->new()->output($format); + +sub today ($;$) { # NOTE: sets date value to today (and returns it in the requested or current format) + my $class = shift; + $class = ref($class) || $class; + my $format = (@_) ? _recognize_format(shift) : _prefformat(); + return $class->new()->output($format); } + sub _recognize_format($) { - my $incoming = shift; - ($incoming eq 'syspref') and return _prefformat(); - (scalar grep (/^$incoming$/, keys %format_map) == 1) or croak "The format you asked for ('$incoming') is unrecognized."; - return $incoming; + my $incoming = shift; + ( $incoming eq 'syspref' ) and return _prefformat(); + ( scalar grep ( /^$incoming$/, keys %format_map ) == 1 ) or croak "The format you asked for ('$incoming') is unrecognized."; + return $incoming; } -sub DHTMLcalendar ($;$) { # interface to posix_map - my $class = shift; - my $format = (@_) ? shift : _prefformat(); - return $posix_map{$format}; + +sub DHTMLcalendar ($;$) { # interface to posix_map + my $class = shift; + my $format = (@_) ? shift : _prefformat(); + return $posix_map{$format}; } -sub format { # get or set dateformat: iso, metric, us, etc. - my $self = shift; - (@_) or return $self->{'dateformat'}; - $self->{'dateformat'} = _recognize_format(shift); + +sub format { # get or set dateformat: iso, metric, us, etc. + my $self = shift; + (@_) or return $self->{'dateformat'}; + $self->{'dateformat'} = _recognize_format(shift); } + sub visual { - my $self = shift; - if (@_) { - return $format_map{ _recognize_format(shift) }; - } - $self eq __PACKAGE__ and return $format_map{_prefformat()}; - return $format_map{ eval { $self->{'dateformat'} } || _prefformat()} ; + my $self = shift; + if (@_) { + return $format_map{ _recognize_format(shift) }; + } + $self eq __PACKAGE__ and return $format_map{ _prefformat() }; + return $format_map{ eval { $self->{'dateformat'} } || _prefformat() }; } # like the functions from the old C4::Date.pm sub format_date { - return __PACKAGE__ -> new(shift,'iso')->output((@_) ? shift : _prefformat()); + return __PACKAGE__->new( shift, 'iso' )->output( (@_) ? shift : _prefformat() ); } + sub format_date_in_iso { - return __PACKAGE__ -> new(shift,_prefformat())->output('iso'); + return __PACKAGE__->new( shift, _prefformat() )->output('iso'); } 1; @@ -192,6 +237,7 @@ The formats supported by Koha are: us - U.S. standard metric - European standard (slight misnomer, not really decimalized metric) sql - log format, not really for human consumption + rfc822 - Standard for using with RSS feeds, etc. =head2 ->new([string_date,][date_format]) @@ -200,19 +246,19 @@ used. If date_format is not supplied, the system preference from C4::Context is Examples: - my $now = C4::Dates->new(); - my $date1 = C4::Dates->new("09-21-1989","us"); - my $date2 = C4::Dates->new("19890921 143907","sql"); + my $now = C4::Dates->new(); + my $date1 = C4::Dates->new("09-21-1989","us"); + my $date2 = C4::Dates->new("19890921 143907","sql"); =head2 ->output([date_format]) The date value is stored independent of any specific format. Therefore any format can be invoked when displaying it. - my $date = C4::Dates->new(); # say today is July 12th, 2010 - print $date->output("iso"); # prints "2010-07-12" - print "\n"; - print $date->output("metric"); # prints "12-07-2010" + my $date = C4::Dates->new(); # say today is July 12th, 2010 + print $date->output("iso"); # prints "2010-07-12" + print "\n"; + print $date->output("metric"); # prints "12-07-2010" However, it is still necessary to know the format of any incoming date value (e.g., setting the value of an object with new()). Like new(), output() assumes the system preference @@ -228,32 +274,32 @@ method/function to tell you whether or not a Dates.pm object is of the 'iso' typ can see by this example that such a test is trivial to accomplish, and not necessary to include in the module: - sub is_iso { - my $self = shift; - return ($self->format() eq "iso"); - } + sub is_iso { + my $self = shift; + return ($self->format() eq "iso"); + } Note: A similar function would need to be included for each format. Instead a dependent script can retrieve the format of the object directly and decide what to do with it from there: - my $date = C4::Dates->new(); - my $format = $date->format(); - ($format eq "iso") or do_something($date); + my $date = C4::Dates->new(); + my $format = $date->format(); + ($format eq "iso") or do_something($date); Or if you just want to print a given value and format, no problem: - my $date = C4::Dates->new("1989-09-21", "iso"); - print $date->output; + my $date = C4::Dates->new("1989-09-21", "iso"); + print $date->output; Alternatively: - print C4::Dates->new("1989-09-21", "iso")->output; + print C4::Dates->new("1989-09-21", "iso")->output; Or even: - print C4::Dates->new("21-09-1989", "metric")->output("iso"); + print C4::Dates->new("21-09-1989", "metric")->output("iso"); =head2 "syspref" -- System Preference(s) @@ -263,24 +309,24 @@ psuedo-format argument "syspref". For example, to print an ISO date (from the database) in the format: - my $date = C4::Dates->new($date_from_database,"iso"); - my $datestring_for_display = $date->output("syspref"); - print $datestring_for_display; + my $date = C4::Dates->new($date_from_database,"iso"); + my $datestring_for_display = $date->output("syspref"); + print $datestring_for_display; Or even: - print C4::Dates->new($date_from_database,"iso")->output("syspref"); + print C4::Dates->new($date_from_database,"iso")->output("syspref"); If you just want to know what the is, a default Dates object can tell you: - C4::Dates->new()->format(); + C4::Dates->new()->format(); =head2 ->DHMTLcalendar([date_format]) Returns the format string for DHTML Calendar Display based on date_format. If date_format is not supplied, the return is based on system preference. - C4::Dates->DHTMLcalendar(); # e.g., returns "%m/%d/%Y" for 'us' system preference + C4::Dates->DHTMLcalendar(); # e.g., returns "%m/%d/%Y" for 'us' system preference =head3 Error Handling @@ -290,12 +336,12 @@ fatal error (because it is programmer error, not user error, typically). Scripts must still perform validation of user input. Attempting to set an invalid value will return 0 or undefined, so a script might check as follows: - my $date = C4::Dates->new($input) or deal_with_it("$input didn't work"); + my $date = C4::Dates->new($input) or deal_with_it("$input didn't work"); To validate before creating a new object, use the regexp method of the class: - $input =~ C4::Dates->regexp("iso") or deal_with_it("input ($input) invalid as iso format"); - my $date = C4::Dates->new($input,"iso"); + $input =~ C4::Dates->regexp("iso") or deal_with_it("input ($input) invalid as iso format"); + my $date = C4::Dates->new($input,"iso"); More verbose debugging messages are sent in the presence of non-zero $ENV{"DEBUG"}. diff --git a/C4/Review.pm b/C4/Review.pm index 0b7dbc3..f94dbc8 100644 --- a/C4/Review.pm +++ b/C4/Review.pm @@ -29,7 +29,7 @@ BEGIN { $VERSION = 3.00; require Exporter; @ISA = qw(Exporter); - @EXPORT = qw(getreview savereview updatereview numberofreviews + @EXPORT = qw(getreview savereview updatereview numberofreviews numberofreviewsbybiblionumber getreviews getallreviews approvereview deletereview); } @@ -91,6 +91,15 @@ sub updatereview { } sub numberofreviews { + my $dbh = C4::Context->dbh; + my $query = + "SELECT count(*) FROM reviews WHERE approved=?"; + my $sth = $dbh->prepare($query); + $sth->execute( 1 ); + return $sth->fetchrow; +} + +sub numberofreviewsbybiblionumber { my ($biblionumber) = @_; my $dbh = C4::Context->dbh; my $query = @@ -111,12 +120,13 @@ sub getreviews { } sub getallreviews { - my ($status) = @_; + my ($status, $offset, $row_count) = @_; + my @params = ($status,($offset ? $offset : 0),($row_count ? $row_count : 20)); my $dbh = C4::Context->dbh; my $query = - "SELECT * FROM reviews WHERE approved=? order by datereviewed desc"; - my $sth = $dbh->prepare($query); - $sth->execute($status); + "SELECT * FROM reviews WHERE approved=? order by datereviewed desc LIMIT ?, ?"; + my $sth = $dbh->prepare($query) || warn $dbh->err_str; + $sth->execute(@params); return $sth->fetchall_arrayref({}); } diff --git a/koha-tmpl/opac-tmpl/prog/en/css/opac.css b/koha-tmpl/opac-tmpl/prog/en/css/opac.css index f47c8c2..1132ca6 100644 --- a/koha-tmpl/opac-tmpl/prog/en/css/opac.css +++ b/koha-tmpl/opac-tmpl/prog/en/css/opac.css @@ -1021,8 +1021,7 @@ a.cancel { .searchresults p { margin: 0; - padding: 0; - padding-top : .6em; + padding: 0 0 .6em 0; } td.resultscontrol img { @@ -1970,3 +1969,28 @@ div.ft { list-style:disc outside url("../../images/item-bullet.gif"); padding:0.2em 0; } + +#recentcomments { + margin:auto; + max-width:750px; +} + +.searchresults .commentline { + background-color : rgb(255, 255, 204); + background-color : rgba(255, 255, 204, 0.4); + border : 1px solid #CCC; + display: inline-block; + -webkit-border-radius: 4px; + -moz-border-radius: 4px; + border-radius: 4px; + -webkit-box-shadow: 1px 1px 1px rgba(0, 0, 0, 0.2); + -moz-box-shadow: 1px 1px 1px rgba(0, 0, 0, 0.2); + box-shadow: 1px 1px 1px rgba(0, 0, 0, 0.2); + margin : .3em; + padding : .4em; +} + +.searchresults .commentline.yours { + background-color : rgb(239, 254, 213); + background-color : rgba(239, 254, 213, 0.4); +} \ No newline at end of file diff --git a/koha-tmpl/opac-tmpl/prog/en/modules/opac-showreviews-rss.tmpl b/koha-tmpl/opac-tmpl/prog/en/modules/opac-showreviews-rss.tmpl new file mode 100644 index 0000000..1a81e2e --- /dev/null +++ b/koha-tmpl/opac-tmpl/prog/en/modules/opac-showreviews-rss.tmpl @@ -0,0 +1,36 @@ + + + + <![CDATA[<!-- TMPL_IF NAME="LibraryNameTitle" --><!-- TMPL_VAR NAME="LibraryNameTitle" --><!-- TMPL_ELSE -->Koha Online<!-- /TMPL_IF --> Catalog Recent Comments]]> + /cgi-bin/koha/opac-showreviews.pl&format=rss2 + Koha Online Catalog. Comments can be made by logged in users and are moderated by library staff.]]> + /cgi-bin/koha/opac-showreviews.pl&format=rss2" rel="self" type="application/rss+xml" /> + + + + New comment on <!-- TMPL_VAR NAME="title" ESCAPE="html" --> <!-- TMPL_LOOP NAME="subtitle" -->, <!-- TMPL_VAR ESCAPE="HTML" NAME="subfield" --><!-- /TMPL_LOOP --> + /cgi-bin/koha/opac-detail.pl?biblionumber=#comments + .01.TZZZZZZZ.jpg" alt="" /> + +/SC.GIF&client=&type=xw10&upc=&oclc=" alt="" /> + +/SC.GIF&client=&type=xw10&upc=&oclc=" alt="" /> + + +">See Baker & Taylor" /> +

By .

+

+ + . + , + . +

+

commented on :

+ ]]>
+ /cgi-bin/koha/opac-detail.pl?biblionumber=&reviewid= + +
+ +
+
\ No newline at end of file diff --git a/koha-tmpl/opac-tmpl/prog/en/modules/opac-showreviews.tmpl b/koha-tmpl/opac-tmpl/prog/en/modules/opac-showreviews.tmpl index c8c7260..42ea224 100644 --- a/koha-tmpl/opac-tmpl/prog/en/modules/opac-showreviews.tmpl +++ b/koha-tmpl/opac-tmpl/prog/en/modules/opac-showreviews.tmpl @@ -1,39 +1,97 @@ -Koha Online Catalog › +Koha Online Catalog › Recent Comments +Koha Online Catalog Recent Comments" href="/cgi-bin/koha/opac-showreviews.pl?format=rss" /> + - - - -
+
+ - + \ No newline at end of file diff --git a/opac/opac-showreviews.pl b/opac/opac-showreviews.pl index ac8343a..de39021 100755 --- a/opac/opac-showreviews.pl +++ b/opac/opac-showreviews.pl @@ -1,5 +1,8 @@ #!/usr/bin/perl +# Copyright 2000-2002 Katipo Communications +# Parts copyright 2010 Nelsonville Public Library +# # This file is part of Koha. # # Koha is free software; you can redistribute it and/or modify it under the @@ -25,26 +28,135 @@ use C4::Output; use C4::Circulation; use C4::Review; use C4::Biblio; +use C4::Dates qw/format_date/; +use C4::Members qw/GetMemberDetails/; +use POSIX qw(ceil strftime); + +my $template_name; +my $query = new CGI; +my $format = $query->param("format") || ''; +my $count = C4::Context->preference('OPACnumSearchResults') || 20; +my $results_per_page = $query->param('count') || $count; +my $offset = $query->param('offset') || 0; +my $page = $query->param('page') || 1; +$offset = ($page-1)*$results_per_page if $page>1; -my $query = new CGI; -my $biblionumber = $query->param('biblionumber'); +if ($format eq "rss") { + $template_name = "opac-showreviews-rss.tmpl"; +} else { + $template_name = "opac-showreviews.tmpl", +} my ( $template, $borrowernumber, $cookie ) = &get_template_and_user( { - template_name => "opac-showreviews.tmpl", + template_name => $template_name, query => $query, type => "opac", authnotrequired => 1, } ); -my $biblio = GetBiblioData( $biblionumber ); -my $reviews = getreviews( $biblionumber, 1 ); +if($format eq "rss"){ + my $lastbuilddate = C4::Dates->new(); + my $lastbuilddate_output = $lastbuilddate->output("rfc822"); + $template->param( + rss => 1, + timestamp => $lastbuilddate_output + ); +} + +my $reviews = getallreviews(1,$offset,$results_per_page); +my $marcflavour = C4::Context->preference("marcflavour"); +my $hits = numberofreviews(); +my $i = 0; +my $latest_comment_date; +for my $result (@$reviews){ + my $biblionumber = $result->{biblionumber}; + my $bib = &GetBiblioData($biblionumber); + my $record = GetMarcBiblio($biblionumber); + my $frameworkcode = GetFrameworkCode($biblionumber); + my ( $borr ) = GetMemberDetails( $result->{borrowernumber} ); + $result->{normalized_upc} = GetNormalizedUPC($record,$marcflavour); + $result->{normalized_ean} = GetNormalizedEAN($record,$marcflavour); + $result->{normalized_oclc} = GetNormalizedOCLCNumber($record,$marcflavour); + $result->{normalized_isbn} = GetNormalizedISBN(undef,$record,$marcflavour); + $result->{title} = $bib->{'title'}; + $result->{subtitle} = GetRecordValue('subtitle', $record, $frameworkcode); + $result->{author} = $bib->{'author'}; + $result->{place} = $bib->{'place'}; + $result->{publishercode} = $bib->{'publishercode'}; + $result->{copyrightdate} = $bib->{'copyrightdate'}; + $result->{pages} = $bib->{'pages'}; + $result->{size} = $bib->{'size'}; + $result->{notes} = $bib->{'notes'}; + $result->{timestamp} = $bib->{'timestamp'}; + $result->{firstname} = $borr->{'firstname'}; + $result->{surname} = $borr->{'surname'}; + if ($result->{borrowernumber} eq $borrowernumber) { + $result->{your_comment} = 1; + } + + if($format eq "rss"){ + my $rsstimestamp = C4::Dates->new($result->{datereviewed},"iso"); + my $rsstimestamp_output = $rsstimestamp->output("rfc822"); + $result->{timestamp} = $rsstimestamp_output; + $result->{datereviewed} = format_date($result->{datereviewed}); + } else { + $result->{datereviewed} = format_date($result->{datereviewed}); + } +} +## Build the page numbers on the bottom of the page + my @page_numbers; + my $previous_page_first; + my $previous_page_offset; + # total number of pages there will be + my $pages = ceil($hits / $results_per_page); + # default page number + my $current_page_number = 1; + $current_page_number = ($offset / $results_per_page + 1) if $offset; + if($offset - $results_per_page == 0){ + $previous_page_first = 1; + } elsif ($offset - $results_per_page > 0){ + $previous_page_offset = $offset - $results_per_page; + } + my $next_page_offset = $offset + $results_per_page; + # If we're within the first 10 pages, keep it simple + if ($current_page_number < 10) { + # just show the first 10 pages + # Loop through the pages + my $pages_to_show = 10; + $pages_to_show = $pages if $pages<10; + for ($i=1; $i<=$pages_to_show;$i++) { + # the offset for this page + my $this_offset = (($i*$results_per_page)-$results_per_page); + # the page number for this page + my $this_page_number = $i; + # it should only be highlighted if it's the current page + my $highlight = 1 if ($this_page_number == $current_page_number); + # put it in the array + push @page_numbers, { offset => $this_offset, pg => $this_page_number, highlight => $highlight }; + + } + + } + # now, show twenty pages, with the current one smack in the middle + else { + for ($i=$current_page_number; $i<=($current_page_number + 20 );$i++) { + my $this_offset = ((($i-9)*$results_per_page)-$results_per_page); + my $this_page_number = $i-9; + my $highlight = 1 if ($this_page_number == $current_page_number); + if ($this_page_number <= $pages) { + push @page_numbers, { offset => $this_offset, pg => $this_page_number, highlight => $highlight }; + } + } + } +$template->param( PAGE_NUMBERS => \@page_numbers, + previous_page_first => $previous_page_first, + previous_page_offset => $previous_page_offset) unless $pages < 2; +$template->param(next_page_offset => $next_page_offset) unless $pages eq $current_page_number; $template->param( reviews => $reviews, - title => $biblio->{'title'}, ); -output_html_with_http_headers $query, $cookie, $template->output; - +output_html_with_http_headers $query, $cookie, $template->output; \ No newline at end of file diff --git a/t/Dates.t b/t/Dates.t index da6f377..148bb3e 100644 --- a/t/Dates.t +++ b/t/Dates.t @@ -3,44 +3,43 @@ use strict; use warnings; -use Test::More tests => 276; +use Test::More tests => 327; + BEGIN { - use FindBin; - use lib $FindBin::Bin; - use_ok('C4::Dates', qw(format_date format_date_in_iso)); + use FindBin; + use lib $FindBin::Bin; + use_ok( 'C4::Dates', qw(format_date format_date_in_iso) ); } sub describe ($$) { - my $front = sprintf("%-25s", shift); - my $tail = shift || 'FAILED'; - return "$front : $tail"; + my $front = sprintf( "%-25s", shift ); + my $tail = shift || 'FAILED'; + return "$front : $tail"; } -# Keep the number of test elements per [array] equal or the predicted number of tests +# Keep the number of test elements per [array] equal or the predicted number of tests # needs to be different for different (fake) sysprefs. my %thash = ( - iso => ['2001-1-1','1989-9-21','1952-1-0', '1989-9-21 13:46:02','2001-01-01','1989-09-21','1952-01-00', '1989-09-21 13:46:02'], - metric => ["1-1-2001",'21-9-1989','00-1-1952', '21-9-1989 13:46:02',"01-01-2001",'21-09-1989','00-01-1952', '21-09-1989 13:46:02'], - us => ["01-01-2001",'09-21-1989','01-00-1952', '09-21-1989 13:46:02'], - sql => ['20010101 010101', - '19890921 143907', - '19520100 000000', - '19890921 134602' ], + iso => [ '2001-1-1', '1989-9-21', '1952-1-0', '1989-9-21 13:46:02', '2001-01-01', '1989-09-21', '1952-01-00', '1989-09-21 13:46:02' ], + metric => [ "1-1-2001", '21-9-1989', '00-1-1952', '21-9-1989 13:46:02', "01-01-2001", '21-09-1989', '00-01-1952', '21-09-1989 13:46:02' ], + us => [ "01-01-2001", '09-21-1989', '01-00-1952', '09-21-1989 13:46:02' ], + sql => [ '20010101 010101', '19890921 143907', '19520100 000000', '19890921 134602' ], + rfc822 => [ 'Wed, 02 Oct 2002 15:00:00 +0200', 'Fri, 10 Sep 2010 08:00:00 +0500' ], ); -my ($date, $format, $today, $today0, $val, $re, $syspref); -my @formats = sort keys %thash; +my ( $date, $format, $today, $today0, $val, $re, $syspref ); +my @formats = sort keys %thash; my $fake_syspref_default = 'us'; -my $fake_syspref = (@ARGV) ? shift : $ENV{KOHA_TEST_DATE_FORMAT}; +my $fake_syspref = (@ARGV) ? shift : $ENV{KOHA_TEST_DATE_FORMAT}; if ($fake_syspref) { diag "You asked for date format '$fake_syspref'."; - unless (scalar grep {/^$fake_syspref$/} @formats) { + unless ( scalar grep { /^$fake_syspref$/ } @formats ) { diag "Warning: Unkown date format '$fake_syspref', reverting to default '$fake_syspref_default'."; $fake_syspref = $fake_syspref_default; } } $fake_syspref or $fake_syspref = $fake_syspref_default; -$C4::Dates::prefformat = $fake_syspref; # So Dates doesn't have to ask the DB anything. +$C4::Dates::prefformat = $fake_syspref; # So Dates doesn't have to ask the DB anything. diag <new->format(), "Your system preference is: $syspref"); +ok( $syspref = C4::Dates->new->format(), "Your system preference is: $syspref" ); print "\n"; -foreach (@{$thash{'iso'}}) { - ok($val = format_date($_), "format_date('$_'): $val" ); +foreach ( @{ $thash{'iso'} } ) { + ok( $val = format_date($_), "format_date('$_'): $val" ); } -foreach (@{$thash{$syspref}}) { - ok($val = format_date_in_iso($_), "format_date_in_iso('$_'): $val" ); +foreach ( @{ $thash{$syspref} } ) { + ok( $val = format_date_in_iso($_), "format_date_in_iso('$_'): $val" ); } -ok($today0 = C4::Dates->today(), "(default) CLASS ->today : $today0" ); +ok( $today0 = C4::Dates->today(), "(default) CLASS ->today : $today0" ); diag "\nTesting " . scalar(@formats) . " formats.\nTesting no input (defaults):\n"; print "\n"; foreach (@formats) { - my $pre = sprintf '(%-6s)', $_; - ok($date = C4::Dates->new(), "$pre Date Creation : new()"); - ok($_ eq ($format = $date->format($_)), "$pre format($_) : " . ($format|| 'FAILED') ); - ok($format = $date->visual(), "$pre visual() : " . ($format|| 'FAILED') ); - ok($today = $date->output(), "$pre output() : " . ($today || 'FAILED') ); - ok($today = $date->today(), "$pre object->today : " . ($today || 'FAILED') ); - print "\n"; + my $pre = sprintf '(%-6s)', $_; + ok( $date = C4::Dates->new(), "$pre Date Creation : new()" ); + ok( $_ eq ( $format = $date->format($_) ), "$pre format($_) : " . ( $format || 'FAILED' ) ); + ok( $format = $date->visual(), "$pre visual() : " . ( $format || 'FAILED' ) ); + ok( $today = $date->output(), "$pre output() : " . ( $today || 'FAILED' ) ); + ok( $today = $date->today(), "$pre object->today : " . ( $today || 'FAILED' ) ); + print "\n"; } diag "\nTesting with valid inputs:\n"; foreach $format (@formats) { - my $pre = sprintf '(%-6s)', $format; - foreach my $testval (@{$thash{ $format }}) { - ok($date = C4::Dates->new($testval,$format), "$pre Date Creation : new('$testval','$format')"); - ok($re = $date->regexp, "$pre has regexp()" ); - ok($testval =~ /^$re$/, "$pre has regexp() match $testval"); - ok($val = $date->output(), describe("$pre output()", $val) ); - SKIP: { - skip("special case with explicit regexp('syspref') because $format isn't $syspref", 1) unless ($format eq $syspref); - my $re_syspref = C4::Dates->regexp('syspref'); - ok($testval =~ /^$re_syspref$/, "$pre has regexp('syspref') match $testval"); + my $pre = sprintf '(%-6s)', $format; + foreach my $testval ( @{ $thash{$format} } ) { + ok( $date = C4::Dates->new( $testval, $format ), "$pre Date Creation : new('$testval','$format')" ); + ok( $re = $date->regexp, "$pre has regexp()" ); + ok( $testval =~ /^$re$/, "$pre has regexp() match $testval" ); + ok( $val = $date->output(), describe( "$pre output()", $val ) ); + SKIP: { + skip( "special case with explicit regexp('syspref') because $format isn't $syspref", 1 ) unless ( $format eq $syspref ); + my $re_syspref = C4::Dates->regexp('syspref'); + ok( $testval =~ /^$re_syspref$/, "$pre has regexp('syspref') match $testval" ); + } + foreach ( grep { !/$format/ } @formats ) { + ok( $today = $date->output($_), describe( sprintf( "$pre output(%8s)", "'$_'" ), $today ) ); + } + ok( $today = $date->today(), describe( "$pre object->today", $today ) ); + + # ok($today == ($today = C4::Dates->today()), "$pre CLASS ->today : $today" ); + ok( $val = $date->output(), describe( "$pre output()", $val ) ); + + # ok($format eq ($format = $date->format()), "$pre format() : $format" ); + print "\n"; } - foreach (grep {!/$format/} @formats) { - ok($today = $date->output($_), describe(sprintf("$pre output(%8s)","'$_'"), $today) ); - } - ok($today = $date->today(), describe("$pre object->today", $today) ); - # ok($today == ($today = C4::Dates->today()), "$pre CLASS ->today : $today" ); - ok($val = $date->output(), describe("$pre output()", $val) ); - # ok($format eq ($format = $date->format()), "$pre format() : $format" ); - print "\n"; - } } diag "\nTesting object independence from class\n"; -my $in1 = '12/25/1952'; # us -my $in2 = '13/01/2001'; # metric -my $d1 = C4::Dates->new($in1, 'us'); -my $d2 = C4::Dates->new($in2, 'metric'); +my $in1 = '12/25/1952'; # us +my $in2 = '13/01/2001'; # metric +my $d1 = C4::Dates->new( $in1, 'us' ); +my $d2 = C4::Dates->new( $in2, 'metric' ); my $out1 = $d1->output('iso'); my $out2 = $d2->output('iso'); -ok($out1 ne $out2, "subsequent constructors get different dataspace ($out1 != $out2)"); +ok( $out1 ne $out2, "subsequent constructors get different dataspace ($out1 != $out2)" ); diag "done.\n"; -- 1.7.1