Code

Fixed renaming og items
[gosa.git] / gosa-plugins / goto-ng / admin / newConfigManagement / class_newConfigManagement.inc
1 <?php
3 /*! \brief  This class allows to manage backend config items and packages.
4  */
5 class newConfigManagement extends plugin
6 {
7     var $initTime;
8     var $plHeadline = "Config management";
9     var $plDescription = "Config management";
11     var $selectedContainer;
13     var $dataModel = NULL;
14     var $listing = NULL;
16     var $cfgItemMap = NULL;
18     var $addableContainerItems = array();
19     var $currentObject = NULL;
20     var $itemsPerMethod = NULL;
22     /*! \brief  Initialize the plugin and finally update the data model.
23      */
24     function __construct($config, $dn)
25     {
26         $this->config = &$config;
27         $this->listing = new ConfigManagementListing($this->config, get_userinfo(), $this);
29         // Load the template engine and tell her what template
30         //  to use for the HTML it produces.
31         $this->TemplateEngine = new TemplateEngine($config);
33         // Preset item config - with Distribution and Release objects.
34         $items = array();
35         $items['root']['container'] = array('Distribution');
36         $items['root']['name'] = '/';
37         $items['root']['description'] = _('Root');
39         $items['Distribution']['container'] = array('Release');
40         $items['Distribution']['name'] = 'Distribution';
41         $items['Distribution']['description'] = _('Distribution');
42         $items['Distribution']['options']['name']['description'] = _("Name");
43         $items['Distribution']['options']['name']['default'] = "";
44         $items['Distribution']['options']['name']['value'] = "";
45         $items['Distribution']['options']['name']['required'] = true;
46         $items['Distribution']['options']['name']['type'] = 'string';
47         $items['Distribution']['options']['name']['display'] = _('Name');
48         $items['Distribution']['options']['type']['description'] = _("Distribution type");
49         $items['Distribution']['options']['type']['default'] = "deb";
50         $items['Distribution']['options']['type']['value'] = "deb";
51         $items['Distribution']['options']['type']['values'] = array("deb" => 'deb', "rpm" => 'rpm');
52         $items['Distribution']['options']['type']['required'] = true;
53         $items['Distribution']['options']['type']['type'] = 'combobox';
54         $items['Distribution']['options']['type']['display'] = _('Distribution type');
56         $items['Release']['container'] = array('Release', '__CFG_ITEMS__');
57         $items['Release']['name'] = 'Release';
58         $items['Release']['description'] = _('Release');
59         $items['Release']['options']['name']['description'] = _("Name");
60         $items['Release']['options']['name']['default'] = "";
61         $items['Release']['options']['name']['value'] = "";
62         $items['Release']['options']['name']['required'] = true;
63         $items['Release']['options']['name']['type'] = 'string';
64         $items['Release']['options']['name']['display'] = _('Name');
66         $this->installationMethods = array();
67         $this->installationMethods['root']['description'] = _('root');
68         $this->installationMethods['root']['name'] = 'root';
69         $this->installationMethods['root']['title'] = _('root');
70         $this->installationMethods['root']['items']['Distribution'] = &$items['Distribution'];
71         $this->installationMethods['root']['items']['Release'] = &$items['Release'];
72         $this->installationMethods['root']['items']['root'] = &$items['root'];
74         // Request an update of the data model
75         $this->loadInstallationMethods();
76         $this->updateDataModel();
77         $this->listing->setListingTypes($this->getListingTypes());
78     }
81     /*! \brief  Intializes this plugin
82      *          All available installation methods will be loaded
83      */
84     function loadInstallationMethods()
85     {
86         // Reset erros
87         $this->rpcError = $this->initFailed = FALSE;
89         // Load configuration via rpc.
90         $rpc = $this->config->getRpcHandle();
91         $res = $rpc->getSupportedInstallMethods();
92         if(!$rpc->success()){
93             $this->rpcError = TRUE;
94             $this->errorMessage = $rpc->get_error();;
95             return;
96         }
98         // Populate install methods on success.
99         if(!count($res)){
100             $this->errorMessage = _("No selectable install methods returned!");
101             msg_dialog::display(_("Setup"), $this->errorMessage , ERROR_DIALOG);
102             $this->initFailed = TRUE;
103             return;
104         }else{
106             // Merge result with hard coded methods
107             $this->installationMethods = array_merge($this->installationMethods, $res);
109             // Walk through entries and create useful mappings.
110             $this->cfgItemMap = array();
111             $this->itemConfig = array();
112             $this->itemsPerMethod = array();
113             $rootElements = array();
114             foreach($this->installationMethods as $method => $items){
115                 foreach($items['items'] as $itemName => $item){
116                     $this->itemsPerMethod[$method][] = $itemName;
117                     $this->cfgItemMap[$itemName] = $method;
118                     $this->itemConfig[$itemName] = &$this->installationMethods[$method]['items'][$itemName];
119  
120                     // This enables us to create the first level of config items when 
121                     //  a release is selected.
122                     if($item['name'] == "/" && $itemName != 'root'){
123                         $rootElements = array_merge($rootElements, $item['container']);
124                     }
125                 }
126             }
128             // Merge in root elements to releases.
129             foreach($this->itemConfig as $item => $data){
130                 if(in_array('__CFG_ITEMS__', $data['container'])){
131                     $this->itemConfig[$item]['container'] = array_merge($this->itemConfig[$item]['container'], $rootElements );
132                 }
133             }
134         }
135     }
138     /*! \brief  Updates all distributions, releases, packages and items in the dataModel
139      *          Load information from the backend.
140      */
141     function updateDataModel()
142     {
143         // Recreate the data model, to have a clean and fresh instance.
144         $this->dataModel = new ConfigManagementDataModel();
146         // Load distributions 
147         $rpc = $this->config->getRpcHandle();
148         $res = $rpc->getDistributions();
149         if(!$rpc->success()){
150             msg_dialog::display(_("Error"), sprintf(_("Failed to load distributions: %s"), $rpc->get_error()),ERROR_DIALOG);
151             return(NULL);
152         }else{
153             foreach($res as $dist){
154                 $this->dataModel->addItem('Distribution','/root', $dist['name'], $dist);
155                 if(isset($dist['releases'])){
156                     foreach($dist['releases'] as $release){
157                         $distPath = "/root/{$dist['name']}";
158                         $this->dataModel->addItem('Release',$distPath, $release['name'], $release);
159                     }
160                 }
161             }
162         }
163     }
166     /*! \brief  Keep track of posted values and populate those 
167      *           which are interesting for us.
168      *          Inspects the _POST and _GET values.
169      */
170     function save_object()
171     {
172         // Update the listing class, this is necessary to get post
173         //  actions from it.
174         $this->listing->save_object();
176         // Get the selected distribution and release from the listing widget.
177         $cont = $this->listing->getSelectedContainer();
178         if(isset($_POST['ROOT'])){
179             $this->setCurrentContainer('/root');
180         }elseif(isset($_POST['BACK'])){
181             $path = $this->selectedContainer;
182             if($this->dataModel->itemExistsByPath($path)){
183                 $data = $this->dataModel->getItemByPath($path);
184                 if($data['parentPath']){
185                     $this->setCurrentContainer($data['parentPath']);
186                 }
187             }
188         }else{
189             $this->setCurrentContainer($cont);
190         }
191     }
194     /*! \brief  Load extended sub-objecte like 'config items' or 'packages'
195      *           for the given release path.
196      *  @param  String  The release path to load sub-objects for.
197      *  @return NULL 
198      */
199     function updateItemList($path)
200     {
201         // Fist get Item and check if it is an release 
202         if($this->dataModel->itemExistsByPath($path)){
203             $data = $this->dataModel->getItemByPath($path);
205             // Only releases can contain config-items.
206             if($data['type'] == 'Release' && $data['status'] != "fetched"){
209                 // Request all config items for the selected release via rpc.
210                 $rpc = $this->config->getRpcHandle();
211                 $res = $rpc->listConfigItems($data['name']);
212                 if(!$rpc->success()){
213                     msg_dialog::display(_("Error"),sprintf(_("Failed to load distributions: %s"),$rpc->get_error()),ERROR_DIALOG);
214                 }else{
216                     // Sort entries by path length 
217                     $sLen = array();
218                     foreach($res as $itemPath => $type){
219                         $sLen[strlen($itemPath)."_".$itemPath] = $itemPath;
220                     }
221                     uksort($sLen, "strnatcasecmp");   
223                     // Walk through each entry and then try to add it to the model
224                     foreach($sLen as $unused => $itemPath){
226                         // Do not add the root element '/'
227                         if($itemPath == "/") continue;
229                         $type = $res[$itemPath];
230                 
231                         // Append the items-path to the current path to create the 
232                         //  effective item path in the data model.
233                         $targetPath = trim($path."/".$itemPath);
235                         // Remove trailing and duplicated slashes
236                         $targetPath = rtrim($targetPath, '/');
237                         $targetPath = preg_replace("/\/\/*/","/", $targetPath);
239                         // Extract the items name
240                         $name = preg_replace("/^.*\//","", $targetPath);
241     
242                         // Cleanup the path and then add the item.
243                         $targetPath = preg_replace("/[^\/]*$/","", $targetPath);
244                         $targetPath = rtrim($targetPath,'/');
245                         $this->dataModel->addItem($type, $targetPath, $name,array(),'-' ); 
246                     }
247                     $this->dataModel->setItemStatus($path, 'fetched');
248                 }
249             }
250         }
251     }
254     /*! \brief  Sets the currently selected container and item path. 
255      *  @param  String  The path of the container to set.
256      *  @param  String  The path of the item to set.
257      *  @return 
258      */
259     function setCurrentContainer($cont)
260     {
261         $this->selectedContainer = $cont;
263         // Update list of items within the selected container. 
264         $this->updateItemList($this->selectedContainer);
266         // Transfer checked values back to the listing class.
267         $this->listing->setContainers($this->getContainerList());
268         $this->listing->setContainer($cont);
270         // Update the list of addable sub objects
271         $this->addableContainerItems = $this->getAddableContainersPerPath($cont);
272     }
275     function getAddableContainersPerPath($path)
276     {
277         $currentItem = $this->dataModel->getItemByPath($path);
278         $method = $this->getInstallationMethodPerPath($path);
280         // Get allowed items for the currently selected method 
281         //  merge in root elements, they are allowed everywhere.
282         $allowedItems = $this->itemsPerMethod[$method];
283         $allowedItems = array_merge($allowedItems, $this->itemsPerMethod['root']);
285         // Get addable items
286         $possibleItems = $this->itemConfig[$currentItem['type']]['container'];
287         return(array_unique(array_intersect($allowedItems, $possibleItems)));
288     }
290     
291     function getInstallationMethodPerPath($path)
292     {
293         $path .= '/';
294         while(preg_match("/\//", $path)){
295             $path = preg_replace("/\/[^\/]*$/","",$path);
296             $item = $this->dataModel->getItemByPath($path);
297             if(isset($item['values']['installation_method'])){
298                 return($item['values']['installation_method']);
299             }
300         }
301         return('root'); 
302     }
305     /*! \brief  Generate the HTML content for this plugin.
306      *          Actually renders the listing widget..
307      */
308     function execute()
309     {
310         // Get the selected release and store it in a session variable
311         //  to allow the configFilter to access it and display the
312         //  packages and items.
313         $res = $this->listing->execute();
314         $this->listing->setListingTypes($this->getListingTypes());
315         return($res);
316     }
319     /*! \brief      Returns a list of items which will then be displayed 
320      *               in the management-list. 
321      *              (The management class calls this method from its execute())
322      *  @return     Array   A list of items/objects for the listing. 
323      */
324     function getItemsToBeDisplayed()
325     {
326         $path = $this->selectedContainer;
327         $item = $this->dataModel->getItemByPath($path);
328         return($item);
329     }
332     /*! \brief  Returns a simply list of all distributions.
333      *          This list will then be used to generate the entries of the 
334      *           ItemSelectors in the listing class.
335      */
336     function getContainerList()
337     {
338         $data = $this->dataModel->getItemByPath('/root');
339         $res = array();
340         $res["/root"] = array("name" => "/", "desc" => "");
341         $res = array_merge($res,$this->__recurseItem($data));
342         return($res);
343     }
346     /*! \brief  Recursivly wlks through an item and collects all path and name info.
347      *          The reult can then be used to fill the ItemSelector.
348      *  @param  Array   The Item to recurse. 
349      *  @param  Array   The type of of objects to collect. 
350      *  @param  String  The parent path prefix which should be removed.
351      *  @return Array   An array containing Array[path] = name
352      */
353     function __recurseItem($item, $parent = "")
354     {
355         $res = array();
356         $path = preg_replace("/".preg_quote($parent,'/')."/","",$item['path']);
357         $res[$path] = array('name' => $item['name'],'desc'=>$item['type']);
358         if(count($item['children'])){
359             foreach($item['children'] as $child){
360                 $res = array_merge($res, $this->__recurseItem($child, $parent));
361             }
362         }
363         return($res);
364     }
367     /*! \brief   Returns a info list about all items we can manage,
368      *            this used to fill the listings <objectType> settings.
369      *  @return Array   An array with item info.
370      */
371     function getListingTypes()
372     {
373         $types= array();
374         $types['Distribution']['objectClass'] = 'Distribution';
375         $types['Distribution']['label'] = _('Distribution');
376         $types['Distribution']['image'] = 'images/lists/edit.png';
377         $types['Distribution']['category'] = 'Device';
378         $types['Distribution']['class'] = 'Device';
380         $types['Release']['objectClass'] = 'Release';
381         $types['Release']['label'] = _('Release');
382         $types['Release']['image'] = 'images/lists/delete.png';
383         $types['Release']['category'] = 'Device';
384         $types['Release']['class'] = 'Device';
386         $types['Component']['objectClass'] = 'Component';
387         $types['Component']['label'] = _('Component');
388         $types['Component']['image'] = 'plugins/users/images/select_user.png';
389         $types['Component']['category'] = 'Device';
390         $types['Component']['class'] = 'Device';
392         foreach($this->installationMethods as $method => $items){
393             foreach($items['items'] as $itemName => $item){
394                 $types[$itemName]['objectClass'] = $itemName;
395                 $types[$itemName]['label'] = $item['name'];
396                 $types[$itemName]['image'] = 'plugins/fai/images/fai_script.png';
397                 $types[$itemName]['category'] = 'Device';
398                 $types[$itemName]['class'] = 'Device';
399             }
400         }
402         return($types);
403     }
406     /*! \brief      The plugins ACL and plugin-property definition. 
407      *  @return 
408      */
409     public static function plInfo()
410     {
411         return (array(
412                     "plShortName"   => _("Config management"),
413                     "plDescription" => _("Config management"),
414                     "plSelfModify"  => FALSE,
415                     "plDepends"     => array(),
416                     "plPriority"    => 0,
417                     "plSection"     => array("administration"),
418                     "plCategory"    => array(
419                         "newConfigManagement" => array("description"  => _("Config management"),
420                             "objectClass"  => "FAKE_OC_newConfigManagement")),
421                     "plProvidedAcls"=> array()
422                     ));
423     }
426     /*! \brief  Acts on open requests.
427      *          (This action is received from the ConfigManagementListing class.)
428      *  @param  Array   The items ids. (May contain multiple ids)
429      *  @return
430      */
431     function openEntry($ids)
432     {
433         $id = $ids[0];
434         $item = $this->dataModel->getItemById($id);
435         $this->setCurrentContainer($item['path']);
436         return;
437     }
441     /*! \brief  Removes an entry from the listing.
442      */
443     function removeEntry($ids)
444     {
445         foreach($ids as $id){
446             $item = $this->dataModel->getItemById($id);
448             // Is an config item.
449             if($this->cfgItemMap[$item['type']] != 'root'){
450                 $release = preg_replace("/^.*\//","", $this->getReleasePath($item['path']));
451                 $path = $this->getItemPath($item['path']);
453                 $rpc = $this->config->getRpcHandle();
454                 $rpc->removeConfigItem($release, $path);
455                 if(!$rpc->success()){
456                     msg_dialog::display(_("Error"), sprintf(_("Failed to remove: %s"), $rpc->get_error()),ERROR_DIALOG);
457                     return(NULL);
458                 }else{
459                     $this->dataModel->removeItem($item['path']);
460                 }
461             }else{
462                 echo $item['type']." - are not handled yet!";
463             }
464         }
465     }
468     /*! \brief      Edits a selected list item.
469      */
470     function editEntry($ids)
471     {
472         $item = $this->dataModel->getItemById($ids[0]);
473         $release = preg_replace("/^.*\//","", $this->getReleasePath($item['path']));
474         $path = $this->getItemPath($item['path']);
475         $method = $this->cfgItemMap[$item['type']];
477         // Load item values on demand
478         if($this->cfgItemMap[$item['type']] != 'root'){
479             if($item['status'] == '-'){
480                 $rpc = $this->config->getRpcHandle();
481                 $item['values'] = $rpc->getConfigItem($release, $path);
482                 $this->dataModel->setItemStatus($item['path'], 'fetched');
483                 $this->dataModel->setItemValues($item['path'], $item['values']);
484             }
485         }
487         $this->TemplateEngine->load($this->itemConfig);
488         $this->TemplateEngine->setTemplate($method.".tpl");
489         $this->TemplateEngine->setValues($item['type'],$item['values']);
490         $this->listing->setDialogObject($this->TemplateEngine);
491         $this->currentObject = $item;
492     }
495     /*! \brief  Initiates the creation of a new item
496      */
497     function newEntry($type)
498     {
499         // We've to add a config item
500         $this->TemplateEngine->load($this->itemConfig);
501         if($this->cfgItemMap[$type] != 'root'){
502             $method = $this->cfgItemMap[$type];
503             $this->TemplateEngine->setTemplate($method.".tpl");
504             $this->TemplateEngine->setValues($type,array());
505             $this->listing->setDialogObject($this->TemplateEngine);
506             $this->currentObject = NULL;
507         }else{
508             $this->TemplateEngine->setTemplate("root.tpl");
509             $this->TemplateEngine->setValues($type,array());
510             $this->listing->setDialogObject($this->TemplateEngine);
511             $this->currentObject = NULL;
512         }
513     }
516     /*! \brief  Extracts the item-path out of a path.
517      *          e.g. /debian/squeeze/test/module -> /test/module
518      */
519     function getItemPath($fullPath)
520     {
521         $fPath = $fullPath.'/';
522         while(preg_match("/\//", $fPath)){
523             $fPath = preg_replace("/\/[^\/]*$/","", $fPath);
524             $item = $this->dataModel->getItemByPath($fPath);
525             if(in_array($item['type'], array('Release', 'Distribution', 'root'))){
526                 return(preg_replace("/".preg_quote($item['path'],'/')."/", "", $fullPath));
527             }
528         }
529         return(NULL);
530     }
533     /*! \brief  Extracts the releaes path out of a path.
534      *          e.g. /debian/squeeze/test/module -> /debian/squeeze
535      */
536     function getReleasePath($fullPath)
537     {
538         $fullPath.='/';
539         while(preg_match("/\//", $fullPath)){
540             $fullPath = preg_replace("/\/[^\/]*$/","", $fullPath);
541             $item = $this->dataModel->getItemByPath($fullPath);
542             if($item['type'] == 'Release'){
543                 return($fullPath);
544             }
545         }
546         return(NULL);
547     }
548    
549  
550     function saveItemChanges()
551     {
552         $item = $this->currentObject;
553         $type = $this->TemplateEngine->getItemType();
554         if($this->cfgItemMap[$type] == 'root'){
555             echo "{$type} Cannot be saved yet";
556             $this->listing->clearDialogObject();
557             return;
558         }
560         if($this->cfgItemMap[$type] != 'root'){
562             // Save template engine modifications
563             $this->TemplateEngine->save_object();
564             $release = preg_replace("/^.*\//","", $this->getReleasePath($this->selectedContainer));
566             // Get values to be saved
567             $values = array();
568             foreach($this->TemplateEngine->getWidgets() as $w){
569                 $values[$w->getName()] = $w->getValue();
570             }
571            
572             // Get paths 
573             $newPath = $this->selectedContainer."/".$values['name'];
574             $newItemPath = $this->getItemPath($this->selectedContainer)."/".$values['name'];
575             if($item){
576                 $oldPath = $item['path'];
577                 $oldItemPath = $this->getItemPath($item['path']);
578             }
580             // If this is a new item, then create it now.
581             if($item == NULL){
583                 // Add the new item
584                 $rpc = $this->config->getRpcHandle();
585                 $res = $rpc->setConfigItem($release, $newItemPath, $type, $values);
586                 if(!$rpc->success()){
587                     msg_dialog::display(_("Error"), sprintf(_("Failed to load distributions: %s"), $rpc->get_error()),ERROR_DIALOG);
588                     return(NULL);
589                 }else{
591                     // We've successfully added the item, now add it to the tree.
592                     $this->dataModel->addItem($type, $this->selectedContainer, $values['name'],array(), '-' );
594                     // Finally - close the dialog. 
595                     $this->listing->clearDialogObject();
596                 }
597             }else{
598     
599                 // Write the modifications back to the server.
600                 $rpc = $this->config->getRpcHandle();
601                 $res = $rpc->setConfigItem($release, $oldItemPath, $type, $values);
602                 if(!$rpc->success()){
603                     msg_dialog::display(_("Error"), sprintf(_("Failed to load distributions: %s"), $rpc->get_error()),ERROR_DIALOG);
604                     return(NULL);
605                 }else{
606             
607                     // Update the data model
608                     $item['values'] = $values;
609                     
610                     $this->dataModel->setItemValues($item['path'], $item['values']);
611                     $this->dataModel->moveItem($oldPath, $newPath);
613                     print_a($this);
615                     $this->listing->clearDialogObject();
616                 }
617             }
618         }
619     }
620     function remove_lock() {}
624 ?>