mirror of
https://github.com/Combodo/iTop.git
synced 2026-05-19 07:12:26 +02:00
N°2249 - Supportability - Updater module (application upgrade)
This commit is contained in:
6
datamodels/2.x/itop-core-update/README.md
Normal file
6
datamodels/2.x/itop-core-update/README.md
Normal file
@@ -0,0 +1,6 @@
|
||||
# itop-core-update
|
||||
Application upgrade
|
||||
|
||||
This feature allows administrators to upgrade the application from a downloaded package.
|
||||
|
||||
namespace Combodo\iTop\CoreUpdate;
|
||||
21
datamodels/2.x/itop-core-update/ajax.php
Normal file
21
datamodels/2.x/itop-core-update/ajax.php
Normal file
@@ -0,0 +1,21 @@
|
||||
<?php
|
||||
/**
|
||||
* @copyright Copyright (C) 2010-2019 Combodo SARL
|
||||
* @license http://opensource.org/licenses/AGPL-3.0
|
||||
*/
|
||||
|
||||
namespace Combodo\iTop\CoreUpdate;
|
||||
|
||||
use Combodo\iTop\CoreUpdate\Controller\AjaxController;
|
||||
use ContextTag;
|
||||
|
||||
require_once(APPROOT.'application/startup.inc.php');
|
||||
new ContextTag('Setup');
|
||||
|
||||
$oUpdateController = new AjaxController();
|
||||
$oUpdateController->DisableInDemoMode();
|
||||
$oUpdateController->AllowOnlyAdmin();
|
||||
|
||||
// Allow parallel execution of ajax requests
|
||||
session_write_close();
|
||||
$oUpdateController->HandleOperation();
|
||||
@@ -0,0 +1,11 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<itop_design xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" version="1.0">
|
||||
<menus>
|
||||
<menu id="iTopUpdate" xsi:type="WebPageMenuNode" _delta="define">
|
||||
<rank>60</rank>
|
||||
<parent>System</parent>
|
||||
<url>$pages/exec.php?exec_module=itop-core-update&exec_page=index.php&c[menu]=iTopUpdate&maintenance=true</url>
|
||||
<enable_admin_only>1</enable_admin_only>
|
||||
</menu>
|
||||
</menus>
|
||||
</itop_design>
|
||||
108
datamodels/2.x/itop-core-update/en.dict.itop-core-update.php
Normal file
108
datamodels/2.x/itop-core-update/en.dict.itop-core-update.php
Normal file
@@ -0,0 +1,108 @@
|
||||
<?php
|
||||
/**
|
||||
* Localized data
|
||||
*
|
||||
* @copyright Copyright (C) 2010-2018 Combodo SARL
|
||||
* @license http://opensource.org/licenses/AGPL-3.0
|
||||
*
|
||||
* This file is part of iTop.
|
||||
*
|
||||
* iTop is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* iTop is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with iTop. If not, see <http://www.gnu.org/licenses/>
|
||||
*/
|
||||
|
||||
Dict::Add('EN US', 'English', 'English', array(
|
||||
'iTopUpdate:UI:PageTitle' => 'Application Upgrade',
|
||||
'itop-core-update:UI:SelectUpdateFile' => 'Application Upgrade',
|
||||
'itop-core-update:UI:ConfirmUpdate' => 'Application Upgrade',
|
||||
'itop-core-update:UI:UpdateCoreFiles' => 'Application Upgrade',
|
||||
'itop-core-update:UI:UpdateDone' => 'Application Upgrade',
|
||||
|
||||
'iTopUpdate:UI:SelectUpdateFile' => 'Select an upgrade file to upload',
|
||||
'iTopUpdate:UI:CheckUpdate' => 'Verify upgrade file',
|
||||
'iTopUpdate:UI:ConfirmInstallFile' => 'You are about to install %1$s',
|
||||
'iTopUpdate:UI:DoUpdate' => 'Upgrade',
|
||||
'iTopUpdate:UI:CurrentVersion' => 'Current installed version',
|
||||
'iTopUpdate:UI:Back' => 'Back',
|
||||
'iTopUpdate:UI:Cancel' => 'Cancel',
|
||||
'iTopUpdate:UI:Continue' => 'Continue',
|
||||
'iTopUpdate:UI:WithDBBackup' => 'Database backup',
|
||||
'iTopUpdate:UI:WithFilesBackup' => 'Application files backup',
|
||||
'iTopUpdate:UI:WithoutBackup' => 'No backup is planned',
|
||||
'iTopUpdate:UI:Backup' => 'Backup generated before update',
|
||||
'iTopUpdate:UI:DoFilesArchive' => 'Archive application files',
|
||||
'iTopUpdate:UI:UploadArchive' => 'Select a package to upload',
|
||||
'iTopUpdate:UI:ServerFile' => 'Path of a package already on the server',
|
||||
|
||||
'iTopUpdate:UI:Status' => 'Status',
|
||||
'iTopUpdate:UI:Action' => 'Update',
|
||||
'iTopUpdate:UI:History' => 'Versions History',
|
||||
'iTopUpdate:UI:Progress' => 'Progress of the upgrade',
|
||||
|
||||
'iTopUpdate:UI:DoBackup:Label' => 'Backup files and database',
|
||||
'iTopUpdate:UI:DoBackup:Warning' => 'Backup is not recommended due to limited available disk space',
|
||||
|
||||
'iTopUpdate:UI:DiskFreeSpace' => 'Disk free space',
|
||||
'iTopUpdate:UI:ItopDiskSpace' => 'iTop disk space',
|
||||
'iTopUpdate:UI:DBDiskSpace' => 'Database disk space',
|
||||
'iTopUpdate:UI:FileUploadMaxSize' => 'File upload max size',
|
||||
|
||||
'iTopUpdate:UI:PostMaxSize' => 'PHP ini value post_max_size: %1$s',
|
||||
'iTopUpdate:UI:UploadMaxFileSize' => 'PHP ini value upload_max_filesize: %1$s',
|
||||
|
||||
'iTopUpdate:UI:CanCoreUpdate:Loading' => 'Checking filesystem',
|
||||
'iTopUpdate:UI:CanCoreUpdate:Error' => 'Checking filesystem failed (%1$s)',
|
||||
'iTopUpdate:UI:CanCoreUpdate:ErrorFileNotExist' => 'Checking filesystem failed (File not exist %1$s)',
|
||||
'iTopUpdate:UI:CanCoreUpdate:Failed' => 'Checking filesystem failed',
|
||||
'iTopUpdate:UI:CanCoreUpdate:Yes' => 'Application can be updated',
|
||||
'iTopUpdate:UI:CanCoreUpdate:No' => 'Application cannot be updated: %1$s',
|
||||
|
||||
// Setup Messages
|
||||
'iTopUpdate:UI:SetupMessage:Ready' => 'Ready to start',
|
||||
'iTopUpdate:UI:SetupMessage:EnterMaintenance' => 'Entering maintenance mode',
|
||||
'iTopUpdate:UI:SetupMessage:Backup' => 'Database backup',
|
||||
'iTopUpdate:UI:SetupMessage:FilesArchive' => 'Archive application files',
|
||||
'iTopUpdate:UI:SetupMessage:CopyFiles' => 'Copy new version files',
|
||||
'iTopUpdate:UI:SetupMessage:Compile' => 'Upgrade application and database',
|
||||
'iTopUpdate:UI:SetupMessage:ExitMaintenance' => 'Exiting maintenance mode',
|
||||
'iTopUpdate:UI:SetupMessage:UpdateDone' => 'Upgrade completed',
|
||||
|
||||
// Errors
|
||||
'iTopUpdate:Error:MissingFunction' => 'Impossible to start upgrade, missing function',
|
||||
'iTopUpdate:Error:MissingFile' => 'Missing file: %1$s',
|
||||
'iTopUpdate:Error:CorruptedFile' => 'File %1$s is corrupted',
|
||||
'iTopUpdate:Error:BadFileFormat' => 'Upgrade file is not a zip file',
|
||||
'iTopUpdate:Error:BadFileContent' => 'Upgrade file is not an application archive',
|
||||
'iTopUpdate:Error:BadItopProduct' => 'Upgrade file is not compatible with your application',
|
||||
'iTopUpdate:Error:Copy' => 'Error, cannot copy \'%1$s\' to \'%2$s\'',
|
||||
'iTopUpdate:Error:FileNotFound' => 'File not found',
|
||||
'iTopUpdate:Error:NoFile' => 'No file provided',
|
||||
'iTopUpdate:Error:InvalidToken' => 'Invalid token',
|
||||
'iTopUpdate:Error:UpdateFailed' => 'Upgrade failed ',
|
||||
'iTopUpdate:Error:FileUploadMaxSizeTooSmall' => 'The upload max size seems too small for update. Please change the PHP configuration.',
|
||||
|
||||
'iTopUpdate:UI:RestoreArchive' => 'You can restore your application from the archive \'%1$s\'',
|
||||
'iTopUpdate:UI:RestoreBackup' => 'You can restore the database from \'%1$s\'',
|
||||
'iTopUpdate:UI:MaintenanceModeActive' => 'The application is currently under maintenance, no user can access the application. You have to run a setup or restore the application archive to return in normal mode.',
|
||||
'iTopUpdate:UI:UpdateDone' => 'Upgrade successful',
|
||||
'Menu:iTopUpdate' => 'Application Upgrade',
|
||||
'Menu:iTopUpdate+' => 'Application Upgrade',
|
||||
|
||||
// Missing itop entries
|
||||
'Class:ModuleInstallation/Attribute:installed' => 'Installed on',
|
||||
'Class:ModuleInstallation/Attribute:name' => 'Name',
|
||||
'Class:ModuleInstallation/Attribute:version' => 'Version',
|
||||
'Class:ModuleInstallation/Attribute:comment' => 'Comment',
|
||||
));
|
||||
|
||||
|
||||
108
datamodels/2.x/itop-core-update/fr.dict.itop-core-update.php
Normal file
108
datamodels/2.x/itop-core-update/fr.dict.itop-core-update.php
Normal file
@@ -0,0 +1,108 @@
|
||||
<?php
|
||||
/**
|
||||
* Localized data
|
||||
*
|
||||
* @copyright Copyright (C) 2010-2018 Combodo SARL
|
||||
* @license http://opensource.org/licenses/AGPL-3.0
|
||||
*
|
||||
* This file is part of iTop.
|
||||
*
|
||||
* iTop is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* iTop is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with iTop. If not, see <http://www.gnu.org/licenses/>
|
||||
*/
|
||||
|
||||
Dict::Add('FR FR', 'French', 'Français', array(
|
||||
'iTopUpdate:UI:PageTitle' => 'Mise à jour de l\'application',
|
||||
'itop-core-update:UI:SelectUpdateFile' => 'Mise à jour',
|
||||
'itop-core-update:UI:ConfirmUpdate' => 'Mise à jour',
|
||||
'itop-core-update:UI:UpdateCoreFiles' => 'Mise à jour',
|
||||
'iTopUpdate:UI:SelectUpdateFile' => 'Sélectionner un fichier de mise à jour',
|
||||
'iTopUpdate:UI:CheckUpdate' => 'Vérification de la mise à jour',
|
||||
'iTopUpdate:UI:ConfirmInstallFile' => 'La mise à jour %1$s va être installée',
|
||||
'iTopUpdate:UI:DoUpdate' => 'Mettre à jour',
|
||||
'iTopUpdate:UI:DoBackup' => 'Faire une sauvegarde des fichiers et de la base',
|
||||
'iTopUpdate:UI:CurrentVersion' => 'Version installée',
|
||||
'iTopUpdate:UI:Back' => 'Annuler',
|
||||
'iTopUpdate:UI:WithBackup' => 'Avec sauvegarde de l\'application, l\'archive sera dans \'%1$s\'',
|
||||
'iTopUpdate:UI:WithoutBackup' => 'Pas de sauvegarde',
|
||||
'iTopUpdate:UI:Status' => 'Versions installées',
|
||||
'iTopUpdate:UI:InstallationCanBeUpdated' => 'L\'application peut être mise à jour',
|
||||
'iTopUpdate:UI:InstallationCanNotBeUpdated' => 'L\'application ne peut pas être mise à jour',
|
||||
'iTopUpdate:UI:DiskFreeSpace' => 'Taille disque disponible',
|
||||
'iTopUpdate:UI:ItopDiskSpace' => 'Taille disque utilisée par l\'application',
|
||||
'iTopUpdate:UI:DBDiskSpace' => 'Taille disque utilisée par la base de données',
|
||||
'iTopUpdate:UI:FileUploadMaxSize' => 'Taille maximale de chargement de fichier',
|
||||
|
||||
'iTopUpdate:UI:PostMaxSize' => 'Valeur PHP ini post_max_size : %1$s',
|
||||
'iTopUpdate:UI:UploadMaxFileSize' => 'Valeur PHP ini upload_max_filesize : %1$s',
|
||||
|
||||
'iTopUpdate:UI:Cancel' => 'Annuler',
|
||||
'iTopUpdate:UI:Continue' => 'Continuer',
|
||||
'iTopUpdate:UI:WithDBBackup' => 'Sauvegarde de la base de données',
|
||||
'iTopUpdate:UI:WithFilesBackup' => 'Archive des fichiers de l\'application' ,
|
||||
'iTopUpdate:UI:Backup' => 'Sauvegarde effectuée avant la mise à jour',
|
||||
'iTopUpdate:UI:DoFilesArchive' => 'Archive les fichiers de l\'application',
|
||||
|
||||
'iTopUpdate:UI:Action' => 'Mettre à jour',
|
||||
'iTopUpdate:UI:History' => 'Historique des versions',
|
||||
'iTopUpdate:UI:Progress' => 'Progression de la mise à jour',
|
||||
'iTopUpdate:UI:DoBackup:Label' => 'Sauvegarde de la base de données',
|
||||
'iTopUpdate:UI:DoBackup:Warning' => 'La sauvegarde n\'est pas conseillée à cause du manque de place disque disponible',
|
||||
'iTopUpdate:UI:CanCoreUpdate:Loading' => 'Vérification des fichiers',
|
||||
'iTopUpdate:UI:CanCoreUpdate:Error' => 'Échec de la vérification des fichiers (%1$s)',
|
||||
'iTopUpdate:UI:CanCoreUpdate:ErrorFileNotExist' => 'Échec de la vérification des fichiers (Fichier manquant %1$s)',
|
||||
'iTopUpdate:UI:CanCoreUpdate:Failed' => 'Échec de la vérification des fichiers',
|
||||
'iTopUpdate:UI:CanCoreUpdate:Yes' => 'L\'application peut être mise à jour',
|
||||
'iTopUpdate:UI:CanCoreUpdate:No' => 'L\'application ne peut pas être mise à jour : %1$s',
|
||||
|
||||
// Setup Messages
|
||||
'iTopUpdate:UI:SetupMessage:Ready' => 'Prêt pour l\installation',
|
||||
'iTopUpdate:UI:SetupMessage:EnterMaintenance' => 'Application en maintenance',
|
||||
'iTopUpdate:UI:SetupMessage:Backup' => 'Sauvegarde des fichiers de l\'application',
|
||||
'iTopUpdate:UI:SetupMessage:FilesArchive' => 'Archivage des fichiers de l\'application',
|
||||
'iTopUpdate:UI:SetupMessage:CopyFiles' => 'Copie des fichiers de la nouvelle version',
|
||||
'iTopUpdate:UI:SetupMessage:Compile' => 'Mise à jour de l\'application et de la base de données',
|
||||
'iTopUpdate:UI:SetupMessage:ExitMaintenance' => 'Application en utilisation normale',
|
||||
'iTopUpdate:UI:SetupMessage:UpdateDone' => 'Installation terminée',
|
||||
|
||||
// Errors
|
||||
'iTopUpdate:Error:MissingFunction' => 'Impossible de mettre à jour',
|
||||
'iTopUpdate:Error:MissingFile' => 'Ficher manquant : %1$s',
|
||||
'iTopUpdate:Error:CorruptedFile' => 'Le fichier %1$s est corrompu',
|
||||
'iTopUpdate:Error:BadFileFormat' => 'Le fichier de mise à jour n\'est pas au format "zip"' ,
|
||||
'iTopUpdate:Error:Copy' => 'Erreur : impossible de copier le fichier \'%1$s\' dans \'%2$s\'',
|
||||
'iTopUpdate:Error:FileNotFound' => 'Fichier manquant',
|
||||
'iTopUpdate:Error:InvalidToken' => 'Information manquante',
|
||||
'iTopUpdate:Error:NoUpdate' => 'La mise à jour a échoué',
|
||||
'iTopUpdate:Error:FileUploadMaxSizeTooSmall' => 'La taille maximale de chargement de fichier semble trop petite pour faire la mise à jour. Veuillez changer la configuration de PHP.',
|
||||
|
||||
'iTopUpdate:UI:RestoreArchive' => 'Vous pouvez restaurer l\'application depuis \'%1$s\'',
|
||||
'iTopUpdate:UI:RestoreBackup' => 'Vous pouvez restaurer la base de données depuis \'%1$s\'',
|
||||
'iTopUpdate:UI:MaintenanceModeActive' => 'L\'application est actuellement en maintenance, aucun utilisateur n\'a accès à l\'application. Vous pouvez lancer un setup ou réinstaller l\'application depuis une archive pour retourner dans un mode normal.',
|
||||
|
||||
'iTopUpdate:UI:UpdateDone' => 'Mise à jour effectuée',
|
||||
'Menu:iTopUpdate' => 'Mise à jour de l\'application',
|
||||
'Menu:iTopUpdate+' => 'Mise à jour de l\'application',
|
||||
'iTopUpdate:Error:BadFileContent' => 'Le fichier n\'est pas une archive valide',
|
||||
'iTopUpdate:Error:BadItopProduct' => 'L\'archive n\'est pas compatible avec votre application',
|
||||
'iTopUpdate:Error:NoFile' => 'Pas d\'archive',
|
||||
'iTopUpdate:Error:UpdateFailed' => 'La mise à jour à échoué ',
|
||||
|
||||
// Missing itop entries
|
||||
'Class:ModuleInstallation/Attribute:installed' => 'Installé le',
|
||||
'Class:ModuleInstallation/Attribute:name' => 'Nom',
|
||||
'Class:ModuleInstallation/Attribute:version' => 'Version',
|
||||
'Class:ModuleInstallation/Attribute:comment' => 'Commentaire',
|
||||
));
|
||||
|
||||
|
||||
19
datamodels/2.x/itop-core-update/index.php
Normal file
19
datamodels/2.x/itop-core-update/index.php
Normal file
@@ -0,0 +1,19 @@
|
||||
<?php
|
||||
/**
|
||||
* @copyright Copyright (C) 2010-2019 Combodo SARL
|
||||
* @license http://opensource.org/licenses/AGPL-3.0
|
||||
*/
|
||||
|
||||
namespace Combodo\iTop\CoreUpdate;
|
||||
|
||||
use Combodo\iTop\CoreUpdate\Controller\UpdateController;
|
||||
use ContextTag;
|
||||
|
||||
require_once(APPROOT.'application/startup.inc.php');
|
||||
new ContextTag('Setup');
|
||||
|
||||
$oUpdateController = new UpdateController();
|
||||
$oUpdateController->DisableInDemoMode();
|
||||
$oUpdateController->AllowOnlyAdmin();
|
||||
$oUpdateController->SetDefaultOperation('SelectUpdateFile');
|
||||
$oUpdateController->HandleOperation();
|
||||
52
datamodels/2.x/itop-core-update/module.itop-core-update.php
Normal file
52
datamodels/2.x/itop-core-update/module.itop-core-update.php
Normal file
@@ -0,0 +1,52 @@
|
||||
<?php
|
||||
/**
|
||||
* @copyright Copyright (C) 2010-2019 Combodo SARL
|
||||
* @license http://opensource.org/licenses/AGPL-3.0
|
||||
*/
|
||||
|
||||
//
|
||||
// iTop module definition file
|
||||
//
|
||||
|
||||
SetupWebPage::AddModule(
|
||||
__FILE__, // Path to the current file, all other file names are relative to the directory containing this file
|
||||
'itop-core-update/1.0.0',
|
||||
array(
|
||||
// Identification
|
||||
//
|
||||
'label' => 'iTop Core Update',
|
||||
'category' => 'business',
|
||||
|
||||
// Setup
|
||||
//
|
||||
'dependencies' => array(
|
||||
'itop-twig-base/1.0.0',
|
||||
'itop-files-information/1.0.0',
|
||||
'combodo-db-tools/1.0.8',
|
||||
),
|
||||
'mandatory' => false,
|
||||
'visible' => true,
|
||||
|
||||
// Components
|
||||
//
|
||||
'datamodel' => array(
|
||||
'model.itop-core-update.php',
|
||||
'src/Service/RunTimeEnvironmentCoreUpdater.php',
|
||||
'src/Service/CoreUpdater.php',
|
||||
'src/Controller/UpdateController.php',
|
||||
'src/Controller/AjaxController.php',
|
||||
),
|
||||
'webservice' => array(),
|
||||
'data.struct' => array(),
|
||||
'data.sample' => array(),
|
||||
|
||||
// Documentation
|
||||
//
|
||||
'doc.manual_setup' => '', // hyperlink to manual setup documentation, if any
|
||||
'doc.more_information' => '', // hyperlink to more information, if any
|
||||
|
||||
// Default settings
|
||||
//
|
||||
'settings' => array(),
|
||||
)
|
||||
);
|
||||
@@ -0,0 +1,184 @@
|
||||
<?php
|
||||
/**
|
||||
* @copyright Copyright (C) 2010-2019 Combodo SARL
|
||||
* @license http://opensource.org/licenses/AGPL-3.0
|
||||
*/
|
||||
|
||||
|
||||
namespace Combodo\iTop\CoreUpdate\Controller;
|
||||
|
||||
|
||||
use Combodo\iTop\CoreUpdate\Service\CoreUpdater;
|
||||
use Combodo\iTop\DBTools\Service\DBToolsUtils;
|
||||
use Combodo\iTop\FilesInformation\Service\FileNotExistException;
|
||||
use Combodo\iTop\FilesInformation\Service\FilesInformation;
|
||||
use Combodo\iTop\TwigBase\Controller\Controller;
|
||||
use Dict;
|
||||
use Exception;
|
||||
use IssueLog;
|
||||
use MetaModel;
|
||||
use SetupUtils;
|
||||
use utils;
|
||||
|
||||
class AjaxController extends Controller
|
||||
{
|
||||
const LOCAL_DIR = __DIR__;
|
||||
|
||||
public function OperationCanUpdateCore()
|
||||
{
|
||||
$aParams = array();
|
||||
|
||||
try
|
||||
{
|
||||
$bCanUpdateCore = FilesInformation::CanUpdateCore($sMessage);
|
||||
$aParams['bStatus'] = $bCanUpdateCore;
|
||||
if ($bCanUpdateCore)
|
||||
{
|
||||
$aParams['sMessage'] = Dict::S('iTopUpdate:UI:CanCoreUpdate:Yes');
|
||||
}
|
||||
else
|
||||
{
|
||||
$aParams['sMessage'] = Dict::Format('iTopUpdate:UI:CanCoreUpdate:No', $sMessage);
|
||||
}
|
||||
}
|
||||
catch (FileNotExistException $e)
|
||||
{
|
||||
$aParams['bStatus'] = false;
|
||||
$aParams['sMessage'] = Dict::Format('iTopUpdate:UI:CanCoreUpdate:ErrorFileNotExist', $e->getMessage());
|
||||
}
|
||||
catch(Exception $e)
|
||||
{
|
||||
$aParams['bStatus'] = false;
|
||||
$aParams['sMessage'] = Dict::Format('iTopUpdate:UI:CanCoreUpdate:Error', $e->getMessage());
|
||||
}
|
||||
|
||||
$this->DisplayJSONPage($aParams);
|
||||
}
|
||||
|
||||
public function OperationGetItopDiskSpace()
|
||||
{
|
||||
$aParams = array();
|
||||
$aParams['iItopDiskSpace'] = FilesInformation::GetItopDiskSpace();
|
||||
$aParams['sItopDiskSpace'] = utils::BytesToFriendlyFormat($aParams['iItopDiskSpace']);
|
||||
$this->DisplayJSONPage($aParams);
|
||||
}
|
||||
|
||||
public function OperationGetDBDiskSpace()
|
||||
{
|
||||
$aParams = array();
|
||||
$aParams['iDBDiskSpace'] = DBToolsUtils::GetDatabaseSize();
|
||||
$aParams['sDBDiskSpace'] = utils::BytesToFriendlyFormat($aParams['iDBDiskSpace']);
|
||||
$this->DisplayJSONPage($aParams);
|
||||
}
|
||||
|
||||
public function OperationGetCurrentVersion()
|
||||
{
|
||||
$aParams = array();
|
||||
$aParams['sVersion'] = Dict::Format('UI:iTopVersion:Long', ITOP_APPLICATION, ITOP_VERSION, ITOP_REVISION, ITOP_BUILD_DATE);
|
||||
$this->DisplayJSONPage($aParams);
|
||||
}
|
||||
|
||||
public function OperationEnterMaintenance()
|
||||
{
|
||||
$aParams = array();
|
||||
try
|
||||
{
|
||||
SetupUtils::EnterReadOnlyMode(MetaModel::GetConfig());
|
||||
$iResponseCode = 200;
|
||||
}
|
||||
catch (Exception $e)
|
||||
{
|
||||
IssueLog::Error("EnterMaintenance: ".$e->getMessage());
|
||||
$aParams['sError'] = $e->getMessage();
|
||||
$iResponseCode = 500;
|
||||
}
|
||||
$this->DisplayJSONPage($aParams, $iResponseCode);
|
||||
}
|
||||
|
||||
public function OperationExitMaintenance()
|
||||
{
|
||||
$aParams = array();
|
||||
try
|
||||
{
|
||||
SetupUtils::ExitReadOnlyMode();
|
||||
$iResponseCode = 200;
|
||||
}
|
||||
catch (Exception $e)
|
||||
{
|
||||
IssueLog::Error("ExitMaintenance: ".$e->getMessage());
|
||||
$aParams['sError'] = $e->getMessage();
|
||||
$iResponseCode = 500;
|
||||
}
|
||||
$this->DisplayJSONPage($aParams, $iResponseCode);
|
||||
}
|
||||
|
||||
public function OperationBackup()
|
||||
{
|
||||
$aParams = array();
|
||||
try
|
||||
{
|
||||
CoreUpdater::Backup();
|
||||
$iResponseCode = 200;
|
||||
}
|
||||
catch (Exception $e)
|
||||
{
|
||||
IssueLog::Error("Backup: ".$e->getMessage());
|
||||
$aParams['sError'] = $e->getMessage();
|
||||
$iResponseCode = 500;
|
||||
}
|
||||
$this->DisplayJSONPage($aParams, $iResponseCode);
|
||||
}
|
||||
|
||||
public function OperationFilesArchive()
|
||||
{
|
||||
$aParams = array();
|
||||
try
|
||||
{
|
||||
CoreUpdater::CreateItopArchive();
|
||||
$iResponseCode = 200;
|
||||
}
|
||||
catch (Exception $e)
|
||||
{
|
||||
IssueLog::Error("FilesArchive: ".$e->getMessage());
|
||||
$aParams['sError'] = $e->getMessage();
|
||||
$iResponseCode = 500;
|
||||
}
|
||||
$this->DisplayJSONPage($aParams, $iResponseCode);
|
||||
}
|
||||
|
||||
public function OperationCopyFiles()
|
||||
{
|
||||
$aParams = array();
|
||||
try
|
||||
{
|
||||
CoreUpdater::CopyCoreFiles();
|
||||
$iResponseCode = 200;
|
||||
}
|
||||
catch (Exception $e)
|
||||
{
|
||||
IssueLog::Error("CopyFiles: ".$e->getMessage());
|
||||
$aParams['sError'] = $e->getMessage();
|
||||
$iResponseCode = 500;
|
||||
}
|
||||
|
||||
$this->DisplayJSONPage($aParams, $iResponseCode);
|
||||
}
|
||||
|
||||
public function OperationCompile()
|
||||
{
|
||||
$aParams = array();
|
||||
try
|
||||
{
|
||||
CoreUpdater::Compile();
|
||||
$iResponseCode = 200;
|
||||
}
|
||||
catch (Exception $e)
|
||||
{
|
||||
IssueLog::Error("Compile: ".$e->getMessage());
|
||||
$aParams['sError'] = $e->getMessage();
|
||||
$iResponseCode = 500;
|
||||
}
|
||||
|
||||
$this->DisplayJSONPage($aParams, $iResponseCode);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,190 @@
|
||||
<?php
|
||||
/**
|
||||
* @copyright Copyright (C) 2010-2019 Combodo SARL
|
||||
* @license http://opensource.org/licenses/AGPL-3.0
|
||||
*/
|
||||
|
||||
namespace Combodo\iTop\CoreUpdate\Controller;
|
||||
|
||||
use Combodo\iTop\CoreUpdate\Service\CoreUpdater;
|
||||
use Combodo\iTop\DBTools\Service\DBToolsUtils;
|
||||
use Combodo\iTop\TwigBase\Controller\Controller;
|
||||
use Dict;
|
||||
use Exception;
|
||||
use SetupUtils;
|
||||
use utils;
|
||||
|
||||
class UpdateController extends Controller
|
||||
{
|
||||
const LOCAL_DIR = __DIR__;
|
||||
|
||||
public function OperationSelectUpdateFile()
|
||||
{
|
||||
$sTransactionId = utils::GetNewTransactionId();
|
||||
$aParams = array();
|
||||
$aParams['sTransactionId'] = $sTransactionId;
|
||||
$aParams['aPreviousInstall'] = $this->GetPreviousInstallations();
|
||||
$aParams['sAjaxURL'] = utils::GetAbsoluteUrlModulePage('itop-core-update', 'ajax.php', array('maintenance' => 'true'));
|
||||
$aParams['iDiskFreeSpace'] = disk_free_space(APPROOT);
|
||||
$aParams['sDiskFreeSpace'] = utils::BytesToFriendlyFormat($aParams['iDiskFreeSpace']);
|
||||
$aParams['iFileUploadMaxSize'] = $this->GetFileUploadMaxSize();
|
||||
$aParams['sFileUploadMaxSize'] = utils::BytesToFriendlyFormat($aParams['iFileUploadMaxSize']);
|
||||
$aParams['sPostMaxSize'] = ini_get('post_max_size');
|
||||
$aParams['sUploadMaxSize'] = ini_get('upload_max_filesize');
|
||||
|
||||
$this->DisplayPage($aParams);
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws \Exception
|
||||
*/
|
||||
public function OperationConfirmUpdate()
|
||||
{
|
||||
$sTransactionId = utils::ReadPostedParam('transaction_id', '', 'transaction_id');
|
||||
if (!utils::IsTransactionValid($sTransactionId))
|
||||
{
|
||||
throw new Exception(Dict::S('iTopUpdate:Error:InvalidToken'));
|
||||
}
|
||||
|
||||
$bDoBackup = utils::ReadPostedParam('doBackup', 0, 'integer') == 1;
|
||||
$bDoFilesArchive = utils::ReadPostedParam('doFilesArchive', 0, 'integer') == 1;
|
||||
|
||||
$sNewVersion = null;
|
||||
$sName = '';
|
||||
$sVersionToInstall = '';
|
||||
$sError = '';
|
||||
try
|
||||
{
|
||||
if (isset($_FILES['file']))
|
||||
{
|
||||
$aFileInfo = $_FILES['file'];
|
||||
$iError = $aFileInfo['error'];
|
||||
if ($iError === UPLOAD_ERR_OK)
|
||||
{
|
||||
$sDownloadDir = CoreUpdater::DOWNLOAD_DIR;
|
||||
if (is_dir($sDownloadDir))
|
||||
{
|
||||
SetupUtils::rrmdir($sDownloadDir);
|
||||
}
|
||||
SetupUtils::builddir($sDownloadDir);
|
||||
$sTmpName = $aFileInfo['tmp_name'];
|
||||
$sName = $aFileInfo['name'];
|
||||
$sNewVersion = $sDownloadDir.$sName;
|
||||
if (@move_uploaded_file($sTmpName, $sNewVersion) === false)
|
||||
{
|
||||
throw new Exception(Dict::S('iTopUpdate:Error:FileNotFound'));
|
||||
}
|
||||
CoreUpdater::ExtractDownloadedFile($sNewVersion);
|
||||
$sVersionToInstall = CoreUpdater::GetVersionToInstall();
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new Exception(Dict::S('iTopUpdate:Error:NoFile'));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new Exception(Dict::S('iTopUpdate:Error:NoFile'));
|
||||
}
|
||||
}
|
||||
catch (Exception $e)
|
||||
{
|
||||
$iError = UPLOAD_ERR_NO_FILE;
|
||||
$sError = $e->getMessage();
|
||||
}
|
||||
|
||||
|
||||
$aParams = array();
|
||||
$aParams['sName'] = $sName;
|
||||
$aParams['bSuccess'] = ($iError == 0);
|
||||
$aParams['sError'] = $sError;
|
||||
|
||||
$aParams['bDoBackup'] = $bDoBackup;
|
||||
$aParams['bDoFilesArchive'] = $bDoFilesArchive;
|
||||
$aParams['sItopArchive'] = CoreUpdater::GetItopArchiveFile();
|
||||
$aParams['sBackupFile'] = CoreUpdater::GetBackupFile();
|
||||
|
||||
$sQuestion = Dict::Format('iTopUpdate:UI:ConfirmInstallFile', $sVersionToInstall);
|
||||
$aParams['sQuestion'] = $sQuestion;
|
||||
|
||||
$sTransactionId = utils::GetNewTransactionId();
|
||||
$aParams['sTransactionId'] = $sTransactionId;
|
||||
|
||||
$this->DisplayPage($aParams);
|
||||
}
|
||||
|
||||
public function OperationUpdateCoreFiles()
|
||||
{
|
||||
$sTransactionId = utils::ReadPostedParam('transaction_id', '', 'transaction_id');
|
||||
if (!utils::IsTransactionValid($sTransactionId))
|
||||
{
|
||||
throw new Exception(Dict::S('iTopUpdate:Error:InvalidToken'));
|
||||
}
|
||||
|
||||
$sNewVersion = utils::ReadPostedParam('filename', null, 'filename');
|
||||
$bDoBackup = utils::ReadPostedParam('doBackup', 0, 'integer') == 1;
|
||||
$bDoFilesArchive = utils::ReadPostedParam('doFilesArchive', 0, 'integer') == 1;
|
||||
$sCurrentVersion = Dict::Format('UI:iTopVersion:Long', ITOP_APPLICATION, ITOP_VERSION, ITOP_REVISION, ITOP_BUILD_DATE);
|
||||
|
||||
$aParams = array(
|
||||
'sCurrentVersion' => $sCurrentVersion,
|
||||
'bDoBackup' => $bDoBackup,
|
||||
'sBackupFile' => CoreUpdater::GetBackupFile(),
|
||||
'bDoFilesArchive' => $bDoFilesArchive,
|
||||
'sItopArchive' => CoreUpdater::GetItopArchiveFile(),
|
||||
'sNewVersion' => $sNewVersion,
|
||||
'sProgressImage' => utils::GetAbsoluteUrlAppRoot().'setup/orange-progress.gif',
|
||||
'sSetupToken' => SetupUtils::CreateSetupToken(),
|
||||
'sAjaxURL' => utils::GetAbsoluteUrlModulePage('itop-core-update', 'ajax.php', array('maintenance' => 'true')),
|
||||
);
|
||||
$this->AddLinkedScript(utils::GetAbsoluteUrlAppRoot().'setup/jquery.progression.js');
|
||||
|
||||
$this->DisplayPage($aParams);
|
||||
}
|
||||
|
||||
private function GetPreviousInstallations()
|
||||
{
|
||||
return DBToolsUtils::GetPreviousInstallations();
|
||||
}
|
||||
|
||||
// Returns a file size limit in bytes based on the PHP upload_max_filesize
|
||||
// and post_max_size
|
||||
private function GetFileUploadMaxSize()
|
||||
{
|
||||
static $iMaxSize = -1;
|
||||
|
||||
if ($iMaxSize < 0)
|
||||
{
|
||||
// Start with post_max_size.
|
||||
$iPostMaxSize = $this->ParseSize(ini_get('post_max_size'));
|
||||
if ($iPostMaxSize > 0)
|
||||
{
|
||||
$iMaxSize = $iPostMaxSize;
|
||||
}
|
||||
|
||||
// If upload_max_size is less, then reduce. Except if upload_max_size is
|
||||
// zero, which indicates no limit.
|
||||
$iUploadMax = $this->ParseSize(ini_get('upload_max_filesize'));
|
||||
if ($iUploadMax > 0 && $iUploadMax < $iMaxSize)
|
||||
{
|
||||
$iMaxSize = $iUploadMax;
|
||||
}
|
||||
}
|
||||
return $iMaxSize;
|
||||
}
|
||||
|
||||
private function ParseSize($iSize)
|
||||
{
|
||||
$sUnit = preg_replace('/[^bkmgtpezy]/i', '', $iSize); // Remove the non-unit characters from the size.
|
||||
$iSize = preg_replace('/[^0-9.]/', '', $iSize); // Remove the non-numeric characters from the size.
|
||||
if ($sUnit)
|
||||
{
|
||||
// Find the position of the unit in the ordered string which is the power of magnitude to multiply a kilobyte by.
|
||||
return round($iSize * pow(1024, stripos('bkmgtpezy', $sUnit[0])));
|
||||
}
|
||||
else
|
||||
{
|
||||
return round($iSize);
|
||||
}
|
||||
}
|
||||
}
|
||||
522
datamodels/2.x/itop-core-update/src/Service/CoreUpdater.php
Normal file
522
datamodels/2.x/itop-core-update/src/Service/CoreUpdater.php
Normal file
@@ -0,0 +1,522 @@
|
||||
<?php
|
||||
/**
|
||||
* iTop
|
||||
* @copyright Copyright (C) 2010,2019 Combodo SARL
|
||||
* @license http://opensource.org/licenses/AGPL-3.0
|
||||
*
|
||||
*/
|
||||
|
||||
namespace Combodo\iTop\CoreUpdate\Service;
|
||||
|
||||
use Combodo\iTop\FilesInformation\Service\FilesIntegrity;
|
||||
use DBBackup;
|
||||
use Dict;
|
||||
use Exception;
|
||||
use IssueLog;
|
||||
use iTopExtension;
|
||||
use iTopExtensionsMap;
|
||||
use iTopMutex;
|
||||
use MetaModel;
|
||||
use SetupUtils;
|
||||
use utils;
|
||||
use ZipArchive;
|
||||
|
||||
require_once APPROOT.'setup/applicationinstaller.class.inc.php';
|
||||
require_once APPROOT.'setup/runtimeenv.class.inc.php';
|
||||
|
||||
final class CoreUpdater
|
||||
{
|
||||
const DOWNLOAD_DIR = APPROOT.'data/downloaded-core/';
|
||||
const UPDATE_DIR = APPROOT.'data/core-update/';
|
||||
|
||||
/**
|
||||
* @param bool $bDoBackup
|
||||
*
|
||||
* @throws \Exception
|
||||
*/
|
||||
public static function CopyCoreFiles()
|
||||
{
|
||||
set_time_limit(600);
|
||||
|
||||
// Extract updater file from the new version if available
|
||||
if (is_file(APPROOT.'setup/appupgradecopy.php'))
|
||||
{
|
||||
// Remove previous specific updater
|
||||
@unlink(APPROOT.'setup/appupgradecopy.php');
|
||||
}
|
||||
if (is_file(self::UPDATE_DIR.'web/setup/appupgradecopy.php'))
|
||||
{
|
||||
IssueLog::Info('itop-core-update: Use updater provided in the archive');
|
||||
self::CopyFile(self::UPDATE_DIR.'web/setup/appupgradecopy.php', APPROOT.'setup/appupgradecopy.php');
|
||||
@include_once(APPROOT.'setup/appupgradecopy.php');
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
if (function_exists('AppUpgradeCopyFiles'))
|
||||
{
|
||||
// start the update
|
||||
set_time_limit(600);
|
||||
AppUpgradeCopyFiles(self::UPDATE_DIR.'web/');
|
||||
}
|
||||
else
|
||||
{
|
||||
// Local function for older iTop versions
|
||||
IssueLog::Info('itop-core-update: Use default updater');
|
||||
self::LocalUpdateCoreFiles(self::UPDATE_DIR.'web/');
|
||||
}
|
||||
IssueLog::Info('itop-core-update: Update done, check files integrity');
|
||||
FilesIntegrity::CheckInstallationIntegrity(APPROOT);
|
||||
IssueLog::Info('itop-core-update: Files integrity OK');
|
||||
|
||||
}
|
||||
catch (Exception $e)
|
||||
{
|
||||
IssueLog::error($e->getMessage());
|
||||
IssueLog::Info('itop-core-update: ended');
|
||||
throw $e;
|
||||
}
|
||||
finally
|
||||
{
|
||||
self::RRmdir(self::UPDATE_DIR);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws \Exception
|
||||
*/
|
||||
public static function Compile()
|
||||
{
|
||||
try
|
||||
{
|
||||
// Compile code
|
||||
IssueLog::Info('itop-core-update: Start compilation');
|
||||
IssueLog::Info('itop-core-update: Version Dev');
|
||||
|
||||
$sTargetEnv = 'production';
|
||||
$oRuntimeEnv = new RunTimeEnvironmentCoreUpdater($sTargetEnv);
|
||||
$oRuntimeEnv->CheckDirectories($sTargetEnv);
|
||||
$oRuntimeEnv->CompileFrom('production');
|
||||
$oConfig = $oRuntimeEnv->MakeConfigFile($sTargetEnv.' (built on '.date('Y-m-d').')');
|
||||
$oConfig->Set('access_mode', ACCESS_FULL);
|
||||
$oRuntimeEnv->WriteConfigFileSafe($oConfig);
|
||||
$oRuntimeEnv->InitDataModel($oConfig, true);
|
||||
|
||||
$aAvailableModules = $oRuntimeEnv->AnalyzeInstallation($oConfig, $oRuntimeEnv->GetBuildDir());
|
||||
$aSelectedModules = array();
|
||||
foreach ($aAvailableModules as $sModuleId => $aModule)
|
||||
{
|
||||
if (($sModuleId == ROOT_MODULE) || ($sModuleId == DATAMODEL_MODULE))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
else
|
||||
{
|
||||
$aSelectedModules[] = $sModuleId;
|
||||
}
|
||||
}
|
||||
$oRuntimeEnv->CallInstallerHandlers($aAvailableModules, $aSelectedModules, 'BeforeDatabaseCreation');
|
||||
$oRuntimeEnv->CreateDatabaseStructure($oConfig, 'upgrade');
|
||||
$oRuntimeEnv->CallInstallerHandlers($aAvailableModules, $aSelectedModules, 'AfterDatabaseCreation');
|
||||
$oRuntimeEnv->UpdatePredefinedObjects();
|
||||
$oRuntimeEnv->CallInstallerHandlers($aAvailableModules, $aSelectedModules, 'AfterDatabaseSetup');
|
||||
$oRuntimeEnv->LoadData($aAvailableModules, $aSelectedModules, false /* no sample data*/);
|
||||
$oRuntimeEnv->CallInstallerHandlers($aAvailableModules, $aSelectedModules, 'AfterDataLoad');
|
||||
$sDataModelVersion = $oRuntimeEnv->GetCurrentDataModelVersion();
|
||||
$oExtensionsMap = new iTopExtensionsMap();
|
||||
// Default choices = as before
|
||||
$oExtensionsMap->LoadChoicesFromDatabase($oConfig);
|
||||
foreach ($oExtensionsMap->GetAllExtensions() as $oExtension)
|
||||
{
|
||||
// Plus all "remote" extensions
|
||||
if ($oExtension->sSource == iTopExtension::SOURCE_REMOTE)
|
||||
{
|
||||
$oExtensionsMap->MarkAsChosen($oExtension->sCode);
|
||||
}
|
||||
}
|
||||
$aSelectedExtensionCodes = array();
|
||||
foreach ($oExtensionsMap->GetChoices() as $oExtension)
|
||||
{
|
||||
$aSelectedExtensionCodes[] = $oExtension->sCode;
|
||||
}
|
||||
$oRuntimeEnv->RecordInstallation($oConfig, $sDataModelVersion, $aSelectedModules,
|
||||
$aSelectedExtensionCodes, 'Done by the iTop Core Updater');
|
||||
|
||||
IssueLog::Info('itop-core-update: Compilation done');
|
||||
}
|
||||
catch (Exception $e)
|
||||
{
|
||||
IssueLog::error($e->getMessage());
|
||||
throw $e;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $sFromDir
|
||||
*
|
||||
* @throws \Exception
|
||||
*/
|
||||
private static function LocalUpdateCoreFiles($sFromDir)
|
||||
{
|
||||
self::CopyDir($sFromDir, APPROOT);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $sArchiveFile
|
||||
*
|
||||
* @throws \Exception
|
||||
*/
|
||||
private static function ExtractUpdateFile($sArchiveFile)
|
||||
{
|
||||
if (!utils::EndsWith($sArchiveFile, '.zip'))
|
||||
{
|
||||
throw new Exception(Dict::S('iTopUpdate:Error:BadFileFormat'));
|
||||
}
|
||||
|
||||
$oArchive = new ZipArchive();
|
||||
$oArchive->open($sArchiveFile);
|
||||
|
||||
self::RRmdir(self::UPDATE_DIR);
|
||||
SetupUtils::builddir(self::UPDATE_DIR);
|
||||
$oArchive->extractTo(self::UPDATE_DIR);
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws \Exception
|
||||
*/
|
||||
public static function Backup()
|
||||
{
|
||||
$sBackupName = self::GetBackupName();
|
||||
$sBackupFile = self::GetBackupFile();
|
||||
if (file_exists($sBackupFile))
|
||||
{
|
||||
@unlink($sBackupFile);
|
||||
}
|
||||
|
||||
self::DoBackup($sBackupName);
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws \Exception
|
||||
*/
|
||||
public static function CreateItopArchive()
|
||||
{
|
||||
set_time_limit(0);
|
||||
$sItopArchiveFile = self::GetItopArchiveFile();
|
||||
if (file_exists($sItopArchiveFile))
|
||||
{
|
||||
@unlink($sItopArchiveFile);
|
||||
}
|
||||
|
||||
$sTempFile = sys_get_temp_dir().'/'.basename($sItopArchiveFile);
|
||||
if (file_exists($sTempFile))
|
||||
{
|
||||
@unlink($sTempFile);
|
||||
}
|
||||
|
||||
$aPathInfo = pathInfo(realpath(APPROOT));
|
||||
$sParentPath = $aPathInfo['dirname'];
|
||||
$sDirName = $aPathInfo['basename'];
|
||||
|
||||
$oZipArchive = new ZipArchive();
|
||||
$oZipArchive->open($sTempFile, ZIPARCHIVE::CREATE);
|
||||
$oZipArchive->addEmptyDir($sDirName);
|
||||
self::ZipFolder(realpath(APPROOT), $oZipArchive, strlen("$sParentPath/"));
|
||||
$oZipArchive->close();
|
||||
|
||||
if (!file_exists($sTempFile))
|
||||
{
|
||||
IssueLog::Error("Failed to create itop archive $sTempFile");
|
||||
}
|
||||
|
||||
if (@rename($sTempFile, $sItopArchiveFile))
|
||||
{
|
||||
IssueLog::Info("Archive $sItopArchiveFile Created");
|
||||
}
|
||||
else
|
||||
{
|
||||
IssueLog::Error("Failed to create archive $sItopArchiveFile");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param string $sTargetFile
|
||||
* @throws Exception
|
||||
*/
|
||||
private static function DoBackup($sTargetFile)
|
||||
{
|
||||
// Make sure the target directory exists
|
||||
$sBackupDir = dirname($sTargetFile);
|
||||
SetupUtils::builddir($sBackupDir);
|
||||
|
||||
$oBackup = new DBBackup();
|
||||
$oBackup->SetMySQLBinDir(MetaModel::GetConfig()->GetModuleSetting('itop-backup', 'mysql_bindir', ''));
|
||||
|
||||
$oMutex = new iTopMutex('backup.'.utils::GetCurrentEnvironment());
|
||||
$oMutex->Lock();
|
||||
try
|
||||
{
|
||||
$oBackup->CreateCompressedBackup($sTargetFile);
|
||||
IssueLog::Info('itop-core-update: Backup done: '.$sTargetFile);
|
||||
}
|
||||
catch (Exception $e)
|
||||
{
|
||||
$oMutex->Unlock();
|
||||
throw $e;
|
||||
}
|
||||
$oMutex->Unlock();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $sSource
|
||||
* @param $sDest
|
||||
*
|
||||
* @throws \Exception
|
||||
*/
|
||||
public static function CopyDir($sSource, $sDest)
|
||||
{
|
||||
if (is_dir($sSource))
|
||||
{
|
||||
if (!is_dir($sDest))
|
||||
{
|
||||
@mkdir($sDest, 0755);
|
||||
}
|
||||
$aFiles = scandir($sSource);
|
||||
if(sizeof($aFiles) > 0 )
|
||||
{
|
||||
foreach($aFiles as $sFile)
|
||||
{
|
||||
if ($sFile == '.' || $sFile == '..' || $sFile == '.svn' || $sFile == '.git')
|
||||
{
|
||||
// Skip
|
||||
continue;
|
||||
}
|
||||
|
||||
if (is_dir($sSource.'/'.$sFile))
|
||||
{
|
||||
// Recurse
|
||||
self::CopyDir($sSource.'/'.$sFile, $sDest.'/'.$sFile);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (is_link($sDest.'/'.$sFile))
|
||||
{
|
||||
unlink($sDest.'/'.$sFile);
|
||||
}
|
||||
self::CopyFile($sSource.'/'.$sFile, $sDest.'/'.$sFile);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
elseif (is_file($sSource))
|
||||
{
|
||||
self::CopyFile($sSource, $sDest);
|
||||
}
|
||||
}
|
||||
|
||||
public static function RRmdir($sDir) {
|
||||
if (is_dir($sDir))
|
||||
{
|
||||
$oDir = @opendir($sDir);
|
||||
while (false !== ($sFile = @readdir($oDir)))
|
||||
{
|
||||
if (($sFile != '.') && ($sFile != '..'))
|
||||
{
|
||||
$sFull = $sDir.'/'.$sFile;
|
||||
if (is_dir($sFull))
|
||||
{
|
||||
self::RRmdir($sFull);
|
||||
}
|
||||
else
|
||||
{
|
||||
@unlink($sFull);
|
||||
}
|
||||
}
|
||||
}
|
||||
@closedir($oDir);
|
||||
@rmdir($sDir);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $sSource
|
||||
* @param $sDest
|
||||
*
|
||||
* @throws \Exception
|
||||
*/
|
||||
public static function CopyFile($sSource, $sDest)
|
||||
{
|
||||
if (is_file($sSource))
|
||||
{
|
||||
if (!@copy($sSource, $sDest))
|
||||
{
|
||||
// Try changing the mode of the file
|
||||
@chmod($sDest, 0644);
|
||||
if (!@copy($sSource, $sDest))
|
||||
{
|
||||
throw new Exception(Dict::Format('iTopUpdate:Error:Copy', $sSource, $sDest));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Add files and sub-directories in a folder to zip file.
|
||||
*
|
||||
* @param string $sFolder
|
||||
* @param ZipArchive $oZipArchive
|
||||
* @param int $iStrippedLength Number of text to be removed from the file path.
|
||||
*/
|
||||
private static function ZipFolder($sFolder, &$oZipArchive, $iStrippedLength) {
|
||||
$oFolder = opendir($sFolder);
|
||||
while (false !== ($sFile = readdir($oFolder))) {
|
||||
if (($sFile == '.') || ($sFile == '..'))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
$sFilePath = "$sFolder/$sFile";
|
||||
|
||||
$sLocalItopPath = utils::LocalPath($sFilePath);
|
||||
if ($sLocalItopPath == 'data/backups' || $sLocalItopPath == 'log')
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
// Remove prefix from file path before add to zip.
|
||||
$sLocalPath = substr($sFilePath, $iStrippedLength);
|
||||
if (is_file($sFilePath)) {
|
||||
$oZipArchive->addFile($sFilePath, $sLocalPath);
|
||||
} elseif (is_dir($sFilePath)) {
|
||||
// Add sub-directory.
|
||||
$oZipArchive->addEmptyDir($sLocalPath);
|
||||
self::ZipFolder($sFilePath, $oZipArchive, $iStrippedLength);
|
||||
}
|
||||
}
|
||||
closedir($oFolder);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
private static function GetItopArchiveName()
|
||||
{
|
||||
$sItopArchiveName = APPROOT.'data/backups/itop';
|
||||
return $sItopArchiveName;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public static function GetItopArchiveFile()
|
||||
{
|
||||
$sItopArchiveFile = self::GetItopArchiveName().'.zip';
|
||||
return $sItopArchiveFile;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
private static function GetBackupName()
|
||||
{
|
||||
$sBackupName = APPROOT.'data/backups/manual/backup-core-update';
|
||||
return $sBackupName;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public static function GetBackupFile()
|
||||
{
|
||||
$sBackupFile = self::GetBackupName().'.tar.gz';
|
||||
return $sBackupFile;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $sArchiveFile
|
||||
*
|
||||
* @throws \Exception
|
||||
*/
|
||||
public static function ExtractDownloadedFile($sArchiveFile)
|
||||
{
|
||||
try
|
||||
{
|
||||
// Extract archive file
|
||||
self::ExtractUpdateFile($sArchiveFile);
|
||||
|
||||
IssueLog::Info('itop-core-update: Archive extracted, check files integrity');
|
||||
|
||||
// Check files integrity
|
||||
FilesIntegrity::CheckInstallationIntegrity(self::UPDATE_DIR.'web/');
|
||||
|
||||
IssueLog::Info('itop-core-update: Files integrity OK');
|
||||
}
|
||||
catch (Exception $e)
|
||||
{
|
||||
self::RRmdir(self::UPDATE_DIR);
|
||||
throw $e;
|
||||
}
|
||||
finally
|
||||
{
|
||||
self::RRmdir(self::DOWNLOAD_DIR);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
* @throws \Exception
|
||||
*/
|
||||
public static function GetVersionToInstall()
|
||||
{
|
||||
try
|
||||
{
|
||||
$sConfigFile = self::UPDATE_DIR.'web/core/config.class.inc.php';
|
||||
if (!is_file($sConfigFile))
|
||||
{
|
||||
throw new Exception(Dict::S(Dict::S('iTopUpdate:Error:BadFileContent')));
|
||||
}
|
||||
|
||||
$sContents = file_get_contents($sConfigFile);
|
||||
preg_match_all("@define\('(?<name>ITOP_[^']*)', '(?<value>[^']*)'\);@", $sContents, $aMatches);
|
||||
if (empty($aMatches))
|
||||
{
|
||||
throw new Exception(Dict::S(Dict::S('iTopUpdate:Error:BadFileContent')));
|
||||
}
|
||||
$aValues = array();
|
||||
foreach ($aMatches['name'] as $index => $sName)
|
||||
{
|
||||
$aValues[$sName] = $aMatches['value'][$index];
|
||||
}
|
||||
|
||||
if ($aValues['ITOP_APPLICATION'] != ITOP_APPLICATION)
|
||||
{
|
||||
throw new Exception(Dict::S('iTopUpdate:Error:BadItopProduct'));
|
||||
}
|
||||
|
||||
// Extract updater file from the new version if available
|
||||
if (is_file(APPROOT.'setup/appupgradecheck.php'))
|
||||
{
|
||||
// Remove previous specific updater
|
||||
@unlink(APPROOT.'setup/appupgradecheck.php');
|
||||
}
|
||||
if (is_file(self::UPDATE_DIR.'web/setup/appupgradecheck.php'))
|
||||
{
|
||||
IssueLog::Info('itop-core-update: Use updater provided in the archive');
|
||||
self::CopyFile(self::UPDATE_DIR.'web/setup/appupgradecheck.php', APPROOT.'setup/appupgradecheck.php');
|
||||
@include_once(APPROOT.'setup/appupgradecheck.php');
|
||||
}
|
||||
if (function_exists('AppUpgradeCheckInstall'))
|
||||
{
|
||||
AppUpgradeCheckInstall();
|
||||
}
|
||||
|
||||
return Dict::Format('UI:iTopVersion:Long', $aValues['ITOP_APPLICATION'], $aValues['ITOP_VERSION'], $aValues['ITOP_REVISION'], $aValues['ITOP_BUILD_DATE']);
|
||||
}
|
||||
catch (Exception $e)
|
||||
{
|
||||
self::RRmdir(self::UPDATE_DIR);
|
||||
self::RRmdir(self::DOWNLOAD_DIR);
|
||||
throw $e;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,96 @@
|
||||
<?php
|
||||
/**
|
||||
* @copyright Copyright (C) 2010-2019 Combodo SARL
|
||||
* @license http://opensource.org/licenses/AGPL-3.0
|
||||
*/
|
||||
|
||||
|
||||
namespace Combodo\iTop\CoreUpdate\Service;
|
||||
|
||||
require_once(APPROOT."setup/runtimeenv.class.inc.php");
|
||||
|
||||
use Config;
|
||||
use Exception;
|
||||
use RunTimeEnvironment;
|
||||
|
||||
class RunTimeEnvironmentCoreUpdater extends RunTimeEnvironment
|
||||
{
|
||||
public function CheckDirectories($sTargetEnv)
|
||||
{
|
||||
$sTargetDir = APPROOT.'env-'.$sTargetEnv;
|
||||
$sBuildDir = $sTargetDir.'-build';
|
||||
|
||||
self::CheckDirectory($sTargetDir);
|
||||
self::CheckDirectory($sBuildDir);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $sDir
|
||||
* @throws Exception
|
||||
*/
|
||||
public static function CheckDirectory($sDir)
|
||||
{
|
||||
if (!is_dir($sDir))
|
||||
{
|
||||
if (!@mkdir($sDir,0770))
|
||||
{
|
||||
throw new Exception('Creating directory '.$sDir.' is denied (Check access rights)');
|
||||
}
|
||||
}
|
||||
// Try create a file
|
||||
$sTempFile = $sDir.'/__itop_temp_file__';
|
||||
if (!@touch($sTempFile))
|
||||
{
|
||||
throw new Exception('Write access to '.$sDir.' is denied (Check access rights)');
|
||||
}
|
||||
@unlink($sTempFile);
|
||||
}
|
||||
|
||||
public function MakeConfigFile($sEnvironmentLabel = null)
|
||||
{
|
||||
$oConfig = $this->GetConfig();
|
||||
if (!is_null($oConfig))
|
||||
{
|
||||
// Return the existing one
|
||||
$oConfig->UpdateIncludes('env-'.$this->sTargetEnv);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Clone the default 'production' config file
|
||||
//
|
||||
$oConfig = clone($this->GetConfig('production'));
|
||||
|
||||
$oConfig->UpdateIncludes('env-'.$this->sTargetEnv);
|
||||
|
||||
if (is_null($sEnvironmentLabel))
|
||||
{
|
||||
$sEnvironmentLabel = $this->sTargetEnv;
|
||||
}
|
||||
$oConfig->Set('app_env_label', $sEnvironmentLabel);
|
||||
if ($this->sFinalEnv !== 'production')
|
||||
{
|
||||
$oConfig->Set('db_name', $oConfig->Get('db_name').'_'.$this->sFinalEnv);
|
||||
}
|
||||
}
|
||||
|
||||
return $oConfig;
|
||||
}
|
||||
|
||||
protected function GetConfig($sEnvironment = null)
|
||||
{
|
||||
if (is_null($sEnvironment))
|
||||
{
|
||||
$sEnvironment = $this->sTargetEnv;
|
||||
}
|
||||
$sFile = APPCONF.$sEnvironment.'/'.ITOP_CONFIG_FILE;
|
||||
if (file_exists($sFile))
|
||||
{
|
||||
$oConfig = new Config($sFile);
|
||||
return $oConfig;
|
||||
}
|
||||
else
|
||||
{
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
110
datamodels/2.x/itop-core-update/view/ConfirmUpdate.html.twig
Normal file
110
datamodels/2.x/itop-core-update/view/ConfirmUpdate.html.twig
Normal file
@@ -0,0 +1,110 @@
|
||||
{# @copyright Copyright (C) 2010-2019 Combodo SARL #}
|
||||
{# @license http://opensource.org/licenses/AGPL-3.0 #}
|
||||
|
||||
<div class="page_header"><h1>{{ 'iTopUpdate:UI:PageTitle'|dict_s }}</h1></div>
|
||||
|
||||
<div class="display_block display-files">
|
||||
{% if bSuccess %}
|
||||
|
||||
<fieldset>
|
||||
<legend>{{ 'iTopUpdate:UI:Status'|dict_s }}</legend>
|
||||
<div class="header_message message_info">
|
||||
<div>
|
||||
<span>{{ sQuestion }}</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<table style="vertical-align:top" class="one-col-details" data-mode="view">
|
||||
<tbody>
|
||||
<tr>
|
||||
<td style="vertical-align:top" class="">
|
||||
{{ include('DisplayCurrentVersion.html.twig') }}
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</fieldset>
|
||||
|
||||
<fieldset>
|
||||
<legend>{{ 'iTopUpdate:UI:Backup'|dict_s }}</legend>
|
||||
{% if bDoBackup or bDoFilesArchive %}
|
||||
<table style="vertical-align:top" class="one-col-details" data-mode="view">
|
||||
<tbody>
|
||||
<tr>
|
||||
<td style="vertical-align:top" class="">
|
||||
{% if bDoBackup %}
|
||||
<div class="details">
|
||||
<div class="field_container field_small">
|
||||
<div class="field_label label"><span title="">{{ 'iTopUpdate:UI:WithDBBackup'|dict_s }}</span></div>
|
||||
<div class="field_data">
|
||||
<div class="field_value">{{ sBackupFile }}</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
{% if bDoFilesArchive %}
|
||||
<div class="details">
|
||||
<div class="field_container field_small">
|
||||
<div class="field_label label"><span title="">{{ 'iTopUpdate:UI:WithFilesBackup'|dict_s }}</span></div>
|
||||
<div class="field_data">
|
||||
<div class="field_value">{{ sItopArchive }}</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
{% else %}
|
||||
<div class="header_message message_info">
|
||||
<div>
|
||||
<span>{{ 'iTopUpdate:UI:WithoutBackup'|dict_s }}</span>
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
</fieldset>
|
||||
|
||||
<fieldset>
|
||||
<legend>{{ 'iTopUpdate:UI:Action'|dict_s }}</legend>
|
||||
|
||||
<div>
|
||||
<table>
|
||||
<tr>
|
||||
<td>
|
||||
<form enctype="multipart/form-data" method="post">
|
||||
<p><input id="cancel-update" type="submit" value="{{ 'iTopUpdate:UI:Cancel'|dict_s }}"/></p>
|
||||
</form>
|
||||
</td>
|
||||
<td>
|
||||
<form enctype="multipart/form-data" method="post">
|
||||
<p><input id="do-update" type="submit" value="{{ 'iTopUpdate:UI:DoUpdate'|dict_s }}"/> <i id="submit-wait" style="display: none" class="fas fa-spinner fa-spin" aria-hidden="true"></i></p>
|
||||
<input type="hidden" name="operation" value="UpdateCoreFiles"/>
|
||||
<input type="hidden" name="transaction_id" value="{{ sTransactionId }}">
|
||||
<input type="hidden" name="filename" value="{{ sName }}">
|
||||
<input type="hidden" name="doBackup" value="{{ bDoBackup }}">
|
||||
<input type="hidden" name="doFilesArchive" value="{{ bDoFilesArchive }}">
|
||||
</form>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</div>
|
||||
</fieldset>
|
||||
|
||||
{% else %}
|
||||
|
||||
<fieldset>
|
||||
<div class="header_message message_error">
|
||||
<div>
|
||||
<span>{{ sError }}</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<form enctype="multipart/form-data" method="post">
|
||||
<p><input type="submit" value="{{ 'iTopUpdate:UI:Back'|dict_s }}"/></p>
|
||||
</form>
|
||||
|
||||
</fieldset>
|
||||
|
||||
{% endif %}
|
||||
</div>
|
||||
@@ -0,0 +1,12 @@
|
||||
{# @copyright Copyright (C) 2010-2019 Combodo SARL #}
|
||||
{# @license http://opensource.org/licenses/AGPL-3.0 #}
|
||||
|
||||
$("#do-update").on("click", function() {
|
||||
$("#submit-wait").show();
|
||||
$(this).prop("disabled", true);
|
||||
$("#cancel-update").prop("disabled", true);
|
||||
$(this).parents('form').submit();
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
return false;
|
||||
});
|
||||
@@ -0,0 +1,10 @@
|
||||
{# @copyright Copyright (C) 2010-2019 Combodo SARL #}
|
||||
{# @license http://opensource.org/licenses/AGPL-3.0 #}
|
||||
|
||||
{% set sVersion = 'UI:iTopVersion:Long'|dict_format(constant('ITOP_APPLICATION'), constant('ITOP_VERSION'), constant('ITOP_REVISION'), constant('ITOP_BUILD_DATE')) %}
|
||||
<div class="details">
|
||||
<div class="field_container field_small">
|
||||
<div class="field_label label"><span title="">{{ 'iTopUpdate:UI:CurrentVersion'|dict_s }}</span></div>
|
||||
<div class="field_data"><div class="field_value">{{ sVersion }}</div></div>
|
||||
</div>
|
||||
</div>
|
||||
134
datamodels/2.x/itop-core-update/view/SelectUpdateFile.html.twig
Normal file
134
datamodels/2.x/itop-core-update/view/SelectUpdateFile.html.twig
Normal file
@@ -0,0 +1,134 @@
|
||||
{# @copyright Copyright (C) 2010-2019 Combodo SARL #}
|
||||
{# @license http://opensource.org/licenses/AGPL-3.0 #}
|
||||
|
||||
<div class="page_header"><h1>{{ 'iTopUpdate:UI:PageTitle'|dict_s }}</h1></div>
|
||||
|
||||
<div class="display_block display-files">
|
||||
<fieldset>
|
||||
<legend>{{ 'iTopUpdate:UI:Status'|dict_s }}</legend>
|
||||
|
||||
<div id="header-requirements" class="header_message message_info">
|
||||
<div>
|
||||
<span id="can-core-update">{{ 'iTopUpdate:UI:CanCoreUpdate:Loading'|dict_s }} <i class="ajax-spin fas fa-spinner fa-spin" aria-hidden="true"></i></span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<table style="vertical-align:top" class="one-col-details" data-mode="view">
|
||||
<tbody>
|
||||
<tr>
|
||||
<td style="vertical-align:top" class="">
|
||||
|
||||
{{ include('DisplayCurrentVersion.html.twig') }}
|
||||
|
||||
<div class="details">
|
||||
<div class="field_container field_small">
|
||||
<div class="field_label label"><span title="">{{ 'iTopUpdate:UI:DiskFreeSpace'|dict_s }}</span></div>
|
||||
<div class="field_data"><div class="field_value">{{ sDiskFreeSpace }}</div></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="details">
|
||||
<div class="field_container field_small">
|
||||
<div class="field_label label"><span title="">{{ 'iTopUpdate:UI:ItopDiskSpace'|dict_s }}</span></div>
|
||||
<div class="field_data"><div id="itop-disk-space" class="field_value"><i class="ajax-spin fas fa-spinner fa-spin" aria-hidden="true"></i></div></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="details">
|
||||
<div class="field_container field_small">
|
||||
<div class="field_label label"><span title="">{{ 'iTopUpdate:UI:DBDiskSpace'|dict_s }}</span></div>
|
||||
<div class="field_data"><div id="db-disk-space" class="field_value"><i class="ajax-spin fas fa-spinner fa-spin" aria-hidden="true"></i></div></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="details">
|
||||
<div class="field_container field_small">
|
||||
<div class="field_label label"><span title="">{{ 'iTopUpdate:UI:FileUploadMaxSize'|dict_s }}</span></div>
|
||||
<div class="field_data"><div class="field_value">{{ sFileUploadMaxSize }}</div></div>
|
||||
</div>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
</fieldset>
|
||||
|
||||
<fieldset>
|
||||
<legend>{{ 'iTopUpdate:UI:SelectUpdateFile'|dict_s }}</legend>
|
||||
|
||||
<div class="details">
|
||||
<form enctype="multipart/form-data" method="post">
|
||||
<input type="hidden" name="operation" value="ConfirmUpdate"/>
|
||||
<input type="hidden" name="transaction_id" value="{{ sTransactionId }}">
|
||||
|
||||
<div id="header-file-size" class="header_message message_error" style="display: none">
|
||||
<div>
|
||||
<span>{{ 'iTopUpdate:Error:FileUploadMaxSizeTooSmall'|dict_s }}</span>
|
||||
</div>
|
||||
<div>
|
||||
<span>{{ 'iTopUpdate:UI:PostMaxSize'|dict_format(sPostMaxSize) }}</span>
|
||||
</div>
|
||||
<div>
|
||||
<span>{{ 'iTopUpdate:UI:UploadMaxFileSize'|dict_format(sUploadMaxSize) }}</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="field_container field_large">
|
||||
<div class="field_data">
|
||||
<div class="upload_container">
|
||||
<input type="file" id="file" name="file"/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="dobackup-warning" class="header_message message_info" style="display: none">{{ 'iTopUpdate:UI:DoBackup:Warning'|dict_s }}</div>
|
||||
<div class="field_data">
|
||||
<label id="dobackup-label" for="doBackup">{{ 'iTopUpdate:UI:DoBackup:Label'|dict_s }}</label>
|
||||
<input type="checkbox" id="doBackup" name="doBackup" checked="checked" value="1"/>
|
||||
</div>
|
||||
<div class="field_data">
|
||||
<label id="dofilesarchive-label" for="doFilesArchive">{{ 'iTopUpdate:UI:DoFilesArchive'|dict_s }}</label>
|
||||
<input type="checkbox" id="doFilesArchive" name="doFilesArchive" checked="checked" value="1"/>
|
||||
</div>
|
||||
</div>
|
||||
<p><input id="check-update" type="submit" value="{{ 'iTopUpdate:UI:CheckUpdate'|dict_s }}"/> <i id="submit-wait" style="display: none" class="fas fa-spinner fa-spin" aria-hidden="true"></i></p>
|
||||
</form>
|
||||
</div>
|
||||
</fieldset>
|
||||
|
||||
<fieldset>
|
||||
<legend>{{ 'iTopUpdate:UI:History'|dict_s }}</legend>
|
||||
|
||||
<div class="details">
|
||||
{% for aInstall in aPreviousInstall %}
|
||||
{% if loop.first %}
|
||||
<table class="listResults">
|
||||
<tr>
|
||||
<th>{{ 'Class:ModuleInstallation/Attribute:name'|dict_s }}</th>
|
||||
<th>{{ 'Class:ModuleInstallation/Attribute:version'|dict_s }}</th>
|
||||
<th>{{ 'Class:ModuleInstallation/Attribute:installed'|dict_s }}</th>
|
||||
<th>{{ 'Class:ModuleInstallation/Attribute:comment'|dict_s }}</th>
|
||||
</tr>
|
||||
{% endif %}
|
||||
|
||||
{% if (loop.index0 % 2) == 0 %}
|
||||
{% set sRowClass = "odd" %}
|
||||
{% else %}
|
||||
{% set sRowClass = "even" %}
|
||||
{% endif %}
|
||||
|
||||
<tr class="{{ sRowClass }}">
|
||||
<td>{{ aInstall.name }}</td>
|
||||
<td>{{ aInstall.version }}</td>
|
||||
<td>{{ aInstall.installed }}</td>
|
||||
<td>{{ aInstall.comment }}</td>
|
||||
</tr>
|
||||
|
||||
{% if loop.last %}
|
||||
</table>
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
</div>
|
||||
</fieldset>
|
||||
|
||||
</div>
|
||||
@@ -0,0 +1,95 @@
|
||||
{# @copyright Copyright (C) 2010-2019 Combodo SARL #}
|
||||
{# @license http://opensource.org/licenses/AGPL-3.0 #}
|
||||
|
||||
var iDiskFreeSpace = {{ iDiskFreeSpace }};
|
||||
|
||||
$.ajax({
|
||||
method: "POST",
|
||||
url: "{{ sAjaxURL|raw }}",
|
||||
data: {
|
||||
"operation": "CanUpdateCore"
|
||||
},
|
||||
dataType: "json",
|
||||
success: function(data)
|
||||
{
|
||||
var oRequirements = $("#header-requirements");
|
||||
var oCanCoreUpdate = $("#can-core-update");
|
||||
oCanCoreUpdate.html(data.sMessage);
|
||||
oRequirements.removeClass("message_info");
|
||||
if (data.bStatus)
|
||||
{
|
||||
oRequirements.addClass("message_ok");
|
||||
}
|
||||
else
|
||||
{
|
||||
oRequirements.addClass("message_error");
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
var oGetItopDiskSpace = $.ajax({
|
||||
method: "POST",
|
||||
url: "{{ sAjaxURL|raw }}",
|
||||
data: {
|
||||
"operation": "GetItopDiskSpace"
|
||||
},
|
||||
dataType: "json",
|
||||
success: function(data)
|
||||
{
|
||||
var oRequirement = $("#itop-disk-space");
|
||||
oRequirement.html(data.sItopDiskSpace);
|
||||
}
|
||||
});
|
||||
|
||||
var oGetDBDiskSpace = $.ajax({
|
||||
method: "POST",
|
||||
url: "{{ sAjaxURL|raw }}",
|
||||
data: {
|
||||
"operation": "GetDBDiskSpace"
|
||||
},
|
||||
dataType: "json",
|
||||
success: function(data)
|
||||
{
|
||||
var oRequirement = $("#db-disk-space");
|
||||
oRequirement.html(data.sDBDiskSpace);
|
||||
}
|
||||
});
|
||||
|
||||
$.when(oGetItopDiskSpace, oGetDBDiskSpace).then(
|
||||
function(data1, data2)
|
||||
{
|
||||
var iItopDiskSpace = data1[0].iItopDiskSpace;
|
||||
var iDBDiskSpace = data2[0].iDBDiskSpace;
|
||||
if ((2 * (iItopDiskSpace + iDBDiskSpace)) > iDiskFreeSpace)
|
||||
{
|
||||
$("#dobackup-warning").show();
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
$("#file").on("change", function(e) {
|
||||
var selectedFile = $('#file').get(0).files[0];
|
||||
var errorMsg = $("#header-file-size");
|
||||
var submitButton = $("#check-update");
|
||||
if (selectedFile)
|
||||
{
|
||||
if (selectedFile.size > {{ iFileUploadMaxSize }})
|
||||
{
|
||||
errorMsg.show();
|
||||
submitButton.prop("disabled", true);
|
||||
return;
|
||||
}
|
||||
}
|
||||
errorMsg.hide();
|
||||
submitButton.prop("disabled", false);
|
||||
});
|
||||
|
||||
$("#check-update").on("click", function(e) {
|
||||
$("#submit-wait").show();
|
||||
$(this).prop("disabled", true);
|
||||
$(".ajax-spin").removeClass("fa-spinner").removeClass("fa-spin").addClass("fa-times");
|
||||
$(this).parents('form').submit();
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
return false;
|
||||
});
|
||||
@@ -0,0 +1,90 @@
|
||||
{# @copyright Copyright (C) 2010-2019 Combodo SARL #}
|
||||
{# @license http://opensource.org/licenses/AGPL-3.0 #}
|
||||
|
||||
<div class="page_header"><h1>{{ 'iTopUpdate:UI:PageTitle'|dict_s }}</h1></div>
|
||||
|
||||
<div class="display_block display-files">
|
||||
<fieldset id="installation_progress">
|
||||
<legend>{{ 'iTopUpdate:UI:Status'|dict_s }}</legend>
|
||||
|
||||
<div id="current_version" class="header_message message_info">
|
||||
<div>
|
||||
<span id="current-version">{{ sCurrentVersion }}</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<table style="vertical-align:top" class="one-col-details" data-mode="view">
|
||||
<tbody>
|
||||
<tr>
|
||||
<td style="vertical-align:top" class="">
|
||||
{% if bDoBackup %}
|
||||
<div id="do_backup_done" class="details" style="display: none;">
|
||||
<div class="field_container field_small">
|
||||
<div class="field_label label"><span title="">{{ 'iTopUpdate:UI:WithDBBackup'|dict_s }}</span></div>
|
||||
<div class="field_data">
|
||||
<div class="field_value">{{ sBackupFile }}</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
{% if bDoFilesArchive %}
|
||||
<div id="do_files_archive_done" class="details" style="display: none;">
|
||||
<div class="field_container field_small">
|
||||
<div class="field_label label"><span title="">{{ 'iTopUpdate:UI:WithFilesBackup'|dict_s }}</span></div>
|
||||
<div class="field_data">
|
||||
<div class="field_value">{{ sItopArchive }}</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
</fieldset>
|
||||
|
||||
<fieldset id="installation_progress">
|
||||
<legend>{{ 'iTopUpdate:UI:Progress'|dict_s }}</legend>
|
||||
|
||||
<div id="progress_content" style="height: 100px; overflow: auto; text-align: center;">
|
||||
<p class="center">
|
||||
<span id="setup_msg">{{ 'iTopUpdate:UI:SetupMessage:Ready'|dict_s }}</span>
|
||||
</p>
|
||||
<div id="progress" style="
|
||||
margin: 5px auto;
|
||||
display:block;
|
||||
border:1px solid #000000;
|
||||
width: 280px;
|
||||
height: 20px;
|
||||
line-height: 20px;
|
||||
text-align: center;
|
||||
">0%</div>
|
||||
</div>
|
||||
</fieldset>
|
||||
|
||||
<fieldset>
|
||||
<div id="setup_error_outer" class="header_message message_error" style="display: none;">
|
||||
<div>
|
||||
<span id="setup_error"></span>
|
||||
</div>
|
||||
{% if bDoFilesArchive %}
|
||||
<div>
|
||||
<span>{{ 'iTopUpdate:UI:RestoreArchive'|dict_format(sItopArchive) }}</span>
|
||||
</div>
|
||||
{% endif %}
|
||||
{% if bDoBackup %}
|
||||
<div>
|
||||
<span>{{ 'iTopUpdate:UI:RestoreBackup'|dict_format(sBackupFile) }}</span>
|
||||
</div>
|
||||
{% endif %}
|
||||
<div>
|
||||
<span>{{ 'iTopUpdate:UI:MaintenanceModeActive'|dict_s }}</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<form enctype="multipart/form-data" method="post">
|
||||
<p><input id="setup_continue" type="submit" value="{{ 'iTopUpdate:UI:Continue'|dict_s }}" disabled/></p>
|
||||
</form>
|
||||
</fieldset>
|
||||
</div>
|
||||
@@ -0,0 +1,122 @@
|
||||
{# @copyright Copyright (C) 2010-2019 Combodo SARL #}
|
||||
{# @license http://opensource.org/licenses/AGPL-3.0 #}
|
||||
|
||||
function UpdateProgress(sMessage, iPercent) {
|
||||
$('#setup_msg').html(sMessage);
|
||||
$('#progress').progression({
|
||||
Current: iPercent,
|
||||
Maximum: 100,
|
||||
aBackgroundImg: "{{ sProgressImage }}",
|
||||
aTextColor: '#000000'
|
||||
});
|
||||
}
|
||||
|
||||
var oGetCurrentVersion = {
|
||||
method: "POST",
|
||||
url: "{{ sAjaxURL|raw }}",
|
||||
data: {
|
||||
"operation": "GetCurrentVersion"
|
||||
},
|
||||
dataType: "json",
|
||||
success: function(data)
|
||||
{
|
||||
var oCurrentVersion = $("#current-version");
|
||||
if (oCurrentVersion)
|
||||
{
|
||||
oCurrentVersion.html(data.sVersion);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function GetAjaxRequest(sOperation)
|
||||
{
|
||||
oAjaxRequest = {
|
||||
method: "POST",
|
||||
url: "{{ sAjaxURL|raw }}",
|
||||
data: {
|
||||
"operation": sOperation,
|
||||
"authent": "{{ sSetupToken }}"
|
||||
},
|
||||
dataType: "json"
|
||||
};
|
||||
|
||||
if (sOperation === "Backup")
|
||||
{
|
||||
oAjaxRequest.success = function() {
|
||||
$("#do_backup_done").show();
|
||||
};
|
||||
}
|
||||
|
||||
if (sOperation === "FilesArchive")
|
||||
{
|
||||
oAjaxRequest.success = function() {
|
||||
$("#do_files_archive_done").show();
|
||||
};
|
||||
}
|
||||
|
||||
return oAjaxRequest;
|
||||
}
|
||||
|
||||
{% set aSteps = ['EnterMaintenance', 'Backup', 'FilesArchive', 'CopyFiles', 'Compile', 'ExitMaintenance', 'UpdateDone'] %}
|
||||
|
||||
aStepsName = [];
|
||||
|
||||
{% for sStep in aSteps %}
|
||||
aStepsName.push({{ ('iTopUpdate:UI:SetupMessage:' ~ sStep)|dict_s|json_encode|raw }});
|
||||
{% endfor %}
|
||||
|
||||
var sBackupStep;
|
||||
{% if bDoBackup %}
|
||||
sBackupStep = "Backup";
|
||||
{% endif %}
|
||||
|
||||
var sFilesArchiveStep;
|
||||
{% if bDoFilesArchive %}
|
||||
sFilesArchiveStep = "FilesArchive";
|
||||
{% endif %}
|
||||
|
||||
var aStepsAjaxOperation = ["EnterMaintenance", sBackupStep, sFilesArchiveStep, "CopyFiles", "Compile", "ExitMaintenance", null];
|
||||
|
||||
var iNextStep = 0;
|
||||
function ExecNextStep() {
|
||||
if (iNextStep < aStepsAjaxOperation.length)
|
||||
{
|
||||
var sAjaxOperation = aStepsAjaxOperation[iNextStep];
|
||||
var iPercent = (iNextStep + 1) * 100 / aStepsAjaxOperation.length;
|
||||
UpdateProgress(aStepsName[iNextStep], iPercent);
|
||||
iNextStep++;
|
||||
if (sAjaxOperation) {
|
||||
$.ajax(GetAjaxRequest(sAjaxOperation))
|
||||
.done(function () {
|
||||
setTimeout(ExecNextStep, 500);
|
||||
})
|
||||
.fail(function ( jqXHR) {
|
||||
$("#setup_continue").removeAttr("disabled");
|
||||
if (jqXHR && jqXHR.responseJSON) {
|
||||
$("#setup_error").html({{ 'iTopUpdate:Error:UpdateFailed'|dict_s|json_encode|raw }}+" "+jqXHR.responseJSON.sError);
|
||||
}
|
||||
else
|
||||
{
|
||||
$("#setup_error").html({{ 'iTopUpdate:Error:UpdateFailed'|dict_s|json_encode|raw }});
|
||||
}
|
||||
$('.progress').css("background-image", "none").css("background-color", "#fcc");
|
||||
$("#setup_error_outer").show();
|
||||
})
|
||||
;
|
||||
}
|
||||
else
|
||||
{
|
||||
setTimeout(ExecNextStep, 500);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
$.ajax(oGetCurrentVersion);
|
||||
$("#setup_continue").removeAttr("disabled");
|
||||
$("#current_version").removeClass("message_info").addClass("message_ok");
|
||||
$('.progress').css("background-image", "none").css("background-color", "#cfc");
|
||||
}
|
||||
}
|
||||
|
||||
ExecNextStep();
|
||||
|
||||
Reference in New Issue
Block a user