Initial xentral_oss_20.3.c9ffacf

This commit is contained in:
Alex
2021-05-21 08:49:41 +02:00
parent 5406e4a551
commit 34e5ac43d9
18884 changed files with 2109867 additions and 0 deletions
+101
View File
@@ -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);
}
}
+603
View File
@@ -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);
}
}
+96
View File
@@ -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);
}
+120
View File
@@ -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;
}
+558
View File
@@ -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&auml;&szlig;ig ' +
'ausgef&uuml;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();
}
});