Bugzilla – Attachment 111447 Details for
Bug 26145
Add the ability to attach a cover image at item level
Home
|
New
|
Browse
|
Search
|
[?]
|
Reports
|
Help
|
New Account
|
Log In
[x]
|
Forgot Password
Login:
[x]
[patch]
Bug 26145: Add the ability to upload a cover image per item
Bug-26145-Add-the-ability-to-upload-a-cover-image-.patch (text/plain), 21.48 KB, created by
Katrin Fischer
on 2020-10-11 12:50:33 UTC
(
hide
)
Description:
Bug 26145: Add the ability to upload a cover image per item
Filename:
MIME Type:
Creator:
Katrin Fischer
Created:
2020-10-11 12:50:33 UTC
Size:
21.48 KB
patch
obsolete
>From 8da4f82b6d11f3165c52627d5f54d7655660ebd4 Mon Sep 17 00:00:00 2001 >From: Jonathan Druart <jonathan.druart@bugs.koha-community.org> >Date: Tue, 28 Jul 2020 21:18:20 +0200 >Subject: [PATCH] Bug 26145: Add the ability to upload a cover image per item > >This patchset adds the ability to attach cover images at item level. >This commit message will explain the different patches that are >following. > >The main idea is to have cover images for a given item. This is useful >for a bibliographic record linked with a subscription. Each item could >have the cover image for the serial numbers. > >In this first patch there is a limitation to allow only 1 cover per >item, but a later patch will remove it. That way we will take advantage >of the recent work done to display nicely cover images (bug 25031), and >reuse it in this development (staff interface only). > >In order to use a flexible and robust code, the legacy C4 code >(C4::Images) has been moved to Koha::CoverImages. Also the DB table >biblioimages has been renamed cover_images. > >Test plan (for the whole patch set): >0. Turn off AllowMultipleCovers >1. Create a new bibliographic record and items >2. Attach a cover image to the bibliographic record >3. In the item list of the bibliographic detail page, you will notice a >new "Upload image" action. Select it >4. Select an image >=> Notice the new column in the item table >5. Upload another image >=> You cannot upload 2 images, you are going to replace the existing one >6. Turn on AllowMultipleCovers >7. Attach another image to the image >=> Notice the 2 images are displayed nicely, with navigation controls >8. Confirm you can view an image if you click on it and you can delete it >9. Test the OPAC view now >=> Cover image for items are displayed in the table, there is no >navigation controls here however. > >Sponsored-by: Gerhard Sondermann Dialog e.K. (presseplus.de, presseshop.at, presseshop.ch) > >Signed-off-by: Katrin Fischer <katrin.fischer.83@web.de> >--- > C4/Images.pm | 49 +++++++++++++++++----- > catalogue/detail.pl | 14 +++++++ > catalogue/imageviewer.pl | 24 ++++++++--- > .../prog/en/modules/catalogue/detail.tt | 23 +++++++++- > .../prog/en/modules/catalogue/imageviewer.tt | 2 +- > .../prog/en/modules/tools/upload-images.tt | 34 +++++++++------ > svc/cover_images | 13 +++--- > tools/upload-cover-image.pl | 33 ++++++++++----- > 8 files changed, 145 insertions(+), 47 deletions(-) > >diff --git a/C4/Images.pm b/C4/Images.pm >index 37b24179aa..811c144991 100644 >--- a/C4/Images.pm >+++ b/C4/Images.pm >@@ -18,12 +18,11 @@ package C4::Images; > # You should have received a copy of the GNU General Public License > # along with Koha; if not, see <http://www.gnu.org/licenses>. > >-use strict; >-use warnings; >-use 5.010; >+use Modern::Perl; > > use C4::Context; > use GD; >+use Koha::Exceptions; > > use vars qw($debug $noimage @ISA @EXPORT); > >@@ -47,18 +46,32 @@ BEGIN { > > =head2 PutImage > >- PutImage($biblionumber, $srcimage, $replace); >+ PutImage({ biblionumber => $biblionumber, itemnumber => $itemnumber, src_image => $srcimage, replace => $replace }); > >-Stores binary image data and thumbnail in database, optionally replacing existing images for the given biblio. >+Stores binary image data and thumbnail in database, optionally replacing existing images for the given biblio or item. > > =cut > > sub PutImage { >- my ( $biblionumber, $srcimage, $replace ) = @_; >+ my ( $params ) = @_; >+ >+ my $biblionumber = $params->{biblionumber}; >+ my $itemnumber = $params->{itemnumber}; >+ my $srcimage = $params->{src_image}; >+ my $replace = $params->{replace}; >+ >+ Koha::Exceptions::WrongParameter->throw( >+ 'PutImage cannot be called with both biblionumber and itemnumber') >+ if $biblionumber and $itemnumber; >+ >+ Koha::Exceptions::WrongParameter->throw( >+ 'PutImage must be called with "replace" if itemnumber is passed. Only 1 cover per item is allowed.') >+ if $itemnumber and not $replace; >+ > > return -1 unless defined($srcimage); > >- if ($replace) { >+ if ($biblionumber && $replace) { > foreach ( ListImagesForBiblio($biblionumber) ) { > DelImage($_); > } >@@ -66,7 +79,7 @@ sub PutImage { > > my $dbh = C4::Context->dbh; > my $query = >-"INSERT INTO biblioimages (biblionumber, mimetype, imagefile, thumbnail) VALUES (?,?,?,?);"; >+"INSERT INTO biblioimages (biblionumber, itemnumber, mimetype, imagefile, thumbnail) VALUES (?,?,?,?,?);"; > my $sth = $dbh->prepare($query); > > my $mimetype = 'image/png' >@@ -79,10 +92,10 @@ sub PutImage { > ; # MAX pixel dims are 600 X 800 for full-size image... > $debug and warn "thumbnail is " . length($thumbnail) . " bytes."; > >- $sth->execute( $biblionumber, $mimetype, $fullsize->png(), >+ $sth->execute( $biblionumber, $itemnumber, $mimetype, $fullsize->png(), > $thumbnail->png() ); > my $dberror = $sth->errstr; >- warn "Error returned inserting $biblionumber.$mimetype." if $sth->errstr; >+ warn sprintf("Error returned inserting %s.%s.", ($biblionumber || $itemnumber, $mimetype)) if $sth->errstr; > undef $thumbnail; > undef $fullsize; > return $dberror; >@@ -135,6 +148,22 @@ sub ListImagesForBiblio { > return @imagenumbers; > } > >+=head2 GetImageForItem >+ my $image = GetImageForItem($itemnumber); >+ >+Gets the image associated with a particular item. >+ >+=cut >+ >+sub GetImageForItem { >+ my ($itemnumber) = @_; >+ >+ my $dbh = C4::Context->dbh; >+ return $dbh->selectrow_array( >+ 'SELECT imagenumber FROM biblioimages WHERE itemnumber = ?', >+ undef, $itemnumber ); >+} >+ > =head2 DelImage > > my ($dberror) = DelImage($imagenumber); >diff --git a/catalogue/detail.pl b/catalogue/detail.pl >index f454f22c29..3246468015 100755 >--- a/catalogue/detail.pl >+++ b/catalogue/detail.pl >@@ -322,6 +322,7 @@ if ($currentbranch and C4::Context->preference('SeparateHoldings')) { > $template->param(SeparateHoldings => 1); > } > my $separatebranch = C4::Context->preference('SeparateHoldingsBranch') || 'homebranch'; >+my ( $itemloop_has_images, $otheritemloop_has_images ); > foreach my $item (@items) { > my $itembranchcode = $item->{$separatebranch}; > >@@ -406,17 +407,30 @@ foreach my $item (@items) { > } > } > >+ if ( C4::Context->preference("LocalCoverImages") == 1 ) { >+ $item->{imagenumber} = >+ C4::Images::GetImageForItem( $item->{itemnumber} ); >+ } >+ > if ($currentbranch and C4::Context->preference('SeparateHoldings')) { > if ($itembranchcode and $itembranchcode eq $currentbranch) { > push @itemloop, $item; >+ $itemloop_has_images++ if $item->{imagenumber}; > } else { > push @otheritemloop, $item; >+ $otheritemloop_has_images++ if $item->{imagenumber}; > } > } else { > push @itemloop, $item; >+ $itemloop_has_images++ if $item->{imagenumber}; > } > } > >+$template->param( >+ itemloop_has_images => $itemloop_has_images, >+ otheritemloop_has_images => $otheritemloop_has_images, >+); >+ > # Display only one tab if one items list is empty > if (scalar(@itemloop) == 0 || scalar(@otheritemloop) == 0) { > $template->param(SeparateHoldings => 0); >diff --git a/catalogue/imageviewer.pl b/catalogue/imageviewer.pl >index ac7d3204d0..d20fae1364 100755 >--- a/catalogue/imageviewer.pl >+++ b/catalogue/imageviewer.pl >@@ -28,6 +28,7 @@ use C4::Images; > use C4::Search; > > use Koha::Biblios; >+use Koha::Items; > use Koha::Patrons; > > my $query = new CGI; >@@ -40,7 +41,8 @@ my ( $template, $borrowernumber, $cookie ) = get_template_and_user( > } > ); > >-my $biblionumber = $query->param('biblionumber') || $query->param('bib'); >+my $itemnumber = $query->param('itemnumber'); >+my $biblionumber = $query->param('biblionumber') || $query->param('bib') || Koha::Items->find($itemnumber)->biblionumber; > my $imagenumber = $query->param('imagenumber'); > my $biblio = Koha::Biblios->find( $biblionumber ); > my $itemcount = $biblio ? $biblio->items->count : 0; >@@ -65,10 +67,22 @@ if( $query->cookie("searchToOrder") ){ > } > > if ( C4::Context->preference("LocalCoverImages") ) { >- my @images = ListImagesForBiblio($biblionumber); >- $template->{VARS}->{'LocalCoverImages'} = 1; >- $template->{VARS}->{'images'} = \@images; >- $template->{VARS}->{'imagenumber'} = $imagenumber || $images[0] || ''; >+ if ( $itemnumber ) { >+ my $image = C4::Images::GetImageForItem($itemnumber); >+ $template->param( >+ LocalCoverImages => 1, >+ images => [$image], >+ imagenumber => $imagenumber, >+ ); >+ >+ } else { >+ my @images = ListImagesForBiblio($biblionumber); >+ $template->param( >+ LocalCoverImages => 1, >+ images => \@images, >+ imagenumber => $imagenumber || $images[0] || '', >+ ); >+ } > } > $template->{VARS}->{'count'} = $itemcount; > $template->{VARS}->{'biblionumber'} = $biblionumber; >diff --git a/koha-tmpl/intranet-tmpl/prog/en/modules/catalogue/detail.tt b/koha-tmpl/intranet-tmpl/prog/en/modules/catalogue/detail.tt >index d67c3b42c0..da5b91fc70 100644 >--- a/koha-tmpl/intranet-tmpl/prog/en/modules/catalogue/detail.tt >+++ b/koha-tmpl/intranet-tmpl/prog/en/modules/catalogue/detail.tt >@@ -285,6 +285,9 @@ > <thead> > <tr> > [% IF (StaffDetailItemSelection) %]<th id="[% tab | html %]_checkbox" data-colname="[% tab | html %]_checkbox" class="NoSort"></th>[% END %] >+ [% IF ( tab == 'holdings' && itemloop_has_images || tab == 'otherholdings' && otheritemloop_has_images ) %] >+ <th id="[% tab | html %]_cover" data-colname="[% tab | html %]_cover">Cover image</th> >+ [% END %] > [% IF ( item_level_itypes ) %]<th id="[% tab | html %]_itype" data-colname="[% tab | html %]_itype">Item type</th>[% END %] > <th id="[% tab | html %]_holdingbranch" data-colname="[% tab | html %]_holdingbranch">Current library</th> > <th id="[% tab | html %]_homebranch" data-colname="[% tab | html %]_homebranch">Home library</th> >@@ -323,6 +326,16 @@ > <input type="checkbox" value="[% item.itemnumber | html %]" name="itemnumber" /> > </td> > [% END %] >+ [% IF ( tab == 'holdings' && itemloop_has_images || tab == 'otherholdings' && otheritemloop_has_images ) %] >+ <td class="cover"> >+ [% IF item.imagenumber %] >+ <a href="/cgi-bin/koha/catalogue/imageviewer.pl?itemnumber=[% item.itemnumber | uri %]&imagenumber=[% item.imagenumber | uri %]"> >+ <img src="/cgi-bin/koha/catalogue/image.pl?thumbnail=1amp;imagenumber=[% item.imagenumber | uri %]" /> >+ </a> >+ [% END %] >+ </td> >+ [% END %] >+ > [% IF ( item_level_itypes ) %] > <td class="itype"> > [% IF !noItemTypeImages && item.imageurl %] >@@ -533,7 +546,12 @@ Note that permanent location is a code, and location may be an authval. > [% IF CAN_user_editcatalogue_edit_items %] > <td class="actions"> > [% UNLESS item.cannot_be_edited %] >- <a class="btn btn-default btn-xs" href="/cgi-bin/koha/cataloguing/additem.pl?op=edititem&biblionumber=[% item.biblionumber | html %]&itemnumber=[% item.itemnumber | html %]#edititem"><i class="fa fa-pencil"></i> Edit</a> >+ <div class="btn-group"> >+ <a class="btn btn-default btn-xs" href="/cgi-bin/koha/cataloguing/additem.pl?op=edititem&biblionumber=[% item.biblionumber | html %]&itemnumber=[% item.itemnumber | html %]#edititem"><i class="fa fa-pencil"></i> Edit</a><a class="btn btn-default btn-xs dropdown-toggle" data-toggle="dropdown"><span class="caret"></span></a> >+ <ul class="dropdown-menu pull-right"> >+ <li><a href="/cgi-bin/koha/tools/upload-cover-image.pl?itemnumber=[% item.itemnumber | uri %]&filetype=image"><i class="fa fa-upload">Upload image</i></a></li> >+ </ul> >+ </div> > [% END %] > </td> > [% END %] >@@ -541,6 +559,7 @@ Note that permanent location is a code, and location may be an authval. > [% END %] > </tbody> > </table> >+ > [% END %][%# end of block items_table %] > > <div id="holdings"> >@@ -1054,7 +1073,7 @@ Note that permanent location is a code, and location may be an authval. > thumbnail.find("img").css("opacity", ".2"); > thumbnail.find("a.remove").html("<img style='display:inline-block' src='" + interface + "/" + theme + "/img/spinner-small.gif' alt='' />"); > $.ajax({ >- url: "/cgi-bin/koha/svc/cover_images?action=delete&biblionumber=" + biblionumber + "&imagenumber=" + imagenumber, >+ url: "/cgi-bin/koha/svc/cover_images?action=delete&imagenumber=" + imagenumber, > success: function(data) { > $(data).each( function(i) { > if ( this.deleted == 1 ) { >diff --git a/koha-tmpl/intranet-tmpl/prog/en/modules/catalogue/imageviewer.tt b/koha-tmpl/intranet-tmpl/prog/en/modules/catalogue/imageviewer.tt >index a61045636e..f1fb75e98a 100644 >--- a/koha-tmpl/intranet-tmpl/prog/en/modules/catalogue/imageviewer.tt >+++ b/koha-tmpl/intranet-tmpl/prog/en/modules/catalogue/imageviewer.tt >@@ -133,7 +133,7 @@ > thumbnail.find("a.remove").html("<img style='display:inline-block' src='" + interface + "/" + theme + "/img/spinner-small.gif' alt='' />"); > > $.ajax({ >- url: "/cgi-bin/koha/svc/cover_images?action=delete&biblionumber=" + biblionumber + "&imagenumber=" + imagenumber, >+ url: "/cgi-bin/koha/svc/cover_images?action=delete&imagenumber=" + imagenumber, > success: function(data) { > $(data).each( function() { > if ( this.deleted == 1 ) { >diff --git a/koha-tmpl/intranet-tmpl/prog/en/modules/tools/upload-images.tt b/koha-tmpl/intranet-tmpl/prog/en/modules/tools/upload-images.tt >index ee8296b7d4..9abce8f7ec 100644 >--- a/koha-tmpl/intranet-tmpl/prog/en/modules/tools/upload-images.tt >+++ b/koha-tmpl/intranet-tmpl/prog/en/modules/tools/upload-images.tt >@@ -77,24 +77,34 @@ > <fieldset class="rows"> > <legend>File type</legend> > <ol> >- <li class="radio"> >- [% IF (filetype != 'image' ) %]<input type="radio" id="zipfile" name="filetype" value="zip" checked="checked" />[% ELSE %]<input type="radio" id="zipfile" name="filetype" value="zip" />[% END %] >- <label for="zipfile">ZIP file</label> >- </li> >- <li class="radio"> >- [% IF (filetype == 'image' ) %]<input type="radio" id="image" name="filetype" value="image" checked="checked" />[% ELSE %]<input type="radio" id="image" name="filetype" value="image" />[% END %] >- <label for="image">Image file</label> >- </li> >- <li class="radio"> >- [% IF ( filetype == 'image' ) %]<span id="bibnum">[% ELSE %]<span id="bibnum" style="display: none">[% END %]<label for="biblionumber">Enter cover biblionumber: </label><input type="text" id="biblionumber" name="biblionumber" value="[% biblionumber | html %]" size="15" /></span> >- </li> >+ [% UNLESS itemnumber %] >+ <li class="radio"> >+ [% IF (filetype != 'image' ) %]<input type="radio" id="zipfile" name="filetype" value="zip" checked="checked" />[% ELSE %]<input type="radio" id="zipfile" name="filetype" value="zip" />[% END %] >+ <label for="zipfile">ZIP file</label> >+ </li> >+ <li class="radio"> >+ [% IF (filetype == 'image' ) %]<input type="radio" id="image" name="filetype" value="image" checked="checked" />[% ELSE %]<input type="radio" id="image" name="filetype" value="image" />[% END %] >+ <label for="image">Image file</label> >+ </li> >+ <li class="radio"> >+ [% IF ( filetype == 'image' ) %]<span id="bibnum">[% ELSE %]<span id="bibnum" style="display: none">[% END %]<label for="biblionumber">Enter cover biblionumber: </label><input type="text" id="biblionumber" name="biblionumber" value="[% biblionumber | html %]" size="15" /></span> >+ </li> >+ [% ELSE %] >+ <label for="itemnumber">Cover itemnumber: </label> >+ <input type="text" id="itemnumber" name="itemnumber" value="[% itemnumber | html %]" size="15" readonly="readonly" /> >+ <input type="hidden" name="filetype" value="image" /> >+ [% END %] > </ol> > </fieldset> > <fieldset class="rows"> > <legend>Options</legend> > <ol> > <li class="checkbox"> >- [% IF AllowMultipleCovers == 0 %]<input type="checkbox" id="replace" name="replace" checked="checked" disabled="disabled" value="1" />[% ELSE %]<input type="checkbox" id="replace" name="replace" value="1" />[% END %] >+ [% IF AllowMultipleCovers == 0 OR itemnumber%] >+ <input type="checkbox" id="replace" name="replace" checked="checked" disabled="disabled" value="1" /> >+ [% ELSE %] >+ <input type="checkbox" id="replace" name="replace" value="1" /> >+ [% END %] > <label for="replace">Replace existing covers</label> > </li> > </ol> >diff --git a/svc/cover_images b/svc/cover_images >index 590a243dc8..5894410dd7 100755 >--- a/svc/cover_images >+++ b/svc/cover_images >@@ -37,28 +37,27 @@ if ( $auth_status ne "ok" ) { > } > > my $action = $input->param('action'); >-my $biblionumber = $input->param('biblionumber'); > my @imagenumbers = $input->param('imagenumber'); > > # Array to store the reponse JSON > my $response = []; > > if ( $action eq "delete" ) { >- # Build a hash of valid imagenumbers fr the given biblionumber >- my %valid_imagenumbers = map {$_ => 1} ListImagesForBiblio($biblionumber); > > foreach my $imagenumber ( @imagenumbers ) { >- if ( exists( $valid_imagenumbers{ $imagenumber } ) ) { >+ eval { > DelImage($imagenumber); >+ }; >+ if ( $@ ) { > push @$response, { > imagenumber => $imagenumber, >- deleted => 1 >+ deleted => 0, >+ error => "MSG_INVALID_IMAGENUMBER" > }; > } else { > push @$response, { > imagenumber => $imagenumber, >- deleted => 0, >- error => "MSG_INVALID_IMAGENUMBER" >+ deleted => 1 > }; > } > } >diff --git a/tools/upload-cover-image.pl b/tools/upload-cover-image.pl >index b6614df6ff..735987c98e 100755 >--- a/tools/upload-cover-image.pl >+++ b/tools/upload-cover-image.pl >@@ -46,6 +46,7 @@ use C4::Context; > use C4::Auth; > use C4::Output; > use C4::Images; >+use Koha::Items; > use Koha::UploadedFiles; > use C4::Log; > >@@ -66,6 +67,7 @@ my ( $template, $loggedinuser, $cookie ) = get_template_and_user( > > my $filetype = $input->param('filetype'); > my $biblionumber = $input->param('biblionumber'); >+my $itemnumber = $input->param('itemnumber'); > #my $uploadfilename = $input->param('uploadfile'); # obsolete? > my $replace = !C4::Context->preference("AllowMultipleCovers") > || $input->param('replace'); >@@ -75,8 +77,11 @@ my $sessionID = $cookies{'CGISESSID'}->value; > > my $error; > >-$template->{VARS}->{'filetype'} = $filetype; >-$template->{VARS}->{'biblionumber'} = $biblionumber; >+$template->param( >+ filetype => $filetype, >+ biblionumber => $biblionumber, >+ itemnumber => $itemnumber, >+); > > my $total = 0; > >@@ -87,7 +92,7 @@ if ($fileID) { > my $srcimage = GD::Image->new($fh); > $fh->close if $fh; > if ( defined $srcimage ) { >- my $dberror = PutImage( $biblionumber, $srcimage, $replace ); >+ my $dberror = PutImage( { biblionumber => $biblionumber, itemnumber => $itemnumber, src_image => $srcimage, replace => $replace } ); > if ($dberror) { > $error = 'DBERR'; > } >@@ -157,9 +162,13 @@ if ($fileID) { > my $srcimage = GD::Image->new("$dir/$filename"); > if ( defined $srcimage ) { > $total++; >- my $dberror = >- PutImage( $biblionumber, $srcimage, >- $replace ); >+ my $dberror = PutImage( >+ { >+ biblionumber => $biblionumber, >+ src_image => $srcimage, >+ replace => $replace >+ } >+ ); > if ($dberror) { > $error = 'DBERR'; > } >@@ -178,10 +187,14 @@ if ($fileID) { > } > } > } >- $template->{VARS}->{'total'} = $total; >- $template->{VARS}->{'uploadimage'} = 1; >- $template->{VARS}->{'error'} = $error; >- $template->{VARS}->{'biblionumber'} = $biblionumber; >+ >+ $template->param( >+ total => $total, >+ uploadimage => 1, >+ error => $error, >+ biblionumber => $biblionumber || Koha::Items->find($itemnumber)->biblionumber, >+ itemnumber => $itemnumber, >+ ); > } > > output_html_with_http_headers $input, $cookie, $template->output; >-- >2.11.0
You cannot view the attachment while viewing its details because your browser does not support IFRAMEs.
View the attachment on a separate page
.
View Attachment As Diff
View Attachment As Raw
Actions:
View
|
Diff
|
Splinter Review
Attachments on
bug 26145
:
109225
|
109226
|
110342
|
110343
|
110344
|
110345
|
110346
|
110347
|
110348
|
110349
|
110350
|
110351
|
110352
|
110353
|
110354
|
110675
|
110676
|
110677
|
110678
|
110679
|
110680
|
110681
|
110682
|
110683
|
110684
|
110685
|
110800
|
110861
|
110862
|
110863
|
110864
|
110865
|
110866
|
110867
|
110868
|
110869
|
110870
|
110871
|
110872
|
110873
|
110874
|
110875
|
111446
| 111447 |
111448
|
111449
|
111450
|
111451
|
111452
|
111453
|
111454
|
111455
|
111456
|
111457
|
111458