Bug 37893: SIP Server params

Signed-off-by: Andrew Fuerste Henry <andrew@bywatersolutions.com>
Signed-off-by: Lisette Scheer <lisette@bywatersolutions.com>
Signed-off-by: Martin Renvoize <martin.renvoize@openfifth.co.uk>
Signed-off-by: Lucas Gass <lucas@bywatersolutions.com>
This commit is contained in:
Pedro Amorim 2025-02-07 13:13:52 -01:00 committed by Lucas Gass
parent bb6f72b9f7
commit 443d4a069b
No known key found for this signature in database
GPG Key ID: 60B447398B0D36CA
12 changed files with 688 additions and 0 deletions

View File

@ -0,0 +1,111 @@
package Koha::REST::V1::SIP2::ServerParams;
# 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 <http://www.gnu.org/licenses>.
use Modern::Perl;
use Mojo::Base 'Mojolicious::Controller';
use Koha::SIP2::ServerParam;
use Koha::SIP2::ServerParams;
use Try::Tiny qw( catch try );
=head1 API
=head2 Methods
=head3 list
=cut
sub list {
my $c = shift->openapi->valid_input or return;
return try {
my $server_params = $c->objects->search( Koha::SIP2::ServerParams->new );
return $c->render( status => 200, openapi => $server_params );
} catch {
$c->unhandled_exception($_);
};
}
sub update_server_params {
my ($c) = @_;
my $body = $c->req->json;
unless ( $body && ref $body eq 'ARRAY' ) {
return $c->render(
status => 400,
openapi => { error => "Invalid request body" }
);
}
foreach my $server_param (@$body) {
my $server_param_id = $server_param->{key};
my $server_param_obj = Koha::SIP2::ServerParams->search( { key => $server_param->{key} } )->last;
if ( !$server_param_obj ) {
try {
Koha::Database->new->schema->txn_do(
sub {
$server_param_obj = Koha::SIP2::ServerParam->new_from_api($server_param)->store;
}
);
} catch {
if ( blessed $_ ) {
if ( $_->isa('Koha::Exceptions::BadParameter') ) {
return $c->render(
status => 400,
json => { message => 'Some error occurred' }
);
}
}
$c->unhandled_exception($_);
}
} else {
try {
Koha::Database->new->schema->txn_do(
sub {
$server_param_obj->set_from_api($server_param)->store;
}
);
} catch {
if ( blessed $_ ) {
if ( $_->isa('Koha::Exceptions::BadParameter') ) {
return $c->render(
status => 400,
json => { message => 'Some error occurred' }
);
}
}
$c->unhandled_exception($_);
}
}
}
$c->res->headers->location( $c->req->url->to_string );
return $c->render(
status => 200,
json => { message => 'Server params updated successfully' },
);
}
1;

40
Koha/SIP2/ServerParam.pm Normal file
View File

@ -0,0 +1,40 @@
package Koha::SIP2::ServerParam;
# 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 <http://www.gnu.org/licenses>.
use Modern::Perl;
use base qw(Koha::Object);
=head1 NAME
Koha::SIP2::ServerParam- Koha Sip Server Param Object class
=head1 API
=head2 Class Methods
=cut
=head3 type
=cut
sub _type {
return 'SipServerParam';
}
1;

69
Koha/SIP2/ServerParams.pm Normal file
View File

@ -0,0 +1,69 @@
package Koha::SIP2::ServerParams;
# 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 <http://www.gnu.org/licenses>.
use Modern::Perl;
use Koha::SIP2::ServerParam;
use base qw(Koha::Objects);
=head1 NAME
Koha::SIP2::ServerParams- Koha Sip Server Param Object set class
=head1 API
=head2 Class Methods
=cut
=head3 get_for_config
Returns the server params hashref as expected by C4/SIP/Sip/Configuration->new;
=cut
sub get_for_config {
my ($self) = @_;
my $server_params = $self->search();
my $return_hash;
while ( my $server_param = $server_params->next() ) {
next if $server_param->key eq 'config_timestamp';
$return_hash->{ $server_param->key } = $server_param->value;
}
return $return_hash;
}
=head3 type
=cut
sub _type {
return 'SipServerParam';
}
=head3 object_class
=cut
sub object_class {
return 'Koha::SIP2::ServerParam';
}
1;

View File

