/** * Displays the user's changeable preferences * @param $oP WebPage The web page used for the output */ function DisplayPreferences($oP) { $oAppContext = new ApplicationContext(); $sURL = utils::GetAbsoluteUrlAppRoot() . 'pages/UI.php?' . $oAppContext->GetForLink(); $oP->add('<div class="page_header"><h1><img style="vertical-align:middle" src="../images/preferences.png"/> ' . Dict::S('UI:Preferences') . "</h1></div>\n"); $oP->add('<div id="user_prefs" style="max-width:800px; min-width:400px;">'); ////////////////////////////////////////////////////////////////////////// // // User Language selection // ////////////////////////////////////////////////////////////////////////// $oP->add('<fieldset><legend>' . Dict::S('UI:FavoriteLanguage') . '</legend>'); $oP->add('<form method="post">'); $aLanguages = Dict::GetLanguages(); $aSortedlang = array(); foreach ($aLanguages as $sCode => $aLang) { if (MetaModel::GetConfig()->Get('demo_mode')) { if ($sCode != Dict::GetUserLanguage()) { // Demo mode: only the current user language is listed in the available choices continue; } } $aSortedlang[$aLang['description']] = $sCode; } ksort($aSortedlang); $oP->add('<p>' . Dict::S('UI:Favorites:SelectYourLanguage') . ' <select name="language">'); foreach ($aSortedlang as $sCode) { $sSelected = $sCode == Dict::GetUserLanguage() ? 'selected' : ''; $oP->add('<option value="' . $sCode . '" ' . $sSelected . '/>' . $aLanguages[$sCode]['description'] . ' (' . $aLanguages[$sCode]['localized_description'] . ')</option>'); } $oP->add('</select></p>'); $oP->add('<input type="hidden" name="operation" value="apply_language"/>'); $oP->add($oAppContext->GetForForm()); $oP->add('<p><input type="button" onClick="window.location.href=\'' . $sURL . '\'" value="' . Dict::S('UI:Button:Cancel') . '"/>'); $oP->add(' '); $oP->add('<input type="submit" value="' . Dict::S('UI:Button:Apply') . '"/></p>'); $oP->add('</form>'); $oP->add('</fieldset>'); ////////////////////////////////////////////////////////////////////////// // // Other (miscellaneous) settings // ////////////////////////////////////////////////////////////////////////// $oP->add('<fieldset><legend>' . Dict::S('UI:FavoriteOtherSettings') . '</legend>'); $oP->add('<form method="post" onsubmit="return ValidateOtherSettings()">'); $iDefaultPageSize = appUserPreferences::GetPref('default_page_size', MetaModel::GetConfig()->GetMinDisplayLimit()); $oP->add('<p>' . Dict::Format('UI:Favorites:Default_X_ItemsPerPage', '<input id="default_page_size" name="default_page_size" type="text" size="3" value="' . $iDefaultPageSize . '"/><span id="v_default_page_size"></span>') . '</p>'); $oP->add('<input type="hidden" name="operation" value="apply_others"/>'); $oP->add($oAppContext->GetForForm()); $oP->add('<p><input type="button" onClick="window.location.href=\'' . $sURL . '\'" value="' . Dict::S('UI:Button:Cancel') . '"/>'); $oP->add(' '); $oP->add('<input id="other_submit" type="submit" value="' . Dict::S('UI:Button:Apply') . '"/></p>'); $oP->add('</form>'); $oP->add('</fieldset>'); $oP->add_script(<<<EOF function ValidateOtherSettings() { \tvar sPageLength = \$('#default_page_size').val(); \tvar iPageLength = parseInt(sPageLength , 10); \tif (/^[0-9]+\$/.test(sPageLength) && (iPageLength > 0)) \t{ \t\t\$('#v_default_page_size').html(''); \t\t\$('#other_submit').removeAttr('disabled'); \t\treturn true; \t} \telse \t{ \t\t\$('#v_default_page_size').html('<img src="../images/validation_error.png"/>'); \t\t\$('#other_submit').attr('disabled', 'disabled'); \t\treturn false; \t} } EOF ); ////////////////////////////////////////////////////////////////////////// // // Favorite Organizations // ////////////////////////////////////////////////////////////////////////// $oP->add('<fieldset><legend>' . Dict::S('UI:FavoriteOrganizations') . '</legend>'); $oP->p(Dict::S('UI:FavoriteOrganizations+')); $oP->add('<form method="post">'); // Favorite organizations: the organizations listed in the drop-down menu $sOQL = ApplicationMenu::GetFavoriteSiloQuery(); $oFilter = DBObjectSearch::FromOQL($sOQL); $oBlock = new DisplayBlock($oFilter, 'list', false); $oBlock->Display($oP, 1, array('menu' => false, 'selection_mode' => true, 'selection_type' => 'multiple', 'cssCount' => '.selectedCount', 'table_id' => 'user_prefs')); $oP->add($oAppContext->GetForForm()); $oP->add('<input type="hidden" name="operation" value="apply"/>'); $oP->add('<p><input type="button" onClick="window.location.href=\'' . $sURL . '\'" value="' . Dict::S('UI:Button:Cancel') . '"/>'); $oP->add(' '); $oP->add('<input type="submit" value="' . Dict::S('UI:Button:Apply') . '"/></p>'); $oP->add('</form>'); $oP->add('</fieldset>'); $aFavoriteOrgs = appUserPreferences::GetPref('favorite_orgs', null); if ($aFavoriteOrgs == null) { // All checked $oP->add_ready_script(<<<EOF \tif (\$('#user_prefs table.pagination').length > 0) \t{ \t\t// paginated display, restore the selection \t\tvar pager = \$('#user_prefs form .pager'); \t\t\$(':input[name=selectionMode]', pager).val('negative'); \t\t\$('#user_prefs table.listResults').trigger('load_selection'); \t} \telse \t{ \t\t\$('#user_prefs table.listResults').trigger('check_all'); \t} EOF ); } else { $sChecked = implode('","', $aFavoriteOrgs); $oP->add_ready_script(<<<EOF \tvar aChecked = ["{$sChecked}"]; \tif (\$('#user_prefs table.pagination').length > 0) \t{ \t\t// paginated display, restore the selection \t\tvar pager = \$('#user_prefs form .pager'); \t\t\$(':input[name=selectionMode]', pager).val('positive'); \t\tfor (i=0; i<aChecked.length; i++) \t\t{ \t\t\tpager.append('<input type="hidden" name="storedSelection[]" id="'+aChecked[i]+'" value="'+aChecked[i]+'"/>'); \t\t} \t\t\$('#user_prefs table.listResults').trigger('load_selection'); \t\t \t} \telse \t{ \t\t\$('#user_prefs form :checkbox[name^=selectObject]').each( function() \t\t\t{ \t\t\t\tif (\$.inArray(\$(this).val(), aChecked) > -1) \t\t\t\t{ \t\t\t\t\t\$(this).attr('checked', true); \t\t\t\t\t\$(this).trigger('change'); \t\t\t\t} \t\t\t}); \t} EOF ); } ////////////////////////////////////////////////////////////////////////// // // Shortcuts // ////////////////////////////////////////////////////////////////////////// $oP->add('<fieldset><legend>' . Dict::S('Menu:MyShortcuts') . '</legend>'); //$oP->p(Dict::S('UI:Menu:MyShortcuts+')); $oBMSearch = new DBObjectSearch('Shortcut'); $oBMSearch->AddCondition('user_id', UserRights::GetUserId(), '='); //$aExtraParams = array('menu' => false, 'toolkit_menu' => false, 'display_limit' => false, 'localize_values' => $bLocalize, 'zlist' => 'details'); $aExtraParams = array(); $oBlock = new DisplayBlock($oBMSearch, 'list', false, $aExtraParams); $oBlock->Display($oP, 'shortcut_list', array('view_link' => false, 'menu' => false, 'toolkit_menu' => false, 'selection_mode' => true, 'selection_type' => 'multiple', 'cssCount' => '#shortcut_selection_count', 'table_id' => 'user_prefs_shortcuts')); $oP->add('<p>'); $oSet = new DBObjectSet($oBMSearch); if ($oSet->Count() > 0) { $sButtons = '<img src="../images/tv-item-last.gif">'; $sButtons .= ' '; $sButtons .= '<button id="shortcut_btn_rename">' . Dict::S('UI:Button:Rename') . '</button>'; $sButtons .= ' '; $sButtons .= '<button id="shortcut_btn_delete">' . Dict::S('UI:Button:Delete') . '</button>'; // Selection count updated by the pager, and used to enable buttons $oP->add('<input type="hidden" id="shortcut_selection_count"/>'); $oP->add('</fieldset>'); $sConfirmDelete = addslashes(Dict::S('UI:ShortcutDelete:Confirm')); $oP->add_ready_script(<<<EOF function OnShortcutBtnRename() { \tvar oParams = \$('#datatable_shortcut_list').datatable('GetMultipleSelectionParams'); \toParams.operation = 'shortcut_rename_dlg'; \t\$.post(GetAbsoluteUrlAppRoot()+'pages/ajax.render.php', oParams, function(data){ \t\t\$('body').append(data); \t}); \treturn false; } function OnShortcutBtnDelete() { \tif (confirm('{$sConfirmDelete}')) \t{ \t\tvar oParams = \$('#datatable_shortcut_list').datatable('GetMultipleSelectionParams'); \t\toParams.operation = 'shortcut_delete_go'; \t\t\$.post(GetAbsoluteUrlAppRoot()+'pages/ajax.render.php', oParams, function(data){ \t\t\t\$('body').append(data); \t\t}); \t} \treturn false; } function OnSelectionCountChange() { \tvar iCountSelected = \$("#shortcut_selection_count").val(); \tif (iCountSelected == 0) \t{ \t\t\$('#shortcut_btn_rename').attr('disabled', 'disabled'); \t\t\$('#shortcut_btn_delete').attr('disabled', 'disabled'); \t} \telse if (iCountSelected == 1) \t{ \t\t\$('#shortcut_btn_rename').removeAttr('disabled'); \t\t\$('#shortcut_btn_delete').removeAttr('disabled'); \t} \telse \t{ \t\t\$('#shortcut_btn_rename').attr('disabled', 'disabled'); \t\t\$('#shortcut_btn_delete').removeAttr('disabled'); \t} } var oUpperCheckBox = \$('#datatable_shortcut_list .checkAll').first(); oUpperCheckBox.parent().width(oUpperCheckBox.width() + 2); \$('#datatable_shortcut_list').append('<tr><td colspan="2"> {$sButtons}</td></tr>'); \$('#shortcut_selection_count').bind('change', OnSelectionCountChange); \$('#shortcut_btn_rename').bind('click', OnShortcutBtnRename); \$('#shortcut_btn_delete').bind('click', OnShortcutBtnDelete); OnSelectionCountChange(); EOF ); } // if count > 0 ////////////////////////////////////////////////////////////////////////// // // Footer // $oP->add('</div>'); $oP->add_ready_script("\$('#fav_page_length').bind('keyup change', function(){ ValidateOtherSettings(); })"); }
protected static function DoUpdateDBSchema($sMode, $aSelectedModules, $sModulesDir, $sDBServer, $sDBUser, $sDBPwd, $sDBName, $sDBPrefix, $sTargetEnvironment = '', $bOldAddon = false) { SetupPage::log_info("Update Database Schema for environment '{$sTargetEnvironment}'."); $oConfig = new Config(); $aParamValues = array('mode' => $sMode, 'db_server' => $sDBServer, 'db_user' => $sDBUser, 'db_pwd' => $sDBPwd, 'db_name' => $sDBName, 'db_prefix' => $sDBPrefix); $oConfig->UpdateFromParams($aParamValues, $sModulesDir); if ($bOldAddon) { // Old version of the add-on for backward compatibility with pre-2.0 data models $oConfig->SetAddons(array('user rights' => 'addons/userrights/userrightsprofile.db.class.inc.php')); } $oProductionEnv = new RunTimeEnvironment($sTargetEnvironment); $oProductionEnv->InitDataModel($oConfig, true); // load data model only // Migrate application data format // // priv_internalUser caused troubles because MySQL transforms table names to lower case under Windows // This becomes an issue when moving your installation data to/from Windows // Starting 2.0, all table names must be lowercase if ($sMode != 'install') { SetupPage::log_info("Renaming '{$sDBPrefix}priv_internalUser' into '{$sDBPrefix}priv_internaluser' (lowercase)"); // This command will have no effect under Windows... // and it has been written in two steps so as to make it work under windows! CMDBSource::SelectDB($sDBName); try { $sRepair = "RENAME TABLE `{$sDBPrefix}priv_internalUser` TO `{$sDBPrefix}priv_internaluser_other`, `{$sDBPrefix}priv_internaluser_other` TO `{$sDBPrefix}priv_internaluser`"; CMDBSource::Query($sRepair); } catch (Exception $e) { SetupPage::log_info("Renaming '{$sDBPrefix}priv_internalUser' failed (already done in a previous upgrade?)"); } // let's remove the records in priv_change which have no counterpart in priv_changeop SetupPage::log_info("Cleanup of '{$sDBPrefix}priv_change' to remove orphan records"); CMDBSource::SelectDB($sDBName); try { $sTotalCount = "SELECT COUNT(*) FROM `{$sDBPrefix}priv_change`"; $iTotalCount = (int) CMDBSource::QueryToScalar($sTotalCount); SetupPage::log_info("There is a total of {$iTotalCount} records in {$sDBPrefix}priv_change."); $sOrphanCount = "SELECT COUNT(c.id) FROM `{$sDBPrefix}priv_change` AS c left join `{$sDBPrefix}priv_changeop` AS o ON c.id = o.changeid WHERE o.id IS NULL"; $iOrphanCount = (int) CMDBSource::QueryToScalar($sOrphanCount); SetupPage::log_info("There are {$iOrphanCount} useless records in {$sDBPrefix}priv_change (" . sprintf('%.2f', 100.0 * $iOrphanCount / $iTotalCount) . "%)"); if ($iOrphanCount > 0) { SetupPage::log_info("Removing the orphan records..."); $sCleanup = "DELETE FROM `{$sDBPrefix}priv_change` USING `{$sDBPrefix}priv_change` LEFT JOIN `{$sDBPrefix}priv_changeop` ON `{$sDBPrefix}priv_change`.id = `{$sDBPrefix}priv_changeop`.changeid WHERE `{$sDBPrefix}priv_changeop`.id IS NULL;"; CMDBSource::Query($sCleanup); SetupPage::log_info("Cleanup completed successfully."); } else { SetupPage::log_info("Ok, nothing to cleanup."); } } catch (Exception $e) { SetupPage::log_info("Cleanup of orphan records in `{$sDBPrefix}priv_change` failed: " . $e->getMessage()); } } // Module specific actions (migrate the data) // $aAvailableModules = $oProductionEnv->AnalyzeInstallation(MetaModel::GetConfig(), APPROOT . $sModulesDir); foreach ($aAvailableModules as $sModuleId => $aModule) { if ($sModuleId != ROOT_MODULE && in_array($sModuleId, $aSelectedModules) && isset($aAvailableModules[$sModuleId]['installer'])) { $sModuleInstallerClass = $aAvailableModules[$sModuleId]['installer']; SetupPage::log_info("Calling Module Handler: {$sModuleInstallerClass}::BeforeDatabaseCreation(oConfig, {$aModule['version_db']}, {$aModule['version_code']})"); $aCallSpec = array($sModuleInstallerClass, 'BeforeDatabaseCreation'); call_user_func_array($aCallSpec, array(MetaModel::GetConfig(), $aModule['version_db'], $aModule['version_code'])); } } if (!$oProductionEnv->CreateDatabaseStructure(MetaModel::GetConfig(), $sMode)) { throw new Exception("Failed to create/upgrade the database structure for environment '{$sTargetEnvironment}'"); } // priv_change now has an 'origin' field to distinguish between the various input sources // Let's initialize the field with 'interactive' for all records were it's null // Then check if some records should hold a different value, based on a pattern matching in the userinfo field CMDBSource::SelectDB($sDBName); try { $sCount = "SELECT COUNT(*) FROM `{$sDBPrefix}priv_change` WHERE `origin` IS NULL"; $iCount = (int) CMDBSource::QueryToScalar($sCount); if ($iCount > 0) { SetupPage::log_info("Initializing '{$sDBPrefix}priv_change.origin' ({$iCount} records to update)"); // By default all uninitialized values are considered as 'interactive' $sInit = "UPDATE `{$sDBPrefix}priv_change` SET `origin` = 'interactive' WHERE `origin` IS NULL"; CMDBSource::Query($sInit); // CSV Import was identified by the comment at the end $sInit = "UPDATE `{$sDBPrefix}priv_change` SET `origin` = 'csv-import.php' WHERE `userinfo` LIKE '%Web Service (CSV)'"; CMDBSource::Query($sInit); // CSV Import was identified by the comment at the end $sInit = "UPDATE `{$sDBPrefix}priv_change` SET `origin` = 'csv-interactive' WHERE `userinfo` LIKE '%(CSV)' AND origin = 'interactive'"; CMDBSource::Query($sInit); // Syncho data sources were identified by the comment at the end // Unfortunately the comment is localized, so we have to search for all possible patterns $sCurrentLanguage = Dict::GetUserLanguage(); foreach (Dict::GetLanguages() as $sLangCode => $aLang) { Dict::SetUserLanguage($sLangCode); $sSuffix = CMDBSource::Quote('%' . Dict::S('Core:SyncDataExchangeComment')); $aSuffixes[$sSuffix] = true; } Dict::SetUserLanguage($sCurrentLanguage); $sCondition = "`userinfo` LIKE " . implode(" OR `userinfo` LIKE ", array_keys($aSuffixes)); $sInit = "UPDATE `{$sDBPrefix}priv_change` SET `origin` = 'synchro-data-source' WHERE ({$sCondition})"; CMDBSource::Query($sInit); SetupPage::log_info("Initialization of '{$sDBPrefix}priv_change.origin' completed."); } else { SetupPage::log_info("'{$sDBPrefix}priv_change.origin' already initialized, nothing to do."); } } catch (Exception $e) { SetupPage::log_error("Initializing '{$sDBPrefix}priv_change.origin' failed: " . $e->getMessage()); } // priv_async_task now has a 'status' field to distinguish between the various statuses rather than just relying on the date columns // Let's initialize the field with 'planned' or 'error' for all records were it's null CMDBSource::SelectDB($sDBName); try { $sCount = "SELECT COUNT(*) FROM `{$sDBPrefix}priv_async_task` WHERE `status` IS NULL"; $iCount = (int) CMDBSource::QueryToScalar($sCount); if ($iCount > 0) { SetupPage::log_info("Initializing '{$sDBPrefix}priv_async_task.status' ({$iCount} records to update)"); $sInit = "UPDATE `{$sDBPrefix}priv_async_task` SET `status` = 'planned' WHERE (`status` IS NULL) AND (`started` IS NULL)"; CMDBSource::Query($sInit); $sInit = "UPDATE `{$sDBPrefix}priv_async_task` SET `status` = 'error' WHERE (`status` IS NULL) AND (`started` IS NOT NULL)"; CMDBSource::Query($sInit); SetupPage::log_info("Initialization of '{$sDBPrefix}priv_async_task.status' completed."); } else { SetupPage::log_info("'{$sDBPrefix}priv_async_task.status' already initialized, nothing to do."); } } catch (Exception $e) { SetupPage::log_error("Initializing '{$sDBPrefix}priv_async_task.status' failed: " . $e->getMessage()); } SetupPage::log_info("Database Schema Successfully Updated for environment '{$sTargetEnvironment}'."); }