The Hub Connects !!

Adding iTop Hub Connector.

SVN:trunk[5270]
This commit is contained in:
Denis Flaven
2018-01-17 10:04:33 +00:00
parent cbdafbf264
commit ae59780297
24 changed files with 2587 additions and 0 deletions

View File

@@ -16,6 +16,7 @@
<module>itop-profiles-itil</module>
<module>itop-welcome-itil</module>
<module>itop-tickets</module>
<module>itop-hub-connector</module>
</modules>
<mandatory>true</mandatory>
</choice>

View File

@@ -0,0 +1,362 @@
<?php
// Copyright (C) 2017 Combodo SARL
//
// 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/>
/**
* Handles various ajax requests - called through pages/exec.php
*
* @copyright Copyright (C) 2010-2017 Combodo SARL
* @license http://opensource.org/licenses/AGPL-3.0
*/
if (!defined('__DIR__'))
define('__DIR__', dirname(__FILE__));
require_once (APPROOT.'application/webpage.class.inc.php');
require_once (APPROOT.'application/ajaxwebpage.class.inc.php');
require_once (APPROOT.'application/utils.inc.php');
require_once (APPROOT.'core/log.class.inc.php');
IssueLog::Enable(APPROOT.'log/error.log');
require_once (APPROOT.'setup/runtimeenv.class.inc.php');
require_once (APPROOT.'setup/backup.class.inc.php');
require_once (APPROOT.'core/mutex.class.inc.php');
require_once (APPROOT.'core/dict.class.inc.php');
require_once (__DIR__.'/hubruntimeenvironment.class.inc.php');
/**
* Overload of DBBackup to handle logging
*/
class DBBackupWithErrorReporting extends DBBackup
{
protected $aInfos = array();
protected $aErrors = array();
protected function LogInfo($sMsg)
{
$aInfos[] = $sMsg;
}
protected function LogError($sMsg)
{
IssueLog::Error($sMsg);
$aErrors[] = $sMsg;
}
public function GetInfos()
{
return $this->aInfos;
}
public function GetErrors()
{
return $this->aErrors;
}
}
/**
*
* @param string $sTargetFile
* @throws Exception
* @return DBBackupWithErrorReporting
*/
function DoBackup($sTargetFile)
{
// Make sure the target directory exists
$sBackupDir = dirname($sTargetFile);
SetupUtils::builddir($sBackupDir);
$oBackup = new DBBackupWithErrorReporting();
$oBackup->SetMySQLBinDir(MetaModel::GetConfig()->GetModuleSetting('itop-backup', 'mysql_bindir', ''));
$sSourceConfigFile = APPCONF.utils::GetCurrentEnvironment().'/'.ITOP_CONFIG_FILE;
$oMutex = new iTopMutex('backup.'.utils::GetCurrentEnvironment());
$oMutex->Lock();
try
{
$oBackup->CreateCompressedBackup($sTargetFile, $sSourceConfigFile);
}
catch (Exception $e)
{
$oMutex->Unlock();
throw $e;
}
$oMutex->Unlock();
return $oBackup;
}
/**
* Outputs the status of the current ajax execution (as a JSON structure)
*
* @param string $sMessage
* @param bool $bSuccess
* @param number $iErrorCode
* @param array $aMoreFields
* Extra fields to pass to the caller, if needed
*/
function ReportStatus($sMessage, $bSuccess, $iErrorCode = 0, $aMoreFields = array())
{
$oPage = new ajax_page("");
$oPage->no_cache();
$oPage->SetContentType('application/json');
$aResult = array(
'code' => $iErrorCode,
'message' => $sMessage,
'fields' => $aMoreFields
);
$oPage->add(json_encode($aResult));
$oPage->output();
}
/**
* Helper to output the status of a successful execution
*
* @param string $sMessage
* @param array $aMoreFields
* Extra fields to pass to the caller, if needed
*/
function ReportSuccess($sMessage, $aMoreFields = array())
{
ReportStatus($sMessage, true, 0, $aMoreFields);
}
/**
* Helper to output the status of a failed execution
*
* @param string $sMessage
* @param number $iErrorCode
* @param array $aMoreFields
* Extra fields to pass to the caller, if needed
*/
function ReportError($sMessage, $iErrorCode, $aMoreFields = array())
{
if ($iErrorCode==0)
{
// 0 means no error, so change it if no meaningful error code is supplied
$iErrorCode = -1;
}
ReportStatus($sMessage, false, $iErrorCode, $aMoreFields);
}
try
{
utils::PushArchiveMode(false);
ini_set('max_execution_time', max(3600, ini_get('max_execution_time'))); // Under Windows SQL/backup operations are part of the PHP timeout and require extra time
ini_set('display_errors', 1); // Make sure that fatal errors remain visible from the end-user
// Most of the ajax calls are done without the MetaModel being loaded
// Therefore, the language must be passed as an argument,
// and the dictionnaries be loaded here
$sLanguage = utils::ReadParam('language', '');
if ($sLanguage!='')
{
foreach (glob(APPROOT.'env-production/dictionaries/*.dict.php') as $sFilePath)
{
require_once ($sFilePath);
}
$aLanguages = Dict::GetLanguages();
if (array_key_exists($sLanguage, $aLanguages))
{
Dict::SetUserLanguage($sLanguage);
}
}
$sOperation = utils::ReadParam('operation', '');
switch ($sOperation)
{
case 'check_before_backup':
require_once (APPROOT.'/application/startup.inc.php');
require_once (APPROOT.'/application/loginwebpage.class.inc.php');
LoginWebPage::DoLogin(true); // Check user rights and prompt if needed (must be admin)
$sDBBackupPath = APPROOT.'data/backups/manual';
$aChecks = SetupUtils::CheckBackupPrerequisites($sDBBackupPath);
$bFailed = false;
foreach ($aChecks as $oCheckResult)
{
if ($oCheckResult->iSeverity==CheckResult::ERROR)
{
$bFailed = true;
ReportError($oCheckResult->sLabel, -2);
}
}
if (!$bFailed)
{
// Continue the checks
$fFreeSpace = SetupUtils::CheckDiskSpace($sDBBackupPath);
if ($fFreeSpace!==false)
{
$sMessage = Dict::Format('iTopHub:BackupFreeDiskSpaceIn', SetupUtils::HumanReadableSize($fFreeSpace), dirname($sDBBackupPath));
ReportSuccess($sMessage);
}
else
{
ReportError(Dict::S('iTopHub:FailedToCheckFreeDiskSpace'), -1);
}
}
break;
case 'do_backup':
require_once (APPROOT.'/application/startup.inc.php');
require_once (APPROOT.'/application/loginwebpage.class.inc.php');
LoginWebPage::DoLogin(true); // Check user rights and prompt if needed (must be admin)
try
{
set_time_limit(0);
$sBackupPath = APPROOT.'/data/backups/manual/backup-';
$iSuffix = 1;
$sSuffix = '';
// Generate a unique name...
do
{
$sBackupFile = $sBackupPath.date('Y-m-d-His').$sSuffix;
$sSuffix = '-'.$iSuffix;
$iSuffix++ ;
}
while (file_exists($sBackupFile));
$oBackup = DoBackup($sBackupFile);
$aErrors = $oBackup->GetErrors();
if (count($aErrors)>0)
{
ReportError(Dict::S('iTopHub:BackupFailed'), -1, $aErrors);
}
else
{
ReportSuccess(Dict::S('iTopHub:BackupOk'));
}
}
catch (Exception $e)
{
ReportError($e->getMessage(), $e->getCode());
}
break;
case 'compile':
// First step: prepare the datamodel, if it fails, roll-back
$aSelectedExtensionCodes = utils::ReadParam('extension_codes', array());
$aSelectedExtensionDirs = utils::ReadParam('extension_dirs', array());
$oRuntimeEnv = new HubRunTimeEnvironment('production', false); // use a temp environment: production-build
$oRuntimeEnv->MoveSelectedExtensions(APPROOT.'/data/downloaded-extensions/', $aSelectedExtensionDirs);
$oConfig = new Config(APPCONF.'production/'.ITOP_CONFIG_FILE);
$aSelectModules = $oRuntimeEnv->CompileFrom('production', false); // WARNING symlinks does not seem to be compatible with manual Commit
$oRuntimeEnv->UpdateIncludes($oConfig);
$oRuntimeEnv->InitDataModel($oConfig, true /* model only */);
$oRuntimeEnv->CheckMetaModel(); // Will throw an exception if a problem is detected
// Everything seems Ok so far, commit in env-production!
$oRuntimeEnv->WriteConfigFileSafe($oConfig);
$oRuntimeEnv->Commit();
// Report the success in a way that will be detected by the ajax caller
ReportSuccess('Ok'); // No access to Dict::S here
break;
case 'move_to_production':
// Second step: update the schema and the data
// Everything happening below is based on env-production
$oRuntimeEnv = new RunTimeEnvironment('production', true);
try
{
// Load the "production" config file to clone & update it
$oConfig = new Config(APPCONF.'production/'.ITOP_CONFIG_FILE);
$oRuntimeEnv->InitDataModel($oConfig, true /* model only */);
$aAvailableModules = $oRuntimeEnv->AnalyzeInstallation($oConfig, $oRuntimeEnv->GetBuildDir(), true);
$aSelectedModules = array();
foreach ($aAvailableModules as $sModuleId => $aModule)
{
if (($sModuleId==ROOT_MODULE)||($sModuleId==DATAMODEL_MODULE))
{
continue;
}
else
{
$aSelectedModules[] = $sModuleId;
}
}
$oRuntimeEnv->CallInstallerHandlers($aAvailableModules, $aSelectedModules, 'BeforeDatabaseCreation');
// Now I assume that there is a DB for this environment...
$oRuntimeEnv->CreateDatabaseStructure($oConfig, 'upgrade');
$oRuntimeEnv->CallInstallerHandlers($aAvailableModules, $aSelectedModules, 'AfterDatabaseCreation');
$oRuntimeEnv->UpdatePredefinedObjects();
$oRuntimeEnv->CallInstallerHandlers($aAvailableModules, $aSelectedModules, 'AfterDatabaseSetup');
// Record the installation so that the "about box" knows about the installed modules
$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;
}
$aSelectedExtensions = $oExtensionsMap->GetChoices();
$oRuntimeEnv->RecordInstallation($oConfig, $sDataModelVersion, $aSelectedModules, $aSelectedExtensionCodes, 'Done by the iTop Hub Connector');
// Report the success in a way that will be detected by the ajax caller
ReportSuccess(Dict::S('iTopHub:CompiledOK'));
}
catch (Exception $e)
{
// Note: at this point, the dictionnary is not necessarily loaded
IssueLog::Error(get_class($e).': '.Dict::S('iTopHub:ConfigurationSafelyReverted')."\n".$e->getMessage());
IssueLog::Error('Debug trace: '.$e->getTraceAsString());
ReportError($e->getMessage(), $e->getCode());
}
break;
default:
ReportError("Invalid operation: '$sOperation'", -1);
}
}
catch (Exception $e)
{
IssueLog::Error(get_class($e).': '.Dict::S('iTopHub:ConfigurationSafelyReverted')."\n".$e->getMessage());
IssueLog::Error('Debug trace: '.$e->getTraceAsString());
utils::PopArchiveMode();
ReportError($e->getMessage(), $e->getCode());
}

View File