@ -0,0 +1,87 @@
use utf8;
package Koha::Schema::Result::SipServerParam;
# Created by DBIx::Class::Schema::Loader
# DO NOT MODIFY THE FIRST PART OF THIS FILE
=head1 NAME
Koha::Schema::Result::SipServerParam
=cut
use strict;
use warnings;
use base 'DBIx::Class::Core';
=head1 TABLE: C<sip_server_params>
=cut
__PACKAGE__->table("sip_server_params");
=head1 ACCESSORS
=head2 sip_server_param_id
data_type: 'integer'
is_auto_increment: 1
is_nullable: 0
=head2 key
data_type: 'varchar'
is_nullable: 1
size: 80
=head2 value
data_type: 'varchar'
is_nullable: 0
size: 255
=cut
__PACKAGE__->add_columns(
"sip_server_param_id",
{ data_type => "integer", is_auto_increment => 1, is_nullable => 0 },
"key",
{ data_type => "varchar", is_nullable => 1, size => 80 },
"value",
{ data_type => "varchar", is_nullable => 0, size => 255 },
);
=head1 PRIMARY KEY
=over 4
=item * L</sip_server_param_id>
=back
=cut
__PACKAGE__->set_primary_key("sip_server_param_id");
=head1 UNIQUE CONSTRAINTS
=head2 C<server_param_key>
=over 4
=item * L</key>
=back
=cut
__PACKAGE__->add_unique_constraint("server_param_key", ["key"]);
# Created by DBIx::Class::Schema::Loader v0.07051 @ 2025-02-07 16:23:07
# DO NOT MODIFY THIS OR ANYTHING ABOVE! md5sum:VU5dn7xlVS8ZZKB1i2V6oQ
# You can replace this text with custom code or comments, and it will be preserved on regeneration
1;

View File

@ -0,0 +1,19 @@
---
type: object
properties:
sip_server_param_id:
type: integer
description: unique identifier
readOnly: true
key:
description: port
type: string
value:
description: protocol
type:
- string
- number
- "null"
additionalProperties: false
required:
- sip_server_param_id

View File

@ -0,0 +1,114 @@
---
/sip2/server_params:
get:
x-mojo-to: SIP2::ServerParams#list
operationId: listSip2ServerParams
tags:
- sip2_server_params
summary: List server params
produces:
- application/json
parameters:
- description: Case insensitive search on server_param sip_server_param_id
in: query
name: sip_server_param_id
required: false
type: string
collectionFormat: csv
- $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"
responses:
200:
description: A list of SIP2 server params
schema:
items:
$ref: "../swagger.yaml#/definitions/sip2_server_param"
type: array
"400":
description: |
Bad request. Possible `error_code` attribute values:
* `invalid_query`
schema:
$ref: "../swagger.yaml#/definitions/error"
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:
superlibrarian: 1 # TODO: Fix this, currently for superlibrarians only
patch:
x-mojo-to: SIP2::ServerParams#update_server_params
operationId: updateSip2ServerParams
tags:
- sip2_server_params
summary: Update server params
consumes:
- application/json
produces:
- application/json
parameters:
- description: A JSON object containing information about the server params updates
in: body
name: body
required: true
schema:
$ref: "../swagger.yaml#/definitions/sip2_server_param"
responses:
201:
description: A successfully created listener
schema:
items:
$ref: "../swagger.yaml#/definitions/sip2_listener"
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: Ressource not found
schema:
$ref: "../swagger.yaml#/definitions/error"
409:
description: Conflict in creating resource
schema:
$ref: "../swagger.yaml#/definitions/error"
413:
description: Payload too large
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:
superlibrarian: 1 # TODO: Fix this, currently for superlibrarians only

View File

@ -186,6 +186,8 @@ definitions:
$ref: ./definitions/sip2_institution.yaml
sip2_listener:
$ref: ./definitions/sip2_listener.yaml
sip2_server_param:
$ref: ./definitions/sip2_server_param.yaml
smtp_server:
$ref: ./definitions/smtp_server.yaml
file_transport:
@ -615,6 +617,8 @@ paths:
$ref: ./paths/sip2_listeners.yaml#/~1sip2~1listeners
"/sip2/listeners/{sip_listener_id}":
$ref: "./paths/sip2_listeners.yaml#/~1sip2~1listeners~1{sip_listener_id}"
/sip2/serverparams:
$ref: "./paths/sip2_server_params.yaml#/~1sip2~1server_params"
/suggestions:
$ref: ./paths/suggestions.yaml#/~1suggestions
"/suggestions/{suggestion_id}":

View File

@ -306,5 +306,24 @@ return {
$SIPconfig->{listeners}->{$listener_key}->{transport}
);
}
# Server params #
my @server_params_keys = keys %{ $SIPconfig->{'server-params'} };
foreach my $server_params_key (@server_params_keys) {
my $insert_listeners = $dbh->prepare(
q{INSERT IGNORE INTO sip_server_params (`key`, value) VALUES (?, ?) }
);
$insert_listeners->execute(
$server_params_key,
$SIPconfig->{'server-params'}->{$server_params_key}
);
}
my $delete_config_timestamp = $dbh->prepare(q{DELETE FROM sip_server_params WHERE `key` = 'config_timestamp' });
$delete_config_timestamp->execute();
my $timestamp = DateTime->now;
my $insert_config_timestamp = $dbh->prepare(q{INSERT INTO sip_server_params (`key`, value) VALUES (?, ?) });
$insert_config_timestamp->execute( 'config_timestamp', $timestamp->epoch );
},
};

View File

