From 171e46bb13554a515c7a989f47c49d9309f9896b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tom=C3=A1s=20Cohen=20Arazi?= Date: Wed, 5 Nov 2025 10:20:48 -0300 Subject: [PATCH] Bug 41107: Add /status/version API endpoint Adds a new REST API endpoint to retrieve Koha version information. This implementation includes: - Koha::Status class for instance status information - /status/version endpoint returning structured version data - OpenAPI specification with koha_version definition - REST controller for handling the endpoint The returned version object includes: - version: full version string (e.g., '25.06.00.029') - major: major version number - minor: minor version number - release: major.minor version - maintenance: major.minor.maintenance version - development: development version (if applicable) This prepares the foundation for a future /status endpoint that will include all information displayed in the about page. To test: 1. Apply the patch 2. Run: $ ktd --shell k$ yarn api:bundle 3. Run the tests: k$ prove t/Koha/Status.t \ t/db_dependent/api/v1/status.t => SUCCESS: Tests pass! 4. Sign off :-D --- Koha/REST/V1/Status.pm | 56 +++++++++++++ Koha/Status.pm | 85 ++++++++++++++++++++ api/v1/swagger/definitions/koha_version.yaml | 30 +++++++ api/v1/swagger/paths/status.yaml | 44 ++++++++++ api/v1/swagger/swagger.yaml | 7 ++ t/Koha/Status.t | 49 +++++++++++ t/db_dependent/api/v1/status.t | 58 +++++++++++++ 7 files changed, 329 insertions(+) create mode 100644 Koha/REST/V1/Status.pm create mode 100644 Koha/Status.pm create mode 100644 api/v1/swagger/definitions/koha_version.yaml create mode 100644 api/v1/swagger/paths/status.yaml create mode 100755 t/Koha/Status.t create mode 100755 t/db_dependent/api/v1/status.t diff --git a/Koha/REST/V1/Status.pm b/Koha/REST/V1/Status.pm new file mode 100644 index 00000000000..dbec06c43e3 --- /dev/null +++ b/Koha/REST/V1/Status.pm @@ -0,0 +1,56 @@ +package Koha::REST::V1::Status; + +# 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 Try::Tiny qw( catch try ); + +use Koha::Status; + +=head1 NAME + +Koha::REST::V1::Status - Controller library for status related API endpoints + +=head1 API + +=head2 Methods + +=head3 version + +Controller method that returns Koha version information + +=cut + +sub version { + my $c = shift->openapi->valid_input or return; + + return try { + my $status = Koha::Status->new(); + my $version_info = $status->version(); + + return $c->render( + status => 200, + openapi => $version_info + ); + } catch { + $c->unhandled_exception($_); + }; +} + +1; diff --git a/Koha/Status.pm b/Koha/Status.pm new file mode 100644 index 00000000000..d7b6f78fad2 --- /dev/null +++ b/Koha/Status.pm @@ -0,0 +1,85 @@ +package Koha::Status; + +# 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 Koha; + +=head1 NAME + +Koha::Status - Koha instance status information + +=head1 SYNOPSIS + + use Koha::Status; + + my $status = Koha::Status->new(); + my $version_info = $status->version(); + +=head1 DESCRIPTION + +This class provides methods to retrieve status information about the Koha instance. + +=head1 METHODS + +=head2 new + + my $status = Koha::Status->new(); + +Constructor. + +=cut + +sub new { + my ($class) = @_; + return bless {}, $class; +} + +=head2 version + + my $version_info = $status->version(); + +Returns version information in a structured format similar to +Koha::Template::Plugin::Koha->Version but with additional metadata. + +Returns a hashref with the following structure: +- version: full version string +- major: major version number +- minor: minor version number +- release: major.minor version +- maintenance: major.minor.maintenance version +- development: development version (if applicable) + +=cut + +sub version { + my ($self) = @_; + + my $version_string = Koha::version(); + my ( $major, $minor, $maintenance, $development ) = split( '\.', $version_string ); + + return { + version => $version_string, + major => $major, + minor => $minor, + release => $major . "." . $minor, + maintenance => $major . "." . $minor . "." . $maintenance, + development => ( $development && $development ne '000' ) ? $development : undef, + }; +} + +1; diff --git a/api/v1/swagger/definitions/koha_version.yaml b/api/v1/swagger/definitions/koha_version.yaml new file mode 100644 index 00000000000..3582c4900a4 --- /dev/null +++ b/api/v1/swagger/definitions/koha_version.yaml @@ -0,0 +1,30 @@ +--- +type: object +properties: + version: + type: string + description: Full version string + example: "25.06.00.029" + major: + type: string + description: Major version number + example: "25" + minor: + type: string + description: Minor version number + example: "06" + release: + type: string + description: Release version (major.minor) + example: "25.06" + maintenance: + type: string + description: Maintenance version (major.minor.maintenance) + example: "25.06.00" + development: + type: + - string + - "null" + description: Development version number (null if not a development version) + example: "029" +additionalProperties: false diff --git a/api/v1/swagger/paths/status.yaml b/api/v1/swagger/paths/status.yaml new file mode 100644 index 00000000000..a81ea3924fb --- /dev/null +++ b/api/v1/swagger/paths/status.yaml @@ -0,0 +1,44 @@ +--- +"/status/version": + get: + x-mojo-to: Status#version + operationId: getStatusVersion + tags: + - status + summary: Get Koha version information + description: | + Returns version information for this Koha instance including major, minor, + maintenance and development version numbers. + produces: + - application/json + responses: + "200": + description: A suggestion + schema: + $ref: "../swagger.yaml#/definitions/koha_version" + "400": + description: Bad request + schema: + $ref: "../swagger.yaml#/definitions/error" + "403": + description: Access forbidden + schema: + $ref: "../swagger.yaml#/definitions/error" + "404": + description: Suggestion 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: + catalogue: 1 diff --git a/api/v1/swagger/swagger.yaml b/api/v1/swagger/swagger.yaml index 14e41bd327f..50b7af327d6 100644 --- a/api/v1/swagger/swagger.yaml +++ b/api/v1/swagger/swagger.yaml @@ -124,6 +124,8 @@ definitions: $ref: ./definitions/import_batch_profiles.yaml import_record_match: $ref: ./definitions/import_record_match.yaml + koha_version: + $ref: definitions/koha_version.yaml record_source: $ref: ./definitions/record_source.yaml invoice: @@ -609,6 +611,8 @@ paths: $ref: ./paths/transfer_limits.yaml#/~1transfer_limits~1batch "/transfer_limits/{limit_id}": $ref: "./paths/transfer_limits.yaml#/~1transfer_limits~1{limit_id}" + /status/version: + $ref: ./paths/status.yaml#/~1status~1version parameters: advancededitormacro_id_pp: description: Advanced editor macro internal identifier @@ -1345,6 +1349,9 @@ tags: - description: "Manage file transport configurations\n" name: file_transports x-displayName: File transports + - description: "System status\n" + name: status + x-displayName: Status - description: "Manage tickets\n" name: tickets x-displayName: Tickets diff --git a/t/Koha/Status.t b/t/Koha/Status.t new file mode 100755 index 00000000000..20d4c859314 --- /dev/null +++ b/t/Koha/Status.t @@ -0,0 +1,49 @@ +#!/usr/bin/perl + +# 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 => 3; +use Test::NoWarnings; + +use Koha::Status; + +subtest 'new' => sub { + plan tests => 1; + + my $status = Koha::Status->new(); + isa_ok( $status, 'Koha::Status', 'Constructor returns correct object type' ); +}; + +subtest 'version' => sub { + plan tests => 7; + + my $status = Koha::Status->new(); + my $version_info = $status->version(); + + is( ref($version_info), 'HASH', 'version() returns a hashref' ); + + # Check required fields exist + ok( exists $version_info->{version}, 'version field exists' ); + ok( exists $version_info->{major}, 'major field exists' ); + ok( exists $version_info->{minor}, 'minor field exists' ); + ok( exists $version_info->{release}, 'release field exists' ); + ok( exists $version_info->{maintenance}, 'maintenance field exists' ); + + # Check version format and consistency + like( $version_info->{version}, qr/^\d+\.\d+\.\d+\.\d+$/, 'version has correct format' ); +}; diff --git a/t/db_dependent/api/v1/status.t b/t/db_dependent/api/v1/status.t new file mode 100755 index 00000000000..22faff64f5c --- /dev/null +++ b/t/db_dependent/api/v1/status.t @@ -0,0 +1,58 @@ +#!/usr/bin/env perl + +# 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::NoWarnings; +use Test::More tests => 2; +use Test::Mojo; + +use t::lib::TestBuilder; +use t::lib::Mocks; + +use Koha; +use Koha::Database; + +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 'version() tests' => sub { + + plan tests => 8; + + $schema->storage->txn_begin; + + my $librarian = $builder->build_object( + { + class => 'Koha::Patrons', + value => { flags => 2**2 }, # catalogue flag = 2 + } + ); + my $password = 'thePassword123'; + $librarian->set_password( { password => $password, skip_validation => 1 } ); + my $userid = $librarian->userid; + + $t->get_ok("//$userid:$password@/api/v1/status/version")->status_is(200)->json_is( '/version' => Koha::version() ) + ->json_has('/major')->json_has('/minor')->json_has('/release')->json_has('/maintenance') + ->json_like( '/version' => qr/^\d+\.\d+\.\d+\.\d+$/ ); + + $schema->storage->txn_rollback; +}; -- 2.51.2