@@ -0,0 +1,252 @@
#hub_popup_menu li span {
display: block;
padding: 5px 12px;
text-decoration: none;
nowidth: 70px;
white-space: nowrap;
}
#hub_popup_menu li li p {
text-align: left;
margin: 2px;
margin-left: 5px;
margin-right: 5px;
cursor: pointer;
background-color: transparent;
color: #000;
}
#hub_popup_menu > ul > li > ul {
margin-top: 8px;
}
#hub_popup_menu > ul > li > ul > li {
display: block;
border-bottom: 1px #ddd solid;
padding-top: 10px;
padding-bottom: 10px;
}
#hub_popup_menu > ul > li > ul > li:hover {
color: #fff;
background-color: #E87C1E;
}
#hub_popup_menu li li:last-of-type {
border-bottom: 0;
}
#hub_popup_menu li {
list-style: none;
cursor: pointer;
}
#hub_popup_menu li ul {
width: 340px;
}
#top-left-hub-cell {
padding-right: 8px !important;
}
#hub_launch_container {
padding:10px;
overflow: visible;
width: 800px;
margin-left: auto;
margin-right: auto;
}
#hub_launch_container h1 {
font-size: 14pt;
line-height: 24pt;
}
#hub_launch_container h1 img {
vertical-align: middle;
margin-right: 0.25em;
height: 24pt;
}
#hub_launch_image {
width: 120pt;
height: 250pt;
float: left;
padding-top: 10pt;
position: relative;
top: -23px;
}
.animate #rocket, .animate #flame {
animation: animationFrames ease-in 2s;
animation-iteration-count: 1;
transform-origin: 0% 0%;
animation-fill-mode:forwards; /*when the spec is finished*/
}
#flame {
opacity: 0;
}
.animate #flame {
animation: flameAnimationFrames ease-in 2s;
animation-iteration-count: 1;
transform-origin: 0% 0%;
animation-fill-mode:forwards; /*when the spec is finished*/
}
#chameleon {
opacity: 0;
animation: chameleonAnimationFrames linear 1s;
animation-delay: 1s;
animation-iteration-count: 1;
transform-origin: 0% 0%;
animation-fill-mode:forwards; /*when the spec is finished*/
}
@keyframes animationFrames {
0% {
transform: translate(0px,0px) ;
}
15% {
transform: translate(0px,0px) ;
}
100% {
transform: translate(0px,-950px) ;
}
}
@keyframes flameAnimationFrames {
0% {
opacity: 0;
transform: translate(0px,0px) ;
}
15% {
opacity: 1;
transform: translate(0px,0px) ;
}
100% {
opacity: 1;
transform: translate(0px,-950px) ;
}
}
@keyframes chameleonAnimationFrames {
0% {
opacity: 0;
transform: translate(-45px,0px) ;
}
69% {
opacity: 0;
transform: translate(-45px,0px) ;
}
70% {
opacity: 1;
transform: translate(-45px,0px) ;
}
100% {
opacity: 1;
transform: translate(0px,0px) ;
}
}
#backup_form {
display: none;
}
.landing-extension {
padding: 0.25em;
border: 1px solid;
margin-top: 2px;
margin-bottom: 2px;
border-radius: 5px;
}
.landing-upgrade {
background-color: #eeeeff;
border-color: #bbbbdd;
}
.landing-downgrade {
background-color: #ffcccc;
border-color: #dd9999;
}
.landing-installation {
background-color: #eeffee;
border-color: #bbddbb;
}
.landing-no-change, .landing-no-change h2 {
background-color: #eeeeee;
border-color: #bbbbbb;
color: #555555;
}
#hub-landing-page-title h1 {
font-size: 14pt;
line-height: 24pt;
}
#hub-landing-page-title h1 img {
vertical-align: middle;
margin-right: 0.25em;
height: 24pt;
}
#hub-installation-feedback {
display: none;
-moz-box-shadow: 5px 5px 10px 0px #656565;
-webkit-box-shadow: 5px 5px 10px 0px #656565;
-o-box-shadow: 5px 5px 10px 0px #656565;
box-shadow: 5px 5px 10px 0px #656565;
filter:progid:DXImageTransform.Microsoft.Shadow(color=#656565, Direction=134, Strength=10);
padding-bottom: 1em;
background-color: #FFF;
padding-top: 1em;
position: absolute;
top: 50px;
left: 100px;
width: 400px;
}
#hub-installation-progress-text {
text-align: center;
margin-top: 1em;
}
#hub-installation-progress {
height: 20px;
background-image: url(../images/orange-progress.gif);
background-color: #ff9000;
text-align: center;
margin-top: 1em;
margin-bottom: 1em;
margin-left: auto;
margin-right: auto;
width: 300px;
border: 1px solid #000;
}
#hub_top_banner {
height: 77px;
background-color: rgb(27, 28, 29);
}
#hub_launch_content {
width: 100%;
}
button {
cursor: pointer;
font-weight: bold;
box-shadow: 0px 0px 0px 1px transparent inset, 0px 0em 0px 0px rgba(34, 36, 38, 0.15) inset;
border: 0;
background-color: #E0E1E2;
height: 40px;
vertical-align: middle;
padding: 0;
}
button.positive {
background-color: rgb(234, 125, 30);
color: #FFFFFF;
}
button:disabled, button[disabled] {
background-color: #828487!important;
cursor: progress !important;
}
button > span {
display: inline-block;
padding: 0.8em;
padding-left: 1.3em;
padding-right: 1.3em;
}
button:hover {
background-color: #D0D0D0;
}
button.positive:hover {
background-color: rgb(221, 113, 27);
}
button > img {
width: 16px;
height: 16px;
vertical-align: middle;
padding: 12px;
background-color: rgba(0, 0, 0, 0.1);
}
.horiz-spacer {
display: inline-block;
width: 1.5em;
}

View File

@@ -0,0 +1,24 @@
<?xml version="1.0" encoding="UTF-8"?>
<itop_design xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" version="1.0">
<constants>
</constants>
<classes>
</classes>
<menus>
</menus>
<user_rights>
<groups>
</groups>
<profiles>
</profiles>
</user_rights>
<module_parameters>
<parameters id="itop-hub-connector" _delta="define">
<url>https://www.proto2.itophub.io</url>
<route_landing>/my-instances/landing-from-remote</route_landing>
<route_landing_stateless>/stateless-remote-itop/landing-from-remote-stateless</route_landing_stateless>
<route_notifications>/api/notifications</route_notifications>
<setup_url>../pages/exec.php?exec_module=itop-hub-connector&amp;exec_page=launch.php&amp;target=inform_after_setup</setup_url>
</parameters>
</module_parameters>
</itop_design>

View File

@@ -0,0 +1,70 @@
<?php
/**
* Localized data
*
* @copyright Copyright (C) 2013 XXXXX
* @license http://opensource.org/licenses/AGPL-3.0
*/
Dict::Add('EN US', 'English', 'English', array(
// Dictionary entries go here
'Menu:iTopHub' => 'iTop Hub',
'Menu:iTopHub:Register' => 'Connect to iTop Hub',
'Menu:iTopHub:Register+' => 'Go to iTop Hub to update your iTop instance',
'Menu:iTopHub:Register:Description' => '<p>Get access to your community platform iTop Hub!</br>Find all the content and information you need, manage your instances through personalized tools & install more extensions.</br><br/>By connecting to the Hub from this page, you will push information about this iTop instance into the Hub.</p>',
'Menu:iTopHub:MyExtensions' => 'Deployed extensions',
'Menu:iTopHub:MyExtensions+' => 'See the list of extensions deployed on this instance of iTop',
'Menu:iTopHub:BrowseExtensions' => 'Get extensions from iTop Hub',
'Menu:iTopHub:BrowseExtensions+' => 'Browse for more extensions on iTop Hub',
'Menu:iTopHub:BrowseExtensions:Description' => '<p>Look into iTop Hubs store, your one stop place to find wonderful iTop extensions !</br>Find the ones that will help you customize and adapt iTop to your processes.</br><br/>By connecting to the Hub from this page, you will push information about this iTop instance into the Hub.</p>',
'iTopHub:GoBtn' => 'Go To iTop Hub',
'iTopHub:CloseBtn' => 'Close',
'iTopHub:GoBtn:Tooltip' => 'Jump to www.itophub.io',
'iTopHub:OpenInNewWindow' => 'Open iTop Hub in a new window',
'iTopHub:AutoSubmit' => 'Don\'t ask me again. Next time, go to iTop Hub automatically.',
'UI:About:RemoteExtensionSource' => 'iTop Hub',
'iTopHub:Explanation' => 'By clicking this button you will be redirected to iTop Hub.',
'iTopHub:BackupFreeDiskSpaceIn' => '%1$s free disk space in %2$s.',
'iTopHub:FailedToCheckFreeDiskSpace' => 'Failed to check free disk space.',
'iTopHub:BackupOk' => 'Backup Ok.',
'iTopHub:BackupFailed' => 'Backup failed!',
'iTopHub:Landing:Status' => 'Deployment status',
'iTopHub:Landing:Install' => 'Deploying extensions...',
'iTopHub:CompiledOK' => 'Compilation successful.',
'iTopHub:ConfigurationSafelyReverted' => 'Error detected during deployment!<br/>iTop configuration has NOT been modified.',
'iTopHub:InstalledExtensions' => 'Extensions deployed on this instance',
'iTopHub:ExtensionCategory:Manual' => 'Extensions deployed manually',
'iTopHub:ExtensionCategory:Manual+' => 'The following extensions have been deployed by copying them manually in the %1$s directory of iTop:',
'iTopHub:ExtensionCategory:Remote' => 'Extensions deployed from iTop Hub',
'iTopHub:ExtensionCategory:Remote+' => 'The following extensions have been deployed from iTop Hub:',
'iTopHub:NoExtensionInThisCategory' => 'There is no extension in this category.<br/><br/>Browse iTop Hub to find the extensions that will help you customize and adapt iTop to your processes.',
'iTopHub:ExtensionNotInstalled' => 'Not installed',
'iTopHub:GetMoreExtensions' => 'Get extensions from iTop Hub...',
'iTopHub:LandingWelcome' => 'Congratulations! The following extensions were downloaded from iTop Hub and deployed into your iTop.',
'iTopHub:GoBackToITopBtn' => 'Go Back to iTop',
'iTopHub:Uncompressing' => 'Uncompressing extensions...',
'iTopHub:InstallationWelcome' => 'Installation of the extensions downloaded from iTop Hub',
'iTopHub:DBBackupLabel' => 'Instance backup',
'iTopHub:DBBackupSentence' => 'Do a backup of the database and iTop configuration before updating',
'iTopHub:DeployBtn' => 'Deploy !',
'iTopHub:DatabaseBackupProgress' => 'Instance backup...',
'iTopHub:InstallationEffect:Install' => 'Version: %1$s will be installed.',
'iTopHub:InstallationEffect:NoChange' => 'Version: %1$s already installed. Nothing will change.',
'iTopHub:InstallationEffect:Upgrade' => 'Will be <b>upgraded</b> from version %1$s to version %2$s.',
'iTopHub:InstallationEffect:Downgrade' => 'Will be <b>DOWNGRADED</b> from version %1$s to version %2$s.',
'iTopHub:InstallationProgress:DatabaseBackup' => 'iTop Instance backup...',
'iTopHub:InstallationProgress:ExtensionsInstallation' => 'Installation of the extensions',
'iTopHub:InstallationEffect:MissingDependencies' => 'This extension cannot be installed because of unmet dependencies.',
'iTopHub:InstallationEffect:MissingDependencies_Details' => 'The extension requires the module(s): %1$s',
'iTopHub:InstallationProgress:InstallationSuccessful' => 'Installation successful!',
'iTopHub:InstallationStatus:Installed_Version' => '%1$s version: %2$s.',
'iTopHub:InstallationStatus:Installed' => 'Installed',
'iTopHub:InstallationStatus:Version_NotInstalled' => 'Version %1$s <b>NOT</b> installed.',
));

View File

@@ -0,0 +1,9 @@
<?xml version="1.0" encoding="UTF-8"?>
<extension format="1.0">
<extension_code>itop-hub-connector</extension_code>
<version>0.0.4</version>
<label>iTop Hub Connector</label>
<description>Extension to connect iTop with the central iTopHub platform</description>
<mandatory>false</mandatory>
<more_info_url></more_info_url>
</extension>

View File

