From 1cd97c7d12ac519814c327862365011c0954b149 Mon Sep 17 00:00:00 2001 From: Marcel de Rooy Date: Thu, 29 Jun 2023 12:30:08 +0000 Subject: [PATCH] Bug 33537: REST API endpoints Content-Type: text/plain; charset=utf-8 Test plan: Run t/db_dependent/api/v1/domain_limits.t List, add (post), get, update (put) and delete domain limit(s). Using the paths: - api/v1/smtp/domain_limits - api/v1/smtp/domain_limits/{SOME_ID} Signed-off-by: Marcel de Rooy --- Koha/REST/V1/Config/SMTP/DomainLimits.pm | 160 +++++++++++++ .../definitions/smtp_domain_limits.yaml | 44 ++++ api/v1/swagger/paths/smtp_domain_limits.yaml | 213 ++++++++++++++++++ api/v1/swagger/swagger.yaml | 15 ++ t/db_dependent/api/v1/domain_limits.t | 86 +++++++ 5 files changed, 518 insertions(+) create mode 100644 Koha/REST/V1/Config/SMTP/DomainLimits.pm create mode 100644 api/v1/swagger/definitions/smtp_domain_limits.yaml create mode 100644 api/v1/swagger/paths/smtp_domain_limits.yaml create mode 100755 t/db_dependent/api/v1/domain_limits.t diff --git a/Koha/REST/V1/Config/SMTP/DomainLimits.pm b/Koha/REST/V1/Config/SMTP/DomainLimits.pm new file mode 100644 index 0000000000..8e3dfe801a --- /dev/null +++ b/Koha/REST/V1/Config/SMTP/DomainLimits.pm @@ -0,0 +1,160 @@ +package Koha::REST::V1::Config::SMTP::DomainLimits; + +# Copyright 2023 Rijksmuseum, Koha development team +# +# This file is part of Koha. +# +# Koha is free software; you can redistribute it and/or modify it +# under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 3 of the License, or +# (at your option) any later version. +# +# Koha is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with Koha; if not, see . + +use Modern::Perl; +use Mojo::Base 'Mojolicious::Controller'; +use Scalar::Util qw( blessed ); +use Try::Tiny qw( catch try ); + +use Koha::MailDomainLimits; + +=head1 API + +=head2 Methods + +=head3 list + +Controller method that handles listing domain limits + +=cut + +sub list { + my $c = shift->openapi->valid_input or return; + return try { + my $limits = $c->objects->search( Koha::MailDomainLimits->search_with_group_domain ); + return $c->render( _render_helper( 200, undef, result => $limits ) ); + } + catch { + $c->unhandled_exception($_); + }; +} + +=head3 get + +Controller method that handles retrieving a single domain limit + +=cut + +sub get { + my $c = shift->openapi->valid_input or return; + return try { + my $rec = Koha::MailDomainLimits->search_with_group_domain->find( $c->validation->param('domain_limit_id') ); + return $c->render( _render_helper( 404, undef, error => "Domain limit not found" ) ) if !$rec; + return $c->render( _render_helper( 200, undef, result => $rec->to_api ) ); + } + catch { + $c->unhandled_exception($_); + } +} + +=head3 add + +Controller method that handles adding a new domain limit + +=cut + +sub add { + my $c = shift->openapi->valid_input or return; + return try { + my $limit = Koha::MailDomainLimit->new_from_api( $c->validation->param('body') ); + $limit->store->discard_changes; + $c->res->headers->location( $c->req->url->to_string . '/' . $limit->id ); + return $c->render( _render_helper( 201, undef, result => $limit->to_api ) ); + } + catch { + if( blessed($_) ) { + return $c->render( _render_helper( 409, $_ ) ) + if $_->isa('Koha::Exceptions::DomainLimit::NoSelfChaining') + || $_->isa('Koha::Exceptions::DomainLimit::MemberWithLimit') + || $_->isa('Koha::Exceptions::Object::DuplicateID'); + return $c->render( _render_helper( 400, $_, missing => $_->parameter ) ) + if $_->isa('Koha::Exceptions::DomainLimit::EmptyLimitData'); + return $c->render( _render_helper( 404, $_ ) ) + if $_->isa('Koha::Exceptions::Object::FKConstraint'); # on belongs_to + } + $c->unhandled_exception($_); + }; +} + +=head3 update + +Controller method that handles updating a domain limit + +=cut + +sub update { + my $c = shift->openapi->valid_input or return; + my $limit = Koha::MailDomainLimits->find( $c->validation->param('domain_limit_id') ); + return $c->render( _render_helper( 404, undef, error => "Object not found" ) ) if !$limit; + return try { + $limit->set_from_api( $c->validation->param('body') ); + $limit->store->discard_changes; + return $c->render( _render_helper( 200, undef, result => $limit->to_api ) ); + } + catch { + if( blessed($_) ) { + return $c->render(_render_helper( 409, $_ ) ) + if $_->isa('Koha::Exceptions::DomainLimit::NoSelfChaining') + || $_->isa('Koha::Exceptions::DomainLimit::MemberWithLimit') + || $_->isa('Koha::Exceptions::Object::DuplicateID'); + return $c->render(_render_helper( 400, $_, missing => $_->parameter ) ) + if $_->isa('Koha::Exceptions::DomainLimit::EmptyLimitData'); + return $c->render(_render_helper( 404, $_ ) ) + if $_->isa('Koha::Exceptions::Object::FKConstraint'); # on belongs_to + } + $c->unhandled_exception($_); + }; +} + +=head3 delete + +Controller method that handles deleting a domain limit + +=cut + +sub delete { + my $c = shift->openapi->valid_input or return; + my $limit = Koha::MailDomainLimits->find( $c->validation->param('domain_limit_id') ); + return $c->render( _render_helper( 404, undef, error => "Domain limit not found" ) ) if !$limit; + return try { + $limit->delete; + return $c->render( _render_helper( 204, undef, result => q{} ) ); + } + catch { + $c->unhandled_exception($_); + }; +} + +=head2 Internal routines + +=cut + +sub _render_helper { + my ( $status, $exception, %result ) = @_; # %result can be: result => $result to pass only one result + my $resp = { status => $status }; + my @error_message = $exception ? ( error => ( $exception->message || $exception->description ) ) : (); + if( @error_message ) { + $resp->{openapi} = { @error_message, %result }; + } elsif( keys %result ) { + $resp->{openapi} = $result{result} // { %result }; + } + return %$resp; +} + +1; diff --git a/api/v1/swagger/definitions/smtp_domain_limits.yaml b/api/v1/swagger/definitions/smtp_domain_limits.yaml new file mode 100644 index 0000000000..ed267b20b7 --- /dev/null +++ b/api/v1/swagger/definitions/smtp_domain_limits.yaml @@ -0,0 +1,44 @@ +--- +type: object +properties: + domain_limit_id: + description: Internally assigned domain limit identifier + type: integer + readOnly: true + domain_name: + description: Name of domain + type: string + domain_limit: + description: Maximum number of messages per period + type: + - integer + - "null" + units: + description: Number of units per period + type: + - integer + - "null" + unit_type: + description: Unit of time for period + type: + - string + - "null" + enum: + - minutes + - hours + - days + - null + belongs_to: + description: Domain limit identifier of group domain + type: + - integer + - "null" + group_domain: + description: Name of group domain (from self join) + type: + - string + - "null" + readOnly: true +additionalProperties: false +required: + - domain_name diff --git a/api/v1/swagger/paths/smtp_domain_limits.yaml b/api/v1/swagger/paths/smtp_domain_limits.yaml new file mode 100644 index 0000000000..89e1f6a810 --- /dev/null +++ b/api/v1/swagger/paths/smtp_domain_limits.yaml @@ -0,0 +1,213 @@ +--- +/smtp/domain_limits: + get: + x-mojo-to: Config::SMTP::DomainLimits#list + operationId: listDomainLimits + tags: + - domain_limits + summary: List mail domain limits + produces: + - application/json + parameters: + - $ref: ../swagger.yaml#/parameters/match + - $ref: ../swagger.yaml#/parameters/order_by + - $ref: ../swagger.yaml#/parameters/page + - $ref: ../swagger.yaml#/parameters/per_page + - $ref: ../swagger.yaml#/parameters/q_param + - $ref: ../swagger.yaml#/parameters/q_body + - $ref: ../swagger.yaml#/parameters/request_id_header + responses: + "200": + description: A list of domain limits + schema: + type: array + items: + $ref: "../swagger.yaml#/definitions/smtp_domain_limits" + "403": + description: Access forbidden + 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: + parameters: manage_smtp_servers + post: + x-mojo-to: Config::SMTP::DomainLimits#add + operationId: addDomainLimit + tags: + - domain_limits + summary: Add a new domain limit + parameters: + - name: body + in: body + description: A JSON object representing a new domain limit + required: true + schema: + $ref: "../swagger.yaml#/definitions/smtp_domain_limits" + consumes: + - application/json + produces: + - application/json + responses: + "201": + description: Created a domain limit + schema: + $ref: "../swagger.yaml#/definitions/smtp_domain_limits" + "400": + description: Bad Request + schema: + $ref: ../swagger.yaml#/definitions/error + "403": + description: Access forbidden + schema: + $ref: ../swagger.yaml#/definitions/error + "404": + description: Object not found + schema: + $ref: ../swagger.yaml#/definitions/error + "409": + description: Conflict in creating resource + 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: + parameters: manage_smtp_servers +"/smtp/domain_limits/{domain_limit_id}": + get: + x-mojo-to: Config::SMTP::DomainLimits#get + operationId: getDomainLimit + tags: + - domain_limits + summary: Get domain limit + parameters: + - $ref: ../swagger.yaml#/parameters/domain_limit_id_pp + produces: + - application/json + responses: + "200": + description: A domain limit + schema: + $ref: ../swagger.yaml#/definitions/smtp_domain_limits + "404": + description: Object not found + 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: + parameters: manage_smtp_servers + put: + x-mojo-to: Config::SMTP::DomainLimits#update + operationId: updateDomainLimit + tags: + - domain_limits + summary: Update a domain limit + parameters: + - $ref: ../swagger.yaml#/parameters/domain_limit_id_pp + - name: body + in: body + description: A JSON object representing a new domain limit + required: true + schema: + $ref: "../swagger.yaml#/definitions/smtp_domain_limits" + produces: + - application/json + responses: + "200": + description: Updated domain limit + schema: + $ref: ../swagger.yaml#/definitions/smtp_domain_limits + "400": + description: Bad Request + schema: + $ref: ../swagger.yaml#/definitions/error + "403": + description: Access forbidden + schema: + $ref: ../swagger.yaml#/definitions/error + "404": + description: Object not found + schema: + $ref: ../swagger.yaml#/definitions/error + "409": + description: Conflict in creating resource + 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: + parameters: manage_smtp_servers + delete: + x-mojo-to: Config::SMTP::DomainLimits#delete + operationId: delDomainLimit + tags: + - domain_limits + summary: Delete domain limit + parameters: + - $ref: ../swagger.yaml#/parameters/domain_limit_id_pp + produces: + - application/json + responses: + "204": + description: Domain limit deleted + "401": + description: Authentication required + schema: + $ref: ../swagger.yaml#/definitions/error + "403": + description: Access forbidden + schema: + $ref: ../swagger.yaml#/definitions/error + "404": + description: Not found + schema: + $ref: ../swagger.yaml#/definitions/error + "500": + description: | + Internal server error. Possible `error_code` attribute values: + * `internal_server_error` + "503": + description: Under maintenance + schema: + $ref: ../swagger.yaml#/definitions/error + x-koha-authorization: + permissions: + parameters: manage_smtp_servers diff --git a/api/v1/swagger/swagger.yaml b/api/v1/swagger/swagger.yaml index 4eebfdf23d..319a9fca5d 100644 --- a/api/v1/swagger/swagger.yaml +++ b/api/v1/swagger/swagger.yaml @@ -102,6 +102,8 @@ definitions: $ref: ./definitions/search_filter.yaml smtp_server: $ref: ./definitions/smtp_server.yaml + smtp_domain_limits: + $ref: ./definitions/smtp_domain_limits.yaml suggestion: $ref: ./definitions/suggestion.yaml ticket: @@ -353,6 +355,10 @@ paths: $ref: "./paths/return_claims.yaml#/~1return_claims~1{claim_id}~1resolve" "/rotas/{rota_id}/stages/{stage_id}/position": $ref: "./paths/rotas.yaml#/~1rotas~1{rota_id}~1stages~1{stage_id}~1position" + /smtp/domain_limits: + $ref: ./paths/smtp_domain_limits.yaml#/~1smtp~1domain_limits + "/smtp/domain_limits/{domain_limit_id}": + $ref: "./paths/smtp_domain_limits.yaml#/~1smtp~1domain_limits~1{domain_limit_id}" /suggestions: $ref: ./paths/suggestions.yaml#/~1suggestions "/suggestions/{suggestion_id}": @@ -483,6 +489,12 @@ parameters: name: club_id required: true type: integer + domain_limit_id_pp: + description: SMTP domain limit indentifier + in: path + name: domain_limit_id + required: true + type: integer eholdings_title_id_pp: description: Title internal identifier in: path @@ -855,6 +867,9 @@ tags: - description: "Manage SMTP servers configurations\n" name: smtp_servers x-displayName: SMTP servers + - description: "Manage SMTP domain limits\n" + name: domain_limits + x-displayName: SMTP domain limits - description: "Manage transfer limits\n" name: transfer x-displayName: Transfer limits diff --git a/t/db_dependent/api/v1/domain_limits.t b/t/db_dependent/api/v1/domain_limits.t new file mode 100755 index 0000000000..8b60ebeb69 --- /dev/null +++ b/t/db_dependent/api/v1/domain_limits.t @@ -0,0 +1,86 @@ +#!/usr/bin/env perl + +# Copyright 2023 Rijksmuseum, Koha development team +# +# This file is part of Koha. +# +# Koha is free software; you can redistribute it and/or modify it +# under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 3 of the License, or +# (at your option) any later version. +# +# Koha is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with Koha; if not, see . + +use Modern::Perl; +use Test::More tests => 1; +use Test::Mojo; + +use t::lib::TestBuilder; +use t::lib::Mocks; + +use Koha::Database; +use Koha::MailDomainLimits; + +my $schema = Koha::Database->new->schema; +my $builder = t::lib::TestBuilder->new; + +my $t = Test::Mojo->new('Koha::REST::V1'); +t::lib::Mocks::mock_preference( 'RESTBasicAuth', 1 ); + +subtest 'Few CRUD tests' => sub { + plan tests => 28; + $schema->storage->txn_begin; + + Koha::MailDomainLimits->delete; + my $user = $builder->build_object({ class => 'Koha::Patrons' }); + my $userid = $user->userid; + my $password = '2345'; + $user->set_password( { password => $password, skip_validation => 1 } ); + + # Test GET ALL, 403 Unauthorized + $t->get_ok("//$userid:$password@/api/v1/smtp/domain_limits")->status_is(403); + # Change flags + $user->flags(8)->store; + $t->get_ok("//$userid:$password@/api/v1/smtp/domain_limits")->status_is(200)->json_is( [] ); + + # Add with POST + my $data = { domain_name => 'test.nl', domain_limit => 1, units => 2, unit_type => 'minutes' }; + $t->post_ok( "//$userid:$password@/api/v1/smtp/domain_limits" => json => $data )->status_is(201); + is( Koha::MailDomainLimits->count, 1, 'Added record' ); + my $limit = Koha::MailDomainLimits->search->next; + my $limit_id = $limit->id; + is( $limit->domain_name, 'test.nl', 'Check a field' ); + # Add member + $t->post_ok( "//$userid:$password@/api/v1/smtp/domain_limits" => json => { domain_name => 'test.be', belongs_to => $limit_id } ) + ->status_is(201); + + # Single GET, check joined column for member just added + $t->get_ok("//$userid:$password@/api/v1/smtp/domain_limits/0")->status_is(404); + my $member_id = $limit_id + 1; + $t->get_ok("//$userid:$password@/api/v1/smtp/domain_limits/$member_id")->status_is(200)->json_has('/group_domain', 'test.nl'); + + # Modify with PUT + $data->{units} = 3; + $t->put_ok( "//$userid:$password@/api/v1/smtp/domain_limits/$limit_id" => json => $data )->status_is(200); + $limit->discard_changes; + is( $limit->units, 3, 'PUT changed a field' ); + # Try to set belongs_to, triggers exception + $data->{belongs_to} = $limit->id; + $t->put_ok( "//$userid:$password@/api/v1/smtp/domain_limits/$limit_id" => json => $data )->status_is(409); + + # Trigger 409 for duplicate domain_name + $t->post_ok( "//$userid:$password@/api/v1/smtp/domain_limits" => json => $data )->status_is(409); + + # Try DELETE + $t->delete_ok( "//$userid:$password@/api/v1/smtp/domain_limits/$limit_id" )->status_is(204); + is( Koha::MailDomainLimits->count, 0, 'Removed record' ); + $t->delete_ok( "//$userid:$password@/api/v1/smtp/domain_limits/$limit_id" )->status_is(404); + + $schema->storage->txn_rollback; +}; -- 2.30.2