Bugzilla – Attachment 178562 Details for
Bug 39190
Rework new (S)FTP classes to be polymorphic classes
Home
|
New
|
Browse
|
Search
|
[?]
|
Reports
|
Help
|
New Account
|
Log In
[x]
|
Forgot Password
Login:
[x]
[patch]
Bug 39190: Re-implement the connection testing
Bug-39190-Re-implement-the-connection-testing.patch (text/plain), 109.69 KB, created by
Martin Renvoize (ashimema)
on 2025-02-24 13:14:39 UTC
(
hide
)
Description:
Bug 39190: Re-implement the connection testing
Filename:
MIME Type:
Creator:
Martin Renvoize (ashimema)
Created:
2025-02-24 13:14:39 UTC
Size:
109.69 KB
patch
obsolete
>From 8d035d016c189fd7c8dfe72374bef6665229e355 Mon Sep 17 00:00:00 2001 >From: Martin Renvoize <martin.renvoize@ptfs-europe.com> >Date: Wed, 22 Jan 2025 12:38:59 +0000 >Subject: [PATCH] Bug 39190: Re-implement the connection testing > >We now use background jobs triggered by Transport->store to update the >connection status. > >Status is now a json blob with more details, so we update the api >definition to reflect that. >--- > Koha/BackgroundJob.pm | 1 + > Koha/BackgroundJob/TestTransport.pm | 91 + > Koha/File/Transport.pm | 63 +- > Koha/File/Transport/SFTP.pm | 131 +- > Koha/SFTP/Server.pm | 12 +- > admin/sftp_servers.pl | 19 - > api/v1/swagger/definitions/sftp_server.yaml | 2 +- > .../background_jobs/file_transport_test.inc | 48 + > .../prog/en/modules/admin/background_jobs.tt | 4 + > .../prog/en/modules/admin/sftp_servers.tt | 1568 ++++++++--------- > .../intranet-tmpl/prog/js/transport_status.js | 7 + > 11 files changed, 1003 insertions(+), 943 deletions(-) > create mode 100644 Koha/BackgroundJob/TestTransport.pm > create mode 100644 koha-tmpl/intranet-tmpl/prog/en/includes/background_jobs/file_transport_test.inc > create mode 100644 koha-tmpl/intranet-tmpl/prog/js/transport_status.js > >diff --git a/Koha/BackgroundJob.pm b/Koha/BackgroundJob.pm >index 211e2e32f3f..d89a0853e12 100644 >--- a/Koha/BackgroundJob.pm >+++ b/Koha/BackgroundJob.pm >@@ -446,6 +446,7 @@ sub core_types_to_classes { > marc_import_revert_batch => 'Koha::BackgroundJob::MARCImportRevertBatch', > pseudonymize_statistic => 'Koha::BackgroundJob::PseudonymizeStatistic', > import_from_kbart_file => 'Koha::BackgroundJob::ImportKBARTFile', >+ file_transport_test => 'Koha::BackgroundJob::TestTransport', > }; > } > >diff --git a/Koha/BackgroundJob/TestTransport.pm b/Koha/BackgroundJob/TestTransport.pm >new file mode 100644 >index 00000000000..6054ca4b7a0 >--- /dev/null >+++ b/Koha/BackgroundJob/TestTransport.pm >@@ -0,0 +1,91 @@ >+package Koha::BackgroundJob::TestTransport; >+ >+# 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 JSON qw( decode_json encode_json ); >+use Try::Tiny; >+use Koha::File::Transports; >+ >+use base 'Koha::BackgroundJob'; >+ >+=head1 NAME >+ >+Koha::BackgroundJob::TestTransport - Background job derived class to test File::Transports >+ >+=head1 API >+ >+=head2 Class methods >+ >+=head3 job_type >+ >+Define the job type of this job: file_transport_test >+ >+=cut >+ >+sub job_type { >+ return 'file_transport_test'; >+} >+ >+=head3 process >+ >+Process the transport test. >+ >+=cut >+ >+sub process { >+ my ( $self, $args ) = @_; >+ $self->start; >+ >+ my $transport = Koha::File::Transports->find( $args->{transport_id} ); >+ $transport->test_connection; >+ my $status = { status => 'ok' }; >+ my $messages = $transport->object_messages; >+ for my $message (@$messages) { >+ $status->{status} = 'errors' if $message->{type} eq 'error'; >+ push @{ $status->{operations} }, >+ { code => $message->{message}, status => $message->{type}, detail => $message->{payload} }; >+ } >+ $transport->set( { status => encode_json($status) } )->store(); >+ >+ my $data = $status; >+ $self->finish($data); >+} >+ >+=head3 enqueue >+ >+Enqueue the new job >+ >+=cut >+ >+sub enqueue { >+ my ( $self, $args ) = @_; >+ >+ my $transport = $args->{transport_id}; >+ Koha::Exceptions::MissingParameter->throw("Missing transport_id parameter is mandatory") >+ unless $transport; >+ >+ $self->SUPER::enqueue( >+ { >+ job_size => 1, >+ job_args => {%$args}, >+ job_queue => 'default', >+ } >+ ); >+} >+ >+1; >diff --git a/Koha/File/Transport.pm b/Koha/File/Transport.pm >index de13dd73781..cdf17eac4ba 100644 >--- a/Koha/File/Transport.pm >+++ b/Koha/File/Transport.pm >@@ -16,12 +16,16 @@ package Koha::File::Transport; > # along with Koha; if not, see <http://www.gnu.org/licenses>. > > use Modern::Perl; >+ > use constant { > DEFAULT_TIMEOUT => 10, > TEST_FILE_NAME => '.koha_test_file', > TEST_FILE_CONTENT => "Hello, world!\n", > }; >+use JSON qw( decode_json encode_json ); >+use List::MoreUtils qw( any ); > >+use Koha::BackgroundJob::TestTransport; > use Koha::Database; > use Koha::Exceptions::Object; > use Koha::Encryption; >@@ -63,11 +67,24 @@ sub store { > $self->$dir_field( $dir . '/' ) unless substr( $dir, -1 ) eq '/'; > } > >+ my @config_fields = (qw(host port user_name password key_file upload_directory download_directory)); >+ my $changed_config = ( !$self->in_storage || any { $self->_result->is_column_changed($_) } @config_fields ) ? 1 : 0; >+ > # Store > $self->SUPER::store; > >+ # Subclass triggers >+ my $subclass = $self->transport eq 'sftp' ? 'Koha::File::Transport::SFTP' : 'Koha::File::Transport::FTP'; >+ $self = $subclass->_new_from_dbic( $self->_result ); >+ $self->_post_store_trigger; >+ >+ # Enqueue a connection test >+ if ($changed_config) { >+ Koha::BackgroundJob::TestTransport->new->enqueue( { transport_id => $self->id } ); >+ } >+ > # Return the updated object including the encrypt_sensitive_data >- return $self->discard_changes; >+ return $self; > } > > =head3 plain_text_password >@@ -111,7 +128,8 @@ sub to_api { > my ( $self, $params ) = @_; > > my $json = $self->SUPER::to_api($params) or return; >- delete @{$json}{qw(password key_file)}; # Remove sensitive data >+ delete @{$json}{qw(password key_file)}; # Remove sensitive data >+ $json->{status} = $self->status ? decode_json( $self->status ) : undef; # Decode json status > > return $json; > } >@@ -141,14 +159,22 @@ sub test_connection { > $self->connect or return; > > for my $dir_type (qw(download upload)) { >- my $dir = $self->{"${dir_type}_directory"}; >- next if $dir eq ''; >+ my $field = "${dir_type}_directory"; >+ my $dir = $self->$field; >+ $dir ||= undef; > >- $self->change_directory($dir) or return; >- $self->list_files() or return; >+ $self->change_directory(undef) or next; >+ $self->change_directory($dir) or next; >+ $self->list_files() or next; > } > >- return 1; >+ my $return = 1; >+ my $messages = $self->object_messages; >+ for my $message ( @{$messages} ) { >+ $return = 0 if $message->type eq 'error'; >+ } >+ >+ return $return; > } > > =head2 Subclass methods >@@ -220,6 +246,21 @@ sub list_files { > die "Subclass must implement list_files"; > } > >+=head3 _post_store_trigger >+ >+ $server->_post_store_trigger; >+ >+Method triggered by parent store to allow local additions to the store call >+ >+=cut >+ >+sub _post_store_trigger { >+ my ($self) = @_; >+ >+ #Subclass may implement a _post_store_trigger as required >+ return $self; >+} >+ > =head2 Internal methods > > =head3 _encrypt_sensitive_data >@@ -232,14 +273,16 @@ sub _encrypt_sensitive_data { > my ($self) = @_; > my $encryption = Koha::Encryption->new; > >- # Only encrypt if the value has changed (is_changed from Koha::Object) >- if ( ( !$self->in_storage || $self->is_changed('password') ) && $self->password ) { >+ # Only encrypt if the value has changed ($self->_result->is_column_changed from Koha::Object) >+ if ( ( !$self->in_storage || $self->_result->is_column_changed('password') ) && $self->password ) { > $self->password( $encryption->encrypt_hex( $self->password ) ); > } > >- if ( ( !$self->in_storage || $self->is_changed('key_file') ) && $self->key_file ) { >+ if ( ( !$self->in_storage || $self->_result->is_column_changed('key_file') ) && $self->key_file ) { > $self->key_file( $encryption->encrypt_hex( _dos2unix( $self->key_file ) ) ); > } >+ >+ return; > } > > =head3 _dos2unix >diff --git a/Koha/File/Transport/SFTP.pm b/Koha/File/Transport/SFTP.pm >index 3143c6c7bdd..364c3405893 100644 >--- a/Koha/File/Transport/SFTP.pm >+++ b/Koha/File/Transport/SFTP.pm >@@ -32,24 +32,6 @@ Koha::File::Transport::SFTP - SFTP implementation of file transport > > =head2 Class methods > >-=head3 store >- >- $server->store; >- >-Overloaded store method that ensures key_file also gets written to the filesystem. >- >-=cut >- >-sub store { >- my ($self) = @_; >- >- $self->SUPER::store; >- $self->discard_changes; >- $self->_write_key_file; >- >- return $self; >-} >- > =head3 connect > > my $success = $self->connect; >@@ -60,25 +42,34 @@ Start the SFTP transport connect, returns true on success or undefined on failur > > sub connect { > my ($self) = @_; >+ my $operation = "connection"; > >+ # String to capture STDERR output >+ $self->{stderr_capture} = ''; >+ open my $stderr_fh, '>', \$self->{stderr_capture} or die "Can't open scalar as filehandle: $!"; > $self->{connection} = Net::SFTP::Foreign->new( > host => $self->host, > port => $self->port, > user => $self->user_name, > password => $self->plain_text_password, >- key_path => $self->_locate_key_file, >- timeout => $self->DEFAULT_TIMEOUT, >- more => [qw(-o StrictHostKeyChecking=no)], >+ $self->_locate_key_file ? ( key_path => $self->_locate_key_file ) : (), >+ timeout => $self->DEFAULT_TIMEOUT, >+ stderr_fh => $stderr_fh, >+ more => [qw( -v -o StrictHostKeyChecking=no)], > ); >- $self->{connection}->die_on_error("SFTP failure for remote host"); >+ $self->{stderr_fh} = $stderr_fh; > >- return $self->_abort_operation() if ( $self->{connection}->error ); >+ return $self->_abort_operation($operation) if ( $self->{connection}->error ); > > $self->add_message( > { >- message => $self->{connection}->status, >+ message => $operation, > type => 'success', >- payload => { detail => '' } >+ payload => { >+ status => $self->{connection}->status, >+ error => $self->{connection}->error, >+ path => $self->{connection}->cwd >+ } > } > ); > >@@ -97,16 +88,21 @@ Returns true on success or undefined on failure. > > sub upload_file { > my ( $self, $local_file, $remote_file ) = @_; >+ my $operation = "upload"; > > my $logger = Koha::Logger->get_logger(); > >- $self->{connection}->put( $local_file, $remote_file ) or return $self->_abort_operation(); >+ $self->{connection}->put( $local_file, $remote_file ) or return $self->_abort_operation($operation); > > $self->add_message( > { >- message => $self->{connection}->status, >+ message => $operation, > type => 'success', >- payload => { detail => '' } >+ payload => { >+ status => $self->{connection}->status, >+ error => $self->{connection}->error, >+ path => $self->{connection}->cwd >+ } > } > ); > >@@ -125,14 +121,19 @@ Returns true on success or undefined on failure. > > sub download_file { > my ( $self, $remote_file, $local_file ) = @_; >+ my $operation = 'download'; > >- $self->{connection}->get( $remote_file, $local_file ) or return $self->_abort_operation(); >+ $self->{connection}->get( $remote_file, $local_file ) or return $self->_abort_operation($operation); > > $self->add_message( > { >- message => $self->{connection}->status, >+ message => $operation, > type => 'success', >- payload => { detail => '' } >+ payload => { >+ status => $self->{connection}->status, >+ error => $self->{connection}->error, >+ path => $self->{connection}->cwd >+ } > } > ); > >@@ -151,14 +152,19 @@ Returns true on success or undefined on failure. > > sub change_directory { > my ( $self, $remote_directory ) = @_; >+ my $operation = 'change_directory'; > >- $self->{connection}->setcwd($remote_directory) or return $self->_abort_operation(); >+ $self->{connection}->setcwd($remote_directory) or return $self->_abort_operation( $operation, $remote_directory ); > > $self->add_message( > { >- message => $self->{connection}->status, >+ message => $operation, > type => 'success', >- payload => { detail => '' } >+ payload => { >+ status => $self->{connection}->status, >+ error => $self->{connection}->error, >+ path => $self->{connection}->cwd >+ } > } > ); > >@@ -175,14 +181,19 @@ Returns an array of filenames found in the current directory of the server conne > > sub list_files { > my ($self) = @_; >+ my $operation = "list"; > >- my $file_list = $self->{connection}->ls or return $self->_abort_operation(); >+ my $file_list = $self->{connection}->ls or return $self->_abort_operation($operation); > > $self->add_message( > { >- message => $self->{connection}->status, >+ message => $operation, > type => 'success', >- payload => { detail => '' } >+ payload => { >+ status => $self->{connection}->status, >+ error => $self->{connection}->error, >+ path => $self->{connection}->cwd >+ } > } > ); > >@@ -191,6 +202,21 @@ sub list_files { > > =head2 Internal methods > >+=head3 _post_store_trigger >+ >+ $server->post_store_trigger; >+ >+Local trigger run by the parent store method after storage. >+Ensures key_file also gets written to the filesystem. >+ >+=cut >+ >+sub _post_store_trigger { >+ my ($self) = @_; >+ $self->_write_key_file; >+ return $self; >+} >+ > =head3 _write_key_file > > my $success = $server->_write_key_file; >@@ -204,6 +230,8 @@ Returns 1 on success, undef on failure. > sub _write_key_file { > my ($self) = @_; > >+ return unless $self->plain_text_key; >+ > my $upload_path = C4::Context->config('upload_path') or return; > my $logger = Koha::Logger->get; > my $key_path = File::Spec->catdir( $upload_path, 'ssh_keys' ); >@@ -254,13 +282,21 @@ Helper method to abort the current operation and return. > =cut > > sub _abort_operation { >- my ($self) = @_; >+ my ( $self, $operation, $path ) = @_; >+ >+ my $stderr = $self->{stderr_capture}; >+ $self->{stderr_capture} = ''; > > $self->add_message( > { >- message => $self->{connection}->error, >+ message => $operation, > type => 'error', >- payload => { detail => $self->{connection} ? $self->{connection}->status : '' } >+ payload => { >+ status => $self->{connection}->status, >+ error => $self->{connection}->error, >+ path => $path ? $path : $self->{connection}->cwd, >+ error_raw => $stderr >+ } > } > ); > >@@ -271,4 +307,19 @@ sub _abort_operation { > return; > } > >+=head3 DESTROY >+ >+Ensure proper cleanup of open filehandles >+ >+=cut >+ >+sub DESTROY { >+ my ($self) = @_; >+ >+ # Ensure the filehandle is closed properly >+ if ( $self->{stderr_fh} ) { >+ close $self->{stderr_fh} or warn "Failed to close STDERR filehandle: $!"; >+ } >+} >+ > 1; >diff --git a/Koha/SFTP/Server.pm b/Koha/SFTP/Server.pm >index 0db73011c1b..d91a20116cd 100644 >--- a/Koha/SFTP/Server.pm >+++ b/Koha/SFTP/Server.pm >@@ -409,12 +409,12 @@ sub test_conn { > } > } > >- $self->update_status('tests_ok'); >- foreach my $val ( values %$sftp_test_results ) { >- if ( defined $val->{'err'} ) { >- $self->update_status('tests_failed'); >- } >- } >+ # $self->update_status('tests_ok'); >+ # foreach my $val ( values %$sftp_test_results ) { >+ # if ( defined $val->{'err'} ) { >+ # $self->update_status('tests_failed'); >+ # } >+ # } > > return ( 1, $sftp_test_results ); > } >diff --git a/admin/sftp_servers.pl b/admin/sftp_servers.pl >index 209d3a123e5..5c19edc30d7 100755 >--- a/admin/sftp_servers.pl >+++ b/admin/sftp_servers.pl >@@ -192,25 +192,6 @@ if ( $op eq 'cud-add' ) { > reason => 'invalid_id' > }; > } >- >-} elsif ( $op eq 'test_form' ) { >- my $sftp_server_id = $input->param('sftp_server_id'); >- my $sftp_server; >- >- $sftp_server = Koha::File::Transports->find($sftp_server_id) >- unless !$sftp_server_id; >- >- if ($sftp_server) { >- $template->param( >- sftp_server => $sftp_server, >- ); >- } else { >- push @messages, { >- type => 'alert', >- code => 'error_on_test', >- reason => 'invalid_id', >- }; >- } > } > > if ( $op eq 'list' ) { >diff --git a/api/v1/swagger/definitions/sftp_server.yaml b/api/v1/swagger/definitions/sftp_server.yaml >index cbc92605882..48216efae1b 100644 >--- a/api/v1/swagger/definitions/sftp_server.yaml >+++ b/api/v1/swagger/definitions/sftp_server.yaml >@@ -58,7 +58,7 @@ properties: > description: Path on the remote server we upload to (optional) > status: > type: >- - string >+ - object > - "null" > description: Most recent status of the FTP/SFTP server (optional) > debug: >diff --git a/koha-tmpl/intranet-tmpl/prog/en/includes/background_jobs/file_transport_test.inc b/koha-tmpl/intranet-tmpl/prog/en/includes/background_jobs/file_transport_test.inc >new file mode 100644 >index 00000000000..02940554f09 >--- /dev/null >+++ b/koha-tmpl/intranet-tmpl/prog/en/includes/background_jobs/file_transport_test.inc >@@ -0,0 +1,48 @@ >+[% USE Koha %] >+ >+[%- BLOCK operation_description -%] >+ [%- SWITCH operation.code -%] >+ >+ [%- CASE 'connection' -%] >+ <span>Connection</span> >+ [%- CASE 'upload' -%] >+ <span>Upload</span> >+ [%- CASE 'download' -%] >+ <span>Download</span> >+ [%- CASE 'list' -%] >+ <span>List files</span> >+ [%- CASE 'change_directory' -%] >+ <span>Change directory</span> >+ [%- CASE -%] >+ <span>[% operation.code | html %]</span> >+ [%- END -%] >+[%- END -%] >+ >+[% SET report = job.decoded_data %] >+[% BLOCK report %] >+ [% IF job.status == 'finished' %] >+ [% IF report.status == 'errors' %] >+ <div class="alert alert-alert"> Connection test completed with errors </div> >+ [% ELSE %] >+ <div class="alert alert-success"> Connection test completed without errors </div> >+ [% END %] >+ [% ELSIF job.status == 'cancelled' %] >+ <span>The connection test was cancelled before it finished.</span> >+ [% END %] >+[% END %] >+ >+[% BLOCK detail %] >+ [% FOREACH operation IN report.operations %] >+ [% IF operation.status == 'error' %] >+ <div class="text-danger"> <i class="fa-solid fa-circle-xmark"></i> [% PROCESS operation_description %] failed. </div> >+ [% ELSE %] >+ <div class="text-success"> <i class="fa-solid fa-circle-check"></i> [% PROCESS operation_description %] passed. </div> >+ [% END %] >+ [% END %] >+ [% IF job.status == 'cancelled' %] >+ <span>The connection test was cancelled before it finished.</span> >+ [% END %] >+[% END %] >+ >+[% BLOCK js %] >+[% END %] >diff --git a/koha-tmpl/intranet-tmpl/prog/en/modules/admin/background_jobs.tt b/koha-tmpl/intranet-tmpl/prog/en/modules/admin/background_jobs.tt >index 82fcc24e4b8..368dc7ebe1e 100644 >--- a/koha-tmpl/intranet-tmpl/prog/en/modules/admin/background_jobs.tt >+++ b/koha-tmpl/intranet-tmpl/prog/en/modules/admin/background_jobs.tt >@@ -227,6 +227,10 @@ > '_id': 'import_from_kbart_file', > '_str': _("Import titles from a KBART file") > }, >+ { >+ '_id': 'file_transport_test', >+ '_str': _("File transport connection test") >+ } > ]; > > function get_job_type (job_type) { >diff --git a/koha-tmpl/intranet-tmpl/prog/en/modules/admin/sftp_servers.tt b/koha-tmpl/intranet-tmpl/prog/en/modules/admin/sftp_servers.tt >index 2ebea0ec8d7..cc469457dc0 100644 >--- a/koha-tmpl/intranet-tmpl/prog/en/modules/admin/sftp_servers.tt >+++ b/koha-tmpl/intranet-tmpl/prog/en/modules/admin/sftp_servers.tt >@@ -3,37 +3,20 @@ > [% PROCESS 'i18n.inc' %] > [% SET footerjs = 1 %] > [% INCLUDE 'doc-head-open.inc' %] >-<title>[% FILTER collapse %] >- [% IF op == 'add_form' %] >- [% t("New FTP/SFTP server") | html %] › >- [% ELSIF op == 'edit_form' %] >- [% tx("Modify FTP/SFTP server '{sftp_server}'", { sftp_server = sftp_server.name }) | html %] › >- [% ELSIF op == 'test_form' %] >- [% tx("Test FTP/SFTP server '{sftp_server}'", { sftp_server = sftp_server.name }) | html %] › >- [% END %] >- [% t("FTP/SFTP Servers") | html %] › >- [% t("Administration") | html %] › >- [% t("Koha") | html %] >-[% END %]</title> >+<title >+ >[% FILTER collapse %] >+ [% IF op == 'add_form' %] >+ [% t("New FTP/SFTP server") | html %] >+ › >+ [% ELSIF op == 'edit_form' %] >+ [% tx("Modify FTP/SFTP server '{sftp_server}'", { sftp_server = sftp_server.name }) | html %] >+ › >+ [% END %] >+ [% t("FTP/SFTP Servers") | html %] >+ › [% t("Administration") | html %] › [% t("Koha") | html %] >+ [% END %]</title >+> > [% INCLUDE 'doc-head-close.inc' %] >-<style> >- #testOutput { >- font-size: 1.25rem; >- } >- >- #testOutput .pending-loading { >- font-size: 1.5rem; >- margin-left: 1.25rem; >- } >- >- #testOutput code { >- font-size: 87.5%; >- color: #e83e8c; >- background: transparent; >- word-break: break-word; >- } >-</style> >- > </head> > > <body id="admin_sftp_servers" class="admin"> >@@ -47,7 +30,7 @@ > <a href="/cgi-bin/koha/admin/admin-home.pl">Administration</a> > [% END %] > >- [% IF op == 'add_form' || op == 'edit_form' || op == 'test_form' %] >+ [% IF op == 'add_form' || op == 'edit_form' %] > [% WRAPPER breadcrumb_item %] > <a href="/cgi-bin/koha/admin/sftp_servers.pl">FTP/SFTP servers</a> > [% END %] >@@ -57,17 +40,10 @@ > [% WRAPPER breadcrumb_item bc_active= 1 %] > <span>New FTP/SFTP server</span> > [% END %] >- > [% ELSIF op == 'edit_form' %] > [% WRAPPER breadcrumb_item bc_active= 1 %] > [% tx("Modify FTP/SFTP server '{sftp_server}'", { sftp_server = sftp_server.name }) | html %] > [% END %] >- >- [% ELSIF op == 'test_form' %] >- [% WRAPPER breadcrumb_item bc_active= 1 %] >- [% tx("Test FTP/SFTP server '{sftp_server}'", { sftp_server = sftp_server.name }) | html %] >- [% END %] >- > [% ELSE %] > [% WRAPPER breadcrumb_item bc_active= 1 %] > <span>FTP/SFTP servers</span> >@@ -82,882 +58,740 @@ > <main> > [% INCLUDE 'messages.inc' %] > >-[% FOREACH m IN messages %] >- <div class="alert alert-[% m.type | html %]" id="sftp_action_result_dialog"> >- [% SWITCH m.code %] >- [% CASE 'error_on_insert' %] >- <span>An error occurred when adding the server. The passed ID already exists.</span> >- [% CASE 'error_on_update' %] >- <span>An error occurred trying to open the server for editing. The passed ID is invalid.</span> >- [% CASE 'error_on_edit' %] >- <span>An error occurred trying to open the server for editing. The passed ID is invalid.</span> >- [% CASE 'error_on_test' %] >- <span>An error occurred when connecting to this server. Please see the text below for more information.</span> >- [% CASE 'success_on_update' %] >- <span>Server updated successfully.</span> >- [% CASE 'success_on_insert' %] >- <span>Server added successfully.</span> >- [% CASE %] >- <span>[% m.code | html %]</span> >- [% END %] >- </div> >-[% END %] >- >- <div class="alert alert-info" id="sftp_delete_success" style="display: none;"></div> >- <div class="alert alert-warning" id="sftp_delete_error" style="display: none;"></div> >- >-[% IF op == 'add_form' %] >- <!-- Modal --> >- <div id="confirm_key_accept" class="modal" tabindex="-1" role="dialog" aria-labelledby="confirm_key_accept_submit" aria-hidden="true"> >- <div class="modal-dialog modal-lg"> >- <div class="modal-content modal-lg"> >- <div class="modal-header"> >- <h1 class="modal-title">Are you sure?</h1> >- <button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button> >- </div> >- <div class="modal-body"> >- <div id="modal_message" class="alert alert-warning">Because you are using the SFTP transport, please run a test of this connection to accept the server's host key.</div> >- <p>Before saving, please check the following details again to make sure you are certain they are correct. Sending or receiving data from an unknown source potentially puts your system at risk.</p> >- <table class="mx-4 mb-3"> >- <thead></thead> >- <tbody> >- <tr> >- <td><strong>Host</strong></td> >- <td id="modal_host"></td> >- </tr> >- <tr> >- <td><strong>Port</strong></td> >- <td id="modal_port"></td> >- </tr> >- <tr> >- <td><strong>Transport</strong></td> >- <td id="modal_transport"></td> >- </tr> >- <tr> >- <td><strong>Username</strong></td> >- <td id="modal_user_name"></td> >- </tr> >- <tr> >- <td><strong>Authentication mode</strong></td> >- <td id="modal_auth_mode"></td> >- </tr> >- </tbody> >- </table> >- <p>If you are ready to progress with these details, please click Save.</p> >- </div> >- <div class="modal-footer"> >- <button class="btn btn-default approve" type="submit"><i class="fa fa-check"></i> Save</button> >- <button class="btn btn-default deny cancel" type="button" data-bs-dismiss="modal"><i class="fa fa-times"></i> Cancel</button> >+ [% FOREACH m IN messages %] >+ <div class="alert alert-[% m.type | html %]" id="sftp_action_result_dialog"> >+ [% SWITCH m.code %] >+ [% CASE 'error_on_insert' %] >+ <span>An error occurred when adding the server. The passed ID already exists.</span> >+ [% CASE 'error_on_update' %] >+ <span>An error occurred trying to open the server for editing. The passed ID is invalid.</span> >+ [% CASE 'error_on_edit' %] >+ <span>An error occurred trying to open the server for editing. The passed ID is invalid.</span> >+ [% CASE 'success_on_update' %] >+ <span>Server updated successfully.</span> >+ [% CASE 'success_on_insert' %] >+ <span>Server added successfully.</span> >+ [% CASE %] >+ <span>[% m.code | html %]</span> >+ [% END %] > </div> >- </form> >- </div> >- </div> >- </div> >- <!-- END Modal --> >- >- <h1>New FTP/SFTP server</h1> >- >- <form action="/cgi-bin/koha/admin/sftp_servers.pl" id="add" name="add" class="validated" method="post"> >- [% INCLUDE 'csrf-token.inc' %] >- <input type="hidden" name="op" value="cud-add" /> >- <fieldset class="rows"> >- <ol> >- <li> >- <label for="sftp_name" class="required">Name: </label> >- <input type="text" name="sftp_name" id="sftp_name" size="60" class="required focus" required="required" /> >- <span class="required">Required</span> >- </li> >- </ol> >- </fieldset> >- >- <fieldset class="rows"> >- <ol> >- <li> >- <label for="sftp_host" class="required">Host: </label> >- <input type="text" value="localhost" name="sftp_host" id="sftp_host" size="60" class="required" /> >- <span class="required">Required</span> >- </li> >- <li> >- <label for="sftp_port" class="required">Port: </label> >- <input type="text" inputmode="numeric" pattern="[0-9]*" value="22" name="sftp_port" id="sftp_port" size="20" class="required" /> >- <span class="required">Required</span> >- </li> >- <li> >- <label for="sftp_transport" class="required">Transport: </label> >- <select name="sftp_transport" id="sftp_transport" class="required"> >- <option value="ftp">FTP</option> >- <option value="sftp" selected="selected">SFTP</option> >- </select> >- <span class="required">Required</span> >- </li> >- <li> >- <label for="sftp_passive">Passive mode: </label> >- <select name="sftp_passive" id="sftp_passive" disabled="disabled"> >- <option value="1" selected="selected">On (Recommended)</option> >- <option value="0">Off</option> >- </select> >- <span class="hint">Only applies to FTP connections</span> >- </li> >- <li> >- <label for="sftp_auth_mode">Authentication mode: </label> >- <select name="sftp_auth_mode" id="sftp_auth_mode"> >- <option value="password" selected="selected">Password-based</option> >- <option value="key_file">Key file-based</option> >- <option value="noauth">No authentication</option> >- </select> >- </li> >- <li> >- <label for="sftp_user_name" class="required">Username: </label> >- <input type="text" name="sftp_user_name" id="sftp_user_name" size="60" autocomplete="off" class="required" /> >- <span class="required">Required</span> >- </li> >- <li> >- <label for="sftp_password">Password: </label> >- <input type="password" name="sftp_password" id="sftp_password" size="60" autocomplete="off" /> >- </li> >- <li> >- <label for="sftp_key_file">Key file: </label> >- <textarea name="sftp_key_file" id="sftp_key_file" rows="10" cols="58"></textarea> >- <span class="hint">Only applies to SFTP connections</span> >- </li> >- <li> >- <label for="sftp_download_directory" >Remote download directory: </label> >- <input type="text" name="sftp_download_directory" id="sftp_download_directory" size="60" autocomplete="off" /><br /> >- <span class="hint">The path on the remote server where we will download from</span> >- </li> >- <li> >- <label for="sftp_upload_directory" >Remote upload directory: </label> >- <input type="text" name="sftp_upload_directory" id="sftp_upload_directory" size="60" autocomplete="off" /><br /> >- <span class="hint">The path on the remote server where we will upload to</span> >- </li> >- <input type="hidden" value="" name="sftp_status" id="sftp_status"> >- <li> >- <label for="sftp_debug_mode">Debug mode: </label> >- <select name="sftp_debug_mode" id="sftp_debug_mode"> >- <option value="1">Enabled</option> >- <option value="0" selected="selected">Disabled</option> >- </select> >- <span class="hint">Enables additional debug output in the logs</span> >- </li> >- </ol> >- </fieldset> >- <fieldset class="action"> >- <a id="confirm_key_accept_submit" data-bs-target="#confirm_key_accept" class="btn btn-primary" data-bs-toggle="modal">Submit</a> >- <a class="cancel" href="/cgi-bin/koha/admin/sftp_servers.pl">Cancel</a> >- </fieldset> >- </form> >-[% END %] >- >-[% IF op == 'edit_form' && !messages %] >- <!-- Modal --> >- <div id="confirm_key_accept" class="modal" tabindex="-1" role="dialog" aria-labelledby="confirm_key_accept_submit" aria-hidden="true"> >- <div class="modal-dialog modal-lg"> >- <div class="modal-content modal-lg"> >- <div class="modal-header"> >- <h1 class="modal-title">Are you sure?</h1> >- <button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button> >+ [% END %] >+ >+ <div class="alert alert-info" id="sftp_delete_success" style="display: none;"></div> >+ <div class="alert alert-warning" id="sftp_delete_error" style="display: none;"></div> >+ >+ [% IF op == 'add_form' %] >+ <!-- Modal --> >+ <div id="confirm_key_accept" class="modal" tabindex="-1" role="dialog" aria-labelledby="confirm_key_accept_submit" aria-hidden="true"> >+ <div class="modal-dialog modal-lg"> >+ <div class="modal-content modal-lg"> >+ <div class="modal-header"> >+ <h1 class="modal-title">Are you sure?</h1> >+ <button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button> >+ </div> >+ <div class="modal-body"> >+ <div id="modal_message" class="alert alert-warning">Because you are using the SFTP transport, please run a test of this connection to accept the server's host key.</div> >+ <p>Before saving, please check the following details again to make sure you are certain they are correct. Sending or receiving data from an unknown source potentially puts your system at risk.</p> >+ <table class="mx-4 mb-3"> >+ <thead></thead> >+ <tbody> >+ <tr> >+ <td><strong>Host</strong></td> >+ <td id="modal_host"></td> >+ </tr> >+ <tr> >+ <td><strong>Port</strong></td> >+ <td id="modal_port"></td> >+ </tr> >+ <tr> >+ <td><strong>Transport</strong></td> >+ <td id="modal_transport"></td> >+ </tr> >+ <tr> >+ <td><strong>Username</strong></td> >+ <td id="modal_user_name"></td> >+ </tr> >+ <tr> >+ <td><strong>Authentication mode</strong></td> >+ <td id="modal_auth_mode"></td> >+ </tr> >+ </tbody> >+ </table> >+ <p>If you are ready to progress with these details, please click Save.</p> >+ </div> >+ <div class="modal-footer"> >+ <button class="btn btn-default approve" type="submit"><i class="fa fa-check"></i> Save</button> >+ <button class="btn btn-default deny cancel" type="button" data-bs-dismiss="modal"><i class="fa fa-times"></i> Cancel</button> >+ </div> >+ </div> >+ </div> > </div> >- <div class="modal-body"> >- <div id="modal_message" class="alert alert-warning">Because you are using the SFTP transport, please run a test of this connection to accept the server's host key.</div> >- <p>Before saving, please check the following details again to make sure you are certain they are correct. Sending or receiving data from an unknown source potentially puts your system at risk.</p> >- <table class="mx-4 mb-3"> >- <thead></thead> >- <tbody> >- <tr> >- <td><strong>Host</strong></td> >- <td id="modal_host"></td> >- </tr> >- <tr> >- <td><strong>Port</strong></td> >- <td id="modal_port"></td> >- </tr> >- <tr> >- <td><strong>Transport</strong></td> >- <td id="modal_transport"></td> >- </tr> >- <tr> >- <td><strong>Username</strong></td> >- <td id="modal_user_name"></td> >- </tr> >- <tr> >- <td><strong>Authentication mode</strong></td> >- <td id="modal_auth_mode"></td> >- </tr> >- </tbody> >- </table> >- <p>If you are ready to progress with these details, please click Save.</p> >+ <!-- END Modal --> >+ >+ <h1>New FTP/SFTP server</h1> >+ >+ <form action="/cgi-bin/koha/admin/sftp_servers.pl" id="add" name="add" class="validated" method="post"> >+ [% INCLUDE 'csrf-token.inc' %] >+ <input type="hidden" name="op" value="cud-add" /> >+ <fieldset class="rows"> >+ <ol> >+ <li> >+ <label for="sftp_name" class="required">Name: </label> >+ <input type="text" name="sftp_name" id="sftp_name" size="60" class="required focus" required="required" /> >+ <span class="required">Required</span> >+ </li> >+ </ol> >+ </fieldset> >+ >+ <fieldset class="rows"> >+ <ol> >+ <li> >+ <label for="sftp_transport" class="required">Transport: </label> >+ <select name="sftp_transport" id="sftp_transport" class="required"> >+ <option value="ftp">FTP</option> >+ <option value="sftp" selected="selected">SFTP</option> >+ </select> >+ <span class="required">Required</span> >+ </li> >+ <li> >+ <label for="sftp_host" class="required">Host: </label> >+ <input type="text" value="localhost" name="sftp_host" id="sftp_host" size="60" class="required" /> >+ <span class="required">Required</span> >+ </li> >+ <li> >+ <label for="sftp_port" class="required">Port: </label> >+ <input type="text" inputmode="numeric" pattern="[0-9]*" value="22" name="sftp_port" id="sftp_port" size="20" class="required" /> >+ <span class="required">Required</span> >+ </li> >+ <li> >+ <label for="sftp_transport" class="required">Transport: </label> >+ <select name="sftp_transport" id="sftp_transport" class="required"> >+ <option value="ftp">FTP</option> >+ <option value="sftp" selected="selected">SFTP</option> >+ </select> >+ <span class="required">Required</span> >+ </li> >+ <li> >+ <label for="sftp_passive">Passive mode: </label> >+ <select name="sftp_passive" id="sftp_passive" disabled="disabled"> >+ <option value="1" selected="selected">On (Recommended)</option> >+ <option value="0">Off</option> >+ </select> >+ <span class="hint">Only applies to FTP connections</span> >+ </li> >+ <li> >+ <label for="sftp_auth_mode">Authentication mode: </label> >+ <select name="sftp_auth_mode" id="sftp_auth_mode"> >+ <option value="password" selected="selected">Password-based</option> >+ <option value="key_file">Key file-based</option> >+ <option value="noauth">No authentication</option> >+ </select> >+ </li> >+ <li> >+ <label for="sftp_user_name" class="required">Username: </label> >+ <input type="text" name="sftp_user_name" id="sftp_user_name" size="60" autocomplete="off" class="required" /> >+ <span class="required">Required</span> >+ </li> >+ <li> >+ <label for="sftp_password">Password: </label> >+ <input type="password" name="sftp_password" id="sftp_password" size="60" autocomplete="off" /> >+ </li> >+ <li> >+ <label for="sftp_key_file">Key file: </label> >+ <textarea name="sftp_key_file" id="sftp_key_file" rows="10" cols="58"></textarea> >+ <span class="hint">Only applies to SFTP connections</span> >+ </li> >+ <li> >+ <label for="sftp_download_directory">Remote download directory: </label> >+ <input type="text" name="sftp_download_directory" id="sftp_download_directory" size="60" autocomplete="off" /><br /> >+ <span class="hint">The path on the remote server where we will download from</span> >+ </li> >+ <li> >+ <label for="sftp_upload_directory">Remote upload directory: </label> >+ <input type="text" name="sftp_upload_directory" id="sftp_upload_directory" size="60" autocomplete="off" /><br /> >+ <span class="hint">The path on the remote server where we will upload to</span> >+ </li> >+ <input type="hidden" value="" name="sftp_status" id="sftp_status" /> >+ <li> >+ <label for="sftp_debug_mode">Debug mode: </label> >+ <select name="sftp_debug_mode" id="sftp_debug_mode"> >+ <option value="1">Enabled</option> >+ <option value="0" selected="selected">Disabled</option> >+ </select> >+ <span class="hint">Enables additional debug output in the logs</span> >+ </li> >+ </ol> >+ </fieldset> >+ <fieldset class="action"> >+ <a id="confirm_key_accept_submit" data-bs-target="#confirm_key_accept" class="btn btn-primary" data-bs-toggle="modal">Submit</a> >+ <a class="cancel" href="/cgi-bin/koha/admin/sftp_servers.pl">Cancel</a> >+ </fieldset> >+ </form> >+ [% END %] >+ >+ [% IF op == 'edit_form' && !messages %] >+ <!-- Modal --> >+ <div id="confirm_key_accept" class="modal" tabindex="-1" role="dialog" aria-labelledby="confirm_key_accept_submit" aria-hidden="true"> >+ <div class="modal-dialog modal-lg"> >+ <div class="modal-content modal-lg"> >+ <div class="modal-header"> >+ <h1 class="modal-title">Are you sure?</h1> >+ <button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button> >+ </div> >+ <div class="modal-body"> >+ <div id="modal_message" class="alert alert-warning">Because you are using the SFTP transport, please run a test of this connection to accept the server's host key.</div> >+ <p>Before saving, please check the following details again to make sure you are certain they are correct. Sending or receiving data from an unknown source potentially puts your system at risk.</p> >+ <table class="mx-4 mb-3"> >+ <thead></thead> >+ <tbody> >+ <tr> >+ <td><strong>Host</strong></td> >+ <td id="modal_host"></td> >+ </tr> >+ <tr> >+ <td><strong>Port</strong></td> >+ <td id="modal_port"></td> >+ </tr> >+ <tr> >+ <td><strong>Transport</strong></td> >+ <td id="modal_transport"></td> >+ </tr> >+ <tr> >+ <td><strong>Username</strong></td> >+ <td id="modal_user_name"></td> >+ </tr> >+ <tr> >+ <td><strong>Authentication mode</strong></td> >+ <td id="modal_auth_mode"></td> >+ </tr> >+ </tbody> >+ </table> >+ <p>If you are ready to progress with these details, please click Save.</p> >+ </div> >+ <div class="modal-footer"> >+ <button class="btn btn-default approve" type="submit"><i class="fa fa-check"></i> Save</button> >+ <button class="btn btn-default deny cancel" type="button" data-bs-dismiss="modal"><i class="fa fa-times"></i> Cancel</button> >+ </div> >+ </div> >+ </div> > </div> >- <div class="modal-footer"> >- <button class="btn btn-default approve" type="submit"><i class="fa fa-check"></i> Save</button> >- <button class="btn btn-default deny cancel" type="button" data-bs-dismiss="modal"><i class="fa fa-times"></i> Cancel</button> >+ <!-- END Modal --> >+ >+ <h1>[% tx("Modify FTP/SFTP server '{sftp_server}'", { sftp_server = sftp_server.name }) | html %]</h1> >+ >+ <form action="/cgi-bin/koha/admin/sftp_servers.pl" id="edit_save" name="edit_save" class="validated" method="post"> >+ [% INCLUDE 'csrf-token.inc' %] >+ <input type="hidden" name="op" value="cud-edit_save" /> >+ <input type="hidden" name="sftp_server_id" value="[%- sftp_server.id | html -%]" /> >+ <fieldset class="rows"> >+ <ol> >+ <li> >+ <label for="sftp_name" class="required">Name: </label> >+ <input type="text" value="[% sftp_server.name | html %]" name="sftp_name" id="sftp_name" size="60" class="required focus" required="required" /> >+ <span class="required">Required</span> >+ </li> >+ </ol> >+ </fieldset> >+ >+ <fieldset class="rows"> >+ <ol> >+ <li> >+ <label for="sftp_host" class="required">Host: </label> >+ <input type="text" value="[% sftp_server.host | html %]" name="sftp_host" id="sftp_host" size="60" class="required" /> >+ <span class="required">Required</span> >+ </li> >+ <li> >+ <label for="sftp_port" class="required">Port: </label> >+ <input type="text" inputmode="numeric" pattern="[0-9]*" value="[% sftp_server.port | html %]" name="sftp_port" id="sftp_port" size="20" class="required" /> >+ <span class="required">Required</span> >+ </li> >+ <li> >+ <label for="sftp_transport" class="required">Transport: </label> >+ <select name="sftp_transport" id="sftp_transport" class="required"> >+ [% IF sftp_server.transport == 'ftp' %] >+ <option value="ftp" selected="selected">FTP</option> >+ [% ELSE %] >+ <option value="ftp">FTP</option> >+ [% END %] >+ [% IF sftp_server.transport == 'sftp' %] >+ <option value="sftp" selected="selected">SFTP</option> >+ [% ELSE %] >+ <option value="sftp">SFTP</option> >+ [% END %] >+ </select> >+ <span class="required">Required</span> >+ </li> >+ <li> >+ <label for="sftp_passive">Passive mode: </label> >+ <select name="sftp_passive" id="sftp_passive" disabled="disabled"> >+ [% IF sftp_server.passive == 1 %] >+ <option value="1" selected="selected">Enabled (Recommended)</option> >+ [% ELSE %] >+ <option value="1">Enabled (Recommended)</option> >+ [% END %] >+ [% IF sftp_server.passive == 0 %] >+ <option value="0" selected="selected">Disabled</option> >+ [% ELSE %] >+ <option value="0">Disabled</option> >+ [% END %] >+ </select> >+ <span class="hint">Only applies to FTP connections</span> >+ </li> >+ <li> >+ <label for="sftp_auth_mode">Authentication mode: </label> >+ <select name="sftp_auth_mode" id="sftp_auth_mode"> >+ [% IF sftp_server.auth_mode == 'password' %] >+ <option value="password" selected="selected">Password-based</option> >+ [% ELSE %] >+ <option value="password">Password-based</option> >+ [% END %] >+ [% IF sftp_server.auth_mode == 'key_file' %] >+ <option value="key_file" selected="selected">Key file-based</option> >+ [% ELSE %] >+ <option value="key_file">Key file-based</option> >+ [% END %] >+ [% IF sftp_server.auth_mode == 'noauth' %] >+ <option value="noauth" selected="selected">No authentication</option> >+ [% ELSE %] >+ <option value="noauth">No authentication</option> >+ [% END %] >+ </select> >+ </li> >+ <li> >+ <label for="sftp_user_name" class="required">Username: </label> >+ <input type="text" value="[% sftp_server.user_name | html %]" name="sftp_user_name" id="sftp_user_name" size="60" autocomplete="off" class="required" /> >+ <span class="required">Required</span> >+ </li> >+ <li> >+ <label for="sftp_password">Password: </label> >+ <input type="password" value="[% sftp_server_plain_text_password | html %]" name="sftp_password" id="sftp_password" size="60" autocomplete="off" /> >+ </li> >+ <li> >+ <label for="sftp_key_file">Key file path: </label> >+ <textarea name="sftp_key_file" id="sftp_key_file" rows="10" cols="58">[% sftp_server_plain_text_key | html %]</textarea> >+ <span class="hint">Only applies to SFTP connections</span> >+ </li> >+ <li> >+ <label for="sftp_download_directory">Remote download directory: </label> >+ <input type="text" value="[% sftp_server.download_directory | html %]" name="sftp_download_directory" id="sftp_download_directory" size="60" autocomplete="off" /><br /> >+ <span class="hint">The path on the remote server where we will download from</span> >+ </li> >+ <li> >+ <label for="sftp_upload_directory">Remote upload directory: </label> >+ <input type="text" value="[% sftp_server.upload_directory | html %]" name="sftp_upload_directory" id="sftp_upload_directory" size="60" autocomplete="off" /><br /> >+ <span class="hint">The path on the remote server where we will upload to</span> >+ </li> >+ <input type="hidden" value="" name="sftp_status" id="sftp_status" /> >+ <li> >+ <label for="sftp_debug_mode">Debug mode: </label> >+ <select name="sftp_debug_mode" id="sftp_debug_mode"> >+ [% IF sftp_server.debug == 1 %] >+ <option value="1" selected="selected">Enabled</option> >+ [% ELSE %] >+ <option value="1">Enabled</option> >+ [% END %] >+ [% IF sftp_server.debug == 0 %] >+ <option value="0" selected="selected">Disabled</option> >+ [% ELSE %] >+ <option value="0">Disabled</option> >+ [% END %] >+ </select> >+ <span class="hint">Enables additional debug output in the logs</span> >+ </li> >+ </ol> >+ </fieldset> >+ <fieldset class="action"> >+ <a id="confirm_key_accept_submit" data-bs-target="#confirm_key_accept" class="btn btn-primary" data-bs-toggle="modal">Submit</a> >+ <a class="cancel" href="/cgi-bin/koha/admin/sftp_servers.pl">Cancel</a> >+ </fieldset> >+ </form> >+ [% END %] >+ >+ [% IF op == 'list' %] >+ <div id="toolbar" class="btn-toolbar"> >+ <a class="btn btn-default" id="new_sftp_server" href="/cgi-bin/koha/admin/sftp_servers.pl?op=add_form"><i class="fa fa-plus"></i> New FTP/SFTP server</a> > </div> >- </form> >- </div> >- </div> >- </div> >- <!-- END Modal --> >- >- <h1>[% tx("Modify FTP/SFTP server '{sftp_server}'", { sftp_server = sftp_server.name }) | html %]</h1> >- >- <form action="/cgi-bin/koha/admin/sftp_servers.pl" id="edit_save" name="edit_save" class="validated" method="post"> >- [% INCLUDE 'csrf-token.inc' %] >- <input type="hidden" name="op" value="cud-edit_save" /> >- <input type="hidden" name="sftp_server_id" value="[%- sftp_server.id | html -%]" /> >- <fieldset class="rows"> >- <ol> >- <li> >- <label for="sftp_name" class="required">Name: </label> >- <input type="text" value="[% sftp_server.name | html %]" name="sftp_name" id="sftp_name" size="60" class="required focus" required="required" /> >- <span class="required">Required</span> >- </li> >- </ol> >- </fieldset> >- >- <fieldset class="rows"> >- <ol> >- <li> >- <label for="sftp_host" class="required">Host: </label> >- <input type="text" value="[% sftp_server.host | html %]" name="sftp_host" id="sftp_host" size="60" class="required" /> >- <span class="required">Required</span> >- </li> >- <li> >- <label for="sftp_port" class="required">Port: </label> >- <input type="text" inputmode="numeric" pattern="[0-9]*" value="[% sftp_server.port | html %]" name="sftp_port" id="sftp_port" size="20" class="required"/> >- <span class="required">Required</span> >- </li> >- <li> >- <label for="sftp_transport" class="required">Transport: </label> >- <select name="sftp_transport" id="sftp_transport" class="required"> >- [% IF sftp_server.transport == 'ftp' %] >- <option value="ftp" selected="selected">FTP</option> >- [% ELSE %] >- <option value="ftp">FTP</option> >- [% END %] >- [% IF sftp_server.transport == 'sftp' %] >- <option value="sftp" selected="selected">SFTP</option> >- [% ELSE %] >- <option value="sftp">SFTP</option> >- [% END %] >- </select> >- <span class="required">Required</span> >- </li> >- <li> >- <label for="sftp_passive">Passive mode: </label> >- <select name="sftp_passive" id="sftp_passive" disabled="disabled"> >- [% IF sftp_server.passive == 1 %] >- <option value="1" selected="selected">Enabled (Recommended)</option> >- [% ELSE %] >- <option value="1">Enabled (Recommended)</option> >- [% END %] >- [% IF sftp_server.passive == 0 %] >- <option value="0" selected="selected">Disabled</option> >- [% ELSE %] >- <option value="0">Disabled</option> >- [% END %] >- </select> >- <span class="hint">Only applies to FTP connections</span> >- </li> >- <li> >- <label for="sftp_auth_mode">Authentication mode: </label> >- <select name="sftp_auth_mode" id="sftp_auth_mode"> >- [% IF sftp_server.auth_mode == 'password' %] >- <option value="password" selected="selected">Password-based</option> >- [% ELSE %] >- <option value="password">Password-based</option> >- [% END %] >- [% IF sftp_server.auth_mode == 'key_file' %] >- <option value="key_file" selected="selected">Key file-based</option> >- [% ELSE %] >- <option value="key_file">Key file-based</option> >- [% END %] >- [% IF sftp_server.auth_mode == 'noauth' %] >- <option value="noauth" selected="selected">No authentication</option> >- [% ELSE %] >- <option value="noauth">No authentication</option> >- [% END %] >- </select> >- </li> >- <li> >- <label for="sftp_user_name" class="required">Username: </label> >- <input type="text" value="[% sftp_server.user_name | html %]" name="sftp_user_name" id="sftp_user_name" size="60" autocomplete="off" class="required" /> >- <span class="required">Required</span> >- </li> >- <li> >- <label for="sftp_password">Password: </label> >- <input type="password" value="[% sftp_server_plain_text_password | html %]" name="sftp_password" id="sftp_password" size="60" autocomplete="off" /> >- </li> >- <li> >- <label for="sftp_key_file">Key file path: </label> >- <textarea name="sftp_key_file" id="sftp_key_file" rows="10" cols="58">[% sftp_server_plain_text_key | html %]</textarea> >- <span class="hint">Only applies to SFTP connections</span> >- </li> >- <li> >- <label for="sftp_download_directory" >Remote download directory: </label> >- <input type="text" value="[% sftp_server.download_directory | html %]" name="sftp_download_directory" id="sftp_download_directory" size="60" autocomplete="off" /><br /> >- <span class="hint">The path on the remote server where we will download from</span> >- </li> >- <li> >- <label for="sftp_upload_directory" >Remote upload directory: </label> >- <input type="text" value="[% sftp_server.upload_directory | html %]" name="sftp_upload_directory" id="sftp_upload_directory" size="60" autocomplete="off" /><br /> >- <span class="hint">The path on the remote server where we will upload to</span> >- </li> >- <input type="hidden" value="" name="sftp_status" id="sftp_status"> >- <li> >- <label for="sftp_debug_mode">Debug mode: </label> >- <select name="sftp_debug_mode" id="sftp_debug_mode"> >- [% IF sftp_server.debug == 1 %] >- <option value="1" selected="selected">Enabled</option> >- [% ELSE %] >- <option value="1">Enabled</option> >- [% END %] >- [% IF sftp_server.debug == 0 %] >- <option value="0" selected="selected">Disabled</option> >- [% ELSE %] >- <option value="0">Disabled</option> >- [% END %] >- </select> >- <span class="hint">Enables additional debug output in the logs</span> >- </li> >- </ol> >- </fieldset> >- <fieldset class="action"> >- <a id="confirm_key_accept_submit" data-bs-target="#confirm_key_accept" class="btn btn-primary" data-bs-toggle="modal">Submit</a> >- <a class="cancel" href="/cgi-bin/koha/admin/sftp_servers.pl">Cancel</a> >- </fieldset> >- </form> >-[% END %] > >-[% IF op == 'test_form' %] >+ <h1>FTP/SFTP servers</h1> > >- <h1>[% tx("Test FTP/SFTP server '{sftp_server}'", { sftp_server = sftp_server.name }) | html %]</h1> >- [% IF sftp_server.id %] >- <div class="page-section"> >- [% IF sftp_server.transport == 'sftp' %] >- <div class="alert alert-warning"> >- <strong>For your information:</strong> As the transport in use for this server is SFTP, please be aware that running a test attempt will also accept the current host key fingerprint of the destination server. If you have doubts about the authenticity of this server, remove its host key from your authorized_keys file immediately, and contact your System Administrator. >- </div> >- [% END %] >- <div class="row"> >- <div class="col-12 col-lg-6 order-1 order-lg-0"> >- <h3>Test results</h3> >- <div id="testOutput"> >- <!-- tests will appear here --> >- </div> >- </div> >- <div class="col-12 col-lg-6 order-0 order-lg-1"> >- <h3>Test details</h3> >- <p>Connection details are as follows:</p> >- <table class="mx-4 mb-3"> >- <thead></thead> >- <tbody> >- <tr> >- <td><strong>Host</strong></td> >- <td>[% sftp_server.host | html %]</td> >- </tr> >- <tr> >- <td><strong>Port</strong></td> >- <td>[% sftp_server.port | html %]</td> >- </tr> >- <tr> >- <td><strong>Transport</strong></td> >- <td>[% sftp_server.transport FILTER upper | html %]</td> >- </tr> >- <tr> >- <td><strong>Username</strong></td> >- <td>[% sftp_server.user_name | html %]</td> >- </tr> >- <tr> >- <td><strong>Authentication mode</strong></td> >- <td> >- [% IF sftp_server.auth_mode == 'password' %] >- Password-based >- [% ELSE %] >- Key file-based >- [% END %] >- </td> >- </tr> >- <tr> >- <td><strong>Status</strong></td> >- <td> >- [% SWITCH sftp_server.status %] >- [% CASE 'tests_ok' %] >- Tests passing >- [% CASE 'tests_failed' %] >- Tests failing >- [% CASE %] >- <em>Never used</em> >- [% END %] >- </td> >- </tr> >- </tbody> >- </table> >- </div> >- </div> >- </div> >- <fieldset class="action"> >- <a href="/cgi-bin/koha/admin/sftp_servers.pl?op=edit_form&sftp_server_id=[% sftp_server.id | uri %]" class="btn btn-primary"><i class="fa-solid fa-pencil" aria-hidden="true"></i> Edit</a> >- <a href="/cgi-bin/koha/admin/sftp_servers.pl?op=test_form&sftp_server_id=[% sftp_server.id | uri %]" class="cancel">Reset</a> >- </fieldset> >- [% ELSE %] >- <div class="page-section"> >- <h3>Oops – Not Found</h3> >- <p>An FTP/SFTP server with that ID was not found. Please go back and try again.</p> >- </div> >- [% END %] >-[% END %] >- >-[% IF op == 'list' %] >- >- <div id="toolbar" class="btn-toolbar"> >- <a class="btn btn-default" id="new_sftp_server" href="/cgi-bin/koha/admin/sftp_servers.pl?op=add_form"><i class="fa fa-plus"></i> New FTP/SFTP server</a> >- </div> >- >- <h1>FTP/SFTP servers</h1> >- >- [% IF servers_count < 1 %] >- <div class="alert alert-info" id="dno_servers_message"> >- <p> >- <em>There are no FTP/SFTP servers defined.</em><br /> >- To create one, use the <strong>new FTP/SFTP server</strong> button above. >- </p> >- </div> >- [% ELSE %] >- <div class="page-section"> >- <table id="sftp_servers"> >- <thead> >- <tr> >- <th>Name</th> >- <th>Host</th> >- <th>Port</th> >- <th>Transport</th> >- <th>Authentication mode</th> >- <th>Username</th> >- <th>Download directory</th> >- <th>Upload directory</th> >- <th>Status</th> >- <th>Debug</th> >- <th data-class-name="actions noExport">Actions</th> >- </tr> >- </thead> >- </table> >- </div> <!-- /.page-section --> >- [% END %] >-[% END %] >- >- <div id="delete_confirm_modal" class="modal" tabindex="-1" role="dialog" aria-labelledby="delete_confirm_modal_label" aria-hidden="true"> >- <div class="modal-dialog"> >- <div class="modal-content"> >- <div class="modal-header"> >- <h1 class="modal-title" id="delete_confirm_modal_label">Delete server</h1> >- <button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button> >+ [% IF servers_count < 1 %] >+ <div class="alert alert-info" id="dno_servers_message"> >+ <p> >+ <em>There are no FTP/SFTP servers defined.</em><br /> >+ To create one, use the <strong>new FTP/SFTP server</strong> button above. >+ </p> > </div> >- <div class="modal-body"> >- <div id="delete_confirm_dialog"></div> >+ [% ELSE %] >+ <div class="page-section"> >+ <table id="sftp_servers"> >+ <thead> >+ <tr> >+ <th>Name</th> >+ <th>Host</th> >+ <th>Port</th> >+ <th>Transport</th> >+ <th>Authentication mode</th> >+ <th>Username</th> >+ <th>Download directory</th> >+ <th>Upload directory</th> >+ <th>Status</th> >+ <th>Debug</th> >+ <th data-class-name="actions noExport">Actions</th> >+ </tr> >+ </thead> >+ </table> > </div> >- <div class="modal-footer"> >- <button type="button" class="btn btn-danger" id="delete_confirm_modal_button" data-bs-toggle="modal">Delete</button> >- <button type="button" class="btn btn-default" data-bs-dismiss="modal">Close</button> >+ <!-- /.page-section --> >+ [% END %] >+ [% END %] >+ >+ <div id="delete_confirm_modal" class="modal" tabindex="-1" role="dialog" aria-labelledby="delete_confirm_modal_label" aria-hidden="true"> >+ <div class="modal-dialog"> >+ <div class="modal-content"> >+ <div class="modal-header"> >+ <h1 class="modal-title" id="delete_confirm_modal_label">Delete server</h1> >+ <button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button> >+ </div> >+ <div class="modal-body"> >+ <div id="delete_confirm_dialog"></div> >+ </div> >+ <div class="modal-footer"> >+ <button type="button" class="btn btn-danger" id="delete_confirm_modal_button" data-bs-toggle="modal">Delete</button> >+ <button type="button" class="btn btn-default" data-bs-dismiss="modal">Close</button> >+ </div> > </div> >- </div> <!-- /.modal-content --> >- </div> <!-- /.modal-dialog --> >- </div> <!-- #delete_confirm_modal --> >- >+ <!-- /.modal-content --> >+ </div> >+ <!-- /.modal-dialog --> >+ </div> >+ <!-- #delete_confirm_modal --> > </main> >- </div> <!-- /.col-md-10.order-md-2 --> >+ </div> >+ <!-- /.col-md-10.order-md-2 --> > > <div class="col-md-2 order-sm-2 order-md-1"> >- <aside> >- [% INCLUDE 'admin-menu.inc' %] >- </aside> >- </div> <!-- /.col-md-2.order-md-1 --> >- </div> <!-- /.row --> >- >- >-[% MACRO jsinclude BLOCK %] >- [% Asset.js("js/admin-menu.js") | $raw %] >- [% INCLUDE 'datatables.inc' %] >- <script> >- $(document).ready(function() { >- >- var sftp_servers_url = '/api/v1/config/sftp_servers'; >- window.sftp_servers = $("#sftp_servers").kohaTable({ >- "ajax": { >- "url": sftp_servers_url >- }, >- "language": { >- "emptyTable": "<div class=\"alert alert-info\">"+_("There are no FTP/SFTP servers defined.")+"</div>" >- }, >- "columnDefs": [ { >- "targets": [0,1], >- "render": function(data, type, row, meta) { >- if (type == "display") { >- if(data != null) { >- return data.escapeHtml(); >- } else { >- return "Default"; >- } >- } >- return data; >- } >- } ], >- "columns": [ >- { >- "data": "name", >- "searchable": true, >- "orderable": true >- }, >- { >- "data": "host", >- "searchable": true, >- "orderable": true >- }, >- { >- "data": "port", >- "searchable": true, >- "orderable": false >+ <aside> [% INCLUDE 'admin-menu.inc' %] </aside> >+ </div> >+ <!-- /.col-md-2.order-md-1 --> >+ </div> >+ <!-- /.row --> >+ >+ [% MACRO jsinclude BLOCK %] >+ [% Asset.js("js/admin-menu.js") | $raw %] >+ [% Asset.js("js/transport_status.js") | $raw %] >+ [% INCLUDE 'datatables.inc' %] >+ <script> >+ $(document).ready(function() { >+ >+ var sftp_servers_url = '/api/v1/config/sftp_servers'; >+ window.sftp_servers = $("#sftp_servers").kohaTable({ >+ "ajax": { >+ "url": sftp_servers_url > }, >- { >- "data": "transport", >- "render": function(data, type, row, meta) { >- return data.toUpperCase(); >- }, >- "searchable": true, >- "orderable": false >+ "language": { >+ "emptyTable": "<div class=\"alert alert-info\">"+_("There are no FTP/SFTP servers defined.")+"</div>" > }, >- { >- "data": "auth_mode", >+ "columnDefs": [ { >+ "targets": [0,1], > "render": function(data, type, row, meta) { >- if(data == "password") { >- return _("Password-based"); >- } else if(data == "key_file") { >- return _("Key file-based"); >- } else { >- return _("No authentication"); >+ if (type == "display") { >+ if(data != null) { >+ return data.escapeHtml(); >+ } else { >+ return "Default"; >+ } > } >+ return data; >+ } >+ } ], >+ "columns": [ >+ { >+ "data": "name", >+ "searchable": true, >+ "orderable": true > }, >- "searchable": false, >- "orderable": false >- }, >- { >- "data": "user_name", >- "searchable": false, >- "orderable": false >- }, >- { >- "data": "download_directory", >- "render": function(data, type, row, meta) { >- if(data) { >- return data; >- } else { >- return "<em>" + _("Not specified") + "</em>"; >- } >+ { >+ "data": "host", >+ "searchable": true, >+ "orderable": true > }, >- "searchable": false, >- "orderable": false >- }, >- { >- "data": "upload_directory", >- "render": function(data, type, row, meta) { >- if(data) { >- return data; >- } else { >- return "<em>" + _("Not specified") + "</em>"; >- } >+ { >+ "data": "port", >+ "searchable": true, >+ "orderable": false > }, >- "searchable": false, >- "orderable": false >- }, >- { >- "data": "status", >- "render": function(data, type, row, meta) { >- if (data == "tests_ok") { >- return _("Tests passing"); >- } else if (data == "tests_failed") { >- return _("Tests failing"); >- } else { >- return "<em>" + _("Never used") + "</em>"; >- } >+ { >+ "data": "transport", >+ "render": function(data, type, row, meta) { >+ return data.toUpperCase(); >+ }, >+ "searchable": true, >+ "orderable": false > }, >- "searchable": false, >- "orderable": false >- }, >- { >- "data": "debug", >- "render": function(data, type, row, meta) { >- if(data == true) { >- return "[% tp("Active", "On") | html %]"; >- } >- else { >- return _("Off"); >- } >+ { >+ "data": "auth_mode", >+ "render": function(data, type, row, meta) { >+ if(data == "password") { >+ return _("Password-based"); >+ } else if(data == "key_file") { >+ return _("Key file-based"); >+ } else { >+ return _("No authentication"); >+ } >+ }, >+ "searchable": false, >+ "orderable": false > }, >- "searchable": false, >- "orderable": false >- }, >- { >- "data": function(row, type, val, meta) { >- var result = '<a class="btn btn-default btn-xs" role="button" href="/cgi-bin/koha/admin/sftp_servers.pl?op=test_form&sftp_server_id='+ encodeURIComponent(row.sftp_server_id) +'"><i class="fa-solid fa-vial" aria-hidden="true"></i> '+_("Test")+'</a>'+"\n"; >- result += '<a class="btn btn-default btn-xs" role="button" href="/cgi-bin/koha/admin/sftp_servers.pl?op=edit_form&sftp_server_id='+ encodeURIComponent(row.sftp_server_id) +'"><i class="fa-solid fa-pencil" aria-hidden="true"></i> '+_("Edit")+'</a>'+"\n"; >- result += '<a class="btn btn-default btn-xs delete_server" role="button" href="#" data-bs-toggle="modal" data-bs-target="#delete_confirm_modal" data-sftp-server-id="'+ encodeURIComponent(row.sftp_server_id) +'" data-sftp-server-name="'+ encodeURIComponent(row.name.escapeHtml()) +'"><i class="fa fa-trash-can" aria-hidden="true"></i> '+_("Delete")+'</a>'; >- return result; >+ { >+ "data": "user_name", >+ "searchable": false, >+ "orderable": false > }, >- "searchable": false, >- "orderable": false >- } >- ], >- createdRow: function(row, data, dataIndex) { >- if(data.is_default) { >- $(row).addClass('default warn'); >- } >- if(data.debug) { >- $(row).addClass('debug'); >- } >- }, >- }); >- >- $('#sftp_servers').on("click", '.delete_server', function() { >- var sftp_server_id = $(this).data('sftp-server-id'); >- var sftp_server_name = decodeURIComponent($(this).data('sftp-server-name')); >- >- $("#delete_confirm_dialog").html( >- _("You are about to delete the '%s' FTP/SFTP server.").format(sftp_server_name) >- ); >- $("#delete_confirm_modal_button").data('sftp-server-id', sftp_server_id); >- $("#delete_confirm_modal_button").data('sftp-server-name', sftp_server_name); >- }); >+ { >+ "data": "download_directory", >+ "render": function(data, type, row, meta) { >+ if(data) { >+ return data; >+ } else { >+ return "<em>" + _("Not specified") + "</em>"; >+ } >+ }, >+ "searchable": false, >+ "orderable": false >+ }, >+ { >+ "data": "upload_directory", >+ "render": function(data, type, row, meta) { >+ if(data) { >+ return data; >+ } else { >+ return "<em>" + _("Not specified") + "</em>"; >+ } >+ }, >+ "searchable": false, >+ "orderable": false >+ }, >+ { >+ "data": "status", >+ "render": function(data, type, row, meta) { >+ let render = ''; >+ if (data) { >+ if (data.status == "ok") { >+ render += '<i class="text-success fa-solid fa-circle-check"></i> '; >+ render += '<span class="text-success">'; >+ render += _("Tests passing"); >+ render += '</span>' >+ } else if (data.status == "errors") { >+ data.operations.forEach(operation => { >+ render += "<div>"; >+ if ( operation.status == "error" ) { >+ render += '<i class="text-danger fa-solid fa-circle-xmark"></i> '; >+ render += '<span class="text-danger">'; >+ render += operationLabels[operation.code] || operation.code; >+ render += ' ' + _("failed"); >+ render += '</span>'; >+ } else { >+ render += '<i class="text-success fa-solid fa-circle-check"></i> '; >+ render += '<span class="text-success">'; >+ render += operationLabels[operation.code] || operation.code; >+ render += ' ' + _("ok"); >+ render += '</span>'; >+ } >+ render += "</div>"; >+ }); >+ } else { >+ render += "<em>" + _("Never used") + "</em>"; >+ } >+ } else { >+ render += "<em>" + _("Never used") + "</em>"; >+ } >+ return render; >+ }, >+ "searchable": false, >+ "orderable": false >+ }, >+ { >+ "data": "debug", >+ "render": function(data, type, row, meta) { >+ if(data == true) { >+ return "[% tp("Active", "On") | html %]"; >+ } >+ else { >+ return _("Off"); >+ } >+ }, >+ "searchable": false, >+ "orderable": false >+ }, >+ { >+ "data": function(row, type, val, meta) { >+ let result = '<a class="btn btn-default btn-xs" role="button" href="/cgi-bin/koha/admin/sftp_servers.pl?op=edit_form&sftp_server_id='+ encodeURIComponent(row.sftp_server_id) +'"><i class="fa-solid fa-pencil" aria-hidden="true"></i> '+_("Edit")+'</a>'+"\n"; >+ result += '<a class="btn btn-default btn-xs delete_server" role="button" href="#" data-bs-toggle="modal" data-bs-target="#delete_confirm_modal" data-sftp-server-id="'+ encodeURIComponent(row.sftp_server_id) +'" data-sftp-server-name="'+ encodeURIComponent(row.name.escapeHtml()) +'"><i class="fa fa-trash-can" aria-hidden="true"></i> '+_("Delete")+'</a>'; >+ return result; >+ }, >+ "searchable": false, >+ "orderable": false >+ } >+ ], >+ createdRow: function(row, data, dataIndex) { >+ if(data.is_default) { >+ $(row).addClass('default warn'); >+ } >+ if(data.debug) { >+ $(row).addClass('debug'); >+ } >+ }, >+ }); > >- $("#delete_confirm_modal_button").on("click", function() { >+ $('#sftp_servers').on("click", '.delete_server', function() { >+ var sftp_server_id = $(this).data('sftp-server-id'); >+ var sftp_server_name = decodeURIComponent($(this).data('sftp-server-name')); > >- var sftp_server_id = $(this).data('sftp-server-id'); >- var sftp_server_name = $(this).data('sftp-server-name'); >+ $("#delete_confirm_dialog").html( >+ _("You are about to delete the '%s' FTP/SFTP server.").format(sftp_server_name) >+ ); >+ $("#delete_confirm_modal_button").data('sftp-server-id', sftp_server_id); >+ $("#delete_confirm_modal_button").data('sftp-server-name', sftp_server_name); >+ }); > >- $.ajax({ >- method: "DELETE", >- url: "/api/v1/config/sftp_servers/"+sftp_server_id >- }).success(function() { >- window.sftp_servers.api().ajax.reload(function(data) { >- $("#sftp_action_result_dialog").hide(); >- $("#sftp_delete_success").html(_("Server '%s' deleted successfully.").format(sftp_server_name)).show(); >+ $("#delete_confirm_modal_button").on("click", function() { >+ >+ var sftp_server_id = $(this).data('sftp-server-id'); >+ var sftp_server_name = $(this).data('sftp-server-name'); >+ >+ $.ajax({ >+ method: "DELETE", >+ url: "/api/v1/config/sftp_servers/"+sftp_server_id >+ }).success(function() { >+ window.sftp_servers.api().ajax.reload(function(data) { >+ $("#sftp_action_result_dialog").hide(); >+ $("#sftp_delete_success").html(_("Server '%s' deleted successfully.").format(sftp_server_name)).show(); >+ }); >+ }).fail(function() { >+ $("#sftp_delete_error").html(_("Error deleting server '%s'. Please ensure all linked EDI accounts are unlinked or deleted. Check the logs for details.").format(sftp_server_name)).show(); >+ }).done(function() { >+ $("#delete_confirm_modal").modal('hide'); > }); >- }).fail(function() { >- $("#sftp_delete_error").html(_("Error deleting server '%s'. Please ensure all linked EDI accounts are unlinked or deleted. Check the logs for details.").format(sftp_server_name)).show(); >- }).done(function() { >- $("#delete_confirm_modal").modal('hide'); > }); >- }); > >- transportChange(); >- $("#sftp_transport").on("change", function(event) { > transportChange(); >- }); >+ $("#sftp_transport").on("change", function(event) { >+ transportChange(); >+ }); > >- authModeChange(); >- $("#sftp_auth_mode").on("change", function(event) { > authModeChange(); >- }); >+ $("#sftp_auth_mode").on("change", function(event) { >+ authModeChange(); >+ }); > >- $('#confirm_key_accept_submit').on('click', function(event) { >- event.preventDefault(); >+ $('#confirm_key_accept_submit').on('click', function(event) { >+ event.preventDefault(); > >- if ( $('#add').length > 0 ) { >- if( $('#add').valid() == true ) { >- modalChange(); >- $('#confirm_key_accept').modal('show'); >- } else { >- $('#confirm_key_accept').modal('hide'); >+ if ( $('#add').length > 0 ) { >+ if( $('#add').valid() == true ) { >+ modalChange(); >+ $('#confirm_key_accept').modal('show'); >+ } else { >+ $('#confirm_key_accept').modal('hide'); >+ } > } >- } > >- if ( $('#edit_save').length > 0 ) { >- if( $('#edit_save').valid() == true ) { >- modalChange(); >- $('#confirm_key_accept').modal('show'); >- } else { >- $('#confirm_key_accept').modal('hide'); >+ if ( $('#edit_save').length > 0 ) { >+ if( $('#edit_save').valid() == true ) { >+ modalChange(); >+ $('#confirm_key_accept').modal('show'); >+ } else { >+ $('#confirm_key_accept').modal('hide'); >+ } > } >- } > >- }); >+ }); > >- $('#confirm_key_accept .approve').on('click', function() { >- $('#confirm_key_accept .deny').click(); >+ $('#confirm_key_accept .approve').on('click', function() { >+ $('#confirm_key_accept .deny').click(); > >- if ( $('#add').length > 0 ) { >- $('#add').submit(); >- } >+ if ( $('#add').length > 0 ) { >+ $('#add').submit(); >+ } >+ >+ if ( $('#edit_save').length > 0 ) { >+ $('#edit_save').submit(); >+ } >+ }); > >- if ( $('#edit_save').length > 0 ) { >- $('#edit_save').submit(); >- } > }); > >- }); >- >- function transportChange() { >- let sftp_transport = $("#sftp_transport"); >- >- if(sftp_transport.val() == "ftp") { >- $("#sftp_host").removeAttr("disabled"); >- $("#sftp_port").removeAttr("disabled"); >- $("#sftp_passive").removeAttr("disabled"); >- $("#sftp_auth_mode").removeAttr("disabled"); >- $("#sftp_user_name").removeAttr("disabled"); >- $("#sftp_password").removeAttr("disabled"); >- $("#sftp_key_file").attr("disabled", "disabled"); >- >- $("#sftp_auth_mode option[value='password']").removeAttr("disabled"); >- $("#sftp_auth_mode option[value='key_file']").attr("disabled", "disabled"); >- $("#sftp_auth_mode option[value='noauth']").removeAttr("disabled"); >- if($("#sftp_auth_mode option:selected").val() == "key_file") { >- $("#sftp_auth_mode option[value='password']").prop("selected", true); >- } >+ function transportChange() { >+ let sftp_transport = $("#sftp_transport"); >+ >+ if(sftp_transport.val() == "ftp") { >+ $("#sftp_host").removeAttr("disabled"); >+ $("#sftp_port").removeAttr("disabled"); >+ $("#sftp_passive").removeAttr("disabled"); >+ $("#sftp_auth_mode").removeAttr("disabled"); >+ $("#sftp_user_name").removeAttr("disabled"); >+ $("#sftp_password").removeAttr("disabled"); >+ $("#sftp_key_file").attr("disabled", "disabled"); >+ >+ $("#sftp_auth_mode option[value='password']").removeAttr("disabled"); >+ $("#sftp_auth_mode option[value='key_file']").attr("disabled", "disabled"); >+ $("#sftp_auth_mode option[value='noauth']").removeAttr("disabled"); >+ if($("#sftp_auth_mode option:selected").val() == "key_file") { >+ $("#sftp_auth_mode option[value='password']").prop("selected", true); >+ } > >- let sftp_port = $("#sftp_port").val(); >- if(sftp_port == 22) $("#sftp_port").val("21"); >+ let sftp_port = $("#sftp_port").val(); >+ if(sftp_port == 22) $("#sftp_port").val("21"); > >- authModeChange(); >- } else if(sftp_transport.val() == "sftp") { >- $("#sftp_host").removeAttr("disabled"); >- $("#sftp_port").removeAttr("disabled"); >- $("#sftp_passive").attr("disabled", "disabled"); >- $("#sftp_auth_mode").removeAttr("disabled"); >- $("#sftp_user_name").removeAttr("disabled"); >- $("#sftp_password").removeAttr("disabled"); >- $("#sftp_key_file").removeAttr("disabled"); >- >- $("#sftp_auth_mode option[value='password']").removeAttr("disabled"); >- $("#sftp_auth_mode option[value='key_file']").removeAttr("disabled"); >- $("#sftp_auth_mode option[value='noauth']").removeAttr("disabled"); >- $("#sftp_passive option[value='1']").prop("selected", true); >- >- let sftp_port = $("#sftp_port").val(); >- if(sftp_port == 21) $("#sftp_port").val("22"); >- >- return authModeChange(); >- } >- } >- >- function authModeChange() { >- let sftp_auth_mode = $("#sftp_auth_mode").val(); >- >- if(sftp_auth_mode == "password") { >- $("#sftp_password").removeAttr("disabled"); >- $("#sftp_key_file").attr("disabled", "disabled"); >- } else if(sftp_auth_mode == "key_file") { >- $("#sftp_password").attr("disabled", "disabled"); >- $("#sftp_key_file").removeAttr("disabled"); >- } else { >- $("#sftp_password").attr("disabled", "disabled"); >- $("#sftp_key_file").attr("disabled", "disabled"); >- } >- } >- >- function modalChange() { >- $('#modal_message').hide(); >- if ( $('#sftp_transport').val() == 'sftp' ) $('#modal_message').show(); >- >- $('#modal_host').text( $('#sftp_host').val() ); >- $('#modal_port').text( $('#sftp_port').val() ); >- $('#modal_transport').text( $('#sftp_transport option:selected').text() ); >- $('#modal_user_name').text( $('#sftp_user_name').val() ); >- $('#modal_auth_mode').text( $('#sftp_auth_mode option:selected').text() ); >- } >- </script> >- >- [% IF op == 'test_form' %] >- <script> >- $(document).ready(function() { >- handleTests(); >- }); >- >- function handleTests() { >- var testOutput = $('#testOutput'); >- var runTests = $('#runTests'); >- >- runTests.addClass('disabled'); >- testOutput.html('<div class="spinner-border text-warning" style="height:1.5rem;width:1.5rem" role="status"><span class="sr-only">Loading...</span></div><span class="pending-loading">' + _("Running tests . . . ") + '</span>'); >- >- return $.ajax({ >- url: "/api/v1/sftp_server/[% sftp_server.id | html %]/test_connection", >- }) >- .done(function(data) { >- testOutput.text(''); >- >- for ( let [key, value] of Object.entries( data ) ) { >- var title; >- switch(key) { >- case '1_sftp_conn': >- title = _("Testing SFTP connectivity"); >- break; >- case '1_ftp_conn': >- title = _("Testing FTP connectivity"); >- break; >- case '2_ftp_login': >- title = _("Testing we can log in"); >- break; >- case '2a_sftp_cwd_dl': >- case '3a_ftp_cwd_dl': >- title = _("Testing we can cwd to download directory"); >- break; >- case '2b_sftp_ls_dl': >- case '3b_ftp_ls_dl': >- title = _("Testing we can list download directory"); >- break; >- case '2c_sftp_cwd_ul': >- case '3c_ftp_cwd_ul': >- title = _("Testing we can cwd to upload directory"); >- break; >- case '2d_sftp_ls_ul': >- case '3d_ftp_ls_ul': >- title = _("Testing we can list upload directory"); >- break; >- case '3_sftp_write': >- case '4_ftp_write': >- title = _("Testing we can write a test file"); >- break; >- case '4_sftp_del': >- case '5_ftp_del': >- title = _("Testing we can delete test file"); >- break; >- default: >- title = key >- } >+ authModeChange(); >+ } else if(sftp_transport.val() == "sftp") { >+ $("#sftp_host").removeAttr("disabled"); >+ $("#sftp_port").removeAttr("disabled"); >+ $("#sftp_passive").attr("disabled", "disabled"); >+ $("#sftp_auth_mode").removeAttr("disabled"); >+ $("#sftp_user_name").removeAttr("disabled"); >+ $("#sftp_password").removeAttr("disabled"); >+ $("#sftp_key_file").removeAttr("disabled"); > >- if ( value.passed ) { >- testOutput.append( >- '<i class="text-success fa-solid fa-circle-check"></i> ' >- + title >- + '... <span class="text-success">' >- + _("Passed") >- + '</span><br />' >- ); >- if( value.msg ) testOutput.append( _("Message: ") + '<code>' + value.msg + '</code><br />' ); >- } else { >- testOutput.append( >- '<i class="text-danger fa-solid fa-circle-xmark"></i> ' >- + title >- + '... <span class="text-danger">' >- + _("Failed") >- + '</span><br />' >- ); >- if( value.err ) testOutput.append( _("Error message: ") + '<code>' + value.err + '</code><br />' ); >- } >- testOutput.append( '<br />' ); >+ $("#sftp_auth_mode option[value='password']").removeAttr("disabled"); >+ $("#sftp_auth_mode option[value='key_file']").removeAttr("disabled"); >+ $("#sftp_auth_mode option[value='noauth']").removeAttr("disabled"); >+ $("#sftp_passive option[value='1']").prop("selected", true); >+ >+ let sftp_port = $("#sftp_port").val(); >+ if(sftp_port == 21) $("#sftp_port").val("22"); >+ >+ return authModeChange(); > } >- }) >- .fail(function(data) { >- if( data.status == 404 ) { >- return testOutput.text( '<i class="text-success fa-solid fa-circle-check"></i> ' + _("FTP/SFTP Server not found") ); >+ } >+ >+ function authModeChange() { >+ let sftp_auth_mode = $("#sftp_auth_mode").val(); >+ >+ if(sftp_auth_mode == "password") { >+ $("#sftp_password").removeAttr("disabled"); >+ $("#sftp_key_file").attr("disabled", "disabled"); >+ } else if(sftp_auth_mode == "key_file") { >+ $("#sftp_password").attr("disabled", "disabled"); >+ $("#sftp_key_file").removeAttr("disabled"); > } else { >- return testOutput.text( '<i class="text-success fa-solid fa-circle-check"></i> ' + _("Internal Server Error. Please check the server logs") ); >+ $("#sftp_password").attr("disabled", "disabled"); >+ $("#sftp_key_file").attr("disabled", "disabled"); > } >- }) >- .always(function(data) { >- runTests.removeClass('disabled'); >- }); >- } >- </script> >+ } >+ >+ function modalChange() { >+ $('#modal_message').hide(); >+ if ( $('#sftp_transport').val() == 'sftp' ) $('#modal_message').show(); >+ >+ $('#modal_host').text( $('#sftp_host').val() ); >+ $('#modal_port').text( $('#sftp_port').val() ); >+ $('#modal_transport').text( $('#sftp_transport option:selected').text() ); >+ $('#modal_user_name').text( $('#sftp_user_name').val() ); >+ $('#modal_auth_mode').text( $('#sftp_auth_mode option:selected').text() ); >+ } >+ </script> > [% END %] >-[% END %] > >-[% INCLUDE 'intranet-bottom.inc' %] >+ [% INCLUDE 'intranet-bottom.inc' %] >+</div> >diff --git a/koha-tmpl/intranet-tmpl/prog/js/transport_status.js b/koha-tmpl/intranet-tmpl/prog/js/transport_status.js >new file mode 100644 >index 00000000000..bb10d3f8895 >--- /dev/null >+++ b/koha-tmpl/intranet-tmpl/prog/js/transport_status.js >@@ -0,0 +1,7 @@ >+let operationLabels = { >+ connection: __("Connection"), >+ upload: __("Upload"), >+ download: __("Download"), >+ list: __("List Files"), >+ change_directory: __("Change Directory"), >+}; >-- >2.48.1
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 39190
:
178555
|
178556
|
178557
|
178558
|
178559
|
178560
|
178561
|
178562
|
178563
|
178564
|
178565
|
178566
|
178567
|
178568
|
178569
|
178570
|
178571
|
179252
|
179253
|
179254
|
179255
|
179256
|
179257
|
179258
|
179259
|
179260
|
179261
|
179262
|
179263
|
179264
|
179265
|
179266
|
179267
|
179268
|
179396
|
179397
|
179398
|
179399
|
179400
|
179401
|
179402
|
179403
|
179404
|
179405
|
179406
|
179407
|
179408
|
179409
|
179410
|
179411
|
179412
|
179413
|
179589
|
179590
|
179591
|
179592
|
179593
|
179594
|
179595
|
179596
|
179597
|
179598
|
179599
|
179600
|
179601
|
179602
|
179603
|
179604
|
179605
|
179606
|
179646
|
179647
|
179648
|
179649
|
179650
|
179651
|
179652
|
179653
|
179654
|
179655
|
179656
|
179657
|
179658
|
179659
|
179660
|
179661
|
179662
|
179663
|
179992
|
179993
|
179994
|
179995
|
179996
|
179997
|
179998
|
179999
|
180000
|
180001
|
180002
|
180003
|
180004
|
180005
|
180006
|
180010
|
180011
|
180012
|
180013
|
180014
|
180015
|
180016
|
180017
|
180018
|
180019
|
180020
|
180021
|
180022
|
180023
|
180024
|
180025