@@ -0,0 +1,68 @@
<?php
/**
* Localized data
*
* @copyright Copyright (C) 2013 XXXXX
* @license http://opensource.org/licenses/AGPL-3.0
*/
Dict::Add('FR FR', 'French', 'Français', array(
// Dictionary entries go here
'Menu:iTopHub' => 'iTop Hub',
'Menu:iTopHub:Register' => 'Se connecter à iTop Hub',
'Menu:iTopHub:Register+' => 'Connectez-vous à iTop Hub pour enregistrer cette instance d\'iTop',
'Menu:iTopHub:Register:Description' => '<p>Connectez-vous à la communauté iTop Hub!</br>Trouvez tout le contenu dont vous avez besoin, gérer vos instances d\'iTop depuis un tableau de bord centralisé et déployez de nouvelles extensions.</br><br/>En vous connectant au Hub depuis cette page, vous transmettez au Hub des informations relatives à cette instance d\'iTop.</p>',
'Menu:iTopHub:MyExtensions' => 'Extensions déployées',
'Menu:iTopHub:MyExtensions+' => 'Voir la liste des extensions déployes sur cette instance',
'Menu:iTopHub:BrowseExtensions' => 'Obtenir des extensions depuis iTop Hub',
'Menu:iTopHub:BrowseExtensions+' => 'Parcourir la listes des extensions disponibles sur iTop Hub',
'Menu:iTopHub:BrowseExtensions:Description' => '<p>Découvrez le magasin d\'extensions iTop Hub !</br>Trouvez en quelques clics celles qui vous permettront de construire un iTop sur mesure qui se conforme à vos processus.</br><br/>En vous connectant au Hub depuis cette page, vous transmettez au Hub des informations relatives à cette instance d\'iTop.</p>',
'iTopHub:GoBtn' => 'Aller sur iTop Hub',
'iTopHub:CloseBtn' => 'Fermer',
'iTopHub:GoBtn:Tooltip' => 'Naviguer vers www.itophub.io',
'iTopHub:OpenInNewWindow' => 'Ouvrir iTop Hub dans une nouvelle fenêtre',
'iTopHub:AutoSubmit' => 'Ne plus me demander. La prochaine fois, aller sur iTop Hub automatiquement.',
'UI:About:RemoteExtensionSource' => 'iTop Hub',
'iTopHub:Explanation' => 'En cliquant sur ce bouton, vous serez redirigé vers iTop Hub.',
'iTopHub:BackupFreeDiskSpaceIn' => '%1$s d\'espace disque disponible sur %2$s.',
'iTopHub:FailedToCheckFreeDiskSpace' => 'Echec de la vérification de l\'espace disque.',
'iTopHub:BackupOk' => 'Sauvegarde Ok.',
'iTopHub:BackupFailed' => 'Echec de la sauvegarde !',
'iTopHub:Landing:Status' => 'Etat du déploiement',
'iTopHub:Landing:Install' => 'Déploiement des extensions...',
'iTopHub:CompiledOK' => 'Compilation réussie.',
'iTopHub:ConfigurationSafelyReverted' => 'Une erreur a été détectée durant le déploiement!<br/>La configuration d\'iTop n\'a PAS été modifiée.',
'iTopHub:InstalledExtensions' => 'Extensions déployées sur cette instance',
'iTopHub:ExtensionCategory:Manual' => 'Extensions déployées manuellement',
'iTopHub:ExtensionCategory:Manual+' => 'Les extensions ci-dessous ont été déployées en les copiant manuellement dans le répertoire %1$s d\'iTop:',
'iTopHub:ExtensionCategory:Remote' => 'Extensions déployées depuis iTop Hub',
'iTopHub:ExtensionCategory:Remote+' => 'Les extensions ci-dessous ont été déployées depuis iTop Hub:',
'iTopHub:NoExtensionInThisCategory' => 'Il n\'y a pas d\'extension dans cette catégorie<br/><br>Avec iTop Hub trouvez en quelques clics les extensions qui vous permettront de construire un iTop sur mesure qui se conforme à vos processus.',
'iTopHub:ExtensionNotInstalled' => 'Non installée',
'iTopHub:GetMoreExtensions' => 'Obtenir des extensions depuis iTop Hub...',
'iTopHub:LandingWelcome' => 'Félicitations! Les extensions ci-dessous ont été téléchargées depuis iTop Hub et installées sur cette instance d\'iTop.',
'iTopHub:GoBackToITopBtn' => 'Retourner dans iTop',
'iTopHub:Uncompressing' => 'Décompression des extensions...',
'iTopHub:InstallationWelcome' => 'Installation des extensions téléchargées depuis iTop Hub',
'iTopHub:DBBackupLabel' => 'Sauvegarde de l\'instance iTop',
'iTopHub:DBBackupSentence' => 'Faire une sauvegarde de la base de données et des paramétrages d\'iTop',
'iTopHub:DeployBtn' => 'Déployer !',
'iTopHub:DatabaseBackupProgress' => 'Sauvegarde de l\'instance...',
'iTopHub:InstallationEffect:Install' => 'Version: %1$s sera installée.',
'iTopHub:InstallationEffect:NoChange' => 'Version: %1$s déjà installée. Rien ne changera.',
'iTopHub:InstallationEffect:Upgrade' => 'Sera <b>mise à jour</b> de version %1$s en version %2$s.',
'iTopHub:InstallationEffect:Downgrade' => 'Sera <b>DEGRADEE</b> de version %1$s en version %2$s.',
'iTopHub:InstallationEffect:MissingDependencies' => 'Cette extension ne peut pas être installée à cause de ses dépendences.',
'iTopHub:InstallationEffect:MissingDependencies_Details' => 'Cette extension nécessite le(s) module(s): %1$s',
'iTopHub:InstallationProgress:DatabaseBackup' => 'Sauvegarde de l\'instance iTop...',
'iTopHub:InstallationProgress:ExtensionsInstallation' => 'Installation des extensions',
'iTopHub:InstallationProgress:InstallationSuccessful' => 'Installation réussie !',
'iTopHub:InstallationStatus:Installed_Version' => '%1$s version: %2$s.',
'iTopHub:InstallationStatus:Installed' => 'Installée',
'iTopHub:InstallationStatus:Version_NotInstalled' => 'Version %1$s <b>NON</b> installée.'
));

View File

@@ -0,0 +1,119 @@
<?php
require_once(APPROOT."/application/user.preferences.class.inc.php");
class HubConnectorPage extends NiceWebPage
{
public function __construct($sTitle)
{
parent::__construct($sTitle);
$this->add_header("Cache-control: no-cache");
$sImagesDir = utils::GetAbsoluteUrlAppRoot().'images';
$sModuleImagesDir = utils::GetAbsoluteUrlModulesRoot().'itop-hub-connector/images';
$sUserPrefs = appUserPreferences::GetAsJSON();
$this->add_linked_script(utils::GetAbsoluteUrlAppRoot().'js/utils.js');
$this->add_script(
<<<EOF
var oUserPreferences = $sUserPrefs;
EOF
);
$this->add_style(
<<<EOF
body {
background-color: #FFFFFF;
color: rgba(0, 0, 0, 0.87);
font-family: 'Open Sans', 'Helvetica Neue', Arial, Helvetica, sans-serif;
font-size: 14px;
line-height: 1.4285em;
overflow: auto;
}
.centered_box {
background: none repeat scroll 0 0 #333333;
border-color: #000000;
border-style: solid ;
border-width: 1px;
margin-left: auto;
margin-right: auto;
margin-top: 100px;
padding: 20px;
width: 600px;
}
h2 {
font-size: 1.71428571rem;
}
#wiz_buttons > button, #wiz_buttons > form{
margin: 20px;
}
#launcher {
display: inline-block;
}
.header_message {
color: black;
margin-top: 10px;
}
.checkup_info {
background: url("$sImagesDir/info-mini.png") no-repeat left;
padding-left: 2em;
}
.checkup_error {
background: url("$sImagesDir/validation_error.png") no-repeat left;
padding-left: 2em;
}
.ui-state-default, .ui-widget-content .ui-state-default, .ui-widget-header .ui-state-default {
background: url("$sModuleImagesDir/ui-bg_flat_35_555555_40x100.png") repeat-x scroll 50% 50% #555555;
border: 1px solid #555555;
color: #EEEEEE;
font-weight: bold;
}
.ui-state-hover, .ui-widget-content .ui-state-hover, .ui-widget-header .ui-state-hover,
.ui-state-focus, .ui-widget-content .ui-state-focus, .ui-widget-focus .ui-state-focus {
background: url("$sModuleImagesDir/ui-bg_flat_33_F58400_40x100.png") repeat-x scroll 50% 50% #F58400;
border: 1px solid #F58400;
color: #EEEEEE;
font-weight: bold;
}
.ui-corner-all, .ui-corner-bottom, .ui-corner-right, .ui-corner-br {
border-bottom-right-radius: 0;
}
.ui-corner-all, .ui-corner-bottom, .ui-corner-left, .ui-corner-bl {
border-bottom-left-radius: 0;
}
.ui-corner-all, .ui-corner-top, .ui-corner-right, .ui-corner-tr {
border-top-right-radius: 0;
}
.ui-corner-all, .ui-corner-top, .ui-corner-left, .ui-corner-tl {
border-top-left-radius: 0;
}
.ui-widget {
font-family: Verdana,Arial,sans-serif;
font-size: 1.1em;
}
.ui-button, .ui-button:link, .ui-button:visited, .ui-button:hover, .ui-button:active {
text-decoration: none;
}
.ui-button {
cursor: pointer;
display: inline-block;
line-height: normal;
margin-right: 0.1em;
overflow: visible;
padding: 0;
position: relative;
text-align: center;
vertical-align: middle;
}
#db_backup_path {
width: 99%;
}
div#integrity_issues {
background-color: #FFFFFF;
}
div#integrity_issues .query {
font-size: smaller;
}
EOF
);
}
}

View File

@@ -0,0 +1,59 @@
<?php
class HubRunTimeEnvironment extends RunTimeEnvironment
{
/**
* Constructor
* @param string $sEnvironment
* @param string $bAutoCommit
*/
public function __construct($sEnvironment = 'production', $bAutoCommit = true)
{
parent::__construct($sEnvironment, $bAutoCommit);
if ($sEnvironment != $this->sTargetEnv)
{
SetupUtils::copydir(APPROOT.'/data/'.$sEnvironment.'-modules', APPROOT.'/data/'.$this->sTargetEnv.'-modules');
}
}
/**
* Update the includes for the target environment
* @param Config $oConfig
*/
public function UpdateIncludes(Config $oConfig)
{
$oConfig->UpdateIncludes('env-'.$this->sTargetEnv); // TargetEnv != FinalEnv
}
/**
* Move an extension (path to folder of this extension) to the target environment
* @param string $sExtensionDirectory The folder of the extension
* @throws Exception
*/
public function MoveExtension($sExtensionDirectory)
{
if (!is_dir(APPROOT.'/data/'.$this->sTargetEnv.'-modules'))
{
if (!mkdir(APPROOT.'/data/'.$this->sTargetEnv.'-modules')) throw new Exception("ERROR: failed to create directory:'".(APPROOT.'/data/'.$this->sTargetEnv.'-modules')."'");
}
$sDestinationPath = APPROOT.'/data/'.$this->sTargetEnv.'-modules/';
if (!rename($sExtensionDirectory, $sDestinationPath.basename($sExtensionDirectory))) throw new Exception("ERROR: failed move directory:'$sExtensionDirectory' to '".$sDestinationPath.basename($sExtensionDirectory)."'");
}
/**
* Move the selected extensions located in the given directory in data/<target-env>-modules
* @param string $sDownloadedExtensionsDir The directory to scan
* @param string[] $aSelectedExtensionDirs The list of folders to move
* @throws Exception
*/
public function MoveSelectedExtensions($sDownloadedExtensionsDir, $aSelectedExtensionDirs)
{
foreach(glob($sDownloadedExtensionsDir.'*', GLOB_ONLYDIR) as $sExtensionDir)
{
if (in_array(basename($sExtensionDir), $aSelectedExtensionDirs))
{
$this->MoveExtension($sExtensionDir);
}
}
}
}

View File

@@ -0,0 +1,2 @@
<?xml version="1.0" encoding="utf-8"?>
<svg width="1792" height="1792" viewBox="0 0 1792 1792" xmlns="http://www.w3.org/2000/svg"><path d="M1490 1322q0 40-28 68l-136 136q-28 28-68 28t-68-28l-294-294-294 294q-28 28-68 28t-68-28l-136-136q-28-28-28-68t28-68l294-294-294-294q-28-28-28-68t28-68l136-136q28-28 68-28t68 28l294 294 294-294q28-28 68-28t68 28l136 136q28 28 28 68t-28 68l-294 294 294 294q28 28 28 68z"/></svg>

After

Width:  |  Height:  |  Size: 415 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 17 KiB

View File

