Bug 39190: Rework (S)FTP into File::Transport classes
This patch adds polymorphic transport classes to Koha for FTP and SFTP file transport configurations. We introduce a base class for interacting with the base configuration storage and subclasses to impliment the protocol specific transport handling. Signed-off-by: Kyle M Hall <kyle@bywatersolutions.com> Signed-off-by: Tomas Cohen Arazi <tomascohen@theke.io> Signed-off-by: Lucas Gass <lucas@bywatersolutions.com>
This commit is contained in:
parent
9d76089166
commit
3354bed6ef
|
|
@ -0,0 +1,268 @@
|
|||
package Koha::File::Transport;
|
||||
|
||||
# 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 constant {
|
||||
DEFAULT_TIMEOUT => 10,
|
||||
TEST_FILE_NAME => '.koha_test_file',
|
||||
TEST_FILE_CONTENT => "Hello, world!\n",
|
||||
KEY_FILE_PERMISSIONS => '0600',
|
||||
};
|
||||
|
||||
use Koha::Database;
|
||||
use Koha::Exceptions::Object;
|
||||
use Koha::Encryption;
|
||||
|
||||
use base qw(Koha::Object);
|
||||
|
||||
=head1 NAME
|
||||
|
||||
Koha::File::Transport - Base class for file transport handling
|
||||
|
||||
=head1 DESCRIPTION
|
||||
|
||||
Base class providing common functionality for FTP/SFTP file transport.
|
||||
|
||||
=cut
|
||||
|
||||
=head1 API
|
||||
|
||||
=head2 Class methods
|
||||
|
||||
=head3 store
|
||||
|
||||
$server->store;
|
||||
|
||||
Overloaded store method that ensures directory paths end with a forward slash.
|
||||
|
||||
=cut
|
||||
|
||||
sub store {
|
||||
my ($self) = @_;
|
||||
|
||||
# Encrypt sensitive data if changed
|
||||
$self->_encrypt_sensitive_data();
|
||||
|
||||
# Normalize directory paths
|
||||
for my $dir_field (qw(download_directory upload_directory)) {
|
||||
my $dir = $self->$dir_field;
|
||||
next unless $dir && $dir ne '';
|
||||
$self->$dir_field( $dir . '/' ) unless substr( $dir, -1 ) eq '/';
|
||||
}
|
||||
|
||||
# Store
|
||||
$self->SUPER::store;
|
||||
|
||||
# Return the updated object including the encrypt_sensitive_data
|
||||
return $self->discard_changes;
|
||||
}
|
||||
|
||||
=head3 plain_text_password
|
||||
|
||||
my $password = $server->plain_text_password;
|
||||
|
||||
Returns the decrypted plaintext password.
|
||||
|
||||
=cut
|
||||
|
||||
sub plain_text_password {
|
||||
my ($self) = @_;
|
||||
return unless $self->password;
|
||||
return Koha::Encryption->new->decrypt_hex( $self->password );
|
||||
}
|
||||
|
||||
=head3 plain_text_key
|
||||
|
||||
my $key = $server->plain_text_key;
|
||||
|
||||
Returns the decrypted plaintext key file.
|
||||
|
||||
=cut
|
||||
|
||||
sub plain_text_key {
|
||||
my ($self) = @_;
|
||||
return unless $self->key_file;
|
||||
return Koha::Encryption->new->decrypt_hex( $self->key_file ) . "\n";
|
||||
}
|
||||
|
||||
=head3 to_api
|
||||
|
||||
my $json = $transport->to_api;
|
||||
|
||||
Returns a JSON representation of the object suitable for API output,
|
||||
excluding sensitive data.
|
||||
|
||||
=cut
|
||||
|
||||
sub to_api {
|
||||
my ( $self, $params ) = @_;
|
||||
|
||||
my $json = $self->SUPER::to_api($params) or return;
|
||||
delete @{$json}{qw(password key_file)}; # Remove sensitive data
|
||||
|
||||
return $json;
|
||||
}
|
||||
|
||||
=head3 to_api_mapping
|
||||
|
||||
This method returns the mapping for representing a Koha::File::Transport object
|
||||
on the API.
|
||||
|
||||
=cut
|
||||
|
||||
sub to_api_mapping {
|
||||
return { id => 'sftp_server_id' };
|
||||
}
|
||||
|
||||
=head3 test_connection
|
||||
|
||||
$transport->test_connection
|
||||
|
||||
Method to test the connection for the configuration of the current file server
|
||||
|
||||
=cut
|
||||
|
||||
sub test_connection {
|
||||
my ($self) = @_;
|
||||
|
||||
$self->connect or return;
|
||||
|
||||
for my $dir_type (qw(download upload)) {
|
||||
my $dir = $self->{"${dir_type}_directory"};
|
||||
next if $dir eq '';
|
||||
|
||||
$self->change_directory($dir) or return;
|
||||
$self->list_files() or return;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
=head2 Subclass methods
|
||||
|
||||
Interface methods that must be implemented by subclasses
|
||||
|
||||
=head3 connect
|
||||
|
||||
$transport->connect();
|
||||
|
||||
Method for connecting the current transport to the file server
|
||||
|
||||
=cut
|
||||
|
||||
sub connect {
|
||||
my ($self) = @_;
|
||||
die "Subclass must implement connect";
|
||||
}
|
||||
|
||||
=head3 upload_file
|
||||
|
||||
$transport->upload_file($file);
|
||||
|
||||
Method for uploading a file to the current file server
|
||||
|
||||
=cut
|
||||
|
||||
sub upload_file {
|
||||
my ( $self, $local_file, $remote_file ) = @_;
|
||||
die "Subclass must implement upload_file";
|
||||
}
|
||||
|
||||
=head3 download_file
|
||||
|
||||
$transport->download_file($file);
|
||||
|
||||
Method for downloading a file from the current file server
|
||||
|
||||
=cut
|
||||
|
||||
sub download_file {
|
||||
my ( $self, $remote_file, $local_file ) = @_;
|
||||
die "Subclass must implement download_file";
|
||||
}
|
||||
|
||||
=head3 change_directory
|
||||
|
||||
my $files = $transport->change_directory($path);
|
||||
|
||||
Method for changing the current directory on the connected file server
|
||||
|
||||
=cut
|
||||
|
||||
sub change_directory {
|
||||
my ( $self, $path ) = @_;
|
||||
die "Subclass must implement change_directory";
|
||||
}
|
||||
|
||||
=head3 list_files
|
||||
|
||||
my $files = $transport->list_files($path);
|
||||
|
||||
Method for listing files in the current directory of the connected file server
|
||||
|
||||
=cut
|
||||
|
||||
sub list_files {
|
||||
my ( $self, $path ) = @_;
|
||||
die "Subclass must implement list_files";
|
||||
}
|
||||
|
||||
=head2 Internal methods
|
||||
|
||||
=head3 _encrypt_sensitive_data
|
||||
|
||||
Handle encryption of sensitive data
|
||||
|
||||
=cut
|
||||
|
||||
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 ) {
|
||||
$self->password( $encryption->encrypt_hex( $self->password ) );
|
||||
}
|
||||
|
||||
if ( ( !$self->in_storage || $self->is_changed('key_file') ) && $self->key_file ) {
|
||||
$self->key_file( $encryption->encrypt_hex( _dos2unix( $self->key_file ) ) );
|
||||
}
|
||||
}
|
||||
|
||||
=head3 _dos2unix
|
||||
|
||||
Return a CR-free string from an input
|
||||
|
||||
=cut
|
||||
|
||||
sub _dos2unix {
|
||||
my $dosStr = shift;
|
||||
|
||||
return $dosStr =~ s/\015\012/\012/gr;
|
||||
}
|
||||
|
||||
=head3 _type
|
||||
|
||||
Return type of Object relating to Schema Result
|
||||
|
||||
=cut
|
||||
|
||||
sub _type {
|
||||
return 'SftpServer';
|
||||
}
|
||||
|
||||
1;
|
||||
|
|
@ -0,0 +1,183 @@
|
|||
package Koha::File::Transport::FTP;
|
||||
|
||||
# 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 Net::FTP;
|
||||
use Try::Tiny;
|
||||
|
||||
use base qw(Koha::File::Transport);
|
||||
|
||||
=head1 NAME
|
||||
|
||||
Koha::File::Transport::FTP - FTP implementation of file transport
|
||||
|
||||
=head2 Class methods
|
||||
|
||||
=head3 connect
|
||||
|
||||
my $success = $self->connect;
|
||||
|
||||
Start the FTP transport connect, returns true on success or undefined on failure.
|
||||
|
||||
=cut
|
||||
|
||||
sub connect {
|
||||
my ($self) = @_;
|
||||
|
||||
$self->{connection} = Net::FTP->new(
|
||||
$self->host,
|
||||
Port => $self->port,
|
||||
Timeout => $self->DEFAULT_TIMEOUT,
|
||||
Passive => $self->passive ? 1 : 0,
|
||||
) or return $self->_abort_operation();
|
||||
|
||||
$self->{connection}->login( $self->user_name, $self->plain_text_password )
|
||||
or return $self->_abort_operation();
|
||||
|
||||
$self->add_message(
|
||||
{
|
||||
message => "Connect succeeded",
|
||||
type => 'success',
|
||||
payload => { detail => '' }
|
||||
}
|
||||
);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
=head3 upload_file
|
||||
|
||||
my $success = $transport->upload_file($fh);
|
||||
|
||||
Passed a filehandle, this will upload the file to the current directory of the server connection.
|
||||
|
||||
Returns true on success or undefined on failure.
|
||||
|
||||
=cut
|
||||
|
||||
sub upload_file {
|
||||
my ( $self, $local_file, $remote_file ) = @_;
|
||||
|
||||
$self->{connection}->put( $local_file, $remote_file )
|
||||
or return $self->_abort_operation();
|
||||
|
||||
$self->add_message(
|
||||
{
|
||||
message => "Upload succeeded",
|
||||
type => 'success',
|
||||
payload => { detail => '' }
|
||||
}
|
||||
);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
=head3 download_file
|
||||
|
||||
my $success = $transport->download_file($filename);
|
||||
|
||||
Passed a filename, this will download the file from the current directory of the server connection.
|
||||
|
||||
Returns true on success or undefined on failure.
|
||||
|
||||
=cut
|
||||
|
||||
sub download_file {
|
||||
my ( $self, $remote_file, $local_file ) = @_;
|
||||
|
||||
$self->{connection}->get( $remote_file, $local_file )
|
||||
or return $self->_abort_operation();
|
||||
|
||||
$self->add_message(
|
||||
{
|
||||
message => "Download succeeded",
|
||||
type => 'success',
|
||||
payload => { detail => '' }
|
||||
}
|
||||
);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
=head3 change_directory
|
||||
|
||||
my $success = $server->change_directory($directory);
|
||||
|
||||
Passed a directory name, this will change the current directory of the server connection.
|
||||
|
||||
Returns true on success or undefined on failure.
|
||||
|
||||
=cut
|
||||
|
||||
sub change_directory {
|
||||
my ( $self, $remote_directory ) = @_;
|
||||
|
||||
$self->{connection}->cwd($remote_directory) or $self->_abort_operation();
|
||||
|
||||
$self->add_message(
|
||||
{
|
||||
message => "Changed directory succeeded",
|
||||
type => 'success',
|
||||
payload => { detail => '' }
|
||||
}
|
||||
);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
=head3 list_files
|
||||
|
||||
my @files = $server->list_files;
|
||||
|
||||
Returns an array of filenames found in the current directory of the server connection.
|
||||
|
||||
=cut
|
||||
|
||||
sub list_files {
|
||||
my ($self) = @_;
|
||||
my $file_list = $self->{connection}->ls or return $self->_abort_operation();
|
||||
|
||||
$self->add_message(
|
||||
{
|
||||
message => "Listing files succeeded",
|
||||
type => 'success',
|
||||
payload => { detail => '' }
|
||||
}
|
||||
);
|
||||
|
||||
return $file_list;
|
||||
}
|
||||
|
||||
sub _abort_operation {
|
||||
my ( $self, $message ) = @_;
|
||||
|
||||
$self->add_message(
|
||||
{
|
||||
message => $self->{connection} ? $self->{connection}->message : $@,
|
||||
type => 'error',
|
||||
payload => { detail => $self->{connection} ? $self->{connection}->status : '' }
|
||||
}
|
||||
);
|
||||
|
||||
if ( $self->{connection} ) {
|
||||
$self->{connection}->abort;
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
1;
|
||||
|
|
@ -0,0 +1,142 @@
|
|||
package Koha::File::Transport::SFTP;
|
||||
|
||||
# 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::Logger;
|
||||
|
||||
use Net::SFTP::Foreign;
|
||||
use Try::Tiny;
|
||||
|
||||
use base qw(Koha::File::Transport);
|
||||
|
||||
=head1 NAME
|
||||
|
||||
Koha::File::Transport::SFTP - SFTP implementation of file transport
|
||||
|
||||
=cut
|
||||
|
||||
sub connect {
|
||||
my ($self) = @_;
|
||||
|
||||
$self->{connection} = Net::SFTP::Foreign->new(
|
||||
host => $self->host,
|
||||
user => $self->user_name,
|
||||
password => $self->plain_text_password,
|
||||
timeout => $self->DEFAULT_TIMEOUT,
|
||||
more => [qw(-o StrictHostKeyChecking=no)],
|
||||
);
|
||||
$self->{connection}->die_on_error("SFTP failure for remote host");
|
||||
|
||||
return $self->_abort_operation() if ( $self->{connection}->error );
|
||||
|
||||
$self->add_message(
|
||||
{
|
||||
message => $self->{connection}->status,
|
||||
type => 'success',
|
||||
payload => { detail => '' }
|
||||
}
|
||||
);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
sub upload_file {
|
||||
my ( $self, $local_file, $remote_file ) = @_;
|
||||
|
||||
my $logger = Koha::Logger->get_logger();
|
||||
|
||||
$self->{connection}->put( $local_file, $remote_file ) or return $self->_abort_operation();
|
||||
|
||||
$self->add_message(
|
||||
{
|
||||
message => $self->{connection}->status,
|
||||
type => 'success',
|
||||
payload => { detail => '' }
|
||||
}
|
||||
);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
sub download_file {
|
||||
my ( $self, $remote_file, $local_file ) = @_;
|
||||
|
||||
$self->{connection}->get( $remote_file, $local_file ) or return $self->_abort_operation();
|
||||
|
||||
$self->add_message(
|
||||
{
|
||||
message => $self->{connection}->status,
|
||||
type => 'success',
|
||||
payload => { detail => '' }
|
||||
}
|
||||
);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
sub change_directory {
|
||||
my ( $self, $remote_directory ) = @_;
|
||||
|
||||
$self->{connection}->setcwd($remote_directory) or return $self->_abort_operation();
|
||||
|
||||
$self->add_message(
|
||||
{
|
||||
message => $self->{connection}->status,
|
||||
type => 'success',
|
||||
payload => { detail => '' }
|
||||
}
|
||||
);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
sub list_files {
|
||||
my ($self) = @_;
|
||||
|
||||
my $file_list = $self->{connection}->ls or return $self->_abort_operation();
|
||||
|
||||
$self->add_message(
|
||||
{
|
||||
message => $self->{connection}->status,
|
||||
type => 'success',
|
||||
payload => { detail => '' }
|
||||
}
|
||||
);
|
||||
|
||||
return $file_list;
|
||||
}
|
||||
|
||||
sub _abort_operation {
|
||||
my ($self) = @_;
|
||||
|
||||
$self->add_message(
|
||||
{
|
||||
message => $self->{connection}->error,
|
||||
type => 'error',
|
||||
payload => { detail => $self->{connection} ? $self->{connection}->status : '' }
|
||||
}
|
||||
);
|
||||
|
||||
if ( $self->{connection} ) {
|
||||
$self->{connection}->abort;
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
1;
|
||||
|
|
@ -0,0 +1,86 @@
|
|||
package Koha::File::Transports;
|
||||
|
||||
# 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::Database;
|
||||
use Koha::Exceptions;
|
||||
|
||||
use Koha::File::Transport::SFTP;
|
||||
use Koha::File::Transport::FTP;
|
||||
|
||||
use base qw(Koha::Objects);
|
||||
|
||||
=head1 NAME
|
||||
|
||||
Koha::File::Transports - Koha File Transports Object set class
|
||||
|
||||
=head1 API
|
||||
|
||||
=head2 Internal methods
|
||||
|
||||
=head3 _type
|
||||
|
||||
Return type of object, relating to Schema ResultSet
|
||||
|
||||
=cut
|
||||
|
||||
sub _type {
|
||||
return 'SftpServer';
|
||||
}
|
||||
|
||||
=head3 _polymorphic_field
|
||||
|
||||
Return the field in the table that defines the polymorphic class to be built
|
||||
|
||||
=cut
|
||||
|
||||
sub _polymorphic_field {
|
||||
return 'transport'; # This field defines which subclass to use
|
||||
}
|
||||
|
||||
=head3 _polymorphic_map
|
||||
|
||||
Return the mapping for field value to class name for the polymorphic class
|
||||
|
||||
=cut
|
||||
|
||||
sub _polymorphic_map {
|
||||
return {
|
||||
sftp => 'Koha::File::Transport::SFTP',
|
||||
ftp => 'Koha::File::Transport::FTP',
|
||||
};
|
||||
}
|
||||
|
||||
=head3 object_class
|
||||
|
||||
Return object class dynamically based on transport
|
||||
|
||||
=cut
|
||||
|
||||
sub object_class {
|
||||
my ( $self, $object ) = @_;
|
||||
|
||||
return 'Koha::File::Transport' unless $object;
|
||||
|
||||
my $field = $self->_polymorphic_field;
|
||||
my $map = $self->_polymorphic_map;
|
||||
|
||||
return $map->{ lc( $object->$field ) } || 'Koha::File::Transport';
|
||||
}
|
||||
|
||||
1;
|
||||
|
|
@ -0,0 +1,174 @@
|
|||
#!/usr/bin/perl
|
||||
|
||||
# This file is part of Koha.
|
||||
#
|
||||
# Koha is free software; you can redistribute it and/or modify it
|
||||
# under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation; either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# Koha is distributed in the hope that it will be useful, but
|
||||
# WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with Koha; if not, see <http://www.gnu.org/licenses>.
|
||||
|
||||
use Modern::Perl;
|
||||
|
||||
use Test::More tests => 5;
|
||||
use Test::Exception;
|
||||
use Test::NoWarnings;
|
||||
use Test::Warn;
|
||||
|
||||
use Koha::File::Transports;
|
||||
|
||||
use t::lib::TestBuilder;
|
||||
use t::lib::Mocks;
|
||||
|
||||
my $schema = Koha::Database->new->schema;
|
||||
my $builder = t::lib::TestBuilder->new;
|
||||
|
||||
subtest 'store() tests' => sub {
|
||||
plan tests => 6;
|
||||
$schema->storage->txn_begin;
|
||||
|
||||
my $transport = $builder->build_object(
|
||||
{
|
||||
class => 'Koha::File::Transports',
|
||||
value => {
|
||||
transport => 'ftp',
|
||||
password => undef,
|
||||
key_file => undef,
|
||||
download_directory => undef,
|
||||
upload_directory => undef
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
subtest 'Test store with empty directories' => sub {
|
||||
plan tests => 2;
|
||||
|
||||
$transport->set( { download_directory => '', upload_directory => '' } )->store();
|
||||
|
||||
is( $transport->download_directory, '', 'Empty download directory remains empty' );
|
||||
is( $transport->upload_directory, '', 'Empty upload directory remains empty' );
|
||||
};
|
||||
|
||||
subtest 'Test store with directories missing trailing slash' => sub {
|
||||
plan tests => 2;
|
||||
|
||||
$transport->set( { download_directory => '/tmp/download', upload_directory => '/tmp/upload' } )->store();
|
||||
|
||||
is( $transport->download_directory, '/tmp/download/', 'Added trailing slash to download directory' );
|
||||
is( $transport->upload_directory, '/tmp/upload/', 'Added trailing slash to upload directory' );
|
||||
};
|
||||
|
||||
subtest 'Test store with directories having trailing slash' => sub {
|
||||
plan tests => 2;
|
||||
|
||||
$transport->set( { download_directory => '/tmp/download/', upload_directory => '/tmp/upload/' } )->store();
|
||||
|
||||
is( $transport->download_directory, '/tmp/download/', 'Kept existing trailing slash in download directory' );
|
||||
is( $transport->upload_directory, '/tmp/upload/', 'Kept existing trailing slash in upload directory' );
|
||||
};
|
||||
|
||||
subtest 'Test store with mixed trailing slashes' => sub {
|
||||
plan tests => 2;
|
||||
|
||||
$transport->set( { download_directory => '/tmp/download', upload_directory => '/tmp/upload/' } )->store();
|
||||
|
||||
is( $transport->download_directory, '/tmp/download/', 'Added missing trailing slash to download directory' );
|
||||
is( $transport->upload_directory, '/tmp/upload/', 'Kept existing trailing slash in upload directory' );
|
||||
};
|
||||
|
||||
subtest 'Test store with undefined directories' => sub {
|
||||
plan tests => 2;
|
||||
|
||||
$transport->set( { download_directory => undef, upload_directory => undef } )->store();
|
||||
|
||||
is( $transport->download_directory, undef, 'Undefined download directory remains undefined' );
|
||||
is( $transport->upload_directory, undef, 'Undefined upload directory remains undefined' );
|
||||
};
|
||||
|
||||
subtest 'Test encryption of sensitive data' => sub {
|
||||
plan tests => 2;
|
||||
|
||||
$transport->set( { password => "test123", key_file => "test321" } )->store();
|
||||
|
||||
isnt( $transport->password, "test123", 'Password is encrypted on store' );
|
||||
isnt( $transport->upload_directory, "test321", 'Key file is encrypted on store' );
|
||||
|
||||
};
|
||||
|
||||
$schema->storage->txn_rollback;
|
||||
};
|
||||
|
||||
subtest 'to_api() tests' => sub {
|
||||
|
||||
plan tests => 2;
|
||||
|
||||
$schema->storage->txn_begin;
|
||||
|
||||
my $transport = $builder->build_object( { class => 'Koha::File::Transports', value => { status => undef } } );
|
||||
|
||||
ok( !exists $transport->to_api->{password}, 'Password is not part of the API representation' );
|
||||
ok( !exists $transport->to_api->{key_file}, 'Key file is not part of the API representation' );
|
||||
|
||||
$schema->storage->txn_rollback;
|
||||
};
|
||||
|
||||
subtest 'plain_text_password() tests' => sub {
|
||||
|
||||
plan tests => 2;
|
||||
|
||||
$schema->storage->txn_begin;
|
||||
|
||||
my $transport = $builder->build_object(
|
||||
{
|
||||
class => 'Koha::File::Transports',
|
||||
value => {
|
||||
transport => 'ftp',
|
||||
password => undef,
|
||||
key_file => undef,
|
||||
}
|
||||
}
|
||||
);
|
||||
$transport->password('test123')->store();
|
||||
|
||||
my $transport_plain_text_password = $transport->plain_text_password;
|
||||
|
||||
isnt( $transport_plain_text_password, $transport->password, 'Password and password hash shouldn\'t match' );
|
||||
is( $transport_plain_text_password, 'test123', 'Password should be in plain text' );
|
||||
|
||||
$schema->storage->txn_rollback;
|
||||
};
|
||||
|
||||
subtest 'plain_text_key() tests' => sub {
|
||||
|
||||
plan tests => 2;
|
||||
|
||||
$schema->storage->txn_begin;
|
||||
|
||||
my $transport = $builder->build_object(
|
||||
{
|
||||
class => 'Koha::File::Transports',
|
||||
value => {
|
||||
transport => 'ftp',
|
||||
password => undef,
|
||||
key_file => undef
|
||||
}
|
||||
}
|
||||
);
|
||||
$transport->key_file("test321")->store();
|
||||
|
||||
my $transport_plain_text_key = $transport->plain_text_key;
|
||||
|
||||
isnt( $transport_plain_text_key, $transport->key_file, 'Key file and key file hash shouldn\'t match' );
|
||||
is( $transport_plain_text_key, "test321\n", 'Key file should be in plain text' );
|
||||
|
||||
$schema->storage->txn_rollback;
|
||||
};
|
||||
|
||||
1;
|
||||
|
|
@ -0,0 +1,94 @@
|
|||
#!/usr/bin/perl
|
||||
|
||||
# This file is part of Koha.
|
||||
#
|
||||
# Koha is free software; you can redistribute it and/or modify it
|
||||
# under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation; either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# Koha is distributed in the hope that it will be useful, but
|
||||
# WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with Koha; if not, see <http://www.gnu.org/licenses>.
|
||||
|
||||
use Modern::Perl;
|
||||
|
||||
use Test::More tests => 6;
|
||||
use Test::Exception;
|
||||
use Test::NoWarnings;
|
||||
use Test::Warn;
|
||||
|
||||
use Koha::File::Transports;
|
||||
|
||||
use t::lib::TestBuilder;
|
||||
use t::lib::Mocks;
|
||||
|
||||
my $schema = Koha::Database->new->schema;
|
||||
my $builder = t::lib::TestBuilder->new;
|
||||
|
||||
subtest 'connect() tests' => sub {
|
||||
plan tests => 1;
|
||||
|
||||
my $transport = $builder->build_object(
|
||||
{
|
||||
class => 'Koha::File::Transports',
|
||||
value => { transport => 'ftp', password => 'testpass' }
|
||||
}
|
||||
);
|
||||
|
||||
can_ok( $transport, 'connect' );
|
||||
};
|
||||
|
||||
subtest 'upload_file() tests' => sub {
|
||||
plan tests => 1;
|
||||
my $transport = $builder->build_object(
|
||||
{
|
||||
class => 'Koha::File::Transports',
|
||||
value => { transport => 'ftp', password => 'testpass' }
|
||||
}
|
||||
);
|
||||
|
||||
can_ok( $transport, 'upload_file' );
|
||||
};
|
||||
|
||||
subtest 'download_file() tests' => sub {
|
||||
plan tests => 1;
|
||||
my $transport = $builder->build_object(
|
||||
{
|
||||
class => 'Koha::File::Transports',
|
||||
value => { transport => 'ftp', password => 'testpass' }
|
||||
}
|
||||
);
|
||||
|
||||
can_ok( $transport, 'download_file' );
|
||||
};
|
||||
|
||||
subtest 'change_directory() tests' => sub {
|
||||
plan tests => 1;
|
||||
my $transport = $builder->build_object(
|
||||
{
|
||||
class => 'Koha::File::Transports',
|
||||
value => { transport => 'ftp', password => 'testpass' }
|
||||
}
|
||||
);
|
||||
|
||||
can_ok( $transport, 'change_directory' );
|
||||
};
|
||||
|
||||
subtest 'list_files() tests' => sub {
|
||||
plan tests => 1;
|
||||
my $transport = $builder->build_object(
|
||||
{
|
||||
class => 'Koha::File::Transports',
|
||||
value => { transport => 'ftp', password => 'testpass' }
|
||||
}
|
||||
);
|
||||
|
||||
can_ok( $transport, 'list_files' );
|
||||
};
|
||||
|
||||
1;
|
||||
|
|
@ -0,0 +1,95 @@
|
|||
#!/usr/bin/perl
|
||||
|
||||
# This file is part of Koha.
|
||||
#
|
||||
# Koha is free software; you can redistribute it and/or modify it
|
||||
# under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation; either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# Koha is distributed in the hope that it will be useful, but
|
||||
# WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with Koha; if not, see <http://www.gnu.org/licenses>.
|
||||
|
||||
use Modern::Perl;
|
||||
|
||||
use Test::More tests => 5;
|
||||
use Test::Exception;
|
||||
use Test::NoWarnings;
|
||||
use Test::Warn;
|
||||
|
||||
use Koha::File::Transports;
|
||||
|
||||
use t::lib::TestBuilder;
|
||||
use t::lib::Mocks;
|
||||
|
||||
my $schema = Koha::Database->new->schema;
|
||||
my $builder = t::lib::TestBuilder->new;
|
||||
|
||||
subtest 'connect() tests' => sub {
|
||||
plan tests => 2;
|
||||
|
||||
my $transport = $builder->build_object(
|
||||
{
|
||||
class => 'Koha::File::Transports',
|
||||
value => { transport => 'sftp', password => 'testpass' }
|
||||
}
|
||||
);
|
||||
|
||||
can_ok( $transport, 'connect' );
|
||||
dies_ok { $transport->connect } 'connect() should die without proper setup';
|
||||
};
|
||||
|
||||
subtest 'upload_file() tests' => sub {
|
||||
plan tests => 1;
|
||||
my $transport = $builder->build_object(
|
||||
{
|
||||
class => 'Koha::File::Transports',
|
||||
value => { transport => 'sftp', password => 'testpass' }
|
||||
}
|
||||
);
|
||||
|
||||
can_ok( $transport, 'upload_file' );
|
||||
};
|
||||
|
||||
subtest 'download_file() tests' => sub {
|
||||
plan tests => 1;
|
||||
my $transport = $builder->build_object(
|
||||
{
|
||||
class => 'Koha::File::Transports',
|
||||
value => { transport => 'sftp', password => 'testpass' }
|
||||
}
|
||||
);
|
||||
|
||||
can_ok( $transport, 'download_file' );
|
||||
};
|
||||
|
||||
subtest 'change_directory() tests' => sub {
|
||||
plan tests => 1;
|
||||
my $transport = $builder->build_object(
|
||||
{
|
||||
class => 'Koha::File::Transports',
|
||||
value => { transport => 'sftp', password => 'testpass' }
|
||||
}
|
||||
);
|
||||
|
||||
can_ok( $transport, 'change_directory' );
|
||||
};
|
||||
|
||||
subtest 'list_files() tests' => sub {
|
||||
plan tests => 1;
|
||||
my $transport = $builder->build_object(
|
||||
{
|
||||
class => 'Koha::File::Transports',
|
||||
value => { transport => 'sftp', password => 'testpass' }
|
||||
}
|
||||
);
|
||||
|
||||
can_ok( $transport, 'list_files' );
|
||||
};
|
||||
|
||||
1;
|
||||
Loading…
Reference in New Issue