@ -6303,6 +6303,21 @@ CREATE TABLE `sip_listeners` (
UNIQUE KEY `listener_port` (`port`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
--
-- Table structure for table `sip_listeners`
--
DROP TABLE IF EXISTS `sip_server_params`;
/*!40101 SET @saved_cs_client = @@character_set_client */;
/*!40101 SET character_set_client = utf8 */;
CREATE TABLE `sip_server_params` (
`sip_server_param_id` int(11) NOT NULL AUTO_INCREMENT,
`key` varchar(80) DEFAULT NULL,
`value` varchar(255) NOT NULL,
PRIMARY KEY (`sip_server_param_id`),
UNIQUE KEY `server_param_key` (`key`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
--
-- Table structure for table `sms_providers`
--

View File

@ -119,6 +119,20 @@ export class SIP2APIClient {
}),
};
}
get serverparams() {
return {
getAll: params =>
this.getAll({
endpoint: "serverparams",
}),
updateAll: (body) =>
this.patch({
endpoint: "serverparams",
body: body,
}),
};
}
}
export default SIP2APIClient;

View File

@ -0,0 +1,182 @@
<template>
<div v-if="!initialized">{{ $__("Loading") }}</div>
<div v-else id="serverparams">
<h2>
{{ $__("Edit server params") }}
</h2>
<div>
<form @submit="onSubmit($event)">
<fieldset class="rows">
<ol>
<li
v-for="(param, index) in this
.server_params_definitions"
v-bind:key="index"
>
<FormElement
:resource="this.server_params"
:attr="param"
:index="index"
/>
</li>
</ol>
</fieldset>
<fieldset class="action">
<ButtonSubmit />
</fieldset>
</form>
</div>
</div>
</template>
<script>
import { inject } from "vue";
import { APIClient } from "../../fetch/api-client.js";
import FormElement from "../FormElement.vue";
import ButtonSubmit from "../ButtonSubmit.vue";
export default {
setup() {
const { setMessage } = inject("mainStore");
setMessage(
__(
"Please note: Changes to server params require a SIP server restart"
),
true
);
return {
setMessage,
};
},
data() {
return {
initialized: false,
server_params_definitions: [
{
name: "min_servers",
required: true,
type: "number",
label: "min_servers",
},
{
name: "min_spare_servers",
required: true,
type: "number",
label: "min_spare_servers",
},
{
name: "max_servers",
required: true,
type: "number",
label: "max_servers",
},
{
name: "setsid",
required: true,
type: "number",
label: "setsid",
},
{
name: "user",
required: true,
type: "text",
label: "user",
},
{
name: "group",
required: true,
type: "text",
label: "group",
},
{
name: "pid_file",
required: true,
type: "text",
label: "pid_file",
},
{
name: "custom_tcp_keepalive",
required: true,
type: "number",
label: "custom_tcp_keepalive",
},
{
name: "custom_tcp_keepalive_time",
required: true,
type: "number",
label: "custom_tcp_keepalive_time",
},
{
name: "custom_tcp_keepalive_intvl",
required: true,
type: "number",
label: "custom_tcp_keepalive_intvl",
},
],
server_params: {
min_servers: "1",
min_spare_servers: "0",
max_servers: "1",
setsid: "1",
user: "koha",
group: "koha",
pid_file: "/var/run/sipserver.pid",
custom_tcp_keepalive: "0",
custom_tcp_keepalive_time: "7200",
custom_tcp_keepalive_intvl: "75",
},
};
},
created() {
this.getServerParams();
},
methods: {
async getServerParams() {
const client = APIClient.sip2;
client.serverparams.getAll().then(
returned_server_params => {
returned_server_params.forEach(server_param => {
this.server_params[server_param.key] =
server_param.value;
});
this.initialized = true;
},
error => {}
);
},
onSubmit(e) {
e.preventDefault();
const client = APIClient.sip2;
const updatedParams = Object.keys(this.server_params).map(key => {
return { key: key, value: this.server_params[key] };
});
client.serverparams.updateAll(updatedParams).then(
success => {
this.setMessage(
this.$__(
"Server parameters updated. Please restart the SIP server."
),
true
);
},
error => {}
);
},
},
components: {
ButtonSubmit,
FormElement,
},
name: "SIP2ServerParams",
};
</script>
<style scoped>
:deep(fieldset.rows) label {
width: 15rem;
}
</style>

View File

@ -2,6 +2,7 @@ import { markRaw } from "vue";
import Home from "../components/SIP2/Home.vue";
import ResourceWrapper from "../components/ResourceWrapper.vue";
import ServerParams from "../components/SIP2/SIP2ServerParams.vue";
import { $__ } from "../i18n";
export const routes = [
@ -113,6 +114,19 @@ export const routes = [
},
],
},
{
path: "/cgi-bin/koha/sip2/serverparams",
title: $__("Server params"),
icon: "fa fa-cog",
is_end_node: true,
children: [
{
path: "",
name: "SIP2ServerParams",
component: markRaw(ServerParams),
},
]
},
],
},
];