@@ -0,0 +1,105 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
width="123.7746mm"
height="123.7746mm"
viewBox="0 0 438.57143 438.57143"
id="svg4389"
version="1.1"
inkscape:version="0.91 r13725"
sodipodi:docname="itophub-logo.svg">
<defs
id="defs4391" />
<sodipodi:namedview
id="base"
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1.0"
inkscape:pageopacity="0.0"
inkscape:pageshadow="2"
inkscape:zoom="0.7"
inkscape:cx="-162.53939"
inkscape:cy="222.76682"
inkscape:document-units="px"
inkscape:current-layer="layer1"
showgrid="false"
fit-margin-top="0"
fit-margin-left="0"
fit-margin-right="0"
fit-margin-bottom="0"
inkscape:window-width="1920"
inkscape:window-height="1031"
inkscape:window-x="0"
inkscape:window-y="25"
inkscape:window-maximized="1" />
<metadata
id="metadata4394">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title></dc:title>
</cc:Work>
</rdf:RDF>
</metadata>
<g
inkscape:label="Layer 1"
inkscape:groupmode="layer"
id="layer1"
transform="translate(-106.42857,-135.93364)">
<rect
style="opacity:1;fill:#ea7d1e;fill-opacity:1;stroke:none;stroke-width:25;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
id="rect5087"
width="438.57144"
height="438.57144"
x="106.42857"
y="135.93364" />
<g
id="g5079">
<path
id="path4481"
d="m 225.85938,259.86523 c -8.94861,-0.0714 -0.86689,8.07541 -4.50977,12.0918 -9.41456,0.33026 -73.18656,23.33539 -73.86719,87.94531 -0.68063,64.60992 39.14817,96.46928 80.8125,96.47071 41.66433,0.001 53.1669,-22.01498 58.58789,-43.4375 5.42099,-21.42252 -8.93812,-45.39262 -25.2539,-54.04297 -16.31578,-8.65035 -39.46035,-1.16781 -50.50782,8.08203 -11.04747,9.24984 -12.07115,25.30358 -9.65234,36.81641 2.41881,11.51283 19.65862,22.42423 33.0957,22.03906 13.43707,-0.38518 26.91053,-13.13632 28.58008,-24.51172 1.66955,-11.3754 -5.47475,-23.79209 -17.17187,-25.75781 -11.69712,-1.96572 -23.46958,5.10597 -24.6875,15.44726 -1.21792,10.3413 8.15359,14.28917 11.28906,14.74024 8.40489,1.20911 15.15491,-7.48403 7.01367,-10.04297 -5.63635,-1.77161 -8.06872,-4.33354 -5.23242,-8.02344 2.25726,-2.93659 8.9149,-1.575 11.82617,0.71484 4.49339,3.53423 5.53273,10.67937 3.32617,15.95313 -2.6524,6.33932 -10.84608,11.34761 -17.67773,10.60547 -8.28798,-0.90034 -17.45371,-8.86716 -18.1836,-17.17188 -1.49385,-16.99698 11.31857,-29.37504 22.72852,-30.80859 36.45173,-2.77522 45.38636,38.64362 19.69922,59.09375 -19.51179,14.42427 -54.75176,3.05251 -61.11524,-19.19336 -6.36349,-22.24587 8.98742,-51.78249 37.88086,-59.59961 l 69.19532,0 c 7.4791,-1.81702 13.74954,-5.29754 10.60742,-21.71875 -24.07043,-67.6147 -75.46093,-65.02392 -85.86328,-65.6582 -0.32508,-0.0198 -0.63126,-0.0309 -0.91992,-0.0332 z m 52.56445,34.75586 a 13.637059,13.637059 0 0 1 13.63672,13.63672 13.637059,13.637059 0 0 1 -13.63672,13.63867 13.637059,13.637059 0 0 1 -13.63672,-13.63867 13.637059,13.637059 0 0 1 13.63672,-13.63672 z"
style="opacity:1;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
inkscape:connector-curvature="0" />
<circle
r="4.2931485"
cy="308.51111"
cx="283.34781"
id="path5029"
style="opacity:1;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:1.20000005;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
<circle
r="47.741993"
cy="251.56378"
cx="442.69934"
id="path5032"
style="opacity:1;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:1.17543197;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
<circle
r="47.741993"
cy="457.88742"
cx="443.96204"
id="path5032-8"
style="opacity:1;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:1.17543197;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
<path
id="path5049"
d="m 299.62779,400.26702 c -0.32431,9.11127 -1.83785,15.69497 -5.22014,24.56334 l 143.67047,46.46066 7.72657,-23.77735 z"
style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;direction:ltr;block-progression:tb;writing-mode:lr-tb;baseline-shift:baseline;text-anchor:start;white-space:normal;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:25;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
inkscape:connector-curvature="0"
sodipodi:nodetypes="ccccc" />
<path
id="path5049-7"
d="M 456.29297,234.03711 305.60156,283 c 5.07049,6.60068 9.73964,13.80327 13.89844,21.77148 l 144.51953,-46.95898 -7.72656,-23.77539 z"
style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;direction:ltr;block-progression:tb;writing-mode:lr-tb;baseline-shift:baseline;text-anchor:start;white-space:normal;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:25;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
inkscape:connector-curvature="0" />
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 7.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 39 KiB

View File

@@ -0,0 +1,134 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
inkscape:version="0.91 r13725"
version="1.1"
id="svg2"
viewBox="0 0 61.078413 935.82009"
height="100%"
sodipodi:docname="rocket.svg"
width="100%">
<defs
id="defs4" />
<sodipodi:namedview
inkscape:window-maximized="1"
inkscape:window-y="25"
inkscape:window-x="0"
inkscape:window-height="1031"
inkscape:window-width="1920"
showgrid="false"
inkscape:current-layer="rocket"
inkscape:document-units="px"
inkscape:cy="416.76401"
inkscape:cx="-335.1584"
inkscape:zoom="0.94244076"
inkscape:pageshadow="2"
inkscape:pageopacity="0.0"
borderopacity="1.0"
bordercolor="#666666"
pagecolor="#ffffff"
id="base"
fit-margin-top="0"
fit-margin-left="0"
fit-margin-right="0"
fit-margin-bottom="0"
units="pc" />
<metadata
id="metadata7">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title />
</cc:Work>
</rdf:RDF>
</metadata>
<g
inkscape:label="Layer 1"
inkscape:groupmode="layer"
id="layer1"
transform="translate(-339.60641,-51.670254)">
<g
id="rocket"
style="stroke:#eaeaea;stroke-opacity:1">
<g
id="chameleon">
<path
sodipodi:nodetypes="cscccscsssss"
inkscape:connector-curvature="0"
id="path4297"
transform="translate(209.97266,150.47537)"
d="m 132.87696,177.37695 c -6.64729,0.40536 2.06103,6.346 -3.91798,7.9336 -6.43317,1.70819 -14.70379,3.59927 -21.41015,13.0957 l 9.99414,32.14063 49.40625,-0.043 c 6.03623,-0.096 9.98156,-2.99549 10.42187,-7.19336 2.31075,-22.03026 -18.80648,-44.54605 -44.49413,-45.9336 z m 24.99805,18.57422 c 4.34762,-5.3e-4 7.87249,3.52348 7.87304,7.8711 5.2e-4,4.34838 -3.52467,7.87356 -7.87304,7.87304 -4.34763,-5.5e-4 -7.87163,-3.52542 -7.8711,-7.87304 5.4e-4,-4.34687 3.52423,-7.87056 7.8711,-7.8711 z"
style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1.26362705px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" />
<circle
r="2.6387513"
cy="354.47827"
cx="370.46851"
id="eye"
style="fill:#000000;fill-opacity:1;stroke:none;stroke-width:12;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
<path
sodipodi:nodetypes="cccc"
inkscape:connector-curvature="0"
id="path4347"
d="m 367.78516,403.4515 c -0.24947,-15.78457 -19.97022,-20.30463 -33.00781,-19.14063 l 9.17969,16.99219 z"
style="fill:#eaeaea;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" />
</g>
<path
style="fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:12.39999962;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
d="M 158.73242,5.8808594 C 96.139172,94.877559 71.650681,150.59316 56.707031,261.44922 41.763381,372.30528 68.890697,505.23326 84.992188,627.125 c 56.137882,30.96638 106.155892,28.27049 151.523432,0 13.19426,-123.86631 38.91923,-269.90723 28.28321,-369.71484 -0.4716,-4.42542 -0.9947,-8.78321 -1.57031,-13.07813 C 250.82224,151.76272 214.3681,88.384389 158.73242,5.8808594 Z M 156.61328,154.17188 a 48.487324,48.487324 0 0 1 48.48633,48.48828 48.487324,48.487324 0 0 1 -48.48633,48.48632 48.487324,48.487324 0 0 1 -48.48828,-48.48632 48.487324,48.487324 0 0 1 48.48828,-48.48828 z"
transform="translate(209.97266,150.47537)"
id="path3340"
inkscape:connector-curvature="0" />
<path
sodipodi:nodetypes="cccc"
inkscape:connector-curvature="0"
id="path3342"
d="m 279.81226,663.45348 -63.63961,59.59899 4.04061,86.87312 74.75129,-34.34518"
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:12.39999962;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
<path
sodipodi:nodetypes="cccc"
inkscape:connector-curvature="0"
id="path3342-3"
d="m 459.46882,661.23062 64.64976,63.6396 -4.04061,86.87312 -74.75129,-34.34518"
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:12.39999962;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
<path
sodipodi:nodetypes="cccc"
inkscape:connector-curvature="0"
id="path3359"
d="m 437.54131,786.74328 -5.54097,40.45432 c -45.93026,20.7349 -78.70924,18.71458 -122.77049,0.12255 l -7.85714,-46.42857"
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:12.40038872;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
<ellipse
style="opacity:0;fill:#40a49e;fill-opacity:0.2918782;stroke:none;stroke-width:2.06419039;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
id="path4355"
cx="367.00391"
cy="353.45151"
rx="43.327278"
ry="42.546028" />
<path
inkscape:connector-curvature="0"
id="path3361-5-4"
d="m 414.70999,352.67026 a 48.487324,48.487324 0 0 1 -48.48733,48.48732 48.487324,48.487324 0 0 1 -48.48732,-48.48732 48.487324,48.487324 0 0 1 48.48732,-48.48732 48.487324,48.487324 0 0 1 48.48733,48.48732 z"
style="fill:none;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:12.39999962;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
</g>
<g
transform="translate(116.02851,97.629438)"
style="font-style:normal;font-weight:normal;font-size:40px;line-height:125%;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
id="flowRoot4220" />
<path
style="fill:none;fill-rule:evenodd;stroke:#e87c1e;stroke-width:12.01297092;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
d="m 328.31986,855.39477 c -1.20973,21.03265 -13.49909,41.39053 -7.72783,63.59332 6.03559,23.21967 25.17895,34.08396 46.43953,62.49621 14.55002,-21.74909 40.18799,-43.09156 47.36371,-72.77546 5.62417,-23.26555 -6.87313,-37.16558 -6.43991,-56.63222"
id="flame"
inkscape:connector-curvature="0"
sodipodi:nodetypes="cscsc" />
</g>
</svg>

After

Width:  |  Height:  |  Size: 7.1 KiB

View File

@@ -0,0 +1,2 @@
<?xml version="1.0" encoding="utf-8"?>
<svg width="1792" height="1792" viewBox="0 0 1792 1792" xmlns="http://www.w3.org/2000/svg"><path d="M1600 960q0 54-37 91l-651 651q-39 37-91 37-51 0-90-37l-75-75q-38-38-38-91t38-91l293-293h-704q-52 0-84.5-37.5t-32.5-90.5v-128q0-53 32.5-90.5t84.5-37.5h704l-293-294q-38-36-38-90t38-90l75-75q38-38 90-38 53 0 91 38l651 651q37 35 37 90z" fill="#fff"/></svg>

After

Width:  |  Height:  |  Size: 391 B

View File

