Commit Graph

8 Commits

Author SHA1 Message Date
Martin Renvoize ac64e18ce6
Bug 40811: (follow-up) Fix list context bug and add comprehensive tests
This patch fixes a critical bug where plain_text_password() was called
in list context during hash construction. When a transport has no
password, the method's bare 'return' statement returns an empty list ()
in list context rather than undef, causing all subsequent key-value
pairs to shift positions. This resulted in malformed connection
parameters being passed to Net::SFTP::Foreign and Net::FTP.

Example of the bug:
  my %hash = (
    user => 'john',
    password => $self->plain_text_password,  # Returns () when no password
    timeout => 10
  );
  # Results in: (user => 'john', timeout => 10) instead of
  # (user => 'john', password => undef, timeout => 10)

Changes to code:
- Wrap plain_text_password calls with scalar() to force scalar context
  in both FTP.pm and SFTP.pm
- Make SFTP key and password authentication mutually exclusive using
  ternary operator
- Prefer key-based auth over password when both are available (SFTP)

Test plan:
1. Run t/db_dependent/Koha/File/Transport/FTP.t - should pass
2. Run t/db_dependent/Koha/File/Transport/SFTP.t - should pass
3. Verify tests cover:
   - Scalar context behavior with no password
   - FTP authentication with proper parameter passing
   - SFTP password-only authentication
   - SFTP key-only authentication
   - SFTP key preference when both key and password exist

Signed-off-by: Tomás Cohen Arazi <tomascohen@theke.io>
Signed-off-by: Lucas Gass <lucas@bywatersolutions.com>
2026-01-21 15:28:17 -07:00
Martin Renvoize b75d07acd5
Bug 40811: Implement dual API for file transports with simplified auto-management
This patch implements a dual API design for Koha::File::Transport, providing
both a simplified auto-managing API and a traditional explicit API for maximum
flexibility and ease of use.

DUAL API DESIGN
===============

Simplified API (Recommended):
  - Automatic connection management (no connect/disconnect needed)
  - Flexible per-operation directory control via options hashref
  - Stateless operations safe for concurrent usage

  Example:
    $transport->upload_file($local, $remote, { path => '/custom/' });
    $transport->download_file($remote, $local);  # Uses download_directory
    $transport->list_files({ path => '/incoming/' });

Traditional API (Explicit Control):
  - Manual connection/directory management when needed
  - Stateful directory operations via change_directory()
  - Ideal for multiple operations in the same directory

  Example:
    $transport->change_directory('/work/');
    $transport->upload_file($local, 'file1.txt');
    $transport->upload_file($local, 'file2.txt');
    my $files = $transport->list_files();

The APIs can be mixed - calling change_directory() explicitly switches to
manual mode and disables auto-management for subsequent operations.

STANDARDIZED TEMPLATE METHOD PATTERN
=====================================

All transport methods now follow a consistent pattern with clear separation
between public API (parent class) and protocol implementation (subclasses).

Public methods in Koha::File::Transport:
  - connect()          → Resets directory state, calls _connect()
  - disconnect()       → Resets directory state, calls _disconnect()
  - change_directory() → Sets manual mode flag, calls _change_directory()
  - upload_file()      → Manages connection/directory, calls _upload_file()
  - download_file()    → Manages connection/directory, calls _download_file()
  - list_files()       → Manages connection/directory, calls _list_files()
  - rename_file()      → Ensures connection, calls _rename_file()

Subclass responsibilities (SFTP/FTP/Local):
  - Implement _connect() - Protocol-specific connection logic
  - Implement _disconnect() - Protocol-specific disconnection logic
  - Implement _change_directory() - Protocol-specific directory change
  - Implement _upload_file() - Protocol-specific upload logic
  - Implement _download_file() - Protocol-specific download logic
  - Implement _list_files() - Protocol-specific listing logic
  - Implement _rename_file() - Protocol-specific rename logic
  - Implement _is_connected() - Protocol-specific connection check

Test plan:
  prove t/db_dependent/Koha/File/Transports.t

Signed-off-by: Kyle M Hall <kyle@bywatersolutions.com>
Signed-off-by: Tomás Cohen Arazi <tomascohen@theke.io>
Signed-off-by: Lucas Gass <lucas@bywatersolutions.com>
2026-01-21 15:28:17 -07:00
Martin Renvoize 51d5691e35
Bug 38489: Add rename_file method to transport system and Local transport class
This patch enhances the file transport system with file renaming
capabilities and adds a Local transport class for development/testing.

Changes:
- Add rename_file() method to base Transport class and SFTP/FTP subclasses
- Create Koha::File::Transport::Local for local directory operations
- Add 'local' transport type to polymorphic mapping
- Update transport instantiation to handle Local transport
- Add Local transport tests to verify polymorphic behavior
- Enhanced connect() method for Local transport validates directories

The rename_file functionality is needed for EDI file processing workflow
where files are renamed after download to mark them as processed.

Sponsored-by: ByWater Solutions
Signed-off-by: Hannah Dunne-Howrie <hdunne-howrie@westminster.gov.uk>
Signed-off-by: Lucas Gass <lucas@bywatersolutions.com>
2025-10-14 14:51:47 -06:00
Tomás Cohen Arazi 6b478e0da9
Bug 40163: (follow-up) Fix wrong GNU links and update test
Signed-off-by: Tomás Cohen Arazi <tomascohen@theke.io>
Signed-off-by: Lucas Gass <lucas@bywatersolutions.com>
2025-09-24 09:25:04 -06:00
Tomas Cohen Arazi a5f72d7362
Bug 39190: Rename id => file_transport_id and remove mapping
Signed-off-by: Tomas Cohen Arazi <tomascohen@theke.io>
Signed-off-by: Lucas Gass <lucas@bywatersolutions.com>
2025-09-19 13:23:25 -06:00
Tomas Cohen Arazi 7ec377f20c
Bug 39190: Regression tests for polymorphic object creation
This patch adds comprehensive tests to verify that Koha::File::Transports
correctly returns polymorphic objects based on the transport field value.

The tests cover:
- build_object() polymorphic creation
- search() with polymorphic resultset iteration
- find() with polymorphic object return

To test:
1. Apply this patch
2. Run:
   $ ktd --shell
  k$ prove t/db_dependent/Koha/File/Transports.t
=> FAIL: Tests fail - objects return base Koha::File::Transport
   instead of polymorphic Koha::File::Transport::SFTP/FTP classes

Signed-off-by: Tomas Cohen Arazi <tomascohen@theke.io>
Signed-off-by: Lucas Gass <lucas@bywatersolutions.com>
2025-09-19 13:23:24 -06:00
Martin Renvoize 277a02daeb
Bug 39190: Add key handling to SFTP Transports
We add triggers to store in the base class and then use them in the SFTP
transport class to write out the key file to the filesystem for later
use in connect.

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>
2025-09-19 13:23:15 -06:00
Martin Renvoize 3354bed6ef
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>
2025-09-19 13:23:14 -06:00