config = &$config; $this->listing = new ConfigManagementListing($this->config, get_userinfo(), $this); // Load the template engine and tell her what template // to use for the HTML it produces. $this->TemplateEngine = new TemplateEngine($config); // Preset item config - with Distribution and Release objects. $items = array(); $items['root']['container'] = array('Distribution'); $items['root']['name'] = '/'; $items['root']['description'] = _('Root'); $items['Distribution']['container'] = array('Release'); $items['Distribution']['name'] = 'Distribution'; $items['Distribution']['description'] = _('Distribution'); $items['Distribution']['options']['name']['description'] = _("Name"); $items['Distribution']['options']['name']['default'] = ""; $items['Distribution']['options']['name']['value'] = ""; $items['Distribution']['options']['name']['required'] = true; $items['Distribution']['options']['name']['type'] = 'string'; $items['Distribution']['options']['name']['display'] = _('Name'); $items['Distribution']['options']['type']['description'] = _("Distribution type"); $items['Distribution']['options']['type']['default'] = "deb"; $items['Distribution']['options']['type']['value'] = "deb"; $items['Distribution']['options']['type']['values'] = array("deb" => 'deb', "rpm" => 'rpm'); $items['Distribution']['options']['type']['required'] = true; $items['Distribution']['options']['type']['type'] = 'combobox'; $items['Distribution']['options']['type']['display'] = _('Distribution type'); $items['Release']['container'] = array('Release', '__CFG_ITEMS__'); $items['Release']['name'] = 'Release'; $items['Release']['description'] = _('Release'); $items['Release']['options']['name']['description'] = _("Name"); $items['Release']['options']['name']['default'] = ""; $items['Release']['options']['name']['value'] = ""; $items['Release']['options']['name']['required'] = true; $items['Release']['options']['name']['type'] = 'string'; $items['Release']['options']['name']['display'] = _('Name'); $this->installationMethods = array(); $this->installationMethods['root']['description'] = _('root'); $this->installationMethods['root']['name'] = 'root'; $this->installationMethods['root']['title'] = _('root'); $this->installationMethods['root']['items']['Distribution'] = &$items['Distribution']; $this->installationMethods['root']['items']['Release'] = &$items['Release']; $this->installationMethods['root']['items']['root'] = &$items['root']; // Request an update of the data model $this->loadInstallationMethods(); $this->updateDataModel(); $this->listing->setListingTypes($this->getListingTypes()); } /*! \brief Intializes this plugin * All available installation methods will be loaded */ function loadInstallationMethods() { // Reset erros $this->rpcError = $this->initFailed = FALSE; // Load configuration via rpc. $rpc = $this->config->getRpcHandle(); $res = $rpc->getSupportedInstallMethods(); if(!$rpc->success()){ $this->rpcError = TRUE; $this->errorMessage = $rpc->get_error();; return; } // Populate install methods on success. if(!count($res)){ $this->errorMessage = _("No selectable install methods returned!"); msg_dialog::display(_("Setup"), $this->errorMessage , ERROR_DIALOG); $this->initFailed = TRUE; return; }else{ // Merge result with hard coded methods $this->installationMethods = array_merge($this->installationMethods, $res); // Walk through entries and create useful mappings. $this->cfgItemMap = array(); $this->itemConfig = array(); $this->itemsPerMethod = array(); $rootElements = array(); foreach($this->installationMethods as $method => $items){ foreach($items['items'] as $itemName => $item){ $this->itemsPerMethod[$method][] = $itemName; $this->cfgItemMap[$itemName] = $method; $this->itemConfig[$itemName] = &$this->installationMethods[$method]['items'][$itemName]; // This enables us to create the first level of config items when // a release is selected. if($item['name'] == "/" && $itemName != 'root'){ $rootElements = array_merge($rootElements, $item['container']); } } } // Merge in root elements to releases. foreach($this->itemConfig as $item => $data){ if(in_array('__CFG_ITEMS__', $data['container'])){ $this->itemConfig[$item]['container'] = array_merge($this->itemConfig[$item]['container'], $rootElements ); } } } } /*! \brief Updates all distributions, releases, packages and items in the dataModel * Load information from the backend. */ function updateDataModel() { // Recreate the data model, to have a clean and fresh instance. $this->dataModel = new ConfigManagementDataModel(); // Load distributions $rpc = $this->config->getRpcHandle(); $res = $rpc->getDistributions(); if(!$rpc->success()){ msg_dialog::display(_("Error"), sprintf(_("Failed to load distributions: %s"), $rpc->get_error()),ERROR_DIALOG); return(NULL); }else{ foreach($res as $dist){ $this->dataModel->addItem('Distribution','/root', $dist['name'], $dist); if(isset($dist['releases'])){ foreach($dist['releases'] as $release){ $distPath = "/root/{$dist['name']}"; $this->dataModel->addItem('Release',$distPath, $release['name'], $release); } } } } } /*! \brief Keep track of posted values and populate those * which are interesting for us. * Inspects the _POST and _GET values. */ function save_object() { // Update the listing class, this is necessary to get post // actions from it. $this->listing->save_object(); // Get the selected distribution and release from the listing widget. $cont = $this->listing->getSelectedContainer(); if(isset($_POST['ROOT'])){ $this->setCurrentContainer('/root'); }elseif(isset($_POST['BACK'])){ $path = $this->selectedContainer; if($this->dataModel->itemExistsByPath($path)){ $data = $this->dataModel->getItemByPath($path); if($data['parentPath']){ $this->setCurrentContainer($data['parentPath']); } } }else{ $this->setCurrentContainer($cont); } } /*! \brief Load extended sub-objecte like 'config items' or 'packages' * for the given release path. * @param String The release path to load sub-objects for. * @return NULL */ function updateItemList($path) { // Fist get Item and check if it is an release if($this->dataModel->itemExistsByPath($path)){ $data = $this->dataModel->getItemByPath($path); // Only releases can contain config-items. if($data['type'] == 'Release' && $data['status'] != "fetched"){ // Request all config items for the selected release via rpc. $rpc = $this->config->getRpcHandle(); $res = $rpc->listConfigItems($data['name']); if(!$rpc->success()){ msg_dialog::display(_("Error"),sprintf(_("Failed to load distributions: %s"),$rpc->get_error()),ERROR_DIALOG); }else{ // Sort entries by path length $sLen = array(); foreach($res as $itemPath => $type){ $sLen[strlen($itemPath)."_".$itemPath] = $itemPath; } uksort($sLen, "strnatcasecmp"); // Walk through each entry and then try to add it to the model foreach($sLen as $unused => $itemPath){ // Do not add the root element '/' if($itemPath == "/") continue; $type = $res[$itemPath]; // Append the items-path to the current path to create the // effective item path in the data model. $targetPath = trim($path."/".$itemPath); // Remove trailing and duplicated slashes $targetPath = rtrim($targetPath, '/'); $targetPath = preg_replace("/\/\/*/","/", $targetPath); // Extract the items name $name = preg_replace("/^.*\//","", $targetPath); // Cleanup the path and then add the item. $targetPath = preg_replace("/[^\/]*$/","", $targetPath); $targetPath = rtrim($targetPath,'/'); $this->dataModel->addItem($type, $targetPath, $name,array(),'-' ); } $this->dataModel->setItemStatus($path, 'fetched'); } } } } /*! \brief Sets the currently selected container and item path. * @param String The path of the container to set. * @param String The path of the item to set. * @return */ function setCurrentContainer($cont) { $this->selectedContainer = $cont; // Update list of items within the selected container. $this->updateItemList($this->selectedContainer); // Transfer checked values back to the listing class. $this->listing->setContainers($this->getContainerList()); $this->listing->setContainer($cont); // Update the list of addable sub objects $this->addableContainerItems = $this->getAddableContainersPerPath($cont); } function getAddableContainersPerPath($path) { $currentItem = $this->dataModel->getItemByPath($path); $method = $this->getInstallationMethodPerPath($path); // Get allowed items for the currently selected method // merge in root elements, they are allowed everywhere. $allowedItems = $this->itemsPerMethod[$method]; $allowedItems = array_merge($allowedItems, $this->itemsPerMethod['root']); // Get addable items $possibleItems = $this->itemConfig[$currentItem['type']]['container']; return(array_unique(array_intersect($allowedItems, $possibleItems))); } function getInstallationMethodPerPath($path) { $path .= '/'; while(preg_match("/\//", $path)){ $path = preg_replace("/\/[^\/]*$/","",$path); $item = $this->dataModel->getItemByPath($path); if(isset($item['values']['installation_method'])){ return($item['values']['installation_method']); } } return('root'); } /*! \brief Generate the HTML content for this plugin. * Actually renders the listing widget.. */ function execute() { // Get the selected release and store it in a session variable // to allow the configFilter to access it and display the // packages and items. $res = $this->listing->execute(); $this->listing->setListingTypes($this->getListingTypes()); return($res); } /*! \brief Returns a list of items which will then be displayed * in the management-list. * (The management class calls this method from its execute()) * @return Array A list of items/objects for the listing. */ function getItemsToBeDisplayed() { $path = $this->selectedContainer; $item = $this->dataModel->getItemByPath($path); return($item); } /*! \brief Returns a simply list of all distributions. * This list will then be used to generate the entries of the * ItemSelectors in the listing class. */ function getContainerList() { $data = $this->dataModel->getItemByPath('/root'); $res = array(); $res["/root"] = array("name" => "/", "desc" => ""); $res = array_merge($res,$this->__recurseItem($data)); return($res); } /*! \brief Recursivly wlks through an item and collects all path and name info. * The reult can then be used to fill the ItemSelector. * @param Array The Item to recurse. * @param Array The type of of objects to collect. * @param String The parent path prefix which should be removed. * @return Array An array containing Array[path] = name */ function __recurseItem($item, $parent = "") { $res = array(); $path = preg_replace("/".preg_quote($parent,'/')."/","",$item['path']); $res[$path] = array('name' => $item['name'],'desc'=>$item['type']); if(count($item['children'])){ foreach($item['children'] as $child){ $res = array_merge($res, $this->__recurseItem($child, $parent)); } } return($res); } /*! \brief Returns a info list about all items we can manage, * this used to fill the listings settings. * @return Array An array with item info. */ function getListingTypes() { $types= array(); $types['Distribution']['objectClass'] = 'Distribution'; $types['Distribution']['label'] = _('Distribution'); $types['Distribution']['image'] = 'images/lists/edit.png'; $types['Distribution']['category'] = 'Device'; $types['Distribution']['class'] = 'Device'; $types['Release']['objectClass'] = 'Release'; $types['Release']['label'] = _('Release'); $types['Release']['image'] = 'images/lists/delete.png'; $types['Release']['category'] = 'Device'; $types['Release']['class'] = 'Device'; $types['Component']['objectClass'] = 'Component'; $types['Component']['label'] = _('Component'); $types['Component']['image'] = 'plugins/users/images/select_user.png'; $types['Component']['category'] = 'Device'; $types['Component']['class'] = 'Device'; foreach($this->installationMethods as $method => $items){ foreach($items['items'] as $itemName => $item){ $types[$itemName]['objectClass'] = $itemName; $types[$itemName]['label'] = $item['name']; $types[$itemName]['image'] = 'plugins/fai/images/fai_script.png'; $types[$itemName]['category'] = 'Device'; $types[$itemName]['class'] = 'Device'; } } return($types); } /*! \brief The plugins ACL and plugin-property definition. * @return */ public static function plInfo() { return (array( "plShortName" => _("Config management"), "plDescription" => _("Config management"), "plSelfModify" => FALSE, "plDepends" => array(), "plPriority" => 0, "plSection" => array("administration"), "plCategory" => array( "newConfigManagement" => array("description" => _("Config management"), "objectClass" => "FAKE_OC_newConfigManagement")), "plProvidedAcls"=> array() )); } /*! \brief Acts on open requests. * (This action is received from the ConfigManagementListing class.) * @param Array The items ids. (May contain multiple ids) * @return */ function openEntry($ids) { $id = $ids[0]; $item = $this->dataModel->getItemById($id); $this->setCurrentContainer($item['path']); return; } /*! \brief Removes an entry from the listing. */ function removeEntry($ids) { $item = $this->dataModel->getItemById($ids[0]); // Is an config item. if($this->cfgItemMap[$item['type']] != 'root'){ $release = preg_replace("/^.*\//","", $this->getReleasePath($item['path'])); $path = $this->getItemPath($item['path']); $rpc = $this->config->getRpcHandle(); $rpc->removeConfigItem($release, $path); if(!$rpc->success()){ msg_dialog::display(_("Error"), sprintf(_("Failed to remove: %s"), $rpc->get_error()),ERROR_DIALOG); return(NULL); }else{ $this->dataModel->removeItem($item['path']); } }else{ echo $item['type']." - are not handled yet!"; } } /*! \brief Edits a selected list item. */ function editEntry($ids) { $item = $this->dataModel->getItemById($ids[0]); $release = preg_replace("/^.*\//","", $this->getReleasePath($item['path'])); $path = $this->getItemPath($item['path']); $method = $this->cfgItemMap[$item['type']]; // Load item values on demand if($this->cfgItemMap[$item['type']] != 'root'){ if($item['status'] == '-'){ $rpc = $this->config->getRpcHandle(); $item['values'] = $rpc->getConfigItem($release, $path); $this->dataModel->setItemStatus($item['path'], 'fetched'); $this->dataModel->setItemValues($item['path'], $item['values']); } } $this->TemplateEngine->load($this->itemConfig); $this->TemplateEngine->setTemplate($method.".tpl"); $this->TemplateEngine->setValues($item['type'],$item['values']); $this->listing->setDialogObject($this->TemplateEngine); $this->currentObject = $item; } /*! \brief Initiates the creation of a new item */ function newEntry($type) { // We've to add a config item $this->TemplateEngine->load($this->itemConfig); if($this->cfgItemMap[$item['type']] != 'root'){ $method = $this->cfgItemMap[$type]; $this->TemplateEngine->setTemplate($method.".tpl"); $this->TemplateEngine->setValues($type,array()); $this->listing->setDialogObject($this->TemplateEngine); $this->currentObject = NULL; }else{ $this->TemplateEngine->setTemplate("root.tpl"); $this->TemplateEngine->setValues($type,array()); $this->listing->setDialogObject($this->TemplateEngine); $this->currentObject = NULL; } } /*! \brief Extracts the item-path out of a path. * e.g. /debian/squeeze/test/module -> /test/module */ function getItemPath($fullPath) { $fPath = $fullPath.'/'; while(preg_match("/\//", $fPath)){ $fPath = preg_replace("/\/[^\/]*$/","", $fPath); $item = $this->dataModel->getItemByPath($fPath); if(in_array($item['type'], array('Release', 'Distribution', 'root'))){ return(preg_replace("/".preg_quote($item['path'],'/')."/", "", $fullPath)); } } return(NULL); } /*! \brief Extracts the releaes path out of a path. * e.g. /debian/squeeze/test/module -> /debian/squeeze */ function getReleasePath($fullPath) { $fullPath.='/'; while(preg_match("/\//", $fullPath)){ $fullPath = preg_replace("/\/[^\/]*$/","", $fullPath); $item = $this->dataModel->getItemByPath($fullPath); if($item['type'] == 'Release'){ return($fullPath); } } return(NULL); } function saveItemChanges() { $item = $this->currentObject; $type = $this->TemplateEngine->getItemType(); if($this->cfgItemMap[$item['type']] == 'root'){ echo "{$type} Cannot be saved yet"; $this->listing->clearDialogObject(); return; } // Null means a new object has to be added. if($item == NULL){ // Save template engine modifications $this->TemplateEngine->save_object(); $release = preg_replace("/^.*\//","", $this->getReleasePath($this->selectedContainer)); // Collect modified values $values = array(); foreach($this->TemplateEngine->getWidgets() as $w){ $values[$w->getName()] = $w->getValue(); } // Create the elements target path $path = $this->getItemPath($this->selectedContainer)."/".$values['name']; // Add the new item $rpc = $this->config->getRpcHandle(); $res = $rpc->setConfigItem($release, $path, $type, $values); if(!$rpc->success()){ msg_dialog::display(_("Error"), sprintf(_("Failed to load distributions: %s"), $rpc->get_error()),ERROR_DIALOG); return(NULL); }else{ // We've successfully added the item, now add it to the tree. $this->dataModel->addItem($type, $this->selectedContainer, $values['name'],array(), '-' ); // Finally - close the dialog. $this->listing->clearDialogObject(); } }else{ // Collect modified values. $this->TemplateEngine->save_object(); $values = array(); foreach($this->TemplateEngine->getWidgets() as $w){ $values[$w->getName()] = $w->getValue(); } // Get the items release & path info $release = preg_replace("/^.*\//","", $this->getReleasePath($item['path'])); $path = $this->getItemPath($item['path']); // Write the modifications back to the server. $rpc = $this->config->getRpcHandle(); $res = $rpc->setConfigItem($release, $path, $item['type'], $values); if(!$rpc->success()){ msg_dialog::display(_("Error"), sprintf(_("Failed to load distributions: %s"), $rpc->get_error()),ERROR_DIALOG); return(NULL); }else{ // Update the data model $item['values'] = $values; $this->dataModel->setItemValues($item['path'], $item['values']); $this->listing->clearDialogObject(); } } } function remove_lock() {} } ?>