@@ -0,0 +1,212 @@
<?xml version="1.0" encoding="UTF-8"?>
<installation>
<steps type="array">
<step>
<title>Configuration Management options</title>
<description><![CDATA[<h2>The options below allow you to configure the type of elements that are to be managed inside iTop.</h2>]]></description>
<banner>/images/modules.png</banner>
<options type="array">
<choice>
<extension_code>itop-config-mgmt-core</extension_code>
<title>Configuration Management Core</title>
<description>All the base objects that are mandatory in the iTop CMDB: Organizations, Locations, Teams, Persons, etc.</description>
<modules type="array">
<module>itop-config-mgmt</module>
<module>itop-attachments</module>
<module>itop-profiles-itil</module>
<module>itop-welcome-itil</module>
<module>itop-tickets</module>
<module>itop-hub-connector</module>
</modules>
<mandatory>true</mandatory>
</choice>
<choice>
<extension_code>itop-config-mgmt-datacenter</extension_code>
<title>Data Center Devices</title>
<description>Manage Data Center devices such as Racks, Enclosures, PDUs, etc.</description>
<modules type="array">
<module>itop-datacenter-mgmt</module>
</modules>
<default>true</default>
</choice>
<choice>
<extension_code>itop-config-mgmt-end-user</extension_code>
<title>End-User Devices</title>
<description>Manage devices related to end-users: PCs, Phones, Tablets, etc.</description>
<modules type="array">
<module>itop-endusers-devices</module>
</modules>
<default>true</default>
</choice>
<choice>
<extension_code>itop-config-mgmt-storage</extension_code>
<title>Storage Devices</title>
<description>Manage storage devices such as NAS, SAN Switches, Tape Libraries and Tapes, etc.</description>
<modules type="array">
<module>itop-storage-mgmt</module>
</modules>
<default>true</default>
</choice>
<choice>
<extension_code>itop-config-mgmt-virtualization</extension_code>
<title>Virtualization</title>
<description>Manage Hypervisors, Virtual Machines and Farms.</description>
<modules type="array">
<module>itop-virtualization-mgmt</module>
</modules>
<default>true</default>
</choice>
</options>
</step>
<step>
<title>Service Management options</title>
<description><![CDATA[<h2>Select the choice that best describes the relationships between the services and the IT infrastructure in your IT environment.</h2>]]></description>
<banner>./wizard-icons/service.png</banner>
<alternatives type="array">
<choice>
<extension_code>itop-service-mgmt-enterprise</extension_code>
<title>Service Management for Enterprises</title>
<description>Select this option if the IT delivers services based on a shared infrastructure. For example if different organizations within your company subscribe to services (like Mail and Print services) delivered by a single shared backend.</description>
<modules type="array">
<module>itop-service-mgmt</module>
</modules>
<default>true</default>
</choice>
<choice>
<extension_code>itop-service-mgmt-service-provider</extension_code>
<title>Service Management for Service Providers</title>
<description>Select this option if the IT manages the infrastructure of independent customers. This is the most flexible model, since the services can be delivered with a mix of shared and customer specific infrastructure devices.</description>
<modules type="array">
<module>itop-service-mgmt-provider</module>
</modules>
</choice>
</alternatives>
</step>
<step>
<title>Tickets Management options</title>
<description><![CDATA[<h2>Select the type of tickets you want to use in order to respond to user requests and incidents.</h2>]]></description>
<banner>./itop-incident-mgmt-itil/images/incident-escalated.png</banner>
<alternatives type="array">
<choice>
<extension_code>itop-ticket-mgmt-simple-ticket</extension_code>
<title>Simple Ticket Management</title>
<description>Select this option to use one single type of tickets for all kind of requests.</description>
<modules type="array">
<module>itop-request-mgmt</module>
</modules>
<default>true</default>
<sub_options>
<options type="array">
<choice>
<extension_code>itop-ticket-mgmt-simple-ticket-enhanced-portal</extension_code>
<title>Enhanced Customer Portal</title>
<description>Replace the built-in customer portal with a more modern version, working better with hand-held devices and bringing new features</description>
<modules type="array">
<module>itop-portal</module>
<module>itop-portal-base</module>
</modules>
<default>true</default>
</choice>
</options>
</sub_options>
</choice>
<choice>
<extension_code>itop-ticket-mgmt-itil</extension_code>
<title>ITIL Compliant Tickets Management</title>
<description>Select this option to have different types of ticket for managing user requests and incidents. Each type of ticket has a specific life cycle and specific fields</description>
<sub_options>
<options type="array">
<choice>
<extension_code>itop-ticket-mgmt-itil-user-request</extension_code>
<title>User Request Management</title>
<description>Manage User Request tickets in iTop</description>
<modules type="array">
<module>itop-request-mgmt-itil</module>
</modules>
</choice>
<choice>
<extension_code>itop-ticket-mgmt-itil-incident</extension_code>
<title>Incident Management</title>
<description>Manage Incidents tickets in iTop</description>
<modules type="array">
<module>itop-incident-mgmt-itil</module>
</modules>
</choice>
<choice>
<extension_code>itop-ticket-mgmt-itil-enhanced-portal</extension_code>
<title>Enhanced Customer Portal</title>
<description>Replace the built-in customer portal with a more modern version, working better with hand-held devices and bringing new features</description>
<modules type="array">
<module>itop-portal</module>
<module>itop-portal-base</module>
</modules>
<default>true</default>
</choice>
</options>
</sub_options>
</choice>
<choice>
<extension_code>itop-ticket-mgmt-none</extension_code>
<title>No Tickets Management</title>
<description>Don't manage incidents or user requests in iTop</description>
<modules type="array">
</modules>
</choice>
</alternatives>
</step>
<step>
<title>Change Management options</title>
<description><![CDATA[<h2>Select the type of tickets you want to use in order to manage changes to the IT infrastructure.</h2>]]></description>
<banner>./itop-change-mgmt/images/change.png</banner>
<alternatives type="array">
<choice>
<extension_code>itop-change-mgmt-simple</extension_code>
<title>Simple Change Management</title>
<description>Select this option to use one type of ticket for all kind of changes.</description>
<modules type="array">
<module>itop-change-mgmt</module>
</modules>
<default>true</default>
</choice>
<choice>
<extension_code>itop-change-mgmt-itil</extension_code>
<title>ITIL Change Management</title>
<description>Select this option to use Normal/Routine/Emergency change tickets.</description>
<modules type="array">
<module>itop-change-mgmt-itil</module>
</modules>
</choice>
<choice>
<extension_code>itop-change-mgmt-none</extension_code>
<title>No Change Management</title>
<description>Don't manage changes in iTop</description>
<modules type="array">
</modules>
</choice>
</alternatives>
</step>
<step>
<title>Additional ITIL tickets</title>
<description><![CDATA[<h2>Pick from the list below the additional ITIL processes that are to be implemented in iTop.</h2>]]></description>
<banner>./itop-knownerror-mgmt/images/known-error.png</banner>
<options type="array">
<choice>
<extension_code>itop-kown-error-mgmt</extension_code>
<title>Known Errors Management</title>
<description>Select this option to track "Known Errors" and FAQs in iTop.</description>
<modules type="array">
<module>itop-knownerror-mgmt</module>
</modules>
</choice>
<choice>
<extension_code>itop-problem-mgmt</extension_code>
<title>Problem Management</title>
<description>Select this option track "Problems" in iTop.</description>
<modules type="array">
<module>itop-problem-mgmt</module>
</modules>
</choice>
</options>
</step>
</steps>
</installation>

View File

@@ -0,0 +1,187 @@
//jQuery UI style "widget" for running the installation
$(function()
{
// the widget definition, where "itop" is the namespace,
// "fieldsorter" the widget name
$.widget( "itop.hub_installation",
{
// default options
options:
{
self_url: '',
redirect_after_completion_url: '',
iframe_url: '',
mysql_bindir: '',
main_page_url: './UI.php',
labels: {
database_backup: 'Database backup...',
extensions_installation: 'Installation of the extensions...',
installation_successful: 'Installation successful!',
rollback: 'iTop configuration has NOT been modified.'
}
},
// the constructor
_create: function()
{
var me = this;
this.element
.addClass('itop-hub_installation');
$( document ).ajaxError( function(event, jqxhr, settings, thrownError) { me._on_ajax_error(event, jqxhr, settings, thrownError);} );
},
// events bound via _bind are removed automatically
// revert other modifications here
_destroy: function()
{
this.element
.removeClass('itop-hub_installation');
},
// _setOptions is called with a hash of all options that are changing
_setOptions: function()
{
this._superApply(arguments);
},
// _setOption is called for each individual option that is changing
_setOption: function(key, value)
{
if (this.options[key] != value)
{
// If any option changes, clear the cache
this._clearCache();
}
this._superApply(arguments);
},
check_before_backup: function()
{
var me = this;
$.post(this.options.self_url, {operation: 'check_before_backup', mysql_bindir: this.options.mysql_bindir}, function(data) { me._on_check_before_backup(data) }, 'json');
},
_on_check_before_backup: function(data)
{
if (data.code == 0)
{
$('#backup_status').html(data.message);
$('#backup_form').show();
}
else
{
$('#backup_status').html(data.message);
}
if ($('#hub_start_installation').hasClass('ui-button'))
{
$('#hub_start_installation').button('enable');
}
else
{
$('#hub_start_installation').prop('disabled', false);
}
},
backup: function()
{
var me = this;
$('#hub-installation-progress-text').html('<i class="fa fa-database"></i> '+this.options.labels.database_backup);
$.post(this.options.self_url, {operation: 'do_backup'}, function(data) { me._on_backup(data) }, 'json');
},
_on_backup: function(data)
{
if (data.code == 0)
{
this._reportSuccess(data.message);
// continue to the compilation
this.compile();
}
else
{
this._reportError(data.message);
}
},
compile: function()
{
$('#hub-installation-progress-text').html('<i class="fa fa-cogs"></i> '+this.options.labels.extensions_installation);
var me = this;
var aExtensionCodes = [];
var aExtensionDirs = [];
$('.choice :input:checked').each(function() { aExtensionCodes.push($(this).attr('data-extension-code')); aExtensionDirs.push($(this).attr('data-extension-dir')); });
$.post(this.options.self_url, {operation: 'compile', extension_codes: aExtensionCodes, extension_dirs: aExtensionDirs}, function(data) { me._on_compile(data) }, 'json');
},
_on_compile: function(data)
{
if (data.code == 0)
{
this._reportSuccess(data.message);
// continue to the move to prod
this.move_to_prod();
}
else
{
this._reportError(data.message);
}
},
move_to_prod: function()
{
$('#hub-installation-progress-text').html('<i class="fa fa-cogs"></i> '+this.options.labels.extensions_installation);
var me = this;
$.post(this.options.self_url, {operation: 'move_to_production'}, function(data) { me._on_move_to_prod(data) }, 'json');
},
_on_move_to_prod: function(data)
{
if (data.code == 0)
{
this._reportSuccess(data.message);
$('#hub-installation-progress-text').html('<i class="fa fa-trophy"></i> '+this.options.labels.installation_successful);
// Report the installation status to iTop Hub
$('#at_the_end').append('<iframe style="border:0; width:200px; height: 20px;" src="'+this.options.iframe_url+'">Support of IFRAMES required, sorry</iframe>');
if (this.options.redirect_after_completion_url != '')
{
var sUrl = this.options.redirect_after_completion_url;
window.setTimeout(function() { window.location.href = sUrl; }, 500);
}
}
else
{
this._reportError(data.message);
}
},
start_installation: function()
{
$('#installation-summary :input').prop('disabled', true); // Prevent changing the settings
$('#database-backup-fieldset').hide();
$('#hub-installation-feedback').show();
if ($('#hub_start_installation').hasClass('ui-button'))
{
$('#hub_start_installation').button('disable');
}
else
{
$('#hub_start_installation').prop('disabled', true);
}
if ($('#backup_checkbox').prop('checked'))
{
this.backup();
}
else
{
this.compile();
}
},
_reportError: function(sMessage)
{
$('#hub-installation-progress-text').html('<span style="color:red; font-size:12pt; line-height:18pt;"><i class="fa fa-exclamation-triangle"></i> '+this.options.labels.rollback+'</span><br/><span style="color:#666; display:block; padding:10px;max-height:10em; overflow: auto;padding-top:0; margin-top:10px; text-align:left;">'+sMessage+'</span>');
$('#hub_start_installation').val('Go Back to iTop');
$('#hub_start_installation').prop('disabled', false);
$('#hub-installation-progress').hide();
var me = this;
$('#hub_start_installation').off('click').on('click', function() { window.location.href = me.options.main_page_url; })
},
_reportSuccess: function(sMessage)
{
},
_on_ajax_error: function(event, jqxhr, settings, thrownError)
{
this._reportError(jqxhr.responseText);
}
});
});

View File

