Compare commits
5 Commits
development
..
rc
| Author | SHA1 | Date | |
|---|---|---|---|
| 91ab8a1f1c | |||
| fed7e4bb9c | |||
| 291f09223d | |||
| 674fd0f6b9 | |||
| 0d2e4b0c01 |
@@ -1,21 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<mokoplatform xmlns="https://standards.mokoconsulting.tech/mokoplatform/1.0" schema-version="1.0">
|
|
||||||
<identity>
|
|
||||||
<name>MokoSuiteBackup</name>
|
|
||||||
<display-name>Package - MokoSuiteBackup</display-name>
|
|
||||||
<org>MokoConsulting</org>
|
|
||||||
<description>Full-site backup and restore for Joomla — database, files, and configuration</description>
|
|
||||||
<version>01.23.01-dev</version>
|
|
||||||
<license spdx="GPL-3.0-or-later">GNU General Public License v3</license>
|
|
||||||
</identity>
|
|
||||||
<governance>
|
|
||||||
<platform>joomla</platform>
|
|
||||||
<standards-version>05.00.00</standards-version>
|
|
||||||
<standards-source>https://git.mokoconsulting.tech/MokoConsulting/mokoplatform</standards-source>
|
|
||||||
</governance>
|
|
||||||
<build>
|
|
||||||
<language>PHP</language>
|
|
||||||
<package-type>joomla-extension</package-type>
|
|
||||||
<entry-point>source/</entry-point>
|
|
||||||
</build>
|
|
||||||
</mokoplatform>
|
|
||||||
@@ -5,7 +5,7 @@
|
|||||||
# FILE INFORMATION
|
# FILE INFORMATION
|
||||||
# DEFGROUP: Gitea.Workflow
|
# DEFGROUP: Gitea.Workflow
|
||||||
# INGROUP: mokoplatform.Automation
|
# INGROUP: mokoplatform.Automation
|
||||||
# VERSION: 01.23.01
|
# VERSION: 01.25.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"
|
||||||
|
|||||||
+4
-4
@@ -1,6 +1,10 @@
|
|||||||
# Changelog
|
# Changelog
|
||||||
## [Unreleased]
|
## [Unreleased]
|
||||||
|
|
||||||
|
## [01.25.00] --- 2026-06-19
|
||||||
|
|
||||||
|
## [01.24.00] --- 2026-06-19
|
||||||
|
|
||||||
## [01.23.00] --- 2026-06-18
|
## [01.23.00] --- 2026-06-18
|
||||||
|
|
||||||
## [01.21.00] --- 2026-06-16
|
## [01.21.00] --- 2026-06-16
|
||||||
@@ -13,7 +17,3 @@
|
|||||||
- Use `margin-inline-end` instead of `margin-right` for RTL layout support
|
- Use `margin-inline-end` instead of `margin-right` for RTL layout support
|
||||||
|
|
||||||
## [01.08.00] --- 2026-06-07
|
## [01.08.00] --- 2026-06-07
|
||||||
|
|
||||||
## [01.07.00] --- 2026-06-07
|
|
||||||
|
|
||||||
## [01.06.00] --- 2026-06-07
|
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
# MokoSuiteBackup
|
# MokoSuiteBackup
|
||||||
|
|
||||||
<!-- VERSION: 01.23.01 -->
|
<!-- VERSION: 01.25.00 -->
|
||||||
|
|
||||||
Full-site backup and restore for Joomla — database, files, and configuration.
|
Full-site backup and restore for Joomla — database, files, and configuration.
|
||||||
|
|
||||||
|
|||||||
+1
-1
@@ -7,7 +7,7 @@
|
|||||||
-->
|
-->
|
||||||
<extension type="plugin" group="webservices" method="upgrade">
|
<extension type="plugin" group="webservices" method="upgrade">
|
||||||
<name>Web Services - MokoSuiteBackup</name>
|
<name>Web Services - MokoSuiteBackup</name>
|
||||||
<version>01.23.01-dev</version>
|
<version>01.25.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>
|
||||||
|
|||||||
@@ -7,7 +7,7 @@
|
|||||||
-->
|
-->
|
||||||
<extension type="component" method="upgrade">
|
<extension type="component" method="upgrade">
|
||||||
<name>MokoSuiteBackup</name>
|
<name>MokoSuiteBackup</name>
|
||||||
<version>01.23.01-dev</version>
|
<version>01.25.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>
|
||||||
|
|||||||
@@ -1,173 +0,0 @@
|
|||||||
<?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\Utility;
|
|
||||||
|
|
||||||
defined('_JEXEC') or die;
|
|
||||||
|
|
||||||
use Joomla\CMS\Factory;
|
|
||||||
use Joomla\Database\DatabaseInterface;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Provides a public API for external plugins (e.g. MokoSuiteClient bridge)
|
|
||||||
* to query backup status without depending on internal model internals.
|
|
||||||
*
|
|
||||||
* @since 01.22.07
|
|
||||||
*/
|
|
||||||
class BackupStatusHelper
|
|
||||||
{
|
|
||||||
/**
|
|
||||||
* Get a summary of the latest backup status.
|
|
||||||
*
|
|
||||||
* Returns an array suitable for inclusion in heartbeat payloads.
|
|
||||||
*
|
|
||||||
* @param int $staleDays Days without backup before status is degraded.
|
|
||||||
*
|
|
||||||
* @return array
|
|
||||||
*/
|
|
||||||
public static function getStatus(int $staleDays = 7): array
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
$db = Factory::getContainer()->get(DatabaseInterface::class);
|
|
||||||
}
|
|
||||||
catch (\Throwable $e)
|
|
||||||
{
|
|
||||||
return ['installed' => true, 'status' => 'error', 'message' => 'Database unavailable'];
|
|
||||||
}
|
|
||||||
|
|
||||||
// Most recently inserted backup record (by ID, any status)
|
|
||||||
$query = $db->getQuery(true)
|
|
||||||
->select([
|
|
||||||
$db->quoteName('id'),
|
|
||||||
$db->quoteName('description'),
|
|
||||||
$db->quoteName('status'),
|
|
||||||
$db->quoteName('backup_type'),
|
|
||||||
$db->quoteName('total_size'),
|
|
||||||
$db->quoteName('backupstart'),
|
|
||||||
$db->quoteName('backupend'),
|
|
||||||
$db->quoteName('origin'),
|
|
||||||
$db->quoteName('filesexist'),
|
|
||||||
])
|
|
||||||
->from($db->quoteName('#__mokosuitebackup_records'))
|
|
||||||
->order($db->quoteName('id') . ' DESC');
|
|
||||||
|
|
||||||
$db->setQuery($query, 0, 1);
|
|
||||||
$latest = $db->loadObject();
|
|
||||||
|
|
||||||
if (!$latest)
|
|
||||||
{
|
|
||||||
return [
|
|
||||||
'installed' => true,
|
|
||||||
'status' => 'degraded',
|
|
||||||
'message' => 'No backups found',
|
|
||||||
];
|
|
||||||
}
|
|
||||||
|
|
||||||
$db->setQuery(
|
|
||||||
$db->getQuery(true)
|
|
||||||
->select('COUNT(*)')
|
|
||||||
->from($db->quoteName('#__mokosuitebackup_records'))
|
|
||||||
->where($db->quoteName('status') . ' = ' . $db->quote('complete'))
|
|
||||||
);
|
|
||||||
$totalBackups = (int) $db->loadResult();
|
|
||||||
|
|
||||||
$cutoff = date('Y-m-d H:i:s', strtotime("-{$staleDays} days"));
|
|
||||||
$db->setQuery(
|
|
||||||
$db->getQuery(true)
|
|
||||||
->select('COUNT(*)')
|
|
||||||
->from($db->quoteName('#__mokosuitebackup_records'))
|
|
||||||
->where($db->quoteName('status') . ' = ' . $db->quote('complete'))
|
|
||||||
->where($db->quoteName('backupstart') . ' >= ' . $db->quote($cutoff))
|
|
||||||
);
|
|
||||||
$recentBackups = (int) $db->loadResult();
|
|
||||||
|
|
||||||
// Failures in last 7 days
|
|
||||||
$db->setQuery(
|
|
||||||
$db->getQuery(true)
|
|
||||||
->select('COUNT(*)')
|
|
||||||
->from($db->quoteName('#__mokosuitebackup_records'))
|
|
||||||
->where($db->quoteName('status') . ' = ' . $db->quote('fail'))
|
|
||||||
->where($db->quoteName('backupstart') . ' >= ' . $db->quote($cutoff))
|
|
||||||
);
|
|
||||||
$failCount7d = (int) $db->loadResult();
|
|
||||||
|
|
||||||
// Determine overall status
|
|
||||||
$daysSince = 999;
|
|
||||||
|
|
||||||
if (!empty($latest->backupstart) && $latest->backupstart !== '0000-00-00 00:00:00')
|
|
||||||
{
|
|
||||||
$daysSince = (int) ((time() - strtotime($latest->backupstart)) / 86400);
|
|
||||||
}
|
|
||||||
|
|
||||||
$status = 'ok';
|
|
||||||
|
|
||||||
if ($latest->status === 'fail')
|
|
||||||
{
|
|
||||||
$status = 'degraded';
|
|
||||||
}
|
|
||||||
elseif ($latest->status !== 'complete')
|
|
||||||
{
|
|
||||||
$status = ($latest->status === 'running') ? 'ok' : 'degraded';
|
|
||||||
}
|
|
||||||
elseif ($daysSince > $staleDays)
|
|
||||||
{
|
|
||||||
$status = 'degraded';
|
|
||||||
}
|
|
||||||
|
|
||||||
$sizeMb = $latest->total_size
|
|
||||||
? round($latest->total_size / 1048576)
|
|
||||||
: null;
|
|
||||||
|
|
||||||
return [
|
|
||||||
'installed' => true,
|
|
||||||
'status' => $status,
|
|
||||||
'last_backup' => $latest->backupstart,
|
|
||||||
'last_status' => $latest->status,
|
|
||||||
'last_size_mb' => $sizeMb,
|
|
||||||
'days_since' => $daysSince,
|
|
||||||
'backup_type' => $latest->backup_type,
|
|
||||||
'origin' => $latest->origin,
|
|
||||||
'total_backups' => $totalBackups,
|
|
||||||
'recent_7d' => $recentBackups,
|
|
||||||
'fail_count_7d' => $failCount7d,
|
|
||||||
'files_exist' => (bool) $latest->filesexist,
|
|
||||||
'description' => $latest->description,
|
|
||||||
];
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Check if MokoSuiteBackup component is installed.
|
|
||||||
*
|
|
||||||
* Useful for external plugins that want to check before calling getStatus().
|
|
||||||
*
|
|
||||||
* @return bool
|
|
||||||
*/
|
|
||||||
public static function isInstalled(): bool
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
$db = Factory::getContainer()->get(DatabaseInterface::class);
|
|
||||||
|
|
||||||
$query = $db->getQuery(true)
|
|
||||||
->select('COUNT(*)')
|
|
||||||
->from($db->quoteName('#__extensions'))
|
|
||||||
->where($db->quoteName('element') . ' = ' . $db->quote('com_mokosuitebackup'))
|
|
||||||
->where($db->quoteName('type') . ' = ' . $db->quote('component'));
|
|
||||||
|
|
||||||
$db->setQuery($query);
|
|
||||||
|
|
||||||
return (int) $db->loadResult() > 0;
|
|
||||||
}
|
|
||||||
catch (\Throwable $e)
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -7,7 +7,7 @@
|
|||||||
-->
|
-->
|
||||||
<extension type="plugin" group="actionlog" method="upgrade">
|
<extension type="plugin" group="actionlog" method="upgrade">
|
||||||
<name>Action Log - MokoSuiteBackup</name>
|
<name>Action Log - MokoSuiteBackup</name>
|
||||||
<version>01.23.01-dev</version>
|
<version>01.25.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>
|
||||||
|
|||||||
@@ -7,7 +7,7 @@
|
|||||||
-->
|
-->
|
||||||
<extension type="plugin" group="console" method="upgrade">
|
<extension type="plugin" group="console" method="upgrade">
|
||||||
<name>Console - MokoSuiteBackup</name>
|
<name>Console - MokoSuiteBackup</name>
|
||||||
<version>01.23.01-dev</version>
|
<version>01.25.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>
|
||||||
|
|||||||
@@ -7,7 +7,7 @@
|
|||||||
-->
|
-->
|
||||||
<extension type="plugin" group="content" method="upgrade">
|
<extension type="plugin" group="content" method="upgrade">
|
||||||
<name>Content - MokoSuiteBackup</name>
|
<name>Content - MokoSuiteBackup</name>
|
||||||
<version>01.23.01-dev</version>
|
<version>01.25.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>Quick Icon - MokoSuiteBackup</name>
|
<name>Quick Icon - MokoSuiteBackup</name>
|
||||||
<version>01.23.01-dev</version>
|
<version>01.25.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>
|
||||||
|
|||||||
@@ -7,7 +7,7 @@
|
|||||||
-->
|
-->
|
||||||
<extension type="plugin" group="system" method="upgrade">
|
<extension type="plugin" group="system" method="upgrade">
|
||||||
<name>System - MokoSuiteBackup</name>
|
<name>System - MokoSuiteBackup</name>
|
||||||
<version>01.23.01-dev</version>
|
<version>01.25.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>
|
||||||
|
|||||||
@@ -7,7 +7,7 @@
|
|||||||
-->
|
-->
|
||||||
<extension type="plugin" group="task" method="upgrade">
|
<extension type="plugin" group="task" method="upgrade">
|
||||||
<name>Task - MokoSuiteBackup</name>
|
<name>Task - MokoSuiteBackup</name>
|
||||||
<version>01.23.01-dev</version>
|
<version>01.25.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>
|
||||||
|
|||||||
@@ -7,7 +7,7 @@
|
|||||||
-->
|
-->
|
||||||
<extension type="plugin" group="webservices" method="upgrade">
|
<extension type="plugin" group="webservices" method="upgrade">
|
||||||
<name>Web Services - MokoSuiteBackup</name>
|
<name>Web Services - MokoSuiteBackup</name>
|
||||||
<version>01.23.01-dev</version>
|
<version>01.25.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 - MokoSuiteBackup</name>
|
<name>Package - MokoSuiteBackup</name>
|
||||||
<packagename>mokosuitebackup</packagename>
|
<packagename>mokosuitebackup</packagename>
|
||||||
<version>01.23.01-dev</version>
|
<version>01.25.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>
|
||||||
|
|||||||
@@ -1,98 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @package MokoSuiteBackup
|
|
||||||
* @subpackage plg_webservices_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
|
|
||||||
*
|
|
||||||
* REST API endpoints — wire-compatible with the mcp_mokosuitebackup MCP server.
|
|
||||||
*
|
|
||||||
* Akeeba-compatible routes:
|
|
||||||
* POST /api/index.php/v1/mokosuitebackup/backup — Start backup
|
|
||||||
* GET /api/index.php/v1/mokosuitebackup/backups — List records
|
|
||||||
* DELETE /api/index.php/v1/mokosuitebackup/backup/:id — Delete record
|
|
||||||
* GET /api/index.php/v1/mokosuitebackup/backup/:id/download — Download archive
|
|
||||||
* GET /api/index.php/v1/mokosuitebackup/profiles — List profiles
|
|
||||||
*/
|
|
||||||
|
|
||||||
namespace Joomla\Plugin\WebServices\MokoSuiteBackup\Extension;
|
|
||||||
|
|
||||||
defined('_JEXEC') or die;
|
|
||||||
|
|
||||||
use Joomla\CMS\Plugin\CMSPlugin;
|
|
||||||
use Joomla\CMS\Router\ApiRouter;
|
|
||||||
use Joomla\Event\Event;
|
|
||||||
use Joomla\Event\SubscriberInterface;
|
|
||||||
use Joomla\Router\Route;
|
|
||||||
|
|
||||||
final class MokoSuiteBackupWebServices extends CMSPlugin implements SubscriberInterface
|
|
||||||
{
|
|
||||||
protected $autoloadLanguage = true;
|
|
||||||
|
|
||||||
public static function getSubscribedEvents(): array
|
|
||||||
{
|
|
||||||
return [
|
|
||||||
'onBeforeApiRoute' => 'onBeforeApiRoute',
|
|
||||||
];
|
|
||||||
}
|
|
||||||
|
|
||||||
public function onBeforeApiRoute(Event $event): void
|
|
||||||
{
|
|
||||||
/** @var ApiRouter $router */
|
|
||||||
[$router] = array_values($event->getArguments());
|
|
||||||
|
|
||||||
$defaults = [
|
|
||||||
'component' => 'com_mokosuitebackup',
|
|
||||||
'public' => false,
|
|
||||||
];
|
|
||||||
|
|
||||||
// Standard CRUD for backup records
|
|
||||||
$router->createCRUDRoutes('v1/mokosuitebackup/backups', 'backups', $defaults);
|
|
||||||
|
|
||||||
// Start a backup (POST)
|
|
||||||
$router->addRoute(
|
|
||||||
new Route(
|
|
||||||
['POST'],
|
|
||||||
'v1/mokosuitebackup/backup',
|
|
||||||
'backups.backup',
|
|
||||||
[],
|
|
||||||
$defaults
|
|
||||||
)
|
|
||||||
);
|
|
||||||
|
|
||||||
// Delete a backup (DELETE)
|
|
||||||
$router->addRoute(
|
|
||||||
new Route(
|
|
||||||
['DELETE'],
|
|
||||||
'v1/mokosuitebackup/backup/:id',
|
|
||||||
'backups.delete',
|
|
||||||
['id' => '(\d+)'],
|
|
||||||
$defaults
|
|
||||||
)
|
|
||||||
);
|
|
||||||
|
|
||||||
// Download a backup archive (GET)
|
|
||||||
$router->addRoute(
|
|
||||||
new Route(
|
|
||||||
['GET'],
|
|
||||||
'v1/mokosuitebackup/backup/:id/download',
|
|
||||||
'backups.download',
|
|
||||||
['id' => '(\d+)'],
|
|
||||||
$defaults
|
|
||||||
)
|
|
||||||
);
|
|
||||||
|
|
||||||
// List backup profiles (GET)
|
|
||||||
$router->addRoute(
|
|
||||||
new Route(
|
|
||||||
['GET'],
|
|
||||||
'v1/mokosuitebackup/profiles',
|
|
||||||
'backups.profiles',
|
|
||||||
[],
|
|
||||||
$defaults
|
|
||||||
)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
<!DOCTYPE html><title></title>
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
<!DOCTYPE html><title></title>
|
|
||||||
Reference in New Issue
Block a user