From 0908c6f34af6a18097ef7c406aeaedf7c5984fc9 Mon Sep 17 00:00:00 2001 From: Pedro Amorim Date: Thu, 7 Aug 2025 14:47:00 +0000 Subject: [PATCH] Bug 40613: Add DELETE hold groups REST API endpoint MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit prove t/db_dependent/api/v1/patrons_hold_groups.t Signed-off-by: Anneli Österman --- Koha/REST/V1/Patrons/HoldGroups.pm | 28 +++++++ api/v1/swagger/paths/patrons_hold_groups.yaml | 51 +++++++++++- api/v1/swagger/swagger.yaml | 2 + t/db_dependent/api/v1/patrons_hold_groups.t | 79 ++++++++++++++++++- 4 files changed, 158 insertions(+), 2 deletions(-) diff --git a/Koha/REST/V1/Patrons/HoldGroups.pm b/Koha/REST/V1/Patrons/HoldGroups.pm index b5fa3a54ea..5a776cd7ba 100644 --- a/Koha/REST/V1/Patrons/HoldGroups.pm +++ b/Koha/REST/V1/Patrons/HoldGroups.pm @@ -126,4 +126,32 @@ sub add { }; } +=head3 delete + +Controller method that handles removing a hold group. + +=cut + +sub delete { + my $c = shift->openapi->valid_input or return; + + my $patron = Koha::Patrons->find( $c->param('patron_id') ); + + return $c->render_resource_not_found("Patron") + unless $patron; + + return try { + + my $hold_group = $patron->hold_groups->find( $c->param('hold_group_id') ); + + return $c->render_resource_not_found("Hold group") + unless $hold_group; + + $hold_group->delete; + return $c->render_resource_deleted; + } catch { + $c->unhandled_exception($_); + }; +} + 1; diff --git a/api/v1/swagger/paths/patrons_hold_groups.yaml b/api/v1/swagger/paths/patrons_hold_groups.yaml index 49e6129f02..256a6e8fcf 100644 --- a/api/v1/swagger/paths/patrons_hold_groups.yaml +++ b/api/v1/swagger/paths/patrons_hold_groups.yaml @@ -152,4 +152,53 @@ $ref: "../swagger.yaml#/definitions/error" x-koha-authorization: permissions: - reserveforothers: "1" \ No newline at end of file + reserveforothers: "1" +"/patrons/{patron_id}/hold_groups/{hold_group_id}": + delete: + x-mojo-to: Patrons::HoldGroups#delete + operationId: deletePatronHoldGroups + tags: + - hold_groups + summary: Delete hold group + parameters: + - $ref: "../swagger.yaml#/parameters/patron_id_pp" + produces: + - application/json + responses: + "204": + description: Hold group deleted + "400": + description: Bad request + schema: + $ref: "../swagger.yaml#/definitions/error" + "401": + description: Authentication required + schema: + $ref: "../swagger.yaml#/definitions/error" + "403": + description: Access forbidden + schema: + $ref: "../swagger.yaml#/definitions/error" + "404": + description: Hold group not found + schema: + $ref: "../swagger.yaml#/definitions/error" + "409": + description: | + Conflict. Possible `error_code` attribute values: + schema: + $ref: "../swagger.yaml#/definitions/error" + "500": + description: | + Internal server error. Possible `error_code` attribute values: + + * `internal_server_error` + schema: + $ref: "../swagger.yaml#/definitions/error" + "503": + description: Under maintenance + schema: + $ref: "../swagger.yaml#/definitions/error" + x-koha-authorization: + permissions: + reserveforothers: "1" \ No newline at end of file diff --git a/api/v1/swagger/swagger.yaml b/api/v1/swagger/swagger.yaml index f99cf2eecd..81534ce9ef 100644 --- a/api/v1/swagger/swagger.yaml +++ b/api/v1/swagger/swagger.yaml @@ -485,6 +485,8 @@ paths: $ref: "./paths/patrons_holds.yaml#/~1patrons~1{patron_id}~1holds" "/patrons/{patron_id}/hold_groups": $ref: "./paths/patrons_hold_groups.yaml#/~1patrons~1{patron_id}~1hold_groups" + "/patrons/{patron_id}/hold_groups/{hold_group_id}": + $ref: "./paths/patrons_hold_groups.yaml#/~1patrons~1{patron_id}~1hold_groups~1{hold_group_id}" "/patrons/{patron_id}/checkouts": $ref: "./paths/patrons_checkouts.yaml#/~1patrons~1{patron_id}~1checkouts" "/patrons/{patron_id}/password": diff --git a/t/db_dependent/api/v1/patrons_hold_groups.t b/t/db_dependent/api/v1/patrons_hold_groups.t index 2cb39817b4..e59eb5959a 100755 --- a/t/db_dependent/api/v1/patrons_hold_groups.t +++ b/t/db_dependent/api/v1/patrons_hold_groups.t @@ -18,7 +18,7 @@ use Modern::Perl; use Test::NoWarnings; -use Test::More tests => 3; +use Test::More tests => 4; use Test::MockModule; use Test::Mojo; @@ -171,3 +171,80 @@ subtest 'add() tests' => sub { $schema->storage->txn_rollback; }; + +subtest 'delete() tests' => sub { + plan tests => 8; + + $schema->storage->txn_begin; + + my $authorized_patron = $builder->build_object( + { + class => 'Koha::Patrons', + value => { flags => 1 } + } + ); + my $password = 'thePassword123'; + $authorized_patron->set_password( { password => $password, skip_validation => 1 } ); + my $auth_userid = $authorized_patron->userid; + + my $unauthorized_patron = $builder->build_object( + { + class => 'Koha::Patrons', + value => { flags => 4 } + } + ); + $unauthorized_patron->set_password( { password => $password, skip_validation => 1 } ); + my $unauth_userid = $unauthorized_patron->userid; + + my $hold_1 = $builder->build_object( + { + class => 'Koha::Holds', + value => { borrowernumber => $authorized_patron->id, hold_group_id => undef, found => undef } + } + ); + my $hold_2 = $builder->build_object( + { + class => 'Koha::Holds', + value => { borrowernumber => $authorized_patron->id, hold_group_id => undef, found => undef } + } + ); + + my $hold_3 = $builder->build_object( + { + class => 'Koha::Holds', + value => { borrowernumber => $unauthorized_patron->borrowernumber, hold_group_id => undef, found => undef } + } + ); + my $hold_4 = $builder->build_object( + { + class => 'Koha::Holds', + value => { borrowernumber => $unauthorized_patron->borrowernumber, hold_group_id => undef, found => undef } + } + ); + + my $unauth_hold_group = $unauthorized_patron->create_hold_group( [ $hold_3->reserve_id, $hold_4->reserve_id ] ); + my $hold_group = $authorized_patron->create_hold_group( [ $hold_1->reserve_id, $hold_2->reserve_id ] ); + + # Unauthorized attempt to delete + $t->delete_ok( "//$unauth_userid:$password@/api/v1/patrons/" + . $unauthorized_patron->borrowernumber + . "/hold_groups/" + . $unauth_hold_group->hold_group_id )->status_is(403); + + # Attempt to delete a hold group of another patron + $t->delete_ok( "//$auth_userid:$password@/api/v1/patrons/" + . $authorized_patron->borrowernumber + . "/hold_groups/" + . $unauth_hold_group->hold_group_id )->status_is(404); + + # Successful deletion + $t->delete_ok( "//$auth_userid:$password@/api/v1/patrons/" + . $authorized_patron->borrowernumber + . "/hold_groups/" + . $hold_group->hold_group_id )->status_is( 204, 'REST3.2.4' )->content_is( '', 'REST3.3.4' ); + + my $nonexistent_hold = Koha::HoldGroups->find( $hold_group->hold_group_id ); + is( $nonexistent_hold, undef, 'The hold group does not exist after deletion' ); + + $schema->storage->txn_rollback; +}; -- 2.39.5