@@ -0,0 +1,334 @@
<?php
function DisplayStatus(WebPage $oPage)
{
$oPage->set_title(Dict::S('iTopHub:Landing:Status'));
$oPage->add('<table class="module-selection-banner"><tr>');
$sBannerUrl = utils::GetAbsoluteUrlModulesRoot().'/itop-hub-connector/images/landing-extension.png';
$oPage->add('<td><img style="max-height:72px; margin-right: 10px;" src="'.$sBannerUrl.'"/><td>');
$oPage->add('<td><h2>'.Dict::S('iTopHub:LandingWelcome').'</h2><td>');
$oPage->add('</tr></table>');
$oPage->add('<div class="module-selection-body">');
// Now scan the extensions and display a report of the extensions brought by the hub
$oExtensionsMap = new iTopExtensionsMap();
$sPath = APPROOT.'data/downloaded-extensions/';
if (is_dir($sPath))
{
$oExtensionsMap->ReadDir($sPath, iTopExtension::SOURCE_REMOTE); // Also read the extra downloaded-modules directory
}
$oExtensionsMap->LoadChoicesFromDatabase(MetaModel::GetConfig());
foreach($oExtensionsMap->GetAllExtensions() as $oExtension)
{
if ($oExtension->sSource == iTopExtension::SOURCE_REMOTE)
{
$aCSSClasses = array('landing-extension');
if ($oExtension->sInstalledVersion === '')
{
$aCSSClasses[] = 'landing-installation';
$sInstallation = Dict::Format('iTopHub:InstallationStatus:Version_NotInstalled', $oExtension->sVersion);
}
else
{
$aCSSClasses[] = 'landing-no-change';
$sBadge = '<span style="display:inline-block;font-size:8pt;padding:3px;border-radius:4px;color:#fff;background-color:#1c94c4;margin-left:0.5em;margin-right:0.5em">'.Dict::S('iTopHub:InstallationStatus:Installed').'</span>';
$sInstallation = Dict::Format('iTopHub:InstallationStatus:Installed_Version', $sBadge, $oExtension->sInstalledVersion);
}
$oPage->add('<div class="choice">');
$sCode = $oExtension->sCode;
$sDir = basename($oExtension->sSourceDir);
$oPage->add('<input type="checkbox" data-extension-code="'.$sCode.'" data-extension-dir="'.$sDir.'" checked disabled>&nbsp;');
$oPage->add('<label><b>'.htmlentities($oExtension->sLabel, ENT_QUOTES, 'UTF-8').'</b> '.$sInstallation.'</label>');
$oPage->add('<div class="description">');
$oPage->add('<p>');
if ($oExtension->sDescription != '')
{
$oPage->add(htmlentities($oExtension->sDescription, ENT_QUOTES, 'UTF-8').'</br>');
}
$oPage->add('</p>');
$oPage->add('</div>');
$oPage->add('</div>');
}
}
$oPage->add('</div>');
$oPage->add('<div style="text-align:center"><button onclick="window.location.href=\'./UI.php\';">'.Dict::S('iTopHub:GoBackToITopBtn').'</button></div>');
}
function DoLanding(WebPage $oPage)
{
$oPage->add_linked_stylesheet(utils::GetAbsoluteUrlModulesRoot().'itop-hub-connector/css/hub.css');
$oPage->add('<table class="module-selection-banner"><tr>');
$sBannerUrl = utils::GetAbsoluteUrlModulesRoot().'/itop-hub-connector/images/landing-extension.png';
$oPage->add('<td><img style="max-height:72px; margin-right: 10px;" src="'.$sBannerUrl.'"/><td>');
$oPage->add('<td><h2>'.Dict::S('iTopHub:InstallationWelcome').'</h2><td>');
$oPage->add('</tr></table>');
$oPage->set_title(Dict::S('iTopHub:Landing:Status'));
$oPage->add('<div class="module-selection-body" style="text-align: center; line-height: 14em;"><h2>'.Dict::S('iTopHub:Uncompressing').'</h2></div>');
$sProduct = utils::ReadParam('applicationName', '', false, 'raw_data');
$sVersion = utils::ReadParam('applicationVersion', '', false, 'raw_data');
$sInstanceUUID = utils::ReadParam('uuidFile', '', false, 'raw_data');
$sDatabaseUUID = utils::ReadParam('uuidBdd', '', false, 'raw_data');
$aExtensions = utils::ReadParam('extensions', array(), false, 'raw_data');
// Basic consistency validation
if ($sProduct != ITOP_APPLICATION)
{
throw new Exception("Inconsistent product '$sProduct', expecting '".ITOP_APPLICATION."'");
}
if ($sVersion != ITOP_VERSION)
{
throw new Exception("Inconsistent version '$sVersion', expecting ".ITOP_VERSION."'");
}
$sFileUUID = (string) trim(@file_get_contents(APPROOT."data/instance.txt"), "{} \n");
if ($sInstanceUUID != $sFileUUID)
{
throw new Exception("Inconsistent file UUID '$sInstanceUUID', expecting ".$sFileUUID."'");
}
$sDBUUID = (string) trim(DBProperty::GetProperty('database_uuid', ''), '{}');
if ($sDatabaseUUID != $sDBUUID)
{
throw new Exception("Inconsistent database UUID '$sDatabaseUUID', expecting ".$sDBUUID."'");
}
// Uncompression of extensions in data/downloaded-extensions
// only newly downloaded extensions reside in this folder
$i = 0;
$sPath = APPROOT.'data/downloaded-extensions/';
if (!is_dir($sPath))
{
if (!mkdir($sPath)) throw new Exception("ERROR: Unable to create the directory '$sPath'. Cannot download any extension. Check the access rights on '".dirname($sPath)."'");
}
else
{
// Make sure that the directory is empty
SetupUtils::tidydir($sPath);
}
foreach($aExtensions as $sBase64Archive)
{
$sArchive = base64_decode($sBase64Archive);
$sZipArchiveFile = $sPath."/extension-{$i}.zip";
file_put_contents($sZipArchiveFile, $sArchive);
// Expand the content of extension-x.zip into APPROOT.'data/downloaded-extensions/'
// where the installation will load the extension automatically
$oZip = new ZipArchive();
if (!$oZip->open($sZipArchiveFile))
{
throw new Exception('Unable to open "'.$sZipArchiveFile.'" for extraction. Make sure that the directory "'.$sPath.'" is writable for the web server.');
}
for($idx = 0; $idx < $oZip->numFiles; $idx++)
{
$sCompressedFile = $oZip->getNameIndex($idx);
$oZip->extractTo($sPath, $sCompressedFile);
}
@$oZip->close();
@unlink($sZipArchiveFile); // Get rid of the temporary file
$i++;
}
// Now scan the extensions and display a report of the extensions brought by the hub
$sNextPage = utils::GetAbsoluteUrlModulePage('itop-hub-connector', 'land.php', array('operation' => 'install'));
$oPage->add_ready_script("window.location.href='$sNextPage'");
}
function DoInstall(WebPage $oPage)
{
$oPage->add_linked_stylesheet(utils::GetAbsoluteUrlModulesRoot().'itop-hub-connector/css/hub.css');
$oPage->add('<table class="module-selection-banner"><tr>');
$sBannerUrl = utils::GetAbsoluteUrlModulesRoot().'/itop-hub-connector/images/landing-extension.png';
$oPage->add('<td><img style="max-height:72px; margin-right: 10px;" src="'.$sBannerUrl.'"/><td>');
$oPage->add('<td><h2>'.Dict::S('iTopHub:InstallationWelcome').'</h2><td>');
$oPage->add('</tr></table>');
$oPage->set_title(Dict::S('iTopHub:Landing:Install'));
$oPage->add('<div id="installation-summary" class="module-selection-body" style="position: relative">');
// Now scan the extensions and display a report of the extensions brought by the hub
$oExtensionsMap = new iTopExtensionsMap();
$oExtensionsMap->NormalizeOldExtensions(iTopExtension::SOURCE_REMOTE);
$sPath = APPROOT.'data/downloaded-extensions/';
$oExtensionsMap->ReadDir($sPath, iTopExtension::SOURCE_REMOTE); // Also read the extra downloaded-extensions directory
$oExtensionsMap->LoadChoicesFromDatabase(MetaModel::GetConfig());
foreach($oExtensionsMap->GetAllExtensions() as $oExtension)
{
if ($oExtension->sSource == iTopExtension::SOURCE_REMOTE)
{
if (count($oExtension->aMissingDependencies) > 0)
{
$oPage->add('<div class="choice">');
$oPage->add('<input type="checkbox" disabled>&nbsp;');
$sTitle = Dict::Format('iTopHub:InstallationEffect:MissingDependencies_Details', implode(', ', $oExtension->aMissingDependencies));
$oPage->add('<label><b>'.htmlentities($oExtension->sLabel, ENT_QUOTES, 'UTF-8').'</b> <span style="color:red" title="'.$sTitle.'">'.Dict::S('iTopHub:InstallationEffect:MissingDependencies').'<span></label>');
$oPage->add('<div class="description">');
$oPage->add('<p>');
if ($oExtension->sDescription != '')
{
$oPage->add(htmlentities($oExtension->sDescription, ENT_QUOTES, 'UTF-8').'</br>');
}
$oPage->add('</p>');
$oPage->add('</div>');
$oPage->add('</div>');
}
else
{
$aCSSClasses = array('landing-extension');
if ($oExtension->sInstalledVersion === '')
{
$aCSSClasses[] = 'landing-installation';
$sInstallation = Dict::Format('iTopHub:InstallationEffect:Install', $oExtension->sVersion);
}
else if ($oExtension->sInstalledVersion == $oExtension->sVersion)
{
$aCSSClasses[] = 'landing-no-change';
$sInstallation = Dict::Format('iTopHub:InstallationEffect:NoChange', $oExtension->sVersion);
}
else if (version_compare($oExtension->sInstalledVersion, $oExtension->sVersion, '<'))
{
$aCSSClasses[] = 'landing-upgrade';
$sInstallation = Dict::Format('iTopHub:InstallationEffect:Upgrade', $oExtension->sInstalledVersion, $oExtension->sVersion);
}
else
{
$aCSSClasses[] = 'landing-downgrade';
$sInstallation = Dict::Format('iTopHub:InstallationEffect:Downgrade', $oExtension->sInstalledVersion, $oExtension->sVersion);
}
$oPage->add('<div class="choice">');
$sCode = $oExtension->sCode;
$sDir = basename($oExtension->sSourceDir);
$oPage->add('<input type="checkbox" checked disabled data-extension-code="'.$sCode.'" data-extension-dir="'.$sDir.'">&nbsp;');
$oPage->add('<label><b>'.htmlentities($oExtension->sLabel, ENT_QUOTES, 'UTF-8').'</b> '.$sInstallation.'</label>');
$oPage->add('<div class="description">');
$oPage->add('<p>');
if ($oExtension->sDescription != '')
{
$oPage->add(htmlentities($oExtension->sDescription, ENT_QUOTES, 'UTF-8').'</br>');
}
$oPage->add('</p>');
$oPage->add('</div>');
$oPage->add('</div>');
}
}
}
$oPage->add('<div id="hub-installation-feedback">');
$oPage->add('<div id="hub-installation-progress-text">'.Dict::S('iTopHub:DatabaseBackupProgress').'</div>');
$oPage->add('<div id="hub-installation-progress"></div>');
$oPage->add('</div>');
$oPage->add('</div>'); // module-selection-body
$oPage->add_linked_stylesheet('../css/font-awesome/css/font-awesome.min.css');
$oPage->add('<div id="hub_installation_widget"></div>');
$oPage->add('<fieldset id="database-backup-fieldset"><legend>'.Dict::S('iTopHub:DBBackupLabel').'</legend>');
$oPage->add('<div id="backup_form"><input id="backup_checkbox" type="checkbox" checked><label for="backup_checkbox"> '.Dict::S('iTopHub:DBBackupSentence').'</label></div>');
$oPage->add('<div id="backup_status"></div>');
$oPage->add('</fieldset>');
$oPage->add('<p style="text-align: center"><input type="button" id="hub_start_installation" type="button" disabled value="'.Dict::S('iTopHub:DeployBtn').'"/></p>');
$sIframeUrl = utils::GetAbsoluteUrlModulePage('itop-hub-connector', 'launch.php', array('target' => 'inform_after_setup'));
$sStatusPageUrl = utils::GetAbsoluteUrlModulePage('itop-hub-connector', 'land.php', array('operation' => 'done'));
$aWidgetParams = array(
'self_url' => utils::GetAbsoluteUrlModulePage('itop-hub-connector', 'ajax.php'),
'iframe_url' => $sIframeUrl,
'redirect_after_completion_url' => $sStatusPageUrl,
'mysql_bindir' => MetaModel::GetConfig()->GetModuleSetting('itop-backup', 'mysql_bindir', ''),
'labels' => array(
'database_backup' => Dict::S('iTopHub:InstallationProgress:DatabaseBackup'),
'extensions_installation' => Dict::S('iTopHub:InstallationProgress:ExtensionsInstallation'),
'installation_successful' => Dict::S('iTopHub:InstallationProgress:InstallationSuccessful'),
'rollback' => Dict::S('iTopHub:ConfigurationSafelyReverted'),
),
);
$sWidgetParams = json_encode($aWidgetParams);
$oPage->add_ready_script("$('#hub_installation_widget').hub_installation($sWidgetParams);");
$oPage->add_ready_script("$('#hub_start_installation').click(function() { $('#hub_installation_widget').hub_installation('start_installation');} );");
$oPage->add_ready_script("$('#hub_installation_widget').hub_installation('check_before_backup');");
$oPage->add('<div id="debug"></div>');
}
try
{
require_once(APPROOT.'/application/application.inc.php');
require_once(APPROOT.'/setup/setuppage.class.inc.php');
require_once(APPROOT.'/setup/extensionsmap.class.inc.php');
require_once(APPROOT.'/application/startup.inc.php');
require_once(APPROOT.'/application/loginwebpage.class.inc.php');
LoginWebPage::DoLoginEx(null, true /* $bMustBeAdmin */); // Check user rights and prompt if needed
$oPage = new SetupPage(''); // Title will be set later, depending on $sOperation
$oPage->add_linked_script(utils::GetAbsoluteUrlModulesRoot().'itop-hub-connector/js/hub.js');
$oPage->add_linked_stylesheet('../css/font-combodo/font-combodo.css');
$oPage->add_style("div.choice { margin: 0.5em;}");
$oPage->add_style("div.choice a { text-decoration:none; font-weight: bold; color: #1C94C4 }");
$oPage->add_style("div.description { margin-left: 2em; }");
$oPage->add_style("div.description p { margin-top: 0.25em; margin-bottom: 0.5em; }");
$oPage->add_style(".choice-disabled { color: #999; }");
$sOperation = utils::ReadParam('operation', 'land');
switch($sOperation)
{
case 'done':
DisplayStatus($oPage);
break;
case 'install':
DoInstall($oPage);
break;
case 'land':
default:
DoLanding($oPage);
}
$oPage->output();
}
catch(Exception $e)
{
require_once(APPROOT.'/setup/setuppage.class.inc.php');
$oP = new SetupPage(Dict::S('UI:PageTitle:FatalError'));
$oP->add("<h1>".Dict::S('UI:FatalErrorMessage')."</h1>\n");
$oP->error(Dict::Format('UI:Error_Details', $e->getMessage()));
$oP->output();
if (MetaModel::IsLogEnabledIssue())
{
if (MetaModel::IsValidClass('EventIssue'))
{
$oLog = new EventIssue();
$oLog->Set('message', $e->getMessage());
$oLog->Set('userinfo', '');
$oLog->Set('issue', 'PHP Exception');
$oLog->Set('impact', 'Page could not be displayed');
$oLog->Set('callstack', $e->getTrace());
$oLog->Set('data', array());
$oLog->DBInsertNoReload();
}
IssueLog::Error($e->getMessage());
}
}

