Compare commits
4 Commits
development
..
dev
| Author | SHA1 | Date | |
|---|---|---|---|
| e5fb88e1a4 | |||
| df44518611 | |||
| 5e0683c0c7 | |||
| bbf3dcd449 |
@@ -5,7 +5,7 @@
|
|||||||
<display-name>Package - MokoJoomBackup</display-name>
|
<display-name>Package - MokoJoomBackup</display-name>
|
||||||
<org>MokoConsulting</org>
|
<org>MokoConsulting</org>
|
||||||
<description>Full-site backup and restore for Joomla — database, files, and configuration</description>
|
<description>Full-site backup and restore for Joomla — database, files, and configuration</description>
|
||||||
<version>01.06.01-dev</version>
|
<version>01.07.00-dev</version>
|
||||||
<license spdx="GPL-3.0-or-later">GNU General Public License v3</license>
|
<license spdx="GPL-3.0-or-later">GNU General Public License v3</license>
|
||||||
</identity>
|
</identity>
|
||||||
<governance>
|
<governance>
|
||||||
|
|||||||
@@ -5,7 +5,7 @@
|
|||||||
# FILE INFORMATION
|
# FILE INFORMATION
|
||||||
# DEFGROUP: Gitea.Workflow
|
# DEFGROUP: Gitea.Workflow
|
||||||
# INGROUP: mokoplatform.Automation
|
# INGROUP: mokoplatform.Automation
|
||||||
# VERSION: 01.06.01
|
# VERSION: 01.07.00
|
||||||
# BRIEF: Auto-create feature branch when an issue is opened
|
# BRIEF: Auto-create feature branch when an issue is opened
|
||||||
|
|
||||||
name: "Universal: Issue Branch"
|
name: "Universal: Issue Branch"
|
||||||
|
|||||||
+2
-42
@@ -1,6 +1,8 @@
|
|||||||
# Changelog
|
# Changelog
|
||||||
## [Unreleased]
|
## [Unreleased]
|
||||||
|
|
||||||
|
## [01.07.00] --- 2026-06-07
|
||||||
|
|
||||||
## [01.06.00] --- 2026-06-07
|
## [01.06.00] --- 2026-06-07
|
||||||
|
|
||||||
|
|
||||||
@@ -28,45 +30,3 @@
|
|||||||
|
|
||||||
|
|
||||||
## [01.03.00] --- 2026-06-07
|
## [01.03.00] --- 2026-06-07
|
||||||
|
|
||||||
|
|
||||||
## [01.02.00] --- 2026-06-07
|
|
||||||
|
|
||||||
### Added
|
|
||||||
- Joomla-styled standalone installer (MokoRestore) with 7-step wizard, admin password reset, and client provisioning
|
|
||||||
- Web cron trigger for shared hosting without crontab — URL-based backup with secret word, IP whitelist
|
|
||||||
- Placeholder support for backup directories and archive filenames ([host], [date], [site_name], [profile_name], etc.)
|
|
||||||
- FolderPicker JS placeholder resolution — resolves [site_name]/[host] when browsing, reverse-replaces on selection for portable profiles
|
|
||||||
- Archive Name Format field on backup profiles with customizable filename templates
|
|
||||||
- Interactive directory tree browser for exclude filters (replaces plain text input)
|
|
||||||
- Backup log viewer modal in backup records list and inline in detail view
|
|
||||||
- Clickable dashboard status tiles linking to backup records, detail views, and scheduled tasks
|
|
||||||
- Table exclusion now supports separate Data and Structure checkboxes (backward compatible)
|
|
||||||
- Tar.gz archive format support
|
|
||||||
- User group notifications for backup events
|
|
||||||
- Folder picker field with live server directory browsing
|
|
||||||
- Default directory dashboard warning when backups are stored inside web root
|
|
||||||
- Backup log files written alongside archives (.log)
|
|
||||||
- Backup detail view with checksum, file path, DB size, and embedded log
|
|
||||||
- Browser beforeunload warning during backup progress
|
|
||||||
|
|
||||||
### Changed
|
|
||||||
- Renamed all extension elements from mokobackup to mokojoombackup (pkg, com, all plugins, DB tables, namespaces, language keys)
|
|
||||||
- Renamed source directory from src/ to source/ per MokoStandards convention
|
|
||||||
- Dashboard health check shows actual resolved backup directory path from profiles
|
|
||||||
- Update site post-install notice links to filtered list view (avoids Joomla core bug)
|
|
||||||
- License warning suppressed when download key is already configured
|
|
||||||
- Download key preserved across package updates via preflight/postflight backup
|
|
||||||
|
|
||||||
### Fixed
|
|
||||||
- Download ERR_INVALID_RESPONSE — flush output buffers before sending file headers
|
|
||||||
- Backup directory path resolution for absolute paths outside web root
|
|
||||||
- Schema migrations consolidated to version within extension range
|
|
||||||
- PSR-4 class file naming (MokoBackup*.php → MokoJoomBackup*.php)
|
|
||||||
- Nested package directories from rename flattened
|
|
||||||
- INSERT IGNORE for default profile prevents duplicate key on update
|
|
||||||
- ActionlogsHelper::getIp() replaced — method does not exist in Joomla 5
|
|
||||||
- Console plugin namespace and quickicon translation keys
|
|
||||||
- CLI exit codes and SQL schema defaults
|
|
||||||
- Component Options page (added config.xml)
|
|
||||||
- Placeholder-aware directory checks in FolderPicker and dashboard health
|
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
# MokoJoomBackup
|
# MokoJoomBackup
|
||||||
|
|
||||||
<!-- VERSION: 01.06.01 -->
|
<!-- VERSION: 01.07.00 -->
|
||||||
|
|
||||||
Full-site backup and restore for Joomla — database, files, and configuration.
|
Full-site backup and restore for Joomla — database, files, and configuration.
|
||||||
|
|
||||||
|
|||||||
@@ -8,7 +8,7 @@
|
|||||||
-->
|
-->
|
||||||
<extension type="component" method="upgrade">
|
<extension type="component" method="upgrade">
|
||||||
<name>com_mokojoombackup</name>
|
<name>com_mokojoombackup</name>
|
||||||
<version>01.06.01-dev</version>
|
<version>01.07.00</version>
|
||||||
<creationDate>2026-06-02</creationDate>
|
<creationDate>2026-06-02</creationDate>
|
||||||
<author>Moko Consulting</author>
|
<author>Moko Consulting</author>
|
||||||
<authorEmail>hello@mokoconsulting.tech</authorEmail>
|
<authorEmail>hello@mokoconsulting.tech</authorEmail>
|
||||||
|
|||||||
@@ -30,6 +30,7 @@ namespace Joomla\Component\MokoJoomBackup\Administrator\Engine;
|
|||||||
defined('_JEXEC') or die;
|
defined('_JEXEC') or die;
|
||||||
|
|
||||||
use Joomla\CMS\Factory;
|
use Joomla\CMS\Factory;
|
||||||
|
use Joomla\Component\MokoJoomBackup\Administrator\Utility\BackupDirectory;
|
||||||
|
|
||||||
class AkeebaImporter
|
class AkeebaImporter
|
||||||
{
|
{
|
||||||
@@ -484,7 +485,7 @@ class AkeebaImporter
|
|||||||
$dir = $config['akeeba.basic.output_directory'] ?? '';
|
$dir = $config['akeeba.basic.output_directory'] ?? '';
|
||||||
|
|
||||||
if (empty($dir) || $dir === '[DEFAULT_OUTPUT]') {
|
if (empty($dir) || $dir === '[DEFAULT_OUTPUT]') {
|
||||||
return 'administrator/components/com_mokojoombackup/backups';
|
return BackupDirectory::DEFAULT_RELATIVE;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Convert absolute path to relative
|
// Convert absolute path to relative
|
||||||
@@ -492,7 +493,7 @@ class AkeebaImporter
|
|||||||
$dir = ltrim(substr($dir, strlen(JPATH_ROOT)), '/\\');
|
$dir = ltrim(substr($dir, strlen(JPATH_ROOT)), '/\\');
|
||||||
}
|
}
|
||||||
|
|
||||||
return $dir ?: 'administrator/components/com_mokojoombackup/backups';
|
return $dir ?: BackupDirectory::DEFAULT_RELATIVE;
|
||||||
}
|
}
|
||||||
|
|
||||||
private function mapRemoteStorage(array $config): string
|
private function mapRemoteStorage(array $config): string
|
||||||
|
|||||||
@@ -8,7 +8,7 @@
|
|||||||
-->
|
-->
|
||||||
<extension type="plugin" group="actionlog" method="upgrade">
|
<extension type="plugin" group="actionlog" method="upgrade">
|
||||||
<name>plg_actionlog_mokojoombackup</name>
|
<name>plg_actionlog_mokojoombackup</name>
|
||||||
<version>01.06.01-dev</version>
|
<version>01.07.00</version>
|
||||||
<creationDate>2026-06-04</creationDate>
|
<creationDate>2026-06-04</creationDate>
|
||||||
<author>Moko Consulting</author>
|
<author>Moko Consulting</author>
|
||||||
<authorEmail>hello@mokoconsulting.tech</authorEmail>
|
<authorEmail>hello@mokoconsulting.tech</authorEmail>
|
||||||
|
|||||||
@@ -8,7 +8,7 @@
|
|||||||
-->
|
-->
|
||||||
<extension type="plugin" group="console" method="upgrade">
|
<extension type="plugin" group="console" method="upgrade">
|
||||||
<name>plg_console_mokojoombackup</name>
|
<name>plg_console_mokojoombackup</name>
|
||||||
<version>01.06.01-dev</version>
|
<version>01.07.00</version>
|
||||||
<creationDate>2026-06-04</creationDate>
|
<creationDate>2026-06-04</creationDate>
|
||||||
<author>Moko Consulting</author>
|
<author>Moko Consulting</author>
|
||||||
<authorEmail>hello@mokoconsulting.tech</authorEmail>
|
<authorEmail>hello@mokoconsulting.tech</authorEmail>
|
||||||
|
|||||||
@@ -8,7 +8,7 @@
|
|||||||
-->
|
-->
|
||||||
<extension type="plugin" group="content" method="upgrade">
|
<extension type="plugin" group="content" method="upgrade">
|
||||||
<name>plg_content_mokojoombackup</name>
|
<name>plg_content_mokojoombackup</name>
|
||||||
<version>01.06.01-dev</version>
|
<version>01.07.00</version>
|
||||||
<creationDate>2026-06-04</creationDate>
|
<creationDate>2026-06-04</creationDate>
|
||||||
<author>Moko Consulting</author>
|
<author>Moko Consulting</author>
|
||||||
<authorEmail>hello@mokoconsulting.tech</authorEmail>
|
<authorEmail>hello@mokoconsulting.tech</authorEmail>
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
<extension type="plugin" group="quickicon" method="upgrade">
|
<extension type="plugin" group="quickicon" method="upgrade">
|
||||||
<name>plg_quickicon_mokojoombackup</name>
|
<name>plg_quickicon_mokojoombackup</name>
|
||||||
<version>01.06.01-dev</version>
|
<version>01.07.00</version>
|
||||||
<creationDate>2026-06-02</creationDate>
|
<creationDate>2026-06-02</creationDate>
|
||||||
<author>Moko Consulting</author>
|
<author>Moko Consulting</author>
|
||||||
<authorEmail>hello@mokoconsulting.tech</authorEmail>
|
<authorEmail>hello@mokoconsulting.tech</authorEmail>
|
||||||
|
|||||||
@@ -8,7 +8,7 @@
|
|||||||
-->
|
-->
|
||||||
<extension type="plugin" group="system" method="upgrade">
|
<extension type="plugin" group="system" method="upgrade">
|
||||||
<name>plg_system_mokojoombackup</name>
|
<name>plg_system_mokojoombackup</name>
|
||||||
<version>01.06.01-dev</version>
|
<version>01.07.00</version>
|
||||||
<creationDate>2026-06-02</creationDate>
|
<creationDate>2026-06-02</creationDate>
|
||||||
<author>Moko Consulting</author>
|
<author>Moko Consulting</author>
|
||||||
<authorEmail>hello@mokoconsulting.tech</authorEmail>
|
<authorEmail>hello@mokoconsulting.tech</authorEmail>
|
||||||
|
|||||||
@@ -8,7 +8,7 @@
|
|||||||
-->
|
-->
|
||||||
<extension type="plugin" group="task" method="upgrade">
|
<extension type="plugin" group="task" method="upgrade">
|
||||||
<name>plg_task_mokojoombackup</name>
|
<name>plg_task_mokojoombackup</name>
|
||||||
<version>01.06.01-dev</version>
|
<version>01.07.00</version>
|
||||||
<creationDate>2026-06-02</creationDate>
|
<creationDate>2026-06-02</creationDate>
|
||||||
<author>Moko Consulting</author>
|
<author>Moko Consulting</author>
|
||||||
<authorEmail>hello@mokoconsulting.tech</authorEmail>
|
<authorEmail>hello@mokoconsulting.tech</authorEmail>
|
||||||
|
|||||||
@@ -8,7 +8,7 @@
|
|||||||
-->
|
-->
|
||||||
<extension type="plugin" group="webservices" method="upgrade">
|
<extension type="plugin" group="webservices" method="upgrade">
|
||||||
<name>plg_webservices_mokojoombackup</name>
|
<name>plg_webservices_mokojoombackup</name>
|
||||||
<version>01.06.01-dev</version>
|
<version>01.07.00</version>
|
||||||
<creationDate>2026-06-02</creationDate>
|
<creationDate>2026-06-02</creationDate>
|
||||||
<author>Moko Consulting</author>
|
<author>Moko Consulting</author>
|
||||||
<authorEmail>hello@mokoconsulting.tech</authorEmail>
|
<authorEmail>hello@mokoconsulting.tech</authorEmail>
|
||||||
|
|||||||
@@ -8,7 +8,7 @@
|
|||||||
<extension type="package" method="upgrade">
|
<extension type="package" method="upgrade">
|
||||||
<name>Package - MokoJoomBackup</name>
|
<name>Package - MokoJoomBackup</name>
|
||||||
<packagename>mokojoombackup</packagename>
|
<packagename>mokojoombackup</packagename>
|
||||||
<version>01.06.01-dev</version>
|
<version>01.07.00</version>
|
||||||
<creationDate>2026-06-02</creationDate>
|
<creationDate>2026-06-02</creationDate>
|
||||||
<author>Moko Consulting</author>
|
<author>Moko Consulting</author>
|
||||||
<authorEmail>hello@mokoconsulting.tech</authorEmail>
|
<authorEmail>hello@mokoconsulting.tech</authorEmail>
|
||||||
|
|||||||
+113
-2
@@ -211,14 +211,125 @@ class Pkg_MokoJoomBackupInstallerScript
|
|||||||
file_put_contents($index, '<!DOCTYPE html><title></title>');
|
file_put_contents($index, '<!DOCTYPE html><title></title>');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Create default scheduled task — every 30 days, profile 1
|
||||||
|
$this->createDefaultScheduledTask();
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($type === 'uninstall') {
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Sync submenu icons in #__menu (Joomla doesn't update icons on upgrades)
|
// Sync submenu icons in #__menu (Joomla doesn't update icons on upgrades)
|
||||||
$this->syncMenuIcons();
|
$this->syncMenuIcons();
|
||||||
|
|
||||||
// Warn if no license key configured (skip on uninstall)
|
// Warn if no license key configured
|
||||||
if ($type !== 'uninstall') {
|
|
||||||
$this->warnMissingLicenseKey();
|
$this->warnMissingLicenseKey();
|
||||||
|
|
||||||
|
// Warn if any profile still uses the default backup directory
|
||||||
|
$this->warnDefaultBackupDir();
|
||||||
|
|
||||||
|
// Remind user to review backup profile settings
|
||||||
|
if ($type === 'install') {
|
||||||
|
$profileUrl = Route::_('index.php?option=com_mokojoombackup&view=profiles');
|
||||||
|
|
||||||
|
Factory::getApplication()->enqueueMessage(
|
||||||
|
'<strong>Review Your Backup Settings</strong> — '
|
||||||
|
. 'A default backup profile has been created. Review the profile settings to configure '
|
||||||
|
. 'backup type, schedule, storage location, and notifications. '
|
||||||
|
. '<a href="' . $profileUrl . '" class="btn btn-sm btn-primary ms-2">Review Profiles</a>',
|
||||||
|
'info'
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private function warnDefaultBackupDir(): void
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
$db = Factory::getDbo();
|
||||||
|
$query = $db->getQuery(true)
|
||||||
|
->select('COUNT(*)')
|
||||||
|
->from($db->quoteName('#__mokojoombackup_profiles'))
|
||||||
|
->where($db->quoteName('published') . ' = 1')
|
||||||
|
->where('(' . $db->quoteName('backup_dir') . ' = ' . $db->quote('administrator/components/com_mokojoombackup/backups')
|
||||||
|
. ' OR ' . $db->quoteName('backup_dir') . ' = ' . $db->quote('[DEFAULT_DIR]')
|
||||||
|
. ' OR ' . $db->quoteName('backup_dir') . ' = ' . $db->quote('')
|
||||||
|
. ' OR ' . $db->quoteName('backup_dir') . ' IS NULL)');
|
||||||
|
$db->setQuery($query);
|
||||||
|
|
||||||
|
if ((int) $db->loadResult() > 0) {
|
||||||
|
$profileUrl = Route::_('index.php?option=com_mokojoombackup&view=profiles');
|
||||||
|
|
||||||
|
Factory::getApplication()->enqueueMessage(
|
||||||
|
'<strong>Backup Directory Warning</strong> — '
|
||||||
|
. 'One or more profiles store backups in the default directory inside the web root. '
|
||||||
|
. 'For better security, configure a backup directory outside the web root. '
|
||||||
|
. '<a href="' . $profileUrl . '" class="btn btn-sm btn-warning ms-2">Edit Profiles</a>',
|
||||||
|
'warning'
|
||||||
|
);
|
||||||
|
}
|
||||||
|
} catch (\Throwable $e) {
|
||||||
|
error_log('MokoJoomBackup: warnDefaultBackupDir() failed: ' . $e->getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private function createDefaultScheduledTask(): void
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
$db = Factory::getDbo();
|
||||||
|
|
||||||
|
// Check if a MokoJoomBackup task already exists
|
||||||
|
$query = $db->getQuery(true)
|
||||||
|
->select('COUNT(*)')
|
||||||
|
->from($db->quoteName('#__scheduler_tasks'))
|
||||||
|
->where($db->quoteName('type') . ' = ' . $db->quote('mokojoombackup.run_profile'));
|
||||||
|
$db->setQuery($query);
|
||||||
|
|
||||||
|
if ((int) $db->loadResult() > 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
$now = date('Y-m-d H:i:s');
|
||||||
|
|
||||||
|
$task = (object) [
|
||||||
|
'title' => 'MokoJoomBackup — Monthly Full Backup',
|
||||||
|
'type' => 'mokojoombackup.run_profile',
|
||||||
|
'execution_rules' => json_encode([
|
||||||
|
'rule-type' => 'interval-days',
|
||||||
|
'interval-days' => '30',
|
||||||
|
'exec-day' => '1',
|
||||||
|
'exec-time' => '03:00:00',
|
||||||
|
]),
|
||||||
|
'cron_rules' => json_encode([
|
||||||
|
'type' => 'interval',
|
||||||
|
'exp' => 'P30D',
|
||||||
|
]),
|
||||||
|
'state' => 1,
|
||||||
|
'params' => json_encode([
|
||||||
|
'profile_id' => 1,
|
||||||
|
'individual_log' => true,
|
||||||
|
'log_file' => '',
|
||||||
|
'notifications' => [
|
||||||
|
'success_mail' => '0',
|
||||||
|
'failure_mail' => '1',
|
||||||
|
'notification_failure_groups' => ['8'],
|
||||||
|
'fatal_failure_mail' => '1',
|
||||||
|
'notification_fatal_groups' => ['8'],
|
||||||
|
'orphan_mail' => '0',
|
||||||
|
],
|
||||||
|
]),
|
||||||
|
'priority' => 0,
|
||||||
|
'ordering' => 0,
|
||||||
|
'cli_exclusive' => 0,
|
||||||
|
'note' => '',
|
||||||
|
'created' => $now,
|
||||||
|
'created_by' => Factory::getApplication()->getIdentity()->id ?? 0,
|
||||||
|
'next_execution' => date('Y-m-d 03:00:00', strtotime('+1 day')),
|
||||||
|
];
|
||||||
|
|
||||||
|
$db->insertObject('#__scheduler_tasks', $task);
|
||||||
|
} catch (\Throwable $e) {
|
||||||
|
error_log('MokoJoomBackup: createDefaultScheduledTask() failed: ' . $e->getMessage());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user