dae30161ae
Universal: PR Check / Branch Policy (pull_request) Failing after 2s
Joomla: Extension CI / Lint & Validate (pull_request) Failing after 8s
Joomla: Extension CI / Release Readiness Check (pull_request) Failing after 5s
Generic: Repo Health / Site Health (pull_request) Has been skipped
Generic: Repo Health / Access control (pull_request) Successful in 1s
Universal: PR Check / Validate PR (pull_request) Failing after 7s
Universal: PR Check / Secret Scan (pull_request) Successful in 8s
RC Revert / Rename rc/ back to dev/ (pull_request) Has been skipped
Universal: Build & Release / Promote to RC (pull_request) Has been skipped
Branch Cleanup / Delete merged branch (pull_request) Successful in 2s
Universal: Workflow Sync Trigger / Sync workflows to live repos (pull_request) Failing after 5s
Joomla: Metadata Validation / Validate Joomla Metadata (pull_request) Successful in 41s
Universal: Build & Release / Build & Release Pipeline (pull_request) Successful in 22s
Joomla: Extension CI / Tests (PHP 8.2) (pull_request) Has been cancelled
Joomla: Extension CI / Tests (PHP 8.3) (pull_request) Has been cancelled
Joomla: Extension CI / PHPStan Analysis (pull_request) Has been cancelled
Joomla: Extension CI / Build RC Pre-Release (pull_request) Has been cancelled
Universal: PR Check / Build RC Package (pull_request) Has been cancelled
Universal: PR Check / Report Issues (pull_request) Has been cancelled
Generic: Repo Health / Scripts governance (pull_request) Has been cancelled
Generic: Repo Health / Repository health (pull_request) Has been cancelled
Generic: Repo Health / Report Issues (pull_request) Has been cancelled
New #__mokosuitebackup_remotes table stores remote destinations with JSON params per type (SFTP/S3/GDrive/FTP). Each profile can have multiple enabled destinations — the engine uploads to all of them. Database: - New table with profile_id FK, type, enabled, params JSON, ordering - Migration auto-converts existing profile remote columns to new table - RemoteTable, RemoteModel, RemotesModel classes Engine: - BackupEngine: loadRemoteDestinations() + createUploaderFromParams() iterates all enabled remotes, falls back to legacy columns - SteppedBackupEngine: one upload step per remote destination, persisted via session.remoteDestinations + remoteIndex - Local copy only deleted when ALL uploads succeed UI: - Profile edit: "Remote Destinations" linked table with AJAX CRUD - Add/edit modal with type selector showing dynamic fields - Toggle enabled/disabled, delete with confirmation - Legacy fields hidden when remotes configured, shown as fallback - Secrets masked in responses, merged from DB on save Closes #97
95 lines
2.1 KiB
PHP
95 lines
2.1 KiB
PHP
<?php
|
|
|
|
/**
|
|
* @package MokoSuiteBackup
|
|
* @subpackage com_mokosuitebackup
|
|
* @author Moko Consulting <hello@mokoconsulting.tech>
|
|
* @copyright Copyright (C) 2026 Moko Consulting. All rights reserved.
|
|
* @license GNU General Public License version 3 or later; see LICENSE
|
|
*/
|
|
|
|
namespace Joomla\Component\MokoSuiteBackup\Administrator\Table;
|
|
|
|
defined('_JEXEC') or die;
|
|
|
|
use Joomla\CMS\Table\Table;
|
|
use Joomla\Database\DatabaseDriver;
|
|
|
|
class RemoteTable extends Table
|
|
{
|
|
public function __construct(DatabaseDriver $db)
|
|
{
|
|
parent::__construct('#__mokosuitebackup_remotes', 'id', $db);
|
|
}
|
|
|
|
public function check(): bool
|
|
{
|
|
if (empty($this->profile_id)) {
|
|
$this->setError('Profile ID is required.');
|
|
|
|
return false;
|
|
}
|
|
|
|
$validTypes = ['sftp', 's3', 'google_drive', 'ftp'];
|
|
|
|
if (empty($this->type) || !\in_array($this->type, $validTypes, true)) {
|
|
$this->setError('Invalid remote type. Must be one of: ' . implode(', ', $validTypes));
|
|
|
|
return false;
|
|
}
|
|
|
|
if (empty($this->title)) {
|
|
$this->title = ucfirst(str_replace('_', ' ', $this->type)) . ' Remote';
|
|
}
|
|
|
|
// Ensure params is valid JSON
|
|
if (!empty($this->params) && \is_string($this->params)) {
|
|
$decoded = json_decode($this->params);
|
|
|
|
if (json_last_error() !== JSON_ERROR_NONE) {
|
|
$this->setError('Remote params must be valid JSON.');
|
|
|
|
return false;
|
|
}
|
|
}
|
|
|
|
$now = date('Y-m-d H:i:s');
|
|
|
|
if (empty($this->created) || $this->created === '0000-00-00 00:00:00') {
|
|
$this->created = $now;
|
|
}
|
|
|
|
$this->modified = $now;
|
|
|
|
return true;
|
|
}
|
|
|
|
/**
|
|
* Get the params as a decoded object.
|
|
*
|
|
* @return object
|
|
*/
|
|
public function getParams(): object
|
|
{
|
|
if (empty($this->params)) {
|
|
return (object) [];
|
|
}
|
|
|
|
$decoded = json_decode($this->params);
|
|
|
|
return \is_object($decoded) ? $decoded : (object) [];
|
|
}
|
|
|
|
/**
|
|
* Set params from an array or object, encoding to JSON.
|
|
*
|
|
* @param array|object $params The parameters to encode
|
|
*
|
|
* @return void
|
|
*/
|
|
public function setParams(array|object $params): void
|
|
{
|
|
$this->params = json_encode($params, JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE);
|
|
}
|
|
}
|