View File

@@ -0,0 +1,435 @@
<?php
// Copyright (C) 2017 Combodo SARL
//
// 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/>
/**
* iTop Hub Launch Page
* Collect the information to be posted to iTopHub
*
* @copyright Copyright (c) 2017 Combodo SARL
* @license http://opensource.org/licenses/AGPL-3.0
*/
/**
* Collect the configuration information to be posted to the hub
*
* @return string[][]
*/
/*
*
* json schema available on itop hub, under this url : /bundles/combodoremoteitop/json_schema/itop-configuration.schema.json
*
* syntactically valid fictional file sample, :
*
*
* {
* "itop_hub_target_route": "view_dashboard|browse_extensions|deploy_extensions|read_documentation"
* ,
* "itop_stack":{
* "uuidBdd" : "11a90082-b8a6-11e6-90f5-56524dec1a20",
* "uuidFile" : "11a90082-b8a6-11e6-90f5-56352dec71a2",
* "instance_friendly_name" : "example friendly name",
* "instance_host" : "http://example.com",
* "application_name" : "iTop",
* "application_version" : "2.4.0",
* "itop_user_id" : "42",
* "itop_user_lang" : "fr",
* "itop_modules" : {
* "foo-bar": "1.0.1",
* "barBaz": "1.3-dev"
* },
* "itop_extensions" : {
* "itop-extra-extension": {
* "label": "Super Nice Addon for iTop",
* "value": "1.2.0"
* },
* "itop-hyper-extension": {
* "label": "Hyper Fabulous Extension",
* "value": "2.5.1"
* },
* },
* "itop_installation_options" : {
* "itop-service-mgmt": {
* "label": "Service Management for Enterprises",
* "value": "2.4.0"
* },
* "itop-simple-tickets": {
* "label": "Simple Ticket Managment",
* "value": "2.4.0"
* },
* }
* },
*
* "server_stack":{
* "os_name": "Linux",
* "web_server_name": "apache",
* "web_server_version": "2.4.12",
* "database_name": "MySQL",
* "database_version": "5.7-ubuntu",
* "database_settings":{
* "max_allowed_packet": "314116"
* },
* "php_version": "7.1",
* "php_settings":{
* "timezone": "Europe/Paris",
* "memory_limit": "128M"
* },
* "php_extensions":{
* "php-mysql": "1.2",
* "php-mcrypt": "3.1.6"
* }
* }
* }
*
*
*/
/**
* Return a cleaned (i.e.
* properly truncated) versin number from
* a very long version number like "7.0.18-0unbuntu0-16.04.1"
*
* @param string $sString
* @return string
*/
function CleanVersionNumber($sString)
{
$aMatches = array();
if (preg_match("|^([0-9\\.]+)-|", $sString, $aMatches))
{
return $aMatches[1];
}
return $sString;
}
function collect_configuration()
{
$aConfiguration = array(
'php' => array(),
'mysql' => array(),
'apache' => array()
);
// Database information
$class = new ReflectionClass('CMDBSource');
$m_oMysqli_property = $class->getProperty('m_oMysqli');
$m_oMysqli_property->setAccessible(true);
$m_oMysqli = $m_oMysqli_property->getValue();
$aConfiguration['database_settings']['server'] = (string) $m_oMysqli->server_version;
$aConfiguration['database_settings']['client'] = (string) $m_oMysqli->client_version;
/** @var mysqli_result $resultSet */
$result = CMDBSource::Query('SHOW VARIABLES LIKE "%max_allowed_packet%"');
if ($result)
{
$row = $result->fetch_object();
$aConfiguration['database_settings']['max_allowed_packet'] = (string) $row->Value;
}
/** @var mysqli_result $resultSet */
$result = CMDBSource::Query('SHOW VARIABLES LIKE "%version_comment%"');
if ($result)
{
$row = $result->fetch_object();
if (preg_match('/mariadb/i', $row->Value))
{
$aConfiguration['database_name'] = 'MariaDB';
}
}
// Web server information
if (function_exists('apache_get_version'))
{
$aConfiguration['web_server_name'] = 'apache';
$aConfiguration['web_server_version'] = apache_get_version();
}
else
{
$aConfiguration['web_server_name'] = substr($_SERVER["SERVER_SOFTWARE"], 0, strpos($_SERVER["SERVER_SOFTWARE"], '/'));
$aConfiguration['web_server_version'] = substr($_SERVER["SERVER_SOFTWARE"], strpos($_SERVER["SERVER_SOFTWARE"], '/'), strpos($_SERVER["SERVER_SOFTWARE"], 'PHP'));
}
// PHP extensions
if (!MetaModel::GetConfig()->GetModuleSetting('itop-hub-connector', 'php_extensions_enable', true))
{
$aConfiguration['php_extensions'] = array();
}
else
{
foreach (get_loaded_extensions() as $extension)
{
$aConfiguration['php_extensions'][$extension] = $extension;
}
}
// Collect some PHP settings having a known impact on iTop
$aIniGet = MetaModel::GetConfig()->GetModuleSetting('itop-hub-connector', 'php_settings_array', array()); // by default, on the time of the writting, it values are : array('post_max_size', 'upload_max_filesize', 'apc.enabled', 'timezone', 'memory_limit', 'max_execution_time');
$aConfiguration['php_settings'] = array();
foreach ($aIniGet as $iniGet)
{
$aConfiguration['php_settings'][$iniGet] = (string) ini_get($iniGet);
}
// iTop modules
$oConfig = MetaModel::GetConfig();
$sLatestInstallationDate = CMDBSource::QueryToScalar("SELECT max(installed) FROM ".$oConfig->GetDBSubname()."priv_module_install");
// Get the latest installed modules, without the "root" ones (iTop version and datamodel version)
$aInstalledModules = CMDBSource::QueryToArray("SELECT * FROM ".$oConfig->GetDBSubname()."priv_module_install WHERE installed = '".$sLatestInstallationDate."' AND parent_id != 0");
foreach ($aInstalledModules as $aDBInfo)
{
$aConfiguration['itop_modules'][$aDBInfo['name']] = $aDBInfo['version'];
}
// iTop Installation Options, i.e. "Extensions"
$oExtensionMap = new iTopExtensionsMap();
$oExtensionMap->LoadChoicesFromDatabase($oConfig);
$aConfiguration['itop_extensions'] = array();
foreach ($oExtensionMap->GetChoices() as $oExtension)
{
switch ($oExtension->sSource)
{
case iTopExtension::SOURCE_MANUAL:
case iTopExtension::SOURCE_REMOTE:
$aConfiguration['itop_extensions'][$oExtension->sCode] = array(
'label' => $oExtension->sLabel,
'value' => $oExtension->sInstalledVersion
);
break;
default:
$aConfiguration['itop_installation_options'][$oExtension->sCode] = array(
'label' => $oExtension->sLabel,
'value' => true
);
}
}
return $aConfiguration;
}
function MakeDataToPost($sTargetRoute)
{
$aConfiguration = collect_configuration();
$aDataToPost = array(
'itop_hub_target_route' => $sTargetRoute,
'itop_stack' => array(
"uuidBdd" => (string) trim(DBProperty::GetProperty('database_uuid', ''), '{}'), // TODO check if empty and... regenerate a new UUID ??
"uuidFile" => (string) trim(@file_get_contents(APPROOT."data/instance.txt"), "{} \n"), // TODO check if empty and... regenerate a new UUID ??
'instance_friendly_name' => (string) $_SERVER['SERVER_NAME'],
'instance_host' => (string) utils::GetAbsoluteUrlAppRoot(),
'application_name' => (string) ITOP_APPLICATION,
'application_version' => (string) ITOP_VERSION,
'application_version_full' => (string) Dict::Format('UI:iTopVersion:Long', ITOP_APPLICATION, ITOP_VERSION, ITOP_REVISION, ITOP_BUILD_DATE),
'itop_user_id' => (string) (UserRights::GetUserId()===null) ? "1" : UserRights::GetUserId(),
'itop_user_lang' => (string) UserRights::GetUserLanguage(),
'itop_modules' => (object) $aConfiguration['itop_modules'],
'itop_extensions' => (object) $aConfiguration['itop_extensions'],
'itop_installation_options' => (object) $aConfiguration['itop_installation_options']
),
'server_stack' => array(
'os_name' => (string) PHP_OS,
'web_server_name' => (string) $aConfiguration['web_server_name'],
'web_server_version' => (string) $aConfiguration['web_server_version'],
'database_name' => (string) isset($aConfiguration['database_name']) ? $aConfiguration['database_name'] : 'MySQL', // if we do not detect MariaDB, we assume this is mysql
'database_version' => (string) CMDBSource::GetDBVersion(),
'database_settings' => (object) $aConfiguration['database_settings'],
'php_version' => (string) CleanVersionNumber(phpversion()),
'php_settings' => (object) $aConfiguration['php_settings'],
'php_extensions' => (object) $aConfiguration['php_extensions']
)
);
return $aDataToPost;
}
try
{
require_once (APPROOT.'/application/application.inc.php');
require_once (APPROOT.'/application/itopwebpage.class.inc.php');
require_once (APPROOT.'/setup/extensionsmap.class.inc.php');
require_once ('hubconnectorpage.class.inc.php');
require_once (APPROOT.'/application/startup.inc.php');
$sTargetRoute = utils::ReadParam('target', ''); // ||browse_extensions|deploy_extensions|
if ($sTargetRoute != 'inform_after_setup')
{
require_once (APPROOT.'/application/loginwebpage.class.inc.php');
LoginWebPage::DoLoginEx(null, true /* $bMustBeAdmin */); // Check user rights and prompt if needed
}
$sHubUrlStateless = MetaModel::GetModuleSetting('itop-hub-connector', 'url').MetaModel::GetModuleSetting('itop-hub-connector', 'route_landing_stateless');
$sHubUrl = MetaModel::GetModuleSetting('itop-hub-connector', 'url').MetaModel::GetModuleSetting('itop-hub-connector', 'route_landing');
// Display... or not... the page
switch ($sTargetRoute)
{
case 'inform_after_setup':
// Hidden IFRAME at the end of the setup
require_once (APPROOT.'/application/ajaxwebpage.class.inc.php');
$oPage = new NiceWebPage('');
$aDataToPost = MakeDataToPost($sTargetRoute);
$oPage->add('<form id="hub_launch_form" action="'.$sHubUrlStateless.'" method="post">');
$oPage->add('<input type="hidden" name="json" value="'.htmlentities(json_encode($aDataToPost), ENT_QUOTES, 'UTF-8').'">');
$oPage->add_ready_script('$("#hub_launch_form").submit();');
break;
default:
// All other cases, special "Hub like" web page
if ($sTargetRoute == 'view_dashboard')
{
$sTitle = Dict::S('Menu:iTopHub:Register');
$sLabel = Dict::S('Menu:iTopHub:Register+');
$sText = Dict::S('Menu:iTopHub:Register:Description');
}
else
{
$sTitle = Dict::S('Menu:iTopHub:BrowseExtensions');
$sLabel = Dict::S('Menu:iTopHub:BrowseExtensions+');
$sText = Dict::S('Menu:iTopHub:BrowseExtensions:Description');
}
$sLogoUrl = utils::GetAbsoluteUrlModulesRoot().'/itop-hub-connector/images/itophub-logo.svg';
$sArrowUrl = utils::GetAbsoluteUrlModulesRoot().'/itop-hub-connector/images/white-arrow-right.svg';
$sCloseUrl = utils::GetAbsoluteUrlModulesRoot().'/itop-hub-connector/images/black-close.svg';
$oPage = new HubConnectorPage(Dict::S('iTopHub:Connect'));
$oPage->add_linked_script(utils::GetAbsoluteUrlModulesRoot().'itop-hub-connector/js/hub.js');
$oPage->add_linked_stylesheet('../css/font-combodo/font-combodo.css');
$oPage->add_linked_stylesheet(utils::GetAbsoluteUrlModulesRoot().'itop-hub-connector/css/hub.css');
$aDataToPost = MakeDataToPost($sTargetRoute);
$oPage->add('<div id="hub_top_banner"></div>');
$oPage->add('<div id="hub_launch_content">');
$oPage->add('<div id="hub_launch_container">');
$oPage->add('<div id="hub_launch_image">');
$oPage->add(file_get_contents(__DIR__.'/images/rocket.svg'));
$oPage->add('</div>');
$oPage->add('<h1><img src="'.$sLogoUrl.'"><span>'.$sTitle.'</span></h1>');
$oPage->add($sText);
$oPage->add('<p><button type="button" id="CancelBtn" title="Go back to iTop"><img src="'.$sCloseUrl.'"><span>'.Dict::S('iTopHub:CloseBtn').'</span></button><span class="horiz-spacer"> </span><button class="positive" type="button" id="GoToHubBtn" title="'.Dict::S('iTopHub:GoBtn:Tooltip').'"><span>'.Dict::S('iTopHub:GoBtn').'</span><img src="'.$sArrowUrl.'"></button></p>');
$sFormTarget = appUserPreferences::GetPref('itophub_open_in_new_window', 1) ? 'target="_blank"' : '';
$oPage->add('<form '.$sFormTarget.' id="hub_launch_form" action="'.$sHubUrl.'" method="post">');
$oPage->add('<input type="hidden" name="json" value="'.htmlentities(json_encode($aDataToPost), ENT_QUOTES, 'UTF-8').'">');
// $sNewWindowChecked = appUserPreferences::GetPref('itophub_open_in_new_window', 1) == 1 ? 'checked' : '';
// $oPage->add('<p><input type="checkbox" class="userpref" id="itophub_open_in_new_window" '.$sNewWindowChecked.'><label for="itophub_open_in_new_window">'.Dict::S('iTopHub:OpenInNewWindow').'</label><br/>');
// Beware the combination auto-submit and open in new window (cf above) is blocked by (some) browsers (namely Chrome)
$sAutoSubmitChecked = appUserPreferences::GetPref('itophub_auto_submit', 0)==1 ? 'checked' : '';
$oPage->add('<input type="checkbox" class="userpref" id="itophub_auto_submit" '.$sAutoSubmitChecked.'><label for="itophub_auto_submit">'.Dict::S('iTopHub:AutoSubmit').'</label></p>');
$oPage->add('</form>');
$oPage->add('<div style="clear:both"></div>');
$oPage->add('</div>');
$oPage->add('</div>');
$oPage->add_ready_script('$(".userpref").on("click", function() { var value = $(this).prop("checked") ? 1 : 0; var code = $(this).attr("id"); SetUserPreference(code, value, true); });');
$oPage->add_ready_script(
<<<EOF
$("#GoToHubBtn").on("click", function() {
$(this).prop('disabled', true);
$("#hub_launch_image").addClass("animate");
window.setTimeout(function () {
var bNewWindow = $('#itophub_open_in_new_window').prop("checked");
if(bNewWindow) { $("#hub_launch_form").attr("target", "_blank"); } else { $("#hub_launch_form").removeAttr("target"); }
$('#hub_launch_form').submit();
window.setTimeout(function () {
$("#GoToHubBtn").prop('disabled', false);
$("#hub_launch_image").removeClass("animate");
}, 5000);
}, 1000);
});
$("#CancelBtn").on("click", function() {
window.history.back();
});
EOF
);
if (appUserPreferences::GetPref('itophub_auto_submit', 0) == 1)
{
$oPage->add_ready_script('$("#GoToHubBtn").trigger("click");');
}
if (utils::ReadParam('show-json', false))
{
$oPage->add('<h1>DEBUG : json</h1>');
$oPage->add('<pre class="wizContainer">'.json_encode($aDataToPost, JSON_PRETTY_PRINT).'</pre>');
}
}
$oPage->output();
}
catch (CoreException $e)
{
require_once (APPROOT.'/setup/setuppage.class.inc.php');
$oP = new SetupPage(Dict::S('UI:PageTitle:FatalError'));
$oP->add("<h1>".Dict::S('UI:FatalErrorMessage')."</h1>\n");
$oP->error(Dict::Format('UI:Error_Details', $e->getHtmlDesc()));
$oP->output();
if (MetaModel::IsLogEnabledIssue())
{
if (MetaModel::IsValidClass('EventIssue'))
{
$oLog = new EventIssue();
$oLog->Set('message', $e->getMessage());
$oLog->Set('userinfo', '');
$oLog->Set('issue', $e->GetIssue());
$oLog->Set('impact', 'Page could not be displayed');
$oLog->Set('callstack', $e->getTrace());
$oLog->Set('data', $e->getContextData());
$oLog->DBInsertNoReload();
}
IssueLog::Error($e->getMessage());
}
// For debugging only
// throw $e;
}
catch (Exception $e)
{
require_once (APPROOT.'/setup/setuppage.class.inc.php');
$oP = new SetupPage(Dict::S('UI:PageTitle:FatalError'));
$oP->add("<h1>".Dict::S('UI:FatalErrorMessage')."</h1>\n");
$oP->error(Dict::Format('UI:Error_Details', $e->getMessage()));
$oP->output();
if (MetaModel::IsLogEnabledIssue())
{
if (MetaModel::IsValidClass('EventIssue'))
{
$oLog = new EventIssue();
$oLog->Set('message', $e->getMessage());
$oLog->Set('userinfo', '');
$oLog->Set('issue', 'PHP Exception');
$oLog->Set('impact', 'Page could not be displayed');
$oLog->Set('callstack', $e->getTrace());
$oLog->Set('data', array());
$oLog->DBInsertNoReload();
}
IssueLog::Error($e->getMessage());
}
}

