Compare commits
5 Commits
rc
...
development
| Author | SHA1 | Date | |
|---|---|---|---|
| affe2db36a | |||
| 0c4ba5756b | |||
| 896c4c597e | |||
| a77458a24a | |||
| 937e38bcc6 |
@@ -5,7 +5,7 @@
|
|||||||
<display-name>Package - MokoSuiteBackup</display-name>
|
<display-name>Package - MokoSuiteBackup</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.23.00-dev</version>
|
<version>01.23.01-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.23.00
|
# VERSION: 01.23.01
|
||||||
# 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"
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
# MokoSuiteBackup
|
# MokoSuiteBackup
|
||||||
|
|
||||||
<!-- VERSION: 01.23.00 -->
|
<!-- VERSION: 01.23.01 -->
|
||||||
|
|
||||||
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.00</version>
|
<version>01.23.01-dev</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.00</version>
|
<version>01.23.01-dev</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>
|
||||||
|
|||||||
@@ -0,0 +1,173 @@
|
|||||||
|
<?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.00</version>
|
<version>01.23.01-dev</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.00</version>
|
<version>01.23.01-dev</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.00</version>
|
<version>01.23.01-dev</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.00</version>
|
<version>01.23.01-dev</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.00</version>
|
<version>01.23.01-dev</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.00</version>
|
<version>01.23.01-dev</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.00</version>
|
<version>01.23.01-dev</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.00</version>
|
<version>01.23.01-dev</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>
|
||||||
|
|||||||
Reference in New Issue
Block a user