Initial xentral_oss_20.3.c9ffacf
This commit is contained in:
@@ -0,0 +1,101 @@
|
||||
<?php
|
||||
|
||||
namespace Xentral\Modules\Backup;
|
||||
|
||||
use Xentral\Components\Database\Database;
|
||||
use Xentral\Components\Database\Exception\DatabaseExceptionInterface;
|
||||
|
||||
/**
|
||||
* Class BackupGateway
|
||||
*
|
||||
* @package Xentral\Modules\Backup
|
||||
*/
|
||||
final class BackupGateway
|
||||
{
|
||||
/** @var Database $db */
|
||||
private $db;
|
||||
|
||||
/**
|
||||
* @param Database $db
|
||||
*/
|
||||
public function __construct(Database $db)
|
||||
{
|
||||
$this->db = $db;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
public function getTables()
|
||||
{
|
||||
return $this->db->fetchCol('SHOW TABLES');
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
public function getTablesChecksum()
|
||||
{
|
||||
$ahCheckSum = [];
|
||||
foreach ($this->getTables() as $sTable) {
|
||||
$ahCheckSum[$sTable] = 0;
|
||||
if ($hResult = $this->db->fetchRow('CHECKSUM TABLE ' . $sTable)) {
|
||||
$num = 0;
|
||||
try {
|
||||
$num = $this->db->fetchValue('SELECT COUNT(*) AS `anzahl` FROM ' . $sTable);
|
||||
} catch (DatabaseExceptionInterface $exception) {
|
||||
// nothing
|
||||
}
|
||||
$ahCheckSum[$sTable] = [
|
||||
'checksum' => array_key_exists('Checksum', $hResult) ? $hResult['Checksum'] : 0,
|
||||
'items' => $num,
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
return $ahCheckSum;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
public function getAdminUserIds()
|
||||
{
|
||||
$query = $this->db->select()
|
||||
->cols(['u.id'])
|
||||
->from('user AS u')
|
||||
->where('u.activ = ?', 1)
|
||||
->where('u.type = ?', 'admin');
|
||||
|
||||
return $this->db->fetchAll($query->getStatement(), $query->getBindValues());
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $id
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function getBackupById($id)
|
||||
{
|
||||
if (is_numeric($id)) {
|
||||
$query = $this->db->select()
|
||||
->cols(['b.id', 'b.adresse', 'b.name', 'b.dateiname', 'b.datum'])
|
||||
->from('backup AS b')
|
||||
->where('b.id = ?', $id);
|
||||
|
||||
return $this->db->fetchRow($query->getStatement(), $query->getBindValues());
|
||||
}
|
||||
|
||||
return [];
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
public function getLatestBackup()
|
||||
{
|
||||
$sql = 'SELECT b.id, b.name,b.dateiname, b.adresse,b.datum FROM backup AS `b` ORDER BY b.datum DESC LIMIT 1';
|
||||
|
||||
return $this->db->fetchRow($sql);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,97 @@
|
||||
<?php
|
||||
|
||||
namespace Xentral\Modules\Backup;
|
||||
|
||||
use Xentral\Modules\Backup\Exception\BackupNotificationServiceException;
|
||||
use Xentral\Modules\SystemNotification\Service\NotificationService;
|
||||
|
||||
final class BackupNotificationService
|
||||
{
|
||||
/** @var string login sperre Konfiguration */
|
||||
const BACKUP_CONF_MODE = 'login_lock_mode';
|
||||
|
||||
/** @var NotificationService $notificationService */
|
||||
private $notificationService;
|
||||
/**
|
||||
* @var BackupSystemConfigurationService
|
||||
*/
|
||||
private $configurationService;
|
||||
|
||||
public function __construct(
|
||||
BackupSystemConfigurationService $configurationService,
|
||||
NotificationService $notificationService
|
||||
) {
|
||||
$this->configurationService = $configurationService;
|
||||
$this->notificationService = $notificationService;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $name
|
||||
* @param string $message
|
||||
* @param array $tags
|
||||
* @param string $title
|
||||
* @param string $level
|
||||
*/
|
||||
public function addNotification($name, $message, $tags = [], $title = '', $level = 'warning')
|
||||
{
|
||||
|
||||
if (!is_string($name) || empty(trim($name))) {
|
||||
throw new BackupNotificationServiceException('Name cannot be empty');
|
||||
}
|
||||
|
||||
if (!is_string($message) || empty(trim($message))) {
|
||||
throw new BackupNotificationServiceException('Message cannot be empty');
|
||||
}
|
||||
|
||||
if (empty($tags)) {
|
||||
throw new BackupNotificationServiceException('Tags cannot be empty');
|
||||
}
|
||||
|
||||
if (!is_array($tags)) {
|
||||
throw new BackupNotificationServiceException('Tags should be an array');
|
||||
}
|
||||
|
||||
if (empty(trim($title))) {
|
||||
$title = 'Laufender Backupprozess';
|
||||
}
|
||||
|
||||
$this->notificationService->createPushNotificationForConnectedUsers($level, $title, $message, true, [], $tags);
|
||||
|
||||
$this->configurationService->trySetConfiguration($name, '1');
|
||||
if ($name === static::BACKUP_CONF_MODE) {
|
||||
$this->configurationService->trySetConfiguration('login_lock_mode_time', time());
|
||||
$this->configurationService->trySetConfiguration('login_lock_mode_timeout', '900');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $name
|
||||
* @param array $tags
|
||||
*/
|
||||
public function removeNotification($name, $tags = [])
|
||||
{
|
||||
|
||||
if (!is_string($name) || empty(trim($name))) {
|
||||
throw new BackupNotificationServiceException('Name cannot be empty');
|
||||
}
|
||||
|
||||
if (empty($tags)) {
|
||||
throw new BackupNotificationServiceException('Tags cannot be empty');
|
||||
}
|
||||
|
||||
if (!is_array($tags)) {
|
||||
throw new BackupNotificationServiceException('Tags should be an array');
|
||||
}
|
||||
|
||||
if ($this->configurationService->getConfiguration($name)) {
|
||||
$this->configurationService->trySetConfiguration($name, '0');
|
||||
if ($name === static::BACKUP_CONF_MODE) {
|
||||
$this->configurationService->trySetConfiguration('login_lock_mode_time', '');
|
||||
$this->configurationService->trySetConfiguration('login_lock_mode_timeout', '0');
|
||||
}
|
||||
|
||||
$this->notificationService->deleteByTags($tags, null, false);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,53 @@
|
||||
<?php
|
||||
|
||||
|
||||
namespace Xentral\Modules\Backup;
|
||||
|
||||
use DateTimeInterface;
|
||||
use erpAPI;
|
||||
use Xentral\Modules\Backup\Exception\BackupProcessStarterException;
|
||||
|
||||
/**
|
||||
* Class BackupProcessStarterService
|
||||
*
|
||||
* @property erpAPI erp
|
||||
* @package Xentral\Modules\Backup
|
||||
*/
|
||||
final class BackupProcessStarterService
|
||||
{
|
||||
/** @var erpAPI $erp */
|
||||
private $erp;
|
||||
|
||||
/**
|
||||
* BackupProcessStarterService constructor.
|
||||
*
|
||||
* @param erpAPI $erp
|
||||
*/
|
||||
public function __construct(erpAPI $erp)
|
||||
{
|
||||
$this->erp = $erp;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $cronFile
|
||||
* @param int $period
|
||||
* @param DateTimeInterface $startTime
|
||||
* @param string|null $title
|
||||
*
|
||||
* @throws BackupProcessStarterException
|
||||
*
|
||||
* @return bool|int|string|null
|
||||
*/
|
||||
public function tryCheckProcess($cronFile, $period, DateTimeInterface $startTime, $title = null)
|
||||
{
|
||||
if (empty($cronFile)) {
|
||||
throw new BackupProcessStarterException('Cron file is missing');
|
||||
}
|
||||
if (null === $title) {
|
||||
$title = $cronFile;
|
||||
}
|
||||
|
||||
return $this->erp->CheckProzessstarter($title, 'periodisch', $period, $startTime->format('Y-m-d H:i:s'),
|
||||
'cronjob', $cronFile, 1);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,603 @@
|
||||
<?php
|
||||
|
||||
namespace Xentral\Modules\Backup;
|
||||
|
||||
use Config;
|
||||
use DateInterval;
|
||||
use DateTime;
|
||||
use Exception;
|
||||
use Xentral\Components\Backup\Adapter\AdapterInterface;
|
||||
use Xentral\Components\Backup\FileBackup;
|
||||
use Xentral\Components\Backup\DatabaseBackup;
|
||||
use Xentral\Components\Backup\Logger\BackupLog;
|
||||
use Xentral\Components\Database\Database;
|
||||
use Xentral\Components\Database\DatabaseConfig;
|
||||
use Xentral\Components\Database\Exception\DatabaseExceptionInterface;
|
||||
use Xentral\Modules\Backup\Exception\BackupProcessStarterException;
|
||||
use ZipArchive;
|
||||
use Xentral\Modules\Backup\Exception\RuntimeException;
|
||||
|
||||
/**
|
||||
* Class BackupService
|
||||
*
|
||||
* @package Xentral\Modules\Backup
|
||||
*/
|
||||
final class BackupService
|
||||
{
|
||||
/**
|
||||
* @var BackupGateway
|
||||
*/
|
||||
private $gateway;
|
||||
/**
|
||||
* @var DatabaseBackup
|
||||
*/
|
||||
private $oDbBackup;
|
||||
/**
|
||||
* @var FileBackup
|
||||
*/
|
||||
private $oFileBackup;
|
||||
|
||||
/** @var string */
|
||||
const STATUS_FILE = 'status.txt';
|
||||
|
||||
/** @var string */
|
||||
const SESSION_FILE = 'session.txt';
|
||||
|
||||
/** @var Database $db */
|
||||
private $db;
|
||||
|
||||
/** @var BackupProcessStarterService $processStarter */
|
||||
private $processStarter;
|
||||
|
||||
/** @var BackupSystemConfigurationService $backupSystemConfiguration */
|
||||
private $backupSystemConfiguration;
|
||||
|
||||
/** @var BackupLog $logger */
|
||||
private $logger;
|
||||
|
||||
/** @var int min free disk in Bytes */
|
||||
const MIN_FREE_DISK = 1073741824;
|
||||
|
||||
private static $publicSubdirectories = ['dms', 'pdfarchiv', 'pdfmirror', 'emailbackup', 'tmp', 'uebertragung'];
|
||||
|
||||
/**
|
||||
* BackupService constructor.
|
||||
*
|
||||
* @param BackupGateway $gateway
|
||||
* @param DatabaseBackup $oDbBackup
|
||||
* @param FileBackup $oFileBackup
|
||||
* @param BackupProcessStarterService $processStarter
|
||||
* @param BackupSystemConfigurationService $backupSystemConfiguration
|
||||
* @param Database $database
|
||||
* @param BackupLog $logger
|
||||
*/
|
||||
public function __construct(
|
||||
BackupGateway $gateway,
|
||||
DatabaseBackup $oDbBackup,
|
||||
FileBackup $oFileBackup,
|
||||
BackupProcessStarterService $processStarter,
|
||||
BackupSystemConfigurationService $backupSystemConfiguration,
|
||||
Database $database,
|
||||
BackupLog $logger
|
||||
) {
|
||||
$this->gateway = $gateway;
|
||||
$this->oDbBackup = $oDbBackup;
|
||||
$this->oFileBackup = $oFileBackup;
|
||||
$this->processStarter = $processStarter;
|
||||
$this->backupSystemConfiguration = $backupSystemConfiguration;
|
||||
$this->db = $database;
|
||||
$this->logger = $logger;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $file
|
||||
*
|
||||
* @return false|string
|
||||
*/
|
||||
protected function generateMetaData($file)
|
||||
{
|
||||
/** @var $adminIds */
|
||||
$adminIds = $this->gateway->getAdminUserIds();
|
||||
$hMeta = [
|
||||
'tables' => $this->gateway->getTablesChecksum(),
|
||||
'users' => !empty($adminIds) ? array_column($adminIds, 'id') : [],
|
||||
'created' => time(),
|
||||
'name' => $file,
|
||||
];
|
||||
|
||||
return json_encode($hMeta);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $file
|
||||
*
|
||||
* @return false|int
|
||||
*/
|
||||
protected function addMetadata($file)
|
||||
{
|
||||
$sMetaFile = $this->oDbBackup->getMetaFileName($file);
|
||||
$sMeta = base64_encode($this->generateMetaData($sMetaFile));
|
||||
|
||||
return file_put_contents($sMetaFile, $sMeta);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Config $config
|
||||
*
|
||||
* @return DatabaseConfig
|
||||
*/
|
||||
public function convertLegacyDbConf(Config $config)
|
||||
{
|
||||
return new DatabaseConfig(
|
||||
$config->WFdbhost,
|
||||
$config->WFdbuser,
|
||||
$config->WFdbpass,
|
||||
$config->WFdbname,
|
||||
null,
|
||||
$config->WFdbport
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $backupFile
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getMySQLFileName($backupFile)
|
||||
{
|
||||
$asFile = explode('.', $backupFile);
|
||||
array_pop($asFile);
|
||||
|
||||
return implode('.', $asFile) . '.sql';
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Config $config
|
||||
* @param string $filename
|
||||
* @param array $options
|
||||
* @param int|null $minimumSpace
|
||||
*/
|
||||
public function create(Config $config, $filename, $options = [], $minimumSpace = null)
|
||||
{
|
||||
if (!$this->hasExecutableExtension('zip')) {
|
||||
$this->oFileBackup->breakCleanUp();
|
||||
$this->logger->writePersistent('Required Zip Module is missing!');
|
||||
throw new RuntimeException('Required Zip Module is missing!');
|
||||
}
|
||||
|
||||
// create mysql dump
|
||||
$userPath = $config->WFuserdata;
|
||||
|
||||
if ($sTmpDir = $this->oFileBackup->begin($userPath)) {
|
||||
$ssid = array_key_exists('ssid', $options) ? $options['ssid'] : null;
|
||||
$this->logger->write('--BEGIN--');
|
||||
|
||||
// DELETE OLD BACKUPS ON THE FILESYSTEM (BACKWARDS AS WELL)
|
||||
exec(sprintf('cd %s && ls', $this->oFileBackup->getSnapshotsDir()), $asResult);
|
||||
if (is_array($asResult) && count($asResult) > 0) {
|
||||
foreach ($asResult as $file) {
|
||||
if (!empty($file) && $file !== $filename) {
|
||||
$fullFile = sprintf('%s%s', $this->oFileBackup->getSnapshotsDir(), $file);
|
||||
if (file_exists($fullFile)) {
|
||||
@unlink($fullFile);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (null !== $ssid) {
|
||||
$this->logger->write($ssid, null, static::SESSION_FILE, false, false);
|
||||
}
|
||||
$sMySQLFile = $this->getMySQLFileName($filename);
|
||||
$sMySQLFullPath = $sTmpDir . $sMySQLFile;
|
||||
$this->logger->write('Create MySQL Dump');
|
||||
|
||||
if ($this->hasEnoughFreeDisk($userPath, $minimumSpace) === false) {
|
||||
$this->oFileBackup->breakCleanUp();
|
||||
$this->logger->write('ERROR');
|
||||
$this->logger->writePersistent('Not enough free disk space for Dump creation');
|
||||
throw new RuntimeException('Not enough free disk space for Dump creation');
|
||||
}
|
||||
|
||||
$this->oDbBackup->createDump($this->convertLegacyDbConf($config), $sMySQLFullPath, null);
|
||||
if (filesize($sMySQLFullPath . '.gz') > 1024) {
|
||||
$this->logger->write('Create Dump meta file');
|
||||
// $this->addMetadata($this->oDbBackup->getMetaFileName($this->oFileBackup->getLocalPath($filename,
|
||||
// $userPath)));
|
||||
}
|
||||
|
||||
if ($this->hasEnoughFreeDisk($userPath, $minimumSpace) === false) {
|
||||
$this->oFileBackup->breakCleanUp();
|
||||
$this->logger->write('ERROR');
|
||||
$this->logger->writePersistent(sprintf('Not enough free disk space for %s', $userPath));
|
||||
throw new RuntimeException(sprintf('Not enough free disk space for %s', $userPath));
|
||||
}
|
||||
|
||||
// Create File Backup
|
||||
$this->logger->write('Create File Backup for userdata');
|
||||
$this->oFileBackup->createBackup($filename, $userPath, $sMySQLFile . '.gz');
|
||||
if (filesize($this->getArchivePath($filename, $userPath)) > 1024) {
|
||||
$this->logger->write('Add in Backup table');
|
||||
// DELETE OLD Backup
|
||||
if ($latest = $this->gateway->getLatestBackup()) {
|
||||
$this->db->perform('DELETE FROM backup WHERE id=:id', ['id' => $latest['id']]);
|
||||
}
|
||||
$this->db->perform('INSERT INTO backup (adresse, name, dateiname, datum) VALUES (:addr,:name,:file_name,NOW())',
|
||||
['addr' => $options['addr'], 'name' => $options['name'], 'file_name' => $filename]);
|
||||
}
|
||||
|
||||
$this->logger->write('--END--');
|
||||
$this->removeLoggerFiles();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Config $config
|
||||
* @param string $filename
|
||||
* @param array $options
|
||||
*/
|
||||
public function restore(Config $config, $filename, $options = [])
|
||||
{
|
||||
$userPath = $config->WFuserdata;
|
||||
if ($sTmpDir = $this->oFileBackup->begin($userPath)) {
|
||||
$ssid = array_key_exists('ssid', $options) ? $options['ssid'] : null;
|
||||
|
||||
$this->logger->write('--BEGIN--');
|
||||
if (null !== $ssid) {
|
||||
$this->logger->write($ssid, null, static::SESSION_FILE, false, false);
|
||||
}
|
||||
|
||||
if ($this->hasEnoughFreeDisk($userPath) === false) {
|
||||
$this->oFileBackup->breakCleanUp();
|
||||
$this->logger->write('ERROR');
|
||||
$this->logger->writePersistent('Not enough free disk space for Backup restore');
|
||||
throw new RuntimeException('Not enough free disk space for Backup restore');
|
||||
}
|
||||
|
||||
// Replay SQL DUMP
|
||||
// Backup-Tabelle extra sichern
|
||||
$sBackupTmpFullPath = $sTmpDir . 'backup_temp.sql';
|
||||
$this->logger->write('DUMP backup table');
|
||||
$this->oDbBackup->createDump($this->convertLegacyDbConf($config), $sBackupTmpFullPath, 'backup');
|
||||
$sMySQLFile = $this->getMySQLFileName($filename) . '.gz';
|
||||
|
||||
$FullBckPath = $this->getArchivePath($filename, $userPath);
|
||||
$oZip = new ZipArchive;
|
||||
$xRes = $oZip->open($FullBckPath);
|
||||
$this->logger->write('Fetch Database DUMP from Backup archive');
|
||||
if ($xRes !== true) {
|
||||
$this->oFileBackup->breakCleanUp();
|
||||
$this->logger->write('ERROR');
|
||||
$this->logger->writePersistent(sprintf('Backup File "%s" cannot be unzipped!', $FullBckPath));
|
||||
throw new RuntimeException(sprintf('Backup File "%s" cannot be unzipped!', $FullBckPath));
|
||||
}
|
||||
|
||||
if ($oZip->extractTo($sTmpDir, [$sMySQLFile]) === false) {
|
||||
$this->oFileBackup->breakCleanUp();
|
||||
$this->logger->write('ERROR');
|
||||
$this->logger->writePersistent(sprintf('SQL file not found in achieve file %s', $filename));
|
||||
throw new RuntimeException(sprintf('SQL file not found in achieve file %s', $filename));
|
||||
}
|
||||
|
||||
$oZip->close();
|
||||
|
||||
$asTables = $this->gateway->getTables();
|
||||
$this->logger->write('DROP ALL TABLES');
|
||||
foreach ($asTables as $sTable) {
|
||||
$this->db->perform('DROP TABLE IF EXISTS ' . $sTable);
|
||||
}
|
||||
$sMySQLFullPath = $sTmpDir . $sMySQLFile;
|
||||
$this->logger->write('RESTORE Database DUMP');
|
||||
$this->oDbBackup->restoreDump($this->convertLegacyDbConf($config), $sMySQLFullPath);
|
||||
// remove Backup Dump
|
||||
$this->logger->write('REMOVE DUMP FILE');
|
||||
@unlink($sMySQLFullPath);
|
||||
|
||||
// RESTORE Backup table
|
||||
$this->logger->write('Restore Backup Table');
|
||||
$this->oDbBackup->restoreDump($this->convertLegacyDbConf($config), $sBackupTmpFullPath . '.gz');
|
||||
@unlink($sBackupTmpFullPath . '.gz');
|
||||
|
||||
$this->logger->write('Restore Backup System files');
|
||||
|
||||
$restoreOptions = [];
|
||||
if (array_key_exists('exclude_dir', $options) && is_array($options['exclude_dir'])) {
|
||||
$restoreOptions['exclude_dir'] = $options['exclude_dir'];
|
||||
}
|
||||
$this->oFileBackup->restoreFileSystem($filename, $userPath, $restoreOptions);
|
||||
$iUserId = array_key_exists('user_id', $options) ? $options['user_id'] : 0;
|
||||
if (!empty($iUserId)) {
|
||||
$ssid = array_key_exists('ssid', $options) ? $options['ssid'] : null;
|
||||
$ip = array_key_exists('ip', $options) ? $options['ip'] : null;
|
||||
$this->logger->write('RECONNECT current User');
|
||||
$this->reconnectUser($iUserId, $ssid, $ip);
|
||||
}
|
||||
if (array_key_exists('old_dbname', $options) && !empty($options['old_dbname'])) {
|
||||
$this->migratePublicSubdirectory($options['old_dbname'], $config);
|
||||
}
|
||||
$this->logger->write('--END--');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getArchiveExtension()
|
||||
{
|
||||
return $this->oFileBackup->getBackupExtension();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $filename
|
||||
*
|
||||
* @param string $userPath
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getArchivePath($filename, $userPath)
|
||||
{
|
||||
return $this->oFileBackup->getLocalPath($filename, $userPath);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $iUserId
|
||||
*
|
||||
* @param string $ssid
|
||||
*
|
||||
* @param string|null $ip
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function reconnectUser($iUserId, $ssid, $ip = null)
|
||||
{
|
||||
if (isset($iUserId) && is_numeric($iUserId) && is_string($ssid)) {
|
||||
$ip = null === $ip ? '127.0.0.1' : $ip;
|
||||
$this->db->perform('DELETE FROM useronline WHERE user_id=:uid', ['uid' => $iUserId]);
|
||||
$this->db->perform(
|
||||
'INSERT INTO useronline (user_id, login, sessionid, ip, time) VALUES (:uid,1,:ssid,:ip,NOW())',
|
||||
[
|
||||
'uid' => $iUserId,
|
||||
'ssid' => $ssid,
|
||||
'ip' => $ip,
|
||||
]
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $filename
|
||||
*
|
||||
* @param string|null $userPath
|
||||
*
|
||||
* @return string|null
|
||||
*/
|
||||
public function getDumpMetaData($filename, $userPath = null)
|
||||
{
|
||||
$filePath = $this->oFileBackup->getLocalPath($filename, $userPath, true);
|
||||
|
||||
return $this->oDbBackup->getDumpMetaData($filePath);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $filename
|
||||
* @param string $userPath
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function checkSumOnAfterRecovery($filename, $userPath = null)
|
||||
{
|
||||
$asDiff = [];
|
||||
$hDbCheckSums = $this->oDbBackup->excludeCheckSumTables($this->gateway->getTablesChecksum());
|
||||
if (($xData = $this->getDumpMetaData($filename, $userPath)) && !empty($hFileCheckSums = $xData['tables'])) {
|
||||
$ahFileCheckSums = $this->oDbBackup->excludeCheckSumTables($hFileCheckSums);
|
||||
foreach ($ahFileCheckSums as $table => &$asFileCheckSum) {
|
||||
// downward compatible
|
||||
if (!is_array($asFileCheckSum)) {
|
||||
$params = ['checksum', 'items'];
|
||||
$values = [$asFileCheckSum, 0];
|
||||
$asFileCheckSum = array_combine($params, $values);
|
||||
}
|
||||
if ($asFileCheckSum['checksum'] !== $hDbCheckSums[$table]['checksum'] && $asFileCheckSum['items'] !== $hDbCheckSums[$table]['items']) {
|
||||
$asDiff[] = $table;
|
||||
}
|
||||
}
|
||||
|
||||
return $asDiff;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $xConfig Configuration options for backup
|
||||
* @param string $identifier description/Title of cron action
|
||||
* @param string $sParam Parameter to set in the configuration table for that action
|
||||
* @param string $cronFile Cron file (in .php) located under cronjobs directory
|
||||
* @param string|null $userDataDir userData directory
|
||||
*
|
||||
* @throws RuntimeException
|
||||
* @throws Exception
|
||||
* @return bool
|
||||
*/
|
||||
public function addToProcessStarter(
|
||||
$xConfig,
|
||||
$identifier = 'Backup',
|
||||
$sParam = 'backup_configuration_cron',
|
||||
$cronFile = 'backup',
|
||||
$userDataDir = null
|
||||
) {
|
||||
// check if backup or restore is running?
|
||||
if ($this->oDbBackup->getLockStatus() === AdapterInterface::STATUS_WORKING ||
|
||||
$this->oFileBackup->getLockStatus($userDataDir) === FileBackup::STATUS_WORKING) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$date = new DateTime();
|
||||
$yesterday = $date->sub(new DateInterval('P1D'));
|
||||
|
||||
try {
|
||||
$fakeLastRun = $yesterday->format('Y-m-d H:i:s');
|
||||
// $this->db->perform('UPDATE prozessstarter SET aktiv=:active WHERE mutex=:mut',
|
||||
// ['active' => 0, 'mut' => 0]);
|
||||
// ADD NEW JOB ONLY IF THERE IS NO RUNNING JOB
|
||||
try {
|
||||
$xCheckPS = $this->processStarter->tryCheckProcess($cronFile, 1000, $date, $identifier);
|
||||
} catch (BackupProcessStarterException $exception) {
|
||||
$this->logger->writePersistent($exception->getMessage());
|
||||
throw new RuntimeException($exception->getMessage());
|
||||
}
|
||||
|
||||
$this->backupSystemConfiguration->trySetConfiguration($sParam, $xConfig);
|
||||
if ($xCheckPS === false) {
|
||||
$aiAffected = $this->db->fetchAffected(
|
||||
'UPDATE prozessstarter SET aktiv=:active, letzteausfuerhung=:timestamp,
|
||||
status=:status WHERE parameter=:cron_file',
|
||||
['active' => 1, 'timestamp' => $fakeLastRun, 'cron_file' => $cronFile, 'status' => '']
|
||||
);
|
||||
|
||||
return !empty($aiAffected);
|
||||
}
|
||||
} catch (DatabaseExceptionInterface $exception) {
|
||||
$this->logger->writePersistent($exception->getMessage());
|
||||
throw new RuntimeException($exception->getMessage());
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param null|string $fileName
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function removeLoggerFiles($fileName = null)
|
||||
{
|
||||
if (null !== $fileName && is_file($fileName)) {
|
||||
$tmpBackup = $fileName;
|
||||
$fileExploded = explode('.', $fileName);
|
||||
$extension = array_pop($fileExploded);
|
||||
if ($extension === 'zip') {
|
||||
$tmpMeta = implode('.', $fileExploded) . '.meta';
|
||||
if (is_file($tmpMeta)) {
|
||||
unlink($tmpMeta);
|
||||
}
|
||||
}
|
||||
unlink($tmpBackup);
|
||||
}
|
||||
$this->logger->delete();
|
||||
$this->logger->delete(null, static::SESSION_FILE);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $userData
|
||||
* @param int|null $minFreeDisk
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
private function hasEnoughFreeDisk($userData, $minFreeDisk = null)
|
||||
{
|
||||
$rootPath = $this->getRootPathByUserDataPath($userData);
|
||||
$minFreeDiskAverage = empty($minFreeDisk) || $minFreeDisk < static::MIN_FREE_DISK
|
||||
? static::MIN_FREE_DISK : $minFreeDisk;
|
||||
$free = disk_free_space($rootPath);
|
||||
$minFree = (int)$minFreeDiskAverage;
|
||||
|
||||
return ($free > 0 && $free > $minFree);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $userData
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
private function getRootPathByUserDataPath($userData)
|
||||
{
|
||||
if (empty($userData)) {
|
||||
$this->oFileBackup->breakCleanUp();
|
||||
$this->logger->write('ERROR');
|
||||
$this->logger->writePersistent(sprintf('UserData Dir "%s" is missing!', $userData));
|
||||
throw new RuntimeException(sprintf('UserData Dir "%s" is missing!', $userData));
|
||||
}
|
||||
|
||||
return dirname($userData);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return bool
|
||||
*/
|
||||
public function isInLoginLockMode()
|
||||
{
|
||||
if ($this->backupSystemConfiguration->getConfiguration('login_lock_mode') === '1') {
|
||||
$timeMaintenance = (int)$this->backupSystemConfiguration->getConfiguration('login_lock_mode_time');
|
||||
|
||||
if (empty($timeMaintenance)) {
|
||||
$this->backupSystemConfiguration->trySetConfiguration('login_lock_mode_time', time());
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
$timeOutMaintenance = (int)$this->configurationService->getConfiguration('login_lock_mode_timeout');
|
||||
// default 10min
|
||||
$timeOut = empty($timeOutMaintenance) ? 600 : $timeOutMaintenance;
|
||||
|
||||
if (time() - $timeMaintenance < $timeOut) {
|
||||
return true;
|
||||
}
|
||||
|
||||
$this->backupSystemConfiguration->trySetConfiguration('login_lock_mode', 0);
|
||||
$this->backupSystemConfiguration->trySetConfiguration('login_lock_mode_time', '0');
|
||||
$this->backupSystemConfiguration->trySetConfiguration('login_lock_mode_timeout', '0');
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $old_dbname
|
||||
* @param Config $config
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
protected function migratePublicSubdirectory($old_dbname, Config $config)
|
||||
{
|
||||
$dbName = $config->WFdbname;
|
||||
if ($old_dbname !== $dbName) {
|
||||
$userPath = $config->WFuserdata;
|
||||
$userPath = rtrim($userPath, DIRECTORY_SEPARATOR) . DIRECTORY_SEPARATOR;
|
||||
foreach (self::$publicSubdirectories as $subdirectory) {
|
||||
$oldDbPath = $userPath . $subdirectory . DIRECTORY_SEPARATOR . $old_dbname;
|
||||
$newDbPath = $userPath . $subdirectory . DIRECTORY_SEPARATOR . $dbName;
|
||||
if (is_dir($userPath . $old_dbname) && !is_dir($userPath . $subdirectory)) {
|
||||
$cmd = 'mv %s %s';
|
||||
@exec(sprintf($cmd, $oldDbPath, $newDbPath));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $name
|
||||
*
|
||||
* @throws RuntimeException
|
||||
* @return bool
|
||||
*/
|
||||
public function hasExecutableExtension($name)
|
||||
{
|
||||
if (!function_exists('exec')) {
|
||||
$this->logger->writePersistent('Required Function exec is missing');
|
||||
throw new RuntimeException('Required Function exec is missing');
|
||||
}
|
||||
if (!is_string($name)) {
|
||||
return false;
|
||||
}
|
||||
exec(sprintf('whereis %s', $name), $out);
|
||||
if (empty($out)) {
|
||||
return false;
|
||||
}
|
||||
$result = $out[0];
|
||||
$resultExploded = explode(':', $result);
|
||||
array_shift($resultExploded);
|
||||
|
||||
return !empty(trim(implode('', $resultExploded)));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,96 @@
|
||||
<?php
|
||||
|
||||
namespace Xentral\Modules\Backup;
|
||||
|
||||
use DateTime;
|
||||
use erpAPI;
|
||||
use Exception as DatetimeException;
|
||||
use Xentral\Modules\Backup\Exception\BackupSystemConfigurationException;
|
||||
|
||||
final class BackupSystemConfigurationService
|
||||
{
|
||||
/** @var erpAPI $erp */
|
||||
private $erp;
|
||||
|
||||
/**
|
||||
* @param erpAPI $erp
|
||||
*/
|
||||
public function __construct(erpAPI $erp)
|
||||
{
|
||||
$this->erp = $erp;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $name
|
||||
* @param string $value
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function trySetConfiguration($name, $value)
|
||||
{
|
||||
if (empty($name) || (!is_string($value) && !is_numeric($value))) {
|
||||
throw new BackupSystemConfigurationException('Cannot set Configuration');
|
||||
|
||||
}
|
||||
|
||||
$this->erp->SetKonfigurationValue($name, $value);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $comparedTime time in second to check if the cron has been enabled
|
||||
*
|
||||
* @param string $confName
|
||||
*
|
||||
* @throws DatetimeException
|
||||
* @return bool
|
||||
*/
|
||||
public function tryCheckCronIsEnabled($comparedTime = 300, $confName = 'prozessstarter_letzteraufruf')
|
||||
{
|
||||
|
||||
try {
|
||||
$latestRun = $this->getConfiguration($confName);
|
||||
} catch (BackupSystemConfigurationException $exception) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (empty($latestRun)) {
|
||||
return false;
|
||||
}
|
||||
$latestRunTime = new DateTime($latestRun);
|
||||
|
||||
return $this->getDiffDateTime($latestRunTime) < $comparedTime + 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return difference between $latestRunTime and $now
|
||||
*
|
||||
* @param DateTime $latestRunTime
|
||||
* @param Datetime|String $now
|
||||
*
|
||||
* @throws DatetimeException
|
||||
* @return int
|
||||
*/
|
||||
private function getDiffDateTime(DateTime $latestRunTime, $now = 'NOW')
|
||||
{
|
||||
if (!($now instanceOf DateTime)) {
|
||||
$now = new DateTime($now);
|
||||
}
|
||||
|
||||
return $now->getTimestamp() - $latestRunTime->getTimestamp();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $name
|
||||
*
|
||||
* @return array|mixed|string|null
|
||||
*/
|
||||
public function getConfiguration($name)
|
||||
{
|
||||
if (empty(trim($name))) {
|
||||
throw new BackupSystemConfigurationException('Cannot get Configuration');
|
||||
}
|
||||
|
||||
return $this->erp->GetKonfiguration($name);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,96 @@
|
||||
<?php
|
||||
|
||||
namespace Xentral\Modules\Backup;
|
||||
|
||||
use ApplicationCore;
|
||||
use Xentral\Core\DependencyInjection\ContainerInterface;
|
||||
use Xentral\Modules\Backup\Scheduler\BackupScheduleTask;
|
||||
|
||||
final class Bootstrap
|
||||
{
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
public static function registerServices()
|
||||
{
|
||||
return [
|
||||
'BackupGateway' => 'onInitBackupGateway',
|
||||
'BackupService' => 'onInitBackupService',
|
||||
'BackupSystemConfigurationService' => 'onInitBackupSystemConfigurationService',
|
||||
'BackupProcessStarterService' => 'onInitBackupProcessStarterService',
|
||||
'BackupNotificationService' => 'onInitBackupNotificationService',
|
||||
'BackupScheduleTask' => 'onInitBackupTask',
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param ContainerInterface $container
|
||||
*
|
||||
* @return BackupGateway
|
||||
*/
|
||||
public static function onInitBackupGateway(ContainerInterface $container)
|
||||
{
|
||||
return new BackupGateway($container->get('Database'));
|
||||
}
|
||||
|
||||
/**
|
||||
* @param ContainerInterface $container
|
||||
*
|
||||
* @return BackupService
|
||||
*/
|
||||
public static function onInitBackupService(ContainerInterface $container)
|
||||
{
|
||||
return new BackupService(
|
||||
$container->get('BackupGateway'),
|
||||
$container->get('DatabaseBackup'),
|
||||
$container->get('FileBackup'),
|
||||
$container->get('BackupProcessStarterService'),
|
||||
$container->get('BackupSystemConfigurationService'),
|
||||
$container->get('Database'),
|
||||
$container->get('BackupLog')
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param ContainerInterface $container
|
||||
*
|
||||
* @return BackupSystemConfigurationService
|
||||
*/
|
||||
public static function onInitBackupSystemConfigurationService(ContainerInterface $container)
|
||||
{
|
||||
/** @var ApplicationCore $app */
|
||||
$app = $container->get('LegacyApplication');
|
||||
|
||||
return new BackupSystemConfigurationService($app->erp);
|
||||
}
|
||||
|
||||
public static function onInitBackupProcessStarterService(ContainerInterface $container)
|
||||
{
|
||||
/** @var ApplicationCore $app */
|
||||
$app = $container->get('LegacyApplication');
|
||||
|
||||
return new BackupProcessStarterService($app->erp);
|
||||
}
|
||||
|
||||
public static function onInitBackupNotificationService(ContainerInterface $container)
|
||||
{
|
||||
return new BackupNotificationService(
|
||||
$container->get('BackupSystemConfigurationService'),
|
||||
$container->get('NotificationService')
|
||||
);
|
||||
}
|
||||
|
||||
public function onInitBackupTask(ContainerInterface $container)
|
||||
{
|
||||
/** @var ApplicationCore $app */
|
||||
$app = $container->get('LegacyApplication');
|
||||
|
||||
return new BackupScheduleTask(
|
||||
$container->get('Database'),
|
||||
$container->get('BackupSystemConfigurationService'),
|
||||
$container->get('BackupNotificationService'),
|
||||
$app,
|
||||
$container->get('BackupService')
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
<?php
|
||||
|
||||
namespace Xentral\Modules\Backup\Exception;
|
||||
|
||||
use Xentral\Core\Exception\ModuleExceptionInterface;
|
||||
|
||||
/**
|
||||
* Interface BackupExceptionInterface
|
||||
*
|
||||
* @package Xentral\Modules\Backup\Exception
|
||||
*/
|
||||
interface BackupExceptionInterface extends ModuleExceptionInterface
|
||||
{
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
<?php
|
||||
|
||||
namespace Xentral\Modules\Backup\Exception;
|
||||
|
||||
final class BackupNotificationServiceException extends RuntimeException
|
||||
{
|
||||
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
<?php
|
||||
|
||||
|
||||
namespace Xentral\Modules\Backup\Exception;
|
||||
|
||||
/**
|
||||
* Class BackupProcessStarterException
|
||||
*
|
||||
* @package Xentral\Modules\Backup\Exception
|
||||
*/
|
||||
class BackupProcessStarterException extends RuntimeException
|
||||
{
|
||||
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
<?php
|
||||
|
||||
|
||||
namespace Xentral\Modules\Backup\Exception;
|
||||
|
||||
final class BackupSystemConfigurationException extends RuntimeException
|
||||
{
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
<?php
|
||||
|
||||
namespace Xentral\Modules\Backup\Exception;
|
||||
|
||||
use InvalidArgumentException as SplInvalidArgumentException;
|
||||
|
||||
/**
|
||||
* Class InvalidArgumentException
|
||||
*
|
||||
* @package Xentral\Modules\Backup\Exception
|
||||
*/
|
||||
class InvalidArgumentException extends SplInvalidArgumentException implements BackupExceptionInterface
|
||||
{
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
<?php
|
||||
|
||||
namespace Xentral\Modules\Backup\Exception;
|
||||
|
||||
use RuntimeException as SplRuntimeException;
|
||||
|
||||
class RuntimeException extends SplRuntimeException implements BackupExceptionInterface
|
||||
{
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
<?php
|
||||
|
||||
namespace Xentral\Modules\Backup\Exception;
|
||||
|
||||
use BadMethodCallException as SplBadMethodCallException;
|
||||
|
||||
final class SchedulerAdapterBadMethodException extends SplBadMethodCallException implements BackupExceptionInterface
|
||||
{
|
||||
|
||||
}
|
||||
@@ -0,0 +1,59 @@
|
||||
<?php
|
||||
|
||||
namespace Xentral\Modules\Backup\Scheduler\Adapter;
|
||||
|
||||
use ArrayObject;
|
||||
use Xentral\Modules\Backup\Exception\SchedulerAdapterBadMethodException;
|
||||
use Xentral\Modules\Backup\Scheduler\BackupSchedulerTaskInterface;
|
||||
|
||||
final class SchedulerAdapter
|
||||
{
|
||||
|
||||
public $debugMode = false;
|
||||
|
||||
/**
|
||||
* @var BackupSchedulerTaskInterface
|
||||
*/
|
||||
private $schedulerTask;
|
||||
|
||||
public function __construct(BackupSchedulerTaskInterface $schedulerTask)
|
||||
{
|
||||
$this->schedulerTask = $schedulerTask;
|
||||
}
|
||||
|
||||
public function __call($method, $args)
|
||||
{
|
||||
if (!method_exists($this->schedulerTask, $method)) {
|
||||
$class = get_class($this->schedulerTask);
|
||||
throw new SchedulerAdapterBadMethodException(sprintf('Method %s at %s class is missing', $method, $class));
|
||||
}
|
||||
if (is_callable([$this->schedulerTask, $method])) {
|
||||
$this->debug(json_encode(new ArrayObject($args)));
|
||||
$this->schedulerTask->beforeScheduleAction(new ArrayObject($args));
|
||||
if ($this->debugMode === true) {
|
||||
$message = 'Call ' . get_class($this->schedulerTask) . '::' . $method . ' with args ' . json_encode($args);
|
||||
$this->debug($message);
|
||||
}
|
||||
call_user_func([$this->schedulerTask, $method], $args);
|
||||
$this->schedulerTask->afterScheduleAction(new ArrayObject($args));
|
||||
} else {
|
||||
$class = get_class($this->schedulerTask);
|
||||
throw new SchedulerAdapterBadMethodException(sprintf('No callable method %s at %s class', $method, $class));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $message
|
||||
* @param null|string $debuggerFile
|
||||
*
|
||||
* @return null|void
|
||||
*/
|
||||
public function debug($message, $debuggerFile = null)
|
||||
{
|
||||
if ($this->debugMode === false) {
|
||||
return null;
|
||||
}
|
||||
$logFile = null === $debuggerFile ? sys_get_temp_dir() . '/backup_debug.log' : $debuggerFile;
|
||||
file_put_contents($logFile, date('Y-m-d H:i:s') . '- ' . $message . "\n", FILE_APPEND | LOCK_EX);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,172 @@
|
||||
<?php
|
||||
|
||||
namespace Xentral\Modules\Backup\Scheduler;
|
||||
|
||||
use ApplicationCore;
|
||||
use ArrayObject;
|
||||
use Backup;
|
||||
use Xentral\Components\Database\Database;
|
||||
use Xentral\Modules\Backup\BackupNotificationService;
|
||||
use Xentral\Modules\Backup\BackupService;
|
||||
use Xentral\Modules\Backup\BackupSystemConfigurationService;
|
||||
|
||||
final class BackupScheduleTask implements BackupSchedulerTaskInterface
|
||||
{
|
||||
/** @var string $action */
|
||||
private $action;
|
||||
|
||||
/** @var int waiting time in seconds before start backup Task */
|
||||
const TASK_WAITING_TIMEOUT = 25;
|
||||
|
||||
const SPACE_OF_SET = 2048000000;
|
||||
|
||||
/** @var Database $db */
|
||||
private $db;
|
||||
|
||||
/** @var BackupNotificationService $notificationService */
|
||||
private $notificationService;
|
||||
|
||||
/** @var BackupSystemConfigurationService $configurationService */
|
||||
private $configurationService;
|
||||
|
||||
/** @var ApplicationCore $app */
|
||||
private $app;
|
||||
|
||||
/** @var BackupService $backupService */
|
||||
private $backupService;
|
||||
|
||||
public function __construct(
|
||||
Database $db,
|
||||
BackupSystemConfigurationService $configurationService,
|
||||
BackupNotificationService $notificationService,
|
||||
ApplicationCore $app,
|
||||
BackupService $backupService
|
||||
) {
|
||||
$this->db = $db;
|
||||
$this->configurationService = $configurationService;
|
||||
$this->notificationService = $notificationService;
|
||||
$this->app = $app;
|
||||
$this->backupService = $backupService;
|
||||
}
|
||||
|
||||
public function execute()
|
||||
{
|
||||
$isAutoBackup = false;
|
||||
$autoConfig = null;
|
||||
$dateiname = null;
|
||||
$conf = $this->configurationService->getConfiguration('backup_configuration_cron');
|
||||
|
||||
$minimumSpace = $this->getUsedSpaceFromSystemhealth();
|
||||
|
||||
if (empty($conf)) {
|
||||
// Auto Backup deactivated OS419883
|
||||
$isAutoBackup = false;
|
||||
}
|
||||
|
||||
if ($isAutoBackup === true) {
|
||||
|
||||
$dateiname = date('Y-m-d_') . sprintf('%s_SystemBackup.%s', $this->app->DB->dbname, 'zip');
|
||||
if ($this->db->fetchValue('SELECT true FROM backup WHERE dateiname=:name LIMIT 1',
|
||||
['name' => $dateiname])) {
|
||||
// AUTO BACKUP SHOULD RUN ONLY ONCE PER DAY
|
||||
return;
|
||||
}
|
||||
|
||||
$autoConfig = [
|
||||
'action' => null,
|
||||
'config' => $this->app->Conf,
|
||||
'file_name' => $dateiname,
|
||||
'options' => [
|
||||
'addr' => 1, // just for auto
|
||||
'name' => 'SystemBackup',
|
||||
'ssid' => uniqid('auto', false),
|
||||
'user_id' => 0,
|
||||
'ip' => '0.0.0.0',
|
||||
'auto_backup' => true,
|
||||
],
|
||||
];
|
||||
}
|
||||
|
||||
if ($isAutoBackup === true || (($oConfig = json_decode($conf)) && property_exists($oConfig, 'action'))) {
|
||||
if ($isAutoBackup === true) {
|
||||
$oConfig = (object)$autoConfig;
|
||||
}
|
||||
$this->action = $oConfig->action;
|
||||
$this->notificationService->addNotification(
|
||||
BackupNotificationService::BACKUP_CONF_MODE,
|
||||
'Bitte schließen Sie Ihre Aufgaben, System Backup startet in Kürze',
|
||||
['Backup']
|
||||
);
|
||||
|
||||
// LOGOUT ALL users except LoggedIn USER
|
||||
$userId = 0;
|
||||
if (property_exists($oConfig, 'options')) {
|
||||
$options = (array)$oConfig->options;
|
||||
$userId = array_key_exists('user_id', $options) ? $options['user_id'] : 0;
|
||||
}
|
||||
$this->db->perform('DELETE FROM useronline WHERE user_id <>:uid', ['uid' => $userId]);
|
||||
|
||||
$this->configurationService->trySetConfiguration('backup_configuration_cron', '');
|
||||
|
||||
$this->app->erp->setMaintainance(true);
|
||||
|
||||
$timeout = static::TASK_WAITING_TIMEOUT;
|
||||
// CHECK WHETHER A JOB IS RUNNING
|
||||
while ($this->db->perform('SELECT id FROM prozessstarter WHERE aktiv=1 AND mutex=1 LIMIT 1')) {
|
||||
$timeout -= 5;
|
||||
usleep(5000000);
|
||||
|
||||
if ($timeout <= 0) {
|
||||
// DISABLE ALL CRON JOBS FOR RESTORE
|
||||
if ($oConfig->action === 'RunRestoreJob') {
|
||||
$this->db->perform('UPDATE prozessstarter SET aktiv=0');
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
if ($isAutoBackup === false) {
|
||||
/** @var Backup $backup */
|
||||
$backup = $this->app->loadModule('backup');
|
||||
if (in_array($this->action, ['RunRestoreJob', 'RunCreateJob'])) {
|
||||
$backup->{$this->action}($oConfig);
|
||||
}
|
||||
} elseif (null !== $autoConfig) {
|
||||
$this->backupService->create($this->app->Conf, $dateiname, $autoConfig['options'], $minimumSpace);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public function cleanup()
|
||||
{
|
||||
if ($this->action === 'RunRestoreJob') {
|
||||
$this->app->erp->UpgradeDatabase();
|
||||
}
|
||||
|
||||
$this->notificationService->removeNotification(BackupNotificationService::BACKUP_CONF_MODE, ['Backup']);
|
||||
$this->app->erp->setMaintainance(false);
|
||||
|
||||
}
|
||||
|
||||
public function beforeScheduleAction(ArrayObject $args)
|
||||
{
|
||||
// TODO: Implement beforeScheduleAction() method.
|
||||
}
|
||||
|
||||
public function afterScheduleAction(ArrayObject $args)
|
||||
{
|
||||
// TODO: Implement afterScheduleAction() method.
|
||||
}
|
||||
|
||||
|
||||
private function getUsedSpaceFromSystemhealth(): int
|
||||
{
|
||||
$minimumSpace = self::SPACE_OF_SET + 1024 * 1024
|
||||
* (int)$this->configurationService->getConfiguration('databasesize');
|
||||
|
||||
foreach (['dms', 'pdfarchiv', 'pdfmirror', 'emailbackup', 'tmp', 'uebertragung'] as $subDir) {
|
||||
$minimumSpace *= 1024 * 1024 * (int)$this->configurationService->getConfiguration("userdata{$subDir}size");
|
||||
}
|
||||
|
||||
return $minimumSpace;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
<?php
|
||||
|
||||
namespace Xentral\Modules\Backup\Scheduler;
|
||||
|
||||
use RuntimeException;
|
||||
use Xentral\Modules\Backup\Exception\BackupExceptionInterface;
|
||||
|
||||
class BackupSchedulerException extends RuntimeException implements BackupExceptionInterface
|
||||
{
|
||||
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
<?php
|
||||
|
||||
namespace Xentral\Modules\Backup\Scheduler;
|
||||
|
||||
use ArrayObject;
|
||||
|
||||
interface BackupSchedulerTaskInterface
|
||||
{
|
||||
public function execute();
|
||||
|
||||
public function cleanup();
|
||||
|
||||
public function beforeScheduleAction(ArrayObject $args);
|
||||
|
||||
public function afterScheduleAction(ArrayObject $args);
|
||||
}
|
||||
@@ -0,0 +1,120 @@
|
||||
.visible{
|
||||
display:block;
|
||||
visibility: visible;
|
||||
}
|
||||
.invisible{
|
||||
visibility: hidden;
|
||||
display: none;
|
||||
}
|
||||
div#backupModalTimer.ui-dialog-titlebar-close {
|
||||
visibility: hidden;
|
||||
}
|
||||
/**.ui-dialog-titlebar {
|
||||
display: none;
|
||||
visibility: hidden;
|
||||
}*/
|
||||
.ui-resizable-handle { display: none !important; }
|
||||
div#backupModalTimer.ui-widget-content {
|
||||
border: none !important;
|
||||
outline-width: 0px !important;
|
||||
background: transparent !important;
|
||||
}
|
||||
.ui-dialog.ui-resizable-disabled .ui-resizable-handle { display: none; }
|
||||
a:focus{
|
||||
outline:none;
|
||||
}
|
||||
.bck-status-message{
|
||||
position: absolute;
|
||||
width: auto;
|
||||
height: auto;
|
||||
text-align: center;
|
||||
left: 50%;
|
||||
transform: translate(-50%, -70%);
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
.bck-custom-file {
|
||||
position: relative;
|
||||
-ms-flex: 1 1 0%;
|
||||
flex: 1 1 0%;
|
||||
min-width: 0;
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
.bck-custom-file {
|
||||
position: relative;
|
||||
display: inline-block;
|
||||
width: 100%;
|
||||
height: calc(1.5em + 0.75rem + 2px);
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
#backup-importer {
|
||||
position: relative;
|
||||
z-index: 2;
|
||||
width: 100%;
|
||||
height: calc(1.5em + 0.75rem + 2px);
|
||||
margin: 0;
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
.custom-file-label {
|
||||
border-top-left-radius: 0;
|
||||
border-bottom-left-radius: 0;
|
||||
}
|
||||
|
||||
.custom-control-label::before, .custom-file-label, .custom-select {
|
||||
transition: background-color 0.15s ease-in-out, border-color 0.15s ease-in-out, box-shadow 0.15s ease-in-out;
|
||||
}
|
||||
|
||||
#input-for-backup-importer{
|
||||
position: absolute;
|
||||
top: 0;
|
||||
right: 0;
|
||||
left: 0;
|
||||
z-index: 1;
|
||||
padding: 0.375rem 0.75rem;
|
||||
font-weight: 400;
|
||||
line-height: 1.5;
|
||||
color: var(--grey);
|
||||
background-color: var(--info-color);
|
||||
border: 1px solid var(--current-grey);
|
||||
border-radius: 0.25rem;
|
||||
margin-top: 10px;
|
||||
width: 33%;
|
||||
}
|
||||
@media only screen
|
||||
and (max-width: 640px) {
|
||||
#input-for-backup-importer{
|
||||
width: 50% !important;
|
||||
}
|
||||
}
|
||||
.chunked-file-upload-container{
|
||||
margin-top: 32px !important;
|
||||
}
|
||||
|
||||
.backup-success {
|
||||
background-color: var(--green);
|
||||
background-image: url(/themes/new/images/info.png);
|
||||
background-size: 30px 30px;
|
||||
padding: 15px 10px 15px 50px;
|
||||
margin: 0 0 10px 0;
|
||||
background-repeat: no-repeat;
|
||||
background-position: 10px center;
|
||||
border-radius: 3px;
|
||||
color: var(--error-color);
|
||||
font-size: 13px;
|
||||
}
|
||||
|
||||
.backup-create {
|
||||
background-color: var(--header-counter-background);
|
||||
background-image: url(/themes/new/images/info.png);
|
||||
background-size: 30px 30px;
|
||||
padding: 15px 10px 15px 50px;
|
||||
margin: 0 0 10px 0;
|
||||
background-repeat: no-repeat;
|
||||
background-position: 10px center;
|
||||
border-radius: 3px;
|
||||
color: var(--error-color);
|
||||
font-size: 13px;
|
||||
}
|
||||
@@ -0,0 +1,558 @@
|
||||
var BackupModule = function ($) {
|
||||
'use strict';
|
||||
|
||||
/**
|
||||
*
|
||||
* @type {{readStatus: readStatus, showProcessStarterMissingError: showProcessStarterMissingError, init: init,
|
||||
* saveItem: saveItem, enableDebugMode: enableDebugMode, backupRecovery: backupRecovery, isInitialized:
|
||||
* boolean, runRecovery: runRecovery, storage: {$backupDialog: null, $createItemDialog: null}, initDialog:
|
||||
* initDialog, setCacheBackup: setCacheBackup, hasProcessStarterEnabled: (function(): boolean), resetAdd:
|
||||
* resetAdd, backupImporter: {registerEvents: registerEvents, init: init}, setInterval: (function(): number),
|
||||
* isImporter: boolean, reloadUrl: reloadUrl, createItem: createItem, addDialog: addDialog,
|
||||
* getCacheBackupValue: (function(string): *), disableDebugMode: disableDebugMode, registerEvents:
|
||||
* registerEvents, debugMode: boolean}}
|
||||
*/
|
||||
var me = {
|
||||
|
||||
isInitialized: false,
|
||||
isImporter: false,
|
||||
debugMode: false,
|
||||
|
||||
storage: {
|
||||
$backupDialog: null,
|
||||
$createItemDialog: null
|
||||
},
|
||||
|
||||
/**
|
||||
* @return void
|
||||
*/
|
||||
init: function () {
|
||||
if (me.isInitialized === true) {
|
||||
return;
|
||||
}
|
||||
|
||||
me.storage.$backupDialog = $('#backupModal');
|
||||
me.storage.$createItemDialog = $('#add-backup');
|
||||
|
||||
if (me.storage.$createItemDialog.length === 0) {
|
||||
throw 'Could not initialize DataTableLabelsUi. Required elements are missing.';
|
||||
}
|
||||
|
||||
me.initDialog();
|
||||
me.addDialog();
|
||||
|
||||
me.registerEvents();
|
||||
|
||||
me.isInitialized = true;
|
||||
},
|
||||
|
||||
/**
|
||||
* @return {void}
|
||||
*/
|
||||
enableDebugMode: function () {
|
||||
me.debugMode = true;
|
||||
console.log('Debug mode enabled!');
|
||||
},
|
||||
|
||||
/**
|
||||
* @return {void}
|
||||
*/
|
||||
disableDebugMode: function () {
|
||||
me.debugMode = false;
|
||||
console.log('Debug mode disabled!');
|
||||
},
|
||||
|
||||
/**
|
||||
* @return {number} refreshId
|
||||
*/
|
||||
setInterval: function () {
|
||||
return setInterval(function () {
|
||||
me.readStatus();
|
||||
}, 5000);
|
||||
},
|
||||
|
||||
/**
|
||||
* @return {void}
|
||||
*/
|
||||
initDialog: function () {
|
||||
me.storage.$backupDialog.dialog({
|
||||
modal: true,
|
||||
bgiframe: true,
|
||||
closeOnEscape: false,
|
||||
minWidth: 700,
|
||||
maxHeight: 700,
|
||||
autoOpen: false,
|
||||
buttons: {
|
||||
ABBRECHEN: function () {
|
||||
$(this).dialog('close');
|
||||
},
|
||||
SPEICHERN: {
|
||||
text: 'WIEDERHERSTELLEN',
|
||||
id: 'run-recovery-btn',
|
||||
click: function () {
|
||||
var iBid = $(this).data('bid');
|
||||
// check migration setting choice
|
||||
if (!$('#recovery-migration').hasClass('invisible')) {
|
||||
if ($('#do-migration').prop('checked') === true &&
|
||||
$('#old-dbname').val().replace(/\s/g, '') === '') {
|
||||
alert('Bitte angeben: Alter Datenbankname !');
|
||||
return ;
|
||||
}
|
||||
}
|
||||
$(this).dialog('close');
|
||||
var refreshId = me.setInterval();
|
||||
me.runRecovery(iBid, refreshId);
|
||||
}
|
||||
}
|
||||
},
|
||||
open: function (event, ui) {
|
||||
},
|
||||
close: function (event, ui) {
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
/**
|
||||
* @return {void}
|
||||
*/
|
||||
registerEvents: function () {
|
||||
|
||||
// recover backup
|
||||
$(document).on('click', '#recover-backup', function (e) {
|
||||
e.preventDefault();
|
||||
var fieldId = $(this).data('id');
|
||||
if (me.hasProcessStarterEnabled() === true) {
|
||||
me.backupRecovery(fieldId);
|
||||
} else {
|
||||
me.showProcessStarterMissingError();
|
||||
}
|
||||
});
|
||||
$('#no-migration').on('click', function (event) {
|
||||
$(this).prop('checked', true);
|
||||
$('#do-migration').prop('checked', false);
|
||||
me.hideMigrationDbFieldName();
|
||||
});
|
||||
|
||||
$('#do-migration').on('click', function (event) {
|
||||
$(this).prop('checked', true);
|
||||
$('#no-migration').prop('checked', false);
|
||||
me.showMigrationDbFieldName();
|
||||
});
|
||||
|
||||
$('.remove-backup').on('click', function (e) {
|
||||
e.preventDefault();
|
||||
var url = $(this).data('url');
|
||||
if (typeof url !== 'undefined') {
|
||||
me.confirmDelete(url);
|
||||
}
|
||||
});
|
||||
|
||||
$('#create-backup').on('click', function (e) {
|
||||
e.preventDefault();
|
||||
me.createItem();
|
||||
});
|
||||
},
|
||||
|
||||
/**
|
||||
*Reloads current page with parameter message
|
||||
* @param {string} msg
|
||||
*/
|
||||
reloadUrl: function (msg) {
|
||||
if (me.debugMode === false) {
|
||||
window.location.href = 'index.php?module=backup&action=list&msg=' + msg;
|
||||
} else {
|
||||
console.log('JOB done! But No Redirect. Debug mode has been enabled!');
|
||||
}
|
||||
},
|
||||
|
||||
showMigrationSetting: function () {
|
||||
$('#recovery-migration').removeClass('invisible');
|
||||
},
|
||||
|
||||
showMigrationDbFieldName: function () {
|
||||
$('#tr-old-dbname').removeClass('invisible');
|
||||
},
|
||||
|
||||
hideMigrationDbFieldName: function () {
|
||||
$('#tr-old-dbname').addClass('invisible');
|
||||
},
|
||||
|
||||
/**
|
||||
*
|
||||
* @param {number} bid
|
||||
* @returns {boolean}
|
||||
*/
|
||||
backupRecovery: function (bid) {
|
||||
var bckId = parseInt(bid);
|
||||
if (isNaN(bckId) || bckId <= 0) {
|
||||
return false;
|
||||
}
|
||||
me.setCacheBackup(bckId, 'bid');
|
||||
// Check Meta
|
||||
$.ajax({
|
||||
url: 'index.php?module=backup&action=recover&cmd=check-meta',
|
||||
data: {id: bckId},
|
||||
method: 'post',
|
||||
dataType: 'json',
|
||||
beforeSend: function () {
|
||||
App.loading.open();
|
||||
},
|
||||
success: function (data) {
|
||||
me.storage.$backupDialog.dialog('open');
|
||||
if (data.status === false) {
|
||||
if (typeof data.missing_file !== 'undefined' && data.missing_file === true) {
|
||||
me.storage.$backupDialog.dialog('close');
|
||||
me.reloadUrl(data.message);
|
||||
return;
|
||||
}
|
||||
$('#backupModalTimer').addClass('invisible').loadingOverlay('remove');
|
||||
$('#bck-message').addClass('error').html(data.message);
|
||||
me.showMigrationSetting();
|
||||
} else {
|
||||
$('#bck-message').addClass('warning').html(data.message);
|
||||
me.showMigrationSetting();
|
||||
}
|
||||
if (data.ps_message.replace(/\s/g, '') !== '') {
|
||||
$('#bck-ps-message').addClass('error').append(data.ps_message);
|
||||
}
|
||||
|
||||
},
|
||||
error: function ($xhr, textStatus, errorThrown) {
|
||||
alert('Backup konnte nicht hergestellt werden.');
|
||||
}
|
||||
});
|
||||
|
||||
return false;
|
||||
},
|
||||
|
||||
/**
|
||||
*
|
||||
* @param {number} value
|
||||
* @param {string} value
|
||||
* @param {string} data
|
||||
*/
|
||||
setCacheBackup: function (value, data) {
|
||||
$('#backupModal').attr('data-' + data, value);
|
||||
},
|
||||
|
||||
/**
|
||||
*
|
||||
* @param {string} data
|
||||
* @return {string}|{null}
|
||||
*/
|
||||
getCacheBackupValue: function (data) {
|
||||
return typeof $('#backupModal').data(data) !== 'undefined' ? $('#backupModal').data(data) : null;
|
||||
},
|
||||
|
||||
/**
|
||||
*
|
||||
* @param {number} bid
|
||||
* @param {number} refreshId
|
||||
*/
|
||||
runRecovery: function (bid, refreshId) {
|
||||
$('#run-recovery-btn').prop('disabled', true);
|
||||
me.setCacheBackup(refreshId, 'refresh');
|
||||
// run recovery
|
||||
$('#backupModalTimer').removeClass('invisible').loadingOverlay('show').dialog({
|
||||
modal: true, minWidth: 1200, resizable: false, closeOnEscape: false,
|
||||
dialogClass: 'no-titlebar',
|
||||
open: function (event, ui) {
|
||||
$('.ui-dialog-titlebar').hide();
|
||||
$('#backupModalTimer').css({'overflow': 'hidden'});
|
||||
}
|
||||
});
|
||||
var sData = {id: bid};
|
||||
|
||||
if ($('#do-migration').prop('checked') === true && $('#old-dbname').val().replace(/\s/g, '') !== '') {
|
||||
sData.old_db = $('#old-dbname').val();
|
||||
}
|
||||
|
||||
$.ajax({
|
||||
url: 'index.php?module=backup&action=recover',
|
||||
data: sData,
|
||||
method: 'post',
|
||||
dataType: 'json',
|
||||
success: function (data) {
|
||||
if (data.status === false) {
|
||||
clearInterval(refreshId);
|
||||
me.reloadUrl(data.message);
|
||||
} else if (typeof data.file_name !== 'undefined') {
|
||||
me.setCacheBackup(data.generic_error, 'generic_error');
|
||||
me.setCacheBackup(data.file_name, 'filename');
|
||||
} else if (typeof data.created_at !== 'undefined') {
|
||||
me.setCacheBackup(data.created_at, 'created_at');
|
||||
}
|
||||
},
|
||||
error: function ($xhr, textStatus, errorThrown) {
|
||||
alert('Backup konnte nicht hergestellt werden.');
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
/**
|
||||
* @return {void}
|
||||
*/
|
||||
readStatus: function () {
|
||||
var fileName = me.getCacheBackupValue('filename');
|
||||
var sData = {};
|
||||
if (fileName != null) {
|
||||
sData.file_name = fileName;
|
||||
}
|
||||
var createdAt = me.getCacheBackupValue('created_at');
|
||||
|
||||
if (createdAt != null) {
|
||||
sData.created_at = createdAt;
|
||||
}
|
||||
|
||||
var backupFile = me.getCacheBackupValue('backup_file');
|
||||
|
||||
if (backupFile != null) {
|
||||
sData.backup_file = backupFile;
|
||||
}
|
||||
|
||||
$.ajax({
|
||||
url: 'index.php?module=backup&action=readstatus',
|
||||
data: sData,
|
||||
method: 'post',
|
||||
dataType: 'json',
|
||||
success: function (data) {
|
||||
if (data.finished === true) {
|
||||
var refreshId = me.getCacheBackupValue('refresh');
|
||||
if (refreshId) {
|
||||
clearInterval(refreshId);
|
||||
}
|
||||
me.reloadUrl(data.message);
|
||||
}
|
||||
if ($('.bck-status-message').length > 0) {
|
||||
if ($('.bck-status-message').hasClass('hide')) {
|
||||
$('.bck-status-message').removeClass('hide');
|
||||
}
|
||||
if (data.finished === false && $('#live-status').length > 0) {
|
||||
$('#live-status').html($.trim(data.message) + ' ...');
|
||||
}
|
||||
} else {
|
||||
$('#backupModalTimer div.loading-back').after(
|
||||
'<div class="bck-status-message hide"><p id="live-status"></p></div>');
|
||||
}
|
||||
},
|
||||
error: function ($xhr, textStatus, errorThrown) {
|
||||
var interValId = me.getCacheBackupValue('refresh');
|
||||
var genericErrorMsg = me.getCacheBackupValue('generic_error');
|
||||
if (interValId) {
|
||||
clearInterval(interValId);
|
||||
}
|
||||
|
||||
if (me.debugMode === true) {
|
||||
alert('Debug Mode::\n' + errorThrown);
|
||||
}
|
||||
|
||||
me.reloadUrl(genericErrorMsg);
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
/**
|
||||
* @return {void}
|
||||
*/
|
||||
createItem: function () {
|
||||
if (me.isInitialized === false) {
|
||||
me.init();
|
||||
}
|
||||
if (me.storage.$backupDialog.length === 0) {
|
||||
throw 'Could not initialize DataTableLabelsUi. Required elements are missing.';
|
||||
}
|
||||
|
||||
if ($('.backup-success').length > 0) {
|
||||
alert('Entfernen Sie bitte zuerst das Letzte Backup !');
|
||||
return;
|
||||
}
|
||||
|
||||
me.resetAdd();
|
||||
if (me.hasProcessStarterEnabled() === true) {
|
||||
me.storage.$createItemDialog.dialog('open');
|
||||
} else {
|
||||
me.showProcessStarterMissingError();
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* @return {boolean}
|
||||
*/
|
||||
hasProcessStarterEnabled: function () {
|
||||
return true;
|
||||
//var $backupModalStorage = $('#backupModal');
|
||||
//return parseInt($backupModalStorage.data('ps')) === 1;
|
||||
},
|
||||
|
||||
/**
|
||||
* @return {void}
|
||||
*/
|
||||
showProcessStarterMissingError: function () {
|
||||
var message = 'Es sieht so aus, als ob der Prozessstarter Cronjob nicht regelmäßig ' +
|
||||
'ausgeführt wird! Bitte aktivieren Sie diesen ' +
|
||||
'(<a href="http://helpdesk.wawision.de/doku.php?id=entwickler:grundinstallation#einrichten_des_heartbeat-cronjobs_optional" target="_blank">Link zu Helpdesk</a>)!';
|
||||
me.storage.$backupDialog.dialog('open');
|
||||
$('#run-recovery-btn').hide();
|
||||
$('#bck-message').addClass('error').html(message);
|
||||
},
|
||||
|
||||
/**
|
||||
* @return {void}
|
||||
*/
|
||||
addDialog: function () {
|
||||
me.storage.$createItemDialog.dialog({
|
||||
modal: true,
|
||||
bgiframe: true,
|
||||
closeOnEscape: false,
|
||||
minWidth: 650,
|
||||
maxHeight: 700,
|
||||
autoOpen: false,
|
||||
buttons: {
|
||||
ABBRECHEN: function () {
|
||||
me.resetAdd();
|
||||
$(this).dialog('close');
|
||||
},
|
||||
SPEICHERN: function () {
|
||||
me.saveItem();
|
||||
$(this).dialog('close');
|
||||
}
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
/**
|
||||
* @return {void}
|
||||
*/
|
||||
saveItem: function () {
|
||||
var refreshId = me.setInterval();
|
||||
me.setCacheBackup(refreshId, 'refresh');
|
||||
|
||||
$('#backupModalTimer').removeClass('invisible').loadingOverlay('show').dialog({
|
||||
modal: true, minWidth: 1200, resizable: false, closeOnEscape: false,
|
||||
dialogClass: 'no-titlebar',
|
||||
open: function (event, ui) {
|
||||
$('.ui-dialog-titlebar').hide();
|
||||
$('#backupModalTimer').css({'overflow': 'hidden'});
|
||||
}
|
||||
});
|
||||
$.ajax({
|
||||
url: 'index.php?module=backup&action=create',
|
||||
data: {name: $('#b_name').val()},
|
||||
method: 'post',
|
||||
dataType: 'json',
|
||||
beforeSend: function () {
|
||||
App.loading.open();
|
||||
},
|
||||
success: function (data) {
|
||||
App.loading.close();
|
||||
if (data.status === false) {
|
||||
me.reloadUrl(data.message);
|
||||
}
|
||||
|
||||
me.reloadUrl(data.success_msg);
|
||||
|
||||
me.setCacheBackup(data.generic_error, 'generic_error');
|
||||
if (typeof data.created_at !== 'undefined') {
|
||||
me.setCacheBackup(data.created_at, 'created_at');
|
||||
}
|
||||
if (typeof data.backup_file !== 'undefined') {
|
||||
me.setCacheBackup(data.backup_file, 'backup_file');
|
||||
}
|
||||
},
|
||||
error: function ($xhr, textStatus, errorThrown) {
|
||||
alert('Backup konnte nicht angelegt werden. ');
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
/**
|
||||
* @return void
|
||||
*/
|
||||
resetAdd: function () {
|
||||
$('#add-backup').find('#b_name').val('');
|
||||
},
|
||||
|
||||
/**
|
||||
* @type {{registerEvents: registerEvents, init: init}}
|
||||
*/
|
||||
backupImporter: {
|
||||
isInitialized: false,
|
||||
registerEvents: function () {
|
||||
$('#input-for-backup-importer').on('click', function (e) {
|
||||
e.preventDefault();
|
||||
$('#backup-importer').click();
|
||||
});
|
||||
},
|
||||
init: function () {
|
||||
|
||||
me.backupImporter.registerEvents();
|
||||
|
||||
if (me.backupImporter.isInitialized === true) {
|
||||
return;
|
||||
}
|
||||
|
||||
$('#backup-importer').chunkedUpload({
|
||||
//chunkSize: 2097152, // 2097152 = 2MB
|
||||
upload: {
|
||||
url: 'index.php?module=backup&action=importer&cmd=upload'
|
||||
},
|
||||
fileComplete: function (fileInfo) {
|
||||
if (typeof fileInfo.name === 'undefined') {
|
||||
throw 'File name is missing!';
|
||||
}
|
||||
$.ajax({
|
||||
url: 'index.php?module=backup&action=importer&cmd=completed',
|
||||
data: {file_name: fileInfo.name},
|
||||
method: 'post',
|
||||
dataType: 'json',
|
||||
beforeSend: function () {
|
||||
App.loading.open();
|
||||
},
|
||||
success: function (data) {
|
||||
App.loading.close();
|
||||
if (data.status === false) {
|
||||
me.reloadUrl(data.message);
|
||||
}
|
||||
},
|
||||
error: function ($xhr, textStatus, errorThrown) {
|
||||
alert('Backup konnte nicht importiert werden');
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
me.backupImporter.isInitialized = true;
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* @param {string} value
|
||||
* @return {boolean}|{void}
|
||||
*/
|
||||
confirmDelete: function (value) {
|
||||
|
||||
if (!confirm('Soll der Backup Eintrag wirklich gelöscht werden?')) {
|
||||
return false;
|
||||
}
|
||||
window.location.href = value;
|
||||
}
|
||||
};
|
||||
|
||||
return {
|
||||
init: me.init,
|
||||
enableDebug: me.enableDebugMode,
|
||||
disableDebug: me.disableDebugMode,
|
||||
//createItem: me.createItem,
|
||||
import: me.backupImporter.init
|
||||
};
|
||||
|
||||
}(jQuery);
|
||||
|
||||
$(function () {
|
||||
if ($('#backupModal').length > 0 || ('.backup-template').length > 0) {
|
||||
BackupModule.init();
|
||||
}
|
||||
|
||||
if ($('#backup-importer').length > 0) {
|
||||
BackupModule.import();
|
||||
}
|
||||
});
|
||||
Reference in New Issue
Block a user