Bugzilla – Attachment 189099 Details for
Bug 17387
Add an undelete feature for items/biblios
Home
|
New
|
Browse
|
Search
|
[?]
|
Reports
|
Help
|
New Account
|
Log In
[x]
|
Forgot Password
Login:
[x]
[patch]
Bug 17387: (follow-up) take library groups in to account for permissions check
Bug-17387-follow-up-take-library-groups-in-to-acco.patch (text/plain), 12.70 KB, created by
Jacob O'Mara
on 2025-11-05 15:40:10 UTC
(
hide
)
Description:
Bug 17387: (follow-up) take library groups in to account for permissions check
Filename:
MIME Type:
Creator:
Jacob O'Mara
Created:
2025-11-05 15:40:10 UTC
Size:
12.70 KB
patch
obsolete
>From bbb06c4be16c825c3fd6d06dc756370f407edd37 Mon Sep 17 00:00:00 2001 >From: Jacob O'Mara <Jacob.omara@openfifth.co.uk> >Date: Wed, 5 Nov 2025 14:47:18 +0000 >Subject: [PATCH] Bug 17387: (follow-up) take library groups in to account for > permissions check > >--- > Koha/Old/Biblio.pm | 48 ++++++++++++++++++- > Koha/REST/V1/DeletedBiblios.pm | 23 ++++++++- > Koha/REST/V1/DeletedItems.pm | 9 ++++ > api/v1/swagger/paths/deleted_biblios.yaml | 31 ++++++++++++ > .../prog/en/modules/tools/restore-records.tt | 43 +++++++++++++---- > tools/restore-records.pl | 11 ++++- > 6 files changed, 152 insertions(+), 13 deletions(-) > >diff --git a/Koha/Old/Biblio.pm b/Koha/Old/Biblio.pm >index 754f0b0316d..a8fd3be7193 100644 >--- a/Koha/Old/Biblio.pm >+++ b/Koha/Old/Biblio.pm >@@ -154,18 +154,32 @@ sub to_api_mapping { > =head3 restore > > my $biblio = $deleted_biblio->restore; >+ my $biblio = $deleted_biblio->restore({ >+ patron => $patron, >+ item_ids => \@item_ids, >+ restore_all => 0 >+ }); > > Restores the deleted biblio record back to the biblio table along with > its biblioitems and metadata. This removes the record from the deleted tables > and re-inserts it into the active tables. The biblio record will be reindexed > after restoration. > >+Optional parameters: >+ patron - Koha::Patron object. If provided, only items the patron can edit will be restored. >+ item_ids - Arrayref of item IDs to restore. If not provided and restore_all is false, >+ no items will be restored. >+ restore_all - Boolean. If true and no item_ids provided, restore all items the patron >+ has permission to edit. >+ > Returns the newly restored Koha::Biblio object. > > =cut > > sub restore { >- my ($self) = @_; >+ my ( $self, $params ) = @_; >+ >+ $params //= {}; > > my $biblio_data = $self->unblessed; > my $biblioitem = $self->biblioitem; >@@ -187,13 +201,43 @@ sub restore { > $biblioitem->delete; > $self->delete; > >+ my $patron = $params->{patron}; >+ my $item_ids = $params->{item_ids}; >+ my $restore_all = $params->{restore_all} // 0; >+ >+ my @restored_items; >+ my @skipped_items; >+ >+ if ( $restore_all || $item_ids ) { >+ my $deleted_items = $self->items; >+ while ( my $deleted_item = $deleted_items->next ) { >+ my $should_restore = 0; >+ >+ if ($item_ids) { >+ $should_restore = grep { $_ == $deleted_item->itemnumber } @$item_ids; >+ } elsif ($restore_all) { >+ $should_restore = 1; >+ } >+ >+ if ($should_restore) { >+ if ( $patron && !$patron->can_edit_items_from( $deleted_item->homebranch ) ) { >+ push @skipped_items, $deleted_item->itemnumber; >+ next; >+ } >+ >+ $deleted_item->restore; >+ push @restored_items, $deleted_item->itemnumber; >+ } >+ } >+ } >+ > my $indexer = Koha::SearchEngine::Indexer->new( { index => $Koha::SearchEngine::BIBLIOS_INDEX } ); > $indexer->index_records( $new_biblio->biblionumber, "specialUpdate", "biblioserver" ); > > logaction( "CATALOGUING", "RESTORE", $new_biblio->biblionumber, "biblio", undef, $new_biblio ) > if C4::Context->preference("CataloguingLog"); > >- return $new_biblio; >+ return wantarray ? ( $new_biblio, \@restored_items, \@skipped_items ) : $new_biblio; > } > > =head2 Internal methods >diff --git a/Koha/REST/V1/DeletedBiblios.pm b/Koha/REST/V1/DeletedBiblios.pm >index 6e8f03d1a95..8ba90026c03 100644 >--- a/Koha/REST/V1/DeletedBiblios.pm >+++ b/Koha/REST/V1/DeletedBiblios.pm >@@ -180,12 +180,31 @@ sub restore { > return $c->render_resource_not_found("Bibliographic record") > unless $deleted_biblio; > >+ my $body = $c->req->json; >+ my $item_ids = $body->{item_ids}; >+ my $restore_all = $body->{restore_all} // 0; >+ > return try { >- my $biblio = $deleted_biblio->restore; >+ my $patron = $c->stash('koha.user'); >+ >+ my ( $biblio, $restored_items, $skipped_items ) = $deleted_biblio->restore( >+ { >+ patron => $patron, >+ item_ids => $item_ids, >+ restore_all => $restore_all >+ } >+ ); >+ >+ my $response = { biblio_id => $biblio->biblionumber }; >+ >+ if ( $item_ids || $restore_all ) { >+ $response->{restored_items} = $restored_items if @$restored_items; >+ $response->{skipped_items} = $skipped_items if @$skipped_items; >+ } > > return $c->render( > status => 200, >- openapi => { biblio_id => $biblio->biblionumber } >+ openapi => $response > ); > } catch { > $c->unhandled_exception($_); >diff --git a/Koha/REST/V1/DeletedItems.pm b/Koha/REST/V1/DeletedItems.pm >index fa3522477c1..a6f297b396a 100644 >--- a/Koha/REST/V1/DeletedItems.pm >+++ b/Koha/REST/V1/DeletedItems.pm >@@ -85,6 +85,15 @@ sub restore { > unless $deleted_item; > > return try { >+ my $patron = $c->stash('koha.user'); >+ >+ unless ( $patron->can_edit_items_from( $deleted_item->homebranch ) ) { >+ return $c->render( >+ status => 403, >+ openapi => { error => "You do not have permission to restore items from this library." } >+ ); >+ } >+ > my $item = $deleted_item->restore; > > return $c->render( >diff --git a/api/v1/swagger/paths/deleted_biblios.yaml b/api/v1/swagger/paths/deleted_biblios.yaml >index 4f62a0e3907..5537982a96f 100644 >--- a/api/v1/swagger/paths/deleted_biblios.yaml >+++ b/api/v1/swagger/paths/deleted_biblios.yaml >@@ -135,6 +135,23 @@ > summary: Restore deleted biblio > parameters: > - $ref: "../swagger.yaml#/parameters/biblio_id_pp" >+ - name: body >+ in: body >+ description: Restore options for items >+ required: false >+ schema: >+ type: object >+ properties: >+ item_ids: >+ type: array >+ description: Array of item IDs to restore with the biblio >+ items: >+ type: integer >+ restore_all: >+ type: boolean >+ description: Restore all items the user has permission to edit >+ consumes: >+ - application/json > produces: > - application/json > responses: >@@ -142,6 +159,20 @@ > description: Biblio restored successfully > schema: > type: object >+ properties: >+ biblio_id: >+ type: integer >+ description: The ID of the restored biblio >+ restored_items: >+ type: array >+ description: List of item IDs that were successfully restored >+ items: >+ type: integer >+ skipped_items: >+ type: array >+ description: List of item IDs that were skipped during restoration due to insufficient permissions >+ items: >+ type: integer > "400": > description: Bad request > schema: >diff --git a/koha-tmpl/intranet-tmpl/prog/en/modules/tools/restore-records.tt b/koha-tmpl/intranet-tmpl/prog/en/modules/tools/restore-records.tt >index bd73665c189..6bc918b4f41 100644 >--- a/koha-tmpl/intranet-tmpl/prog/en/modules/tools/restore-records.tt >+++ b/koha-tmpl/intranet-tmpl/prog/en/modules/tools/restore-records.tt >@@ -190,6 +190,16 @@ > } > > $(document).ready(function () { >+ var librariesWhereCanEdit = [% libraries_where_can_edit_json | $raw %]; >+ var canEditAnyLibrary = librariesWhereCanEdit.length === 0; >+ >+ function canEditItem(homebranch) { >+ if (canEditAnyLibrary) { >+ return true; >+ } >+ return librariesWhereCanEdit.includes(homebranch); >+ } >+ > var oneYearAgo = new Date(); > oneYearAgo.setFullYear(oneYearAgo.getFullYear() - 1); > var today = new Date(); >@@ -365,17 +375,22 @@ > { > data: function (row, type) { > if (type === "display") { >- return ( >- '<button class="btn btn-sm btn-default restore-item" data-item-id="' + >+ var canEdit = canEditItem(row.home_library_id); >+ var disabled = canEdit ? '' : ' disabled'; >+ var button = '<button class="btn btn-sm btn-default restore-item" data-item-id="' + > row.item_id + > '" data-barcode="' + > $("<div/>") > .text(row.external_id || row.item_id) > .html() + >- '"><i class="fa fa-undo" aria-hidden="true"></i> ' + >+ '"' + disabled + '><i class="fa fa-undo" aria-hidden="true"></i> ' + > _("Restore") + >- "</button>" >- ); >+ "</button>"; >+ >+ if (!canEdit) { >+ return '<span title="' + _("You do not have permission to restore items from this library") + '" style="cursor: not-allowed;">' + button + '</span>'; >+ } >+ return button; > } > return ""; > }, >@@ -422,7 +437,14 @@ > { > data: function (row, type) { > if (type === "display") { >- return '<input type="checkbox" class="item-checkbox" data-item-id="' + row.item_id + '">'; >+ var canEdit = canEditItem(row.home_library_id); >+ var disabled = canEdit ? '' : ' disabled'; >+ var checkbox = '<input type="checkbox" class="item-checkbox" data-item-id="' + row.item_id + '"' + disabled + '>'; >+ >+ if (!canEdit) { >+ return '<span title="' + _("You do not have permission to restore items from this library") + '">' + checkbox + '</span>'; >+ } >+ return checkbox; > } > return ""; > }, >@@ -462,7 +484,12 @@ > orderable: true, > render: function (data, type, row) { > if (type === "display") { >- return data ? $("<div/>").text(data).html() : ""; >+ var text = data ? $("<div/>").text(data).html() : ""; >+ var canEdit = canEditItem(data); >+ if (!canEdit) { >+ text += ' <span class="badge bg-warning text-dark">' + _("No permission") + '</span>'; >+ } >+ return text; > } > return data || ""; > }, >@@ -570,7 +597,7 @@ > // Select all items checkbox > $("#select-all-items").on("change", function () { > var checked = $(this).prop("checked"); >- $(".item-checkbox").prop("checked", checked); >+ $(".item-checkbox:not(:disabled)").prop("checked", checked); > }); > > // Restore biblio with items >diff --git a/tools/restore-records.pl b/tools/restore-records.pl >index 41d5dbb5888..ef83c80957b 100755 >--- a/tools/restore-records.pl >+++ b/tools/restore-records.pl >@@ -17,10 +17,12 @@ > > use Modern::Perl; > >-use CGI qw ( -utf8 ); >+use CGI qw ( -utf8 ); >+use JSON qw( encode_json ); > > use C4::Auth qw( get_template_and_user ); > use C4::Output qw( output_html_with_http_headers ); >+use Koha::Patrons; > > my $input = CGI->new; > >@@ -33,4 +35,11 @@ my ( $template, $loggedinuser, $cookie ) = get_template_and_user( > } > ); > >+my $patron = Koha::Patrons->find($loggedinuser); >+my @libraries_where_can_edit = $patron->libraries_where_can_edit_items; >+ >+$template->param( >+ libraries_where_can_edit_json => encode_json( \@libraries_where_can_edit ), >+); >+ > output_html_with_http_headers $input, $cookie, $template->output; >-- >2.39.5
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 17387
:
188670
|
188671
|
188672
|
188673
|
188674
|
188675
|
188676
|
188677
|
188678
|
188679
|
188680
|
188681
|
188682
|
188683
|
188684
|
188685
|
188686
|
188687
|
188688
|
188689
|
188690
|
188691
|
188692
|
188693
|
188694
|
188695
|
188696
|
188697
|
188698
|
188699
|
188700
|
188701
|
188780
|
188781
|
188782
|
188783
|
188784
|
188785
|
188786
|
188787
|
188788
|
188789
|
188790
|
188791
|
188792
|
188793
|
188794
|
188795
|
189046
|
189047
|
189048
|
189049
|
189050
|
189051
|
189052
|
189053
|
189054
|
189055
|
189056
|
189057
|
189058
|
189059
|
189060
|
189061
|
189062
|
189082
|
189083
|
189084
|
189085
|
189086
|
189087
|
189088
|
189089
|
189090
|
189091
|
189092
|
189093
|
189094
|
189095
|
189096
|
189097
|
189098
|
189099
|
189100
|
189101
|
189102
|
189103
|
189104
|
189105
|
189106
|
189107
|
189108
|
189109
|
189110
|
189111
|
189112
|
189113
|
189114
|
189115
|
189116
|
189117
|
189118
|
189119