View File

@@ -0,0 +1,19 @@
<?php
class ItopHubMenusHandler extends ModuleHandlerAPI
{
public static function OnMenuCreation()
{
// Add the admin menus
if (UserRights::IsAdministrator())
{
$sRootUrl = utils::GetAbsoluteUrlAppRoot().'pages/exec.php?exec_module=itop-hub-connector&exec_page=launch.php';
$sMyExtensionsUrl = utils::GetAbsoluteUrlAppRoot().'pages/exec.php?exec_module=itop-hub-connector&exec_page=myextensions.php';
$oHubMenu = new MenuGroup('iTopHub', 999 /* fRank */);
$fRank = 1;
new WebPageMenuNode('iTopHub:Register', $sRootUrl.'&target=view_dashboard', $oHubMenu->GetIndex(), $fRank++);
new WebPageMenuNode('iTopHub:MyExtensions', $sMyExtensionsUrl, $oHubMenu->GetIndex(), $fRank++);
new WebPageMenuNode('iTopHub:BrowseExtensions', $sRootUrl.'&target=browse_extensions', $oHubMenu->GetIndex(), $fRank++);
}
}
}

View File

@@ -0,0 +1,17 @@
<?php
// PHP Data Model definition file
// WARNING - WARNING - WARNING
// DO NOT EDIT THIS FILE (unless you know what you are doing)
//
// If you use supply a datamodel.xxxx.xml file with your module
// the this file WILL BE overwritten by the compilation of the
// module (during the setup) if the datamodel.xxxx.xml file
// contains the definition of new classes or menus.
//
// The recommended way to define new classes (for iTop 2.0) is via the XML definition.
// This file remains in the module's template only for the cases where there is:
// - either no new class or menu defined in the XML file
// - or no XML file at all supplied by the module

View File

@@ -0,0 +1,47 @@
<?php
//
// 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-hub-connector/2.4.1',
array(
// Identification
//
'label' => 'iTop Hub Connector',
'category' => 'business',
// Setup
//
'dependencies' => array(
'itop-config-mgmt/2.4.0', // Actually this module requires iTop 2.4.1 minimum
),
'mandatory' => false,
'visible' => true,
// Components
//
'datamodel' => array(
'menus.php',
'model.itop-hub-connector.php'
),
'webservice' => array(
),
'data.struct' => array(
// add your 'structure' definition XML files here,
),
'data.sample' => array(
// add your sample data XML files here,
),
// Documentation
//
'doc.manual_setup' => '', // hyperlink to manual setup documentation, if any
'doc.more_information' => '', // hyperlink to more information, if any
)
);
?>

View File

@@ -0,0 +1,129 @@
<?php
// Copyright (C) 2010-2016 Combodo SARL
//
// 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/>
/**
* Tools to design OQL queries and test them
*
* @copyright Copyright (C) 2010-2016 Combodo SARL
* @license http://opensource.org/licenses/AGPL-3.0
*/
require_once ('../approot.inc.php');
require_once (APPROOT.'/application/application.inc.php');
require_once (APPROOT.'/application/itopwebpage.class.inc.php');
require_once (APPROOT.'setup/extensionsmap.class.inc.php');
require_once (APPROOT.'/application/startup.inc.php');
require_once (APPROOT.'/application/loginwebpage.class.inc.php');
LoginWebPage::DoLogin(true); // Check user rights and prompt if needed (must be admin)
$oAppContext = new ApplicationContext();
$oPage = new iTopWebPage(Dict::S('iTopHub:InstalledExtensions'));
$oPage->SetBreadCrumbEntry('ui-hub-myextensions', Dict::S('Menu:iTopHub:MyExtensions'), Dict::S('Menu:iTopHub:MyExtensions+'), '', utils::GetAbsoluteUrlAppRoot().'images/wrench.png');
function DisplayExtensionInfo(Webpage $oPage, iTopExtension $oExtension)
{
$oPage->add('<li>');
if ($oExtension->sInstalledVersion == '')
{
$oPage->add('<b>'.$oExtension->sLabel.'</b> '.Dict::Format('UI:About:Extension_Version', $oExtension->sVersion).' <span class="extension-source">'.Dict::S('iTopHub:ExtensionNotInstalled').'</span>');
}
else
{
$oPage->add('<b>'.$oExtension->sLabel.'</b> '.Dict::Format('UI:About:Extension_Version', $oExtension->sInstalledVersion));
}
$oPage->add('<p style="margin-top: 0.25em;">'.$oExtension->sDescription.'</p>');
$oPage->add('</li>');
}
// Main program
try
{
$oExtensionsMap = new iTopExtensionsMap();
$oExtensionsMap->LoadChoicesFromDatabase(MetaModel::GetConfig());
$oPage->add('<h1>'.Dict::S('iTopHub:InstalledExtensions').'</h1>');
$oPage->add('<fieldset>');
$oPage->add('<legend>'.Dict::S('iTopHub:ExtensionCategory:Remote').'</legend>');
$oPage->p(Dict::S('iTopHub:ExtensionCategory:Remote+'));
$oPage->add('<ul style="margin: 0;">');
$iCount = 0;
foreach ($oExtensionsMap->GetAllExtensions() as $oExtension)
{
if ($oExtension->sSource == iTopExtension::SOURCE_REMOTE)
{
$iCount++ ;
DisplayExtensionInfo($oPage, $oExtension);
}
}
$oPage->add('</ul>');
if ($iCount == 0)
{
$oPage->p(Dict::S('iTopHub:NoExtensionInThisCategory'));
}
$oPage->add('</fieldset>');
$sUrl = utils::GetAbsoluteUrlModulePage('itop-hub-connector', 'launch.php', array('target' => 'browse_extensions'));
$oPage->add('<p style="text-align:center;"><button onclick="window.location.href=\''.$sUrl.'\'">'.Dict::S('iTopHub:GetMoreExtensions').'</button></p>');
// Display the section about "manually deployed" extensions, only if there are some already
$iCount = 0;
foreach ($oExtensionsMap->GetAllExtensions() as $oExtension)
{
if ($oExtension->sSource == iTopExtension::SOURCE_MANUAL)
{
$iCount++ ;
}
}
if ($iCount > 0)
{
$oPage->add('<fieldset>');
$oPage->add('<legend>'.Dict::S('iTopHub:ExtensionCategory:Manual').'</legend>');
$oPage->p(Dict::Format('iTopHub:ExtensionCategory:Manual+', '<span title="'.(APPROOT.'extensions').'" id="extension-dir-path">"extensions"</span>'));
$oPage->add('<ul style="margin: 0;">');
$iCount = 0;
foreach ($oExtensionsMap->GetAllExtensions() as $oExtension)
{
if ($oExtension->sSource == iTopExtension::SOURCE_MANUAL)
{
DisplayExtensionInfo($oPage, $oExtension);
}
}
$oPage->add('</ul>');
}
$oPage->add('</fieldset>');
$sExtensionsDirTooltip = json_encode(APPROOT.'extensions');
$oPage->add_style(
<<<EOF
#extension-dir-path {
display: inline-block;
border-bottom: 1px #999 dashed;
cursor: help;
}
EOF
);
}
catch (Exception $e)
{
$oPage->p('<b>'.Dict::Format('UI:Error_Details', $e->getMessage()).'</b>');
}
$oPage->output();