1<?php
2function DisplayStatus(WebPage $oPage)
3{
4    $oPage->set_title(Dict::S('iTopHub:Landing:Status'));
5
6    $oPage->add('<table class="module-selection-banner"><tr>');
7    $sBannerUrl = utils::GetAbsoluteUrlModulesRoot().'/itop-hub-connector/images/landing-extension.png';
8    $oPage->add('<td><img style="max-height:72px; margin-right: 10px;" src="'.$sBannerUrl.'"/><td>');
9    $oPage->add('<td><h2>'.Dict::S('iTopHub:LandingWelcome').'</h2><td>');
10    $oPage->add('</tr></table>');
11
12    $oPage->add('<div class="module-selection-body">');
13    // Now scan the extensions and display a report of the extensions brought by the hub
14    $sPath = APPROOT.'data/downloaded-extensions/';
15    $aExtraDirs = array();
16    if (is_dir($sPath))
17    {
18        $aExtraDirs[] = $sPath; // Also read the extra downloaded-modules directory
19    }
20    $oExtensionsMap = new iTopExtensionsMap('production', true, $aExtraDirs);
21    $oExtensionsMap->LoadChoicesFromDatabase(MetaModel::GetConfig());
22
23    foreach($oExtensionsMap->GetAllExtensions() as $oExtension)
24    {
25        if ($oExtension->sSource == iTopExtension::SOURCE_REMOTE)
26        {
27            $aCSSClasses = array('landing-extension');
28            if ($oExtension->sInstalledVersion === '')
29            {
30                $aCSSClasses[] = 'landing-installation';
31                $sInstallation = Dict::Format('iTopHub:InstallationStatus:Version_NotInstalled', $oExtension->sVersion);
32
33            }
34            else
35            {
36                $aCSSClasses[] = 'landing-no-change';
37                $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>';
38                $sInstallation = Dict::Format('iTopHub:InstallationStatus:Installed_Version', $sBadge, $oExtension->sInstalledVersion);
39            }
40
41            $oPage->add('<div class="choice">');
42            $sCode = $oExtension->sCode;
43            $sDir = basename($oExtension->sSourceDir);
44            $oPage->add('<input type="checkbox" data-extension-code="'.$sCode.'" data-extension-dir="'.$sDir.'" checked disabled>&nbsp;');
45            $oPage->add('<label><b>'.htmlentities($oExtension->sLabel, ENT_QUOTES, 'UTF-8').'</b> '.$sInstallation.'</label>');
46            $oPage->add('<div class="description">');
47            $oPage->add('<p>');
48            if ($oExtension->sDescription != '')
49            {
50                $oPage->add(htmlentities($oExtension->sDescription, ENT_QUOTES, 'UTF-8').'</br>');
51            }
52            $oPage->add('</p>');
53            $oPage->add('</div>');
54            $oPage->add('</div>');
55        }
56    }
57    $oPage->add('</div>');
58    $oPage->add('<div style="text-align:center"><button onclick="window.location.href=\'./UI.php\';">'.Dict::S('iTopHub:GoBackToITopBtn').'</button></div>');
59}
60
61function DoLanding(WebPage $oPage)
62{
63    $oPage->add_linked_stylesheet(utils::GetAbsoluteUrlModulesRoot().'itop-hub-connector/css/hub.css');
64    $oPage->add('<table class="module-selection-banner"><tr>');
65    $sBannerUrl = utils::GetAbsoluteUrlModulesRoot().'/itop-hub-connector/images/landing-extension.png';
66    $oPage->add('<td><img style="max-height:72px; margin-right: 10px;" src="'.$sBannerUrl.'"/><td>');
67    $oPage->add('<td><h2>'.Dict::S('iTopHub:InstallationWelcome').'</h2><td>');
68    $oPage->add('</tr></table>');
69
70    $oPage->set_title(Dict::S('iTopHub:Landing:Status'));
71
72    $oPage->add('<div class="module-selection-body" style="text-align: center; line-height: 14em;"><h2>'.Dict::S('iTopHub:Uncompressing').'</h2></div>');
73
74
75    $sProduct = utils::ReadParam('applicationName', '', false, 'raw_data');
76    $sVersion = utils::ReadParam('applicationVersion', '', false, 'raw_data');
77    $sInstanceUUID = utils::ReadParam('uuidFile', '', false, 'raw_data');
78    $sDatabaseUUID = utils::ReadParam('uuidBdd', '', false, 'raw_data');
79    $aExtensions = utils::ReadParam('extensions', array(), false, 'raw_data');
80
81    // Basic consistency validation
82    if ($sProduct != ITOP_APPLICATION)
83    {
84        throw new Exception("Inconsistent product '$sProduct', expecting '".ITOP_APPLICATION."'");
85    }
86
87    if ($sVersion != ITOP_VERSION)
88    {
89        throw new Exception("Inconsistent version '$sVersion', expecting ".ITOP_VERSION."'");
90    }
91
92    $sFileUUID = (string) trim(@file_get_contents(APPROOT."data/instance.txt"), "{} \n");
93    if ($sInstanceUUID != $sFileUUID)
94    {
95        throw new Exception("Inconsistent file UUID '$sInstanceUUID', expecting ".$sFileUUID."'");
96    }
97
98    $sDBUUID = (string) trim(DBProperty::GetProperty('database_uuid', ''), '{}');
99    if ($sDatabaseUUID != $sDBUUID)
100    {
101        throw new Exception("Inconsistent database UUID '$sDatabaseUUID', expecting ".$sDBUUID."'");
102    }
103
104    // Uncompression of extensions in data/downloaded-extensions
105    // only newly downloaded extensions reside in this folder
106    $i = 0;
107    $sPath = APPROOT.'data/downloaded-extensions/';
108    if (!is_dir($sPath))
109    {
110        if (!mkdir($sPath)) throw new Exception("ERROR: Unable to create the directory '$sPath'. Cannot download any extension. Check the access rights on '".dirname('data/downloaded-extensions/')."'");
111    }
112    else
113    {
114    	// Make sure that the directory is empty
115    	SetupUtils::tidydir($sPath);
116    }
117
118    foreach($aExtensions as $sBase64Archive)
119    {
120        $sArchive = base64_decode($sBase64Archive);
121
122        $sZipArchiveFile = $sPath."/extension-{$i}.zip";
123        file_put_contents($sZipArchiveFile, $sArchive);
124        // Expand the content of extension-x.zip into  APPROOT.'data/downloaded-extensions/'
125        // where the installation will load the extension automatically
126        $oZip = new ZipArchive();
127        if (!$oZip->open($sZipArchiveFile))
128        {
129            throw new Exception('Unable to open "'.$sZipArchiveFile.'" for extraction. Make sure that the directory "'.'data/downloaded-extensions/'.'" is writable for the web server.');
130        }
131        for($idx  = 0; $idx < $oZip->numFiles; $idx++)
132        {
133            $sCompressedFile = $oZip->getNameIndex($idx);
134            $oZip->extractTo($sPath, $sCompressedFile);
135        }
136        @$oZip->close();
137        @unlink($sZipArchiveFile); // Get rid of the temporary file
138        $i++;
139    }
140
141    // Now scan the extensions and display a report of the extensions brought by the hub
142    $sNextPage = utils::GetAbsoluteUrlModulePage('itop-hub-connector', 'land.php', array('operation' => 'install'));
143    $oPage->add_ready_script("window.location.href='$sNextPage'");
144
145}
146
147function DoInstall(WebPage $oPage)
148{
149	$sUID = hash('sha256', rand());
150	file_put_contents(APPROOT.'data/hub/compile_authent', $sUID);
151
152    $oPage->add_linked_stylesheet(utils::GetAbsoluteUrlModulesRoot().'itop-hub-connector/css/hub.css');
153    $oPage->add('<table class="module-selection-banner"><tr>');
154    $sBannerUrl = utils::GetAbsoluteUrlModulesRoot().'/itop-hub-connector/images/landing-extension.png';
155    $oPage->add('<td><img style="max-height:72px; margin-right: 10px;" src="'.$sBannerUrl.'"/><td>');
156    $oPage->add('<td><h2>'.Dict::S('iTopHub:InstallationWelcome').'</h2><td>');
157    $oPage->add('</tr></table>');
158
159    $oPage->set_title(Dict::S('iTopHub:Landing:Install'));
160    $oPage->add('<div id="installation-summary" class="module-selection-body" style="position: relative">');
161
162
163    // Now scan the extensions and display a report of the extensions brought by the hub
164    // Now scan the extensions and display a report of the extensions brought by the hub
165    $sPath = APPROOT.'data/downloaded-extensions/';
166    $aExtraDirs = array();
167    if (is_dir($sPath))
168    {
169        $aExtraDirs[] = $sPath; // Also read the extra downloaded-modules directory
170    }
171    $oExtensionsMap = new iTopExtensionsMap('production', true, $aExtraDirs);
172    $oExtensionsMap->LoadChoicesFromDatabase(MetaModel::GetConfig());
173
174    foreach($oExtensionsMap->GetAllExtensions() as $oExtension)
175    {
176        if ($oExtension->sSource == iTopExtension::SOURCE_REMOTE)
177        {
178        	if (count($oExtension->aMissingDependencies) > 0)
179        	{
180        		$oPage->add('<div class="choice">');
181        		$oPage->add('<input type="checkbox" disabled>&nbsp;');
182        		$sTitle = Dict::Format('iTopHub:InstallationEffect:MissingDependencies_Details', implode(', ', $oExtension->aMissingDependencies));
183        		$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>');
184        		$oPage->add('<div class="description">');
185        		$oPage->add('<p>');
186        		if ($oExtension->sDescription != '')
187        		{
188        			$oPage->add(htmlentities($oExtension->sDescription, ENT_QUOTES, 'UTF-8').'</br>');
189        		}
190        		$oPage->add('</p>');
191        		$oPage->add('</div>');
192        		$oPage->add('</div>');
193        	}
194        	else
195        	{
196	            $aCSSClasses = array('landing-extension');
197	            if ($oExtension->sInstalledVersion === '')
198	            {
199	                $aCSSClasses[] = 'landing-installation';
200	                $sInstallation = Dict::Format('iTopHub:InstallationEffect:Install', $oExtension->sVersion);
201	            }
202	            else if ($oExtension->sInstalledVersion == $oExtension->sVersion)
203	            {
204	                $aCSSClasses[] = 'landing-no-change';
205	                $sInstallation = Dict::Format('iTopHub:InstallationEffect:NoChange', $oExtension->sVersion);
206	             }
207	            else if (version_compare($oExtension->sInstalledVersion, $oExtension->sVersion, '<'))
208	            {
209	                $aCSSClasses[] = 'landing-upgrade';
210	                $sInstallation = Dict::Format('iTopHub:InstallationEffect:Upgrade', $oExtension->sInstalledVersion, $oExtension->sVersion);
211	            }
212	            else
213	            {
214	                $aCSSClasses[] = 'landing-downgrade';
215	                $sInstallation = Dict::Format('iTopHub:InstallationEffect:Downgrade', $oExtension->sInstalledVersion, $oExtension->sVersion);
216	            }
217	            $oPage->add('<div class="choice">');
218	            $sCode = $oExtension->sCode;
219	            $sDir = basename($oExtension->sSourceDir);
220	            $oPage->add('<input type="checkbox" checked disabled data-extension-code="'.$sCode.'" data-extension-dir="'.$sDir.'">&nbsp;');
221	            $oPage->add('<label><b>'.htmlentities($oExtension->sLabel, ENT_QUOTES, 'UTF-8').'</b> '.$sInstallation.'</label>');
222	            $oPage->add('<div class="description">');
223	            $oPage->add('<p>');
224	            if ($oExtension->sDescription != '')
225	            {
226	                $oPage->add(htmlentities($oExtension->sDescription, ENT_QUOTES, 'UTF-8').'</br>');
227	            }
228	            $oPage->add('</p>');
229	            $oPage->add('</div>');
230	            $oPage->add('</div>');
231        	}
232        }
233    }
234
235    $oPage->add('<div id="hub-installation-feedback">');
236    $oPage->add('<div id="hub-installation-progress-text">'.Dict::S('iTopHub:DatabaseBackupProgress').'</div>');
237    $oPage->add('<div id="hub-installation-progress"></div>');
238    $oPage->add('</div>');
239
240    $oPage->add('</div>'); // module-selection-body
241
242
243    $oPage->add_linked_stylesheet('../css/font-awesome/css/font-awesome.min.css');
244    $oPage->add('<div id="hub_installation_widget"></div>');
245    $oPage->add('<fieldset id="database-backup-fieldset"><legend>'.Dict::S('iTopHub:DBBackupLabel').'</legend>');
246    $oPage->add('<div id="backup_form"><input id="backup_checkbox" type="checkbox" checked><label for="backup_checkbox"> '.Dict::S('iTopHub:DBBackupSentence').'</label></div>');
247    $oPage->add('<div id="backup_status"></div>');
248    $oPage->add('</fieldset>');
249    $oPage->add('<p style="text-align: center"><input type="button" id="hub_start_installation" type="button" disabled value="'.Dict::S('iTopHub:DeployBtn').'"/></p>');
250
251    $sIframeUrl = utils::GetAbsoluteUrlModulePage('itop-hub-connector', 'launch.php', array('target' => 'inform_after_setup'));
252    $sStatusPageUrl = utils::GetAbsoluteUrlModulePage('itop-hub-connector', 'land.php', array('operation' => 'done'));
253
254    $aWidgetParams = array(
255        'self_url' => utils::GetAbsoluteUrlModulePage('itop-hub-connector', 'ajax.php'),
256        'iframe_url' => $sIframeUrl,
257        'redirect_after_completion_url' => $sStatusPageUrl,
258        'mysql_bindir' => MetaModel::GetConfig()->GetModuleSetting('itop-backup', 'mysql_bindir', ''),
259    	'labels' => array(
260			'database_backup' => Dict::S('iTopHub:InstallationProgress:DatabaseBackup'),
261    		'extensions_installation' => Dict::S('iTopHub:InstallationProgress:ExtensionsInstallation'),
262    		'installation_successful' => Dict::S('iTopHub:InstallationProgress:InstallationSuccessful'),
263    		'rollback' => Dict::S('iTopHub:ConfigurationSafelyReverted'),
264    	),
265	    'authent' => $sUID,
266    );
267
268    $sWidgetParams = json_encode($aWidgetParams);
269
270    $oPage->add_ready_script("$('#hub_installation_widget').hub_installation($sWidgetParams);");
271    $oPage->add_ready_script("$('#hub_start_installation').click(function() { $('#hub_installation_widget').hub_installation('start_installation');} );");
272    $oPage->add_ready_script("$('#hub_installation_widget').hub_installation('check_before_backup');");
273    $oPage->add('<div id="debug"></div>');
274}
275
276
277try
278{
279    require_once(APPROOT.'/application/application.inc.php');
280    require_once(APPROOT.'/setup/setuppage.class.inc.php');
281    require_once(APPROOT.'/setup/extensionsmap.class.inc.php');
282    require_once(APPROOT.'/application/startup.inc.php');
283    require_once(APPROOT.'/application/loginwebpage.class.inc.php');
284
285    LoginWebPage::DoLoginEx(null, true /* $bMustBeAdmin */); // Check user rights and prompt if needed
286    if (MetaModel::GetConfig()->Get('demo_mode')) throw new Exception('Sorry the installation of extensions is not allowed in demo mode');
287
288    $oPage = new SetupPage(''); // Title will be set later, depending on $sOperation
289    $oPage->add_linked_script(utils::GetAbsoluteUrlModulesRoot().'itop-hub-connector/js/hub.js');
290    $oPage->add_linked_stylesheet('../css/font-combodo/font-combodo.css');
291
292    $oPage->add_style("div.choice { margin: 0.5em;}");
293    $oPage->add_style("div.choice a { text-decoration:none; font-weight: bold; color: #1C94C4 }");
294    $oPage->add_style("div.description { margin-left: 2em; }");
295    $oPage->add_style("div.description p { margin-top: 0.25em; margin-bottom: 0.5em; }");
296    $oPage->add_style(".choice-disabled { color: #999; }");
297
298
299    $sOperation = utils::ReadParam('operation', 'land');
300
301    switch($sOperation)
302    {
303        case 'done':
304        DisplayStatus($oPage);
305        break;
306
307        case 'install':
308        if (!file_exists(APPROOT.'data/hub'))
309        {
310	        mkdir(APPROOT.'data/hub');
311        }
312        DoInstall($oPage);
313        break;
314
315        case 'land':
316        default:
317        DoLanding($oPage);
318    }
319
320    $oPage->output();
321
322}
323catch(Exception $e)
324{
325    require_once(APPROOT.'/setup/setuppage.class.inc.php');
326    $oP = new SetupPage(Dict::S('UI:PageTitle:FatalError'));
327    $oP->add("<h1>".Dict::S('UI:FatalErrorMessage')."</h1>\n");
328    $oP->error(Dict::Format('UI:Error_Details', $e->getMessage()));
329    $oP->output();
330
331    if (MetaModel::IsLogEnabledIssue())
332    {
333        if (MetaModel::IsValidClass('EventIssue'))
334        {
335            $oLog = new EventIssue();
336
337            $oLog->Set('message', $e->getMessage());
338            $oLog->Set('userinfo', '');
339            $oLog->Set('issue', 'PHP Exception');
340            $oLog->Set('impact', 'Page could not be displayed');
341            $oLog->Set('callstack', $e->getTrace());
342            $oLog->Set('data', array());
343            $oLog->DBInsertNoReload();
344        }
345
346        IssueLog::Error($e->getMessage());
347    }
348}
349