Code

Updated Config Item mangement, we are now able to set Acls
[gosa.git] / gosa-plugins / goto-ng / admin / newConfigManagement / class_ConfigManagement.inc
1 <?php
3 /*! \brief  This class allows to manage backend config items and packages.
4  */
5 class ConfigManagement extends plugin
6 {
7     var $initTime;
8     var $plHeadline = "Config management";
9     var $plDescription = "Config management";
10     var $plIcon = "plugins/goto/images/ConfigManagement.png";
12     var $selectedContainer;
14     var $dataModel = NULL;
15     var $listing = NULL;
17     var $cfgItemMap = NULL;
19     var $addableContainerItems = array();
20     var $currentObject = NULL;
21     var $itemsPerMethod = NULL;
23     var $initFailed = TRUE;
24     var $initialized = FALSE;
25     var $errorMessage = "";
28     /*! \brief  Initialize the plugin and finally update the data model.
29      */
30     function __construct($config, $dn)
31     {
32         $this->config = &$config;
33         $this->listing = new ConfigManagementListing($this->config, get_userinfo(), $this);
35         // Load the template engine and tell her what template
36         //  to use for the HTML it produces.
37         $this->TemplateEngine = new TemplateEngine($config);
38     }
40     
41     function init()
42     {
43         $success = TRUE;
44         $success &= $this->loadInstallationMethods();
45         $success &= $this->updateDataModel();
46         $this->initFailed = !$success;
47         if($success){
48             $this->initialized = TRUE;
49             $this->listing->setListingTypes($this->getListingTypes());
50             $this->setCurrentContainer('/root');
51         }
52     }
55     /*! \brief  Intializes this plugin
56      *          All available installation methods will be loaded
57      */
58     function loadInstallationMethods()
59     {
60         // Get static installation methods.
61         $this->installationMethods = json_decode(file_get_contents(get_template_path('goto/Config/root.json', TRUE)), TRUE);
63         // Load configuration via rpc.
64         $rpc = $this->config->getRpcHandle();
66         // Load some base install parameters
67         $res = $rpc->getSupportedBaseInstallMethods();
68         $baseInstTypes = $installationTypes = $installationMethods = array();
69         foreach($res as $type => $data){
70             $baseInstTypes[$type] = $type;
71             if(isset($data['repositories'])){
72                 foreach($data['repositories'] as $m){
73                     $installationTypes[$m] = $m;
74                 }
75             }
76             if(isset($data['methods'])){
77                 foreach($data['methods'] as $m){
78                     $installationMethods[$m] =$m;
79                 }
80             }
81         }
83         $res = $rpc->getSupportedInstallMethods();
84         if(!$rpc->success()){
85             $this->errorMessage = $rpc->get_error();;
86             return(FALSE);
87         }
89         // Populate install methods on success.
90         if(!count($res)){
91             $this->errorMessage = _("No selectable install methods returned!");
92             return(FALSE);
93         }else{
95             // Merge result with hard coded methods
96             $this->installationMethods = array_merge($this->installationMethods, $res);
98             // Walk through entries and create useful mappings.
99             $this->cfgItemMap = array();
100             $this->itemConfig = array();
101             $this->itemsPerMethod = array();
102             $rootElements = array('Release');
103             foreach($this->installationMethods as $method => $items){
104                 foreach($items['items'] as $itemName => $item){
105                     $this->itemsPerMethod[$method][] = $itemName;
106                     $this->cfgItemMap[$itemName] = $method;
107                     $this->itemConfig[$itemName] = &$this->installationMethods[$method]['items'][$itemName];
108  
109                     // This enables us to create the first level of config items when 
110                     //  a release is selected.
111                     if($item['name'] == "/" && $itemName != 'root'){
112                         $rootElements = array_merge($rootElements, $item['container']);
113                     }
114                 }
115             }
116         }
118         // Fill replacements
119         $map['%ROOT_CFG_ITEMS'] = &$rootElements;
120         $map['%INSTALLATION_TYPES'] = array('dep' => 'dep', 'rpm' => 'rpm');
121         $map['%INSTALLATION_METHODS'] = array('puppet' => 'puppet');
122         $map['%BASE_INSTALLATION_METHODS'] = array('preseed' => 'preseed');
123         $this->itemConfig = $this->__fillPlaceholder($this->itemConfig, $map);
124         return(TRUE);
125     }
128     /*! \brief  Fill in replacements in the itemConfig
129      *          Some values are dynamic and cannot be hardcoded, a placeholder is
130      *           used in this case in the deinition file root.json. 
131      */
132     function __fillPlaceholder($data, $placeholder)
133     {
134         foreach($data as $name => $sData){
135             if(is_array($sData)){
136                 $data[$name] = $this->__fillPlaceholder($data[$name], $placeholder);
137             }elseif(is_string($sData) && isset($placeholder[$sData])){
138                 $data[$name] = &$placeholder[$sData];
139             }
140         }
141         return($data);
142     }
145     /*! \brief  Updates all distributions, releases, packages and items in the dataModel
146      *          Load information from the backend.
147      */
148     function updateDataModel()
149     {
150         // Recreate the data model, to have a clean and fresh instance.
151         $this->dataModel = new ConfigManagementDataModel();
154         // Load templates from the backend and append them on the base 
155         $rpc = $this->config->getRpcHandle();
156         $res = $rpc->installListTemplates();
157         if(!$rpc->success()){
158             $this->errorMessage = sprintf(_("Failed to load templates: %s"), $rpc->get_error());
159             return(FALSE);
160         } 
161         foreach($res as $tName => $tData){
162             $tData['name'] = $tName;
163             $this->dataModel->addItem('Template','/root', $tName, $tData, '-');
164         }
167         // Load distributions 
168         $rpc = $this->config->getRpcHandle();
169         $res = $rpc->getDistributions();
170         if(!$rpc->success()){
171             $this->errorMessage = sprintf(_("Failed to load distributions: %s"), $rpc->get_error());
172             return(FALSE);
173         }else{
174             if(is_array($res)){
176                 foreach($res as $dist){
177            
178                     // Simple strings 
179                     $values = array();
180                     foreach(array('origin','installation_method', 'installation_method','debian_security',
181                             'debian_volatile', 'name', 'mirror_sources', 'managed', 'path') as $attr){
182                         $values[$attr] = $dist[$attr];
183                     }
185                     // Boxed strings
186                     foreach(array('type') as $attr){
187                         $values[$attr] = $dist[$attr]['name'];
188                     }
190                     // Arrays
191                     foreach(array('releases', 'architectures', 'components', 'sections') as $attr){
192                         $values[$attr] = array();
193                         if(is_array($dist[$attr])){
194                             foreach($dist[$attr] as $aEntry){
195                                 $values[$attr][] = $aEntry['name'];
196                             }
197                         }
198                     }
199         
200                     $this->dataModel->addItem('Distribution','/root', $dist['name'], $values);
202                     if(isset($dist['releases'])){
204                         // Sort releases by name length
205                         $sort = array();
206                         foreach($dist['releases'] as $id => $release){
207                             $sort[strlen($release['name']) . $release['name']]  = $id;
208                         }
209                         uksort($sort, "strnatcasecmp");   
211                         // Append release tags
212                         foreach($sort as $id){
213                             $release = $dist['releases'][$id];
214                             $rPath = $release['name'];
215                             $rPath = "/root/{$dist['name']}/$rPath";
216                             $rName = preg_replace("/^.*\//","", $rPath);
217                             $rPath = preg_replace("/\/[^\/]*$/","", $rPath);
218                             $values = array('name' => $rName);
220                             if(!$this->dataModel->itemExistsByPath($rPath)){
221                                 trigger_error("Invalid release name '{$rName}' in path '{$rPath}' received! Skipping entry!");
222                             }else{
223                                 $id = $this->dataModel->addItem('Release',$rPath, $rName, $values);
224                             }
225                         }
226                     }
227                 }
228             }
229         }
230         return(TRUE);
231     }
234     /*! \brief  Keep track of posted values and populate those 
235      *           which are interesting for us.
236      *          Inspects the _POST and _GET values.
237      */
238     function save_object()
239     {
240         // Update the listing class, this is necessary to get post
241         //  actions from it.
242         $this->listing->save_object();
244         // Get the selected distribution and release from the listing widget.
245         $cont = $this->listing->getSelectedContainer();
246         if(isset($_POST['ROOT'])){
247             $this->setCurrentContainer('/root');
248         }elseif(isset($_POST['BACK'])){
249             $path = $this->selectedContainer;
250             if($this->dataModel->itemExistsByPath($path)){
251                 $data = $this->dataModel->getItemByPath($path);
252                 if($data['parentPath']){
253                     $this->setCurrentContainer($data['parentPath']);
254                 }
255             }
256         }else{
257             $this->setCurrentContainer($cont);
258         }
259     }
262     /*! \brief  Load extended sub-objecte like 'config items' or 'packages'
263      *           for the given release path.
264      *  @param  String  The release path to load sub-objects for.
265      *  @return NULL 
266      */
267     function updateItemList($path)
268     {
269         // Fist get Item and check if it is an release 
270         if($this->dataModel->itemExistsByPath($path)){
271             $data = $this->dataModel->getItemByPath($path);
273             // Only releases can contain config-items.
274             if($data['type'] == 'Release' && $data['status'] != "fetched"){
276                 // Request all config items for the selected release via rpc.
277                 $rpc = $this->config->getRpcHandle();
278                 $releasePath = $this->getReleasePart($path);
279                 $res = $rpc->listConfigItems($releasePath);
280                 if(!$rpc->success()){
281                     msg_dialog::display(_("Error"),sprintf(_("Failed to load distributions: %s"),$rpc->get_error()),ERROR_DIALOG);
282                     return;
283                 }else{
284             
285                     if(!$res) return;
287                     // Sort entries by path length 
288                     $sLen = array();
289                     foreach($res as $itemPath => $type){
290                         $sLen[strlen($itemPath)."_".$itemPath] = $itemPath;
291                     }
292                     uksort($sLen, "strnatcasecmp");   
294                     // Walk through each entry and then try to add it to the model
295                     foreach($sLen as $unused => $itemPath){
297                         // Do not add the root element '/'
298                         if($itemPath == "/") continue;
300                         $type = $res[$itemPath];
301                 
302                         // Append the items-path to the current path to create the 
303                         //  effective item path in the data model.
304                         $targetPath = trim($path."/".$itemPath);
306                         // Remove trailing and duplicated slashes
307                         $targetPath = rtrim($targetPath, '/');
308                         $targetPath = preg_replace("/\/\/*/","/", $targetPath);
310                         // Extract the items name
311                         $name = preg_replace("/^.*\//","", $targetPath);
312     
313                         // Cleanup the path and then add the item.
314                         $targetPath = preg_replace("/[^\/]*$/","", $targetPath);
315                         $targetPath = rtrim($targetPath,'/');
316                         $this->dataModel->addItem($type, $targetPath, $name,array(),'-' ); 
317                     }
318                     $this->dataModel->setItemStatus($path, 'fetched');
319                 }
320             }
321         }
322     }
325     /*! \brief  Sets the currently selected container and item path. 
326      *  @param  String  The path of the container to set.
327      *  @param  String  The path of the item to set.
328      *  @return 
329      */
330     function setCurrentContainer($cont)
331     {
332         // Do nothing while the service wasn't initialized.
333         if(!$this->initialized) return;
335         $this->selectedContainer = $cont;
337         // Update list of items within the selected container. 
338         $this->updateItemList($this->selectedContainer);
340         // Transfer checked values back to the listing class.
341         $this->listing->setContainers($this->getContainerList());
342         $this->listing->setContainer($cont);
344         // Update the list of addable sub objects
345         $this->addableContainerItems = $this->getAddableContainersPerPath($cont);
346     }
349     function getAddableContainersPerPath($path)
350     {
351         $currentItem = $this->dataModel->getItemByPath($path);
352         $method = $this->getInstallationMethodPerPath($path);
354         // Get allowed items for the currently selected method 
355         //  merge in root elements, they are allowed everywhere.
356         $allowedItems = $this->itemsPerMethod[$method];
357         $allowedItems = array_merge($allowedItems, $this->itemsPerMethod['root']);
359         // Get addable items
360         $possibleItems = $this->itemConfig[$currentItem['type']]['container'];
361         return(array_unique(array_intersect($allowedItems, $possibleItems)));
362     }
364     
365     function getInstallationMethodPerPath($path)
366     {
367         $path .= '/';
368         while(preg_match("/\//", $path)){
369             $path = preg_replace("/\/[^\/]*$/","",$path);
370             $item = $this->dataModel->getItemByPath($path);
371             if(isset($item['values']['installation_method'])){
372                 return($item['values']['installation_method']);
373             }
374         }
375         return('root'); 
376     }
379     /*! \brief  Generate the HTML content for this plugin.
380      *          Actually renders the listing widget..
381      */
382     function execute()
383     {
384         // Request an update of the data model
385         if(!$this->initialized){
386             $this->init();
387         }
389         // Act on init fails
390         if($this->initFailed){
391             $smarty = get_smarty();
392             $smarty->assign('error', $this->errorMessage);
393             return($smarty->fetch(get_template_path('rpcError.tpl', TRUE)));
394         }else{
396             // Get the selected release and store it in a session variable
397             //  to allow the configFilter to access it and display the
398             //  packages and items.
399             $res = $this->listing->execute();
400             $this->listing->setListingTypes($this->getListingTypes());
401             return($res);
402         }
403     }
406     /*! \brief      Returns a list of items which will then be displayed 
407      *               in the management-list. 
408      *              (The management class calls this method from its execute())
409      *  @return     Array   A list of items/objects for the listing. 
410      */
411     function getItemsToBeDisplayed()
412     {
413         $path = $this->selectedContainer;
414         $item = $this->dataModel->getItemByPath($path);
415         return($item);
416     }
419     /*! \brief  Returns a simply list of all distributions.
420      *          This list will then be used to generate the entries of the 
421      *           ItemSelectors in the listing class.
422      */
423     function getContainerList()
424     {
425         $data = $this->dataModel->getItemByPath('/root');
426         $res = array();
427         $res["/root"] = array("name" => "/", "desc" => "");
428         $res = array_merge($res,$this->__recurseItem($data));
429         return($res);
430     }
433     /*! \brief  Recursivly wlks through an item and collects all path and name info.
434      *          The reult can then be used to fill the ItemSelector.
435      *  @param  Array   The Item to recurse. 
436      *  @param  Array   The type of of objects to collect. 
437      *  @param  String  The parent path prefix which should be removed.
438      *  @return Array   An array containing Array[path] = name
439      */
440     function __recurseItem($item, $parent = "")
441     {
442         $res = array();
443         $path = preg_replace("/".preg_quote($parent,'/')."/","",$item['path']);
444         $res[$path] = array('name' => $item['name'],'desc'=>$item['type']);
445         if(count($item['children'])){
446             foreach($item['children'] as $child){
447                 $res = array_merge($res, $this->__recurseItem($child, $parent));
448             }
449         }
450         return($res);
451     }
454     /*! \brief   Returns a info list about all items we can manage,
455      *            this used to fill the listings <objectType> settings.
456      *  @return Array   An array with item info.
457      */
458     function getListingTypes()
459     {
460         $types= array();
461         $types['Distribution']['objectClass'] = 'Distribution';
462         $types['Distribution']['label'] = _('Distribution');
463         $types['Distribution']['image'] = 'images/lists/edit.png';
464         $types['Distribution']['category'] = 'Device';
465         $types['Distribution']['class'] = 'Device';
467         $types['Release']['objectClass'] = 'Release';
468         $types['Release']['label'] = _('Release');
469         $types['Release']['image'] = 'images/lists/delete.png';
470         $types['Release']['category'] = 'Device';
471         $types['Release']['class'] = 'Device';
473         $types['Component']['objectClass'] = 'Component';
474         $types['Component']['label'] = _('Component');
475         $types['Component']['image'] = 'plugins/users/images/select_user.png';
476         $types['Component']['category'] = 'Device';
477         $types['Component']['class'] = 'Device';
479         foreach($this->installationMethods as $method => $items){
480             foreach($items['items'] as $itemName => $item){
481                 $types[$itemName]['objectClass'] = $itemName;
482                 $types[$itemName]['label'] = $item['name'];
483                 $types[$itemName]['image'] = 'plugins/fai/images/fai_script.png';
484                 $types[$itemName]['category'] = 'Device';
485                 $types[$itemName]['class'] = 'Device';
486             }
487         }
489         return($types);
490     }
493     /*! \brief      The plugins ACL and plugin-property definition. 
494      *  @return 
495      */
496     public static function plInfo()
497     {
498         return (array(
499                     "plShortName"   => _("Config management"),
500                     "plDescription" => _("Config management"),
501                     "plSelfModify"  => FALSE,
502                     "plDepends"     => array(),
503                     "plPriority"    => 0,
504                     "plSection"     => array("administration"),
505                     "plCategory"    => array(
506                         "ConfigManagement" => array("description"  => _("Config management"),
507                             "objectClass"  => "FAKE_OC_ConfigManagement")),
508                     "plProvidedAcls"=> array(
509                             "cfgItem" => _("Config item")
510                         )
511                     ));
512     }
515     /*! \brief  Acts on open requests.
516      *          (This action is received from the ConfigManagementListing class.)
517      *  @param  Array   The items ids. (May contain multiple ids)
518      *  @return
519      */
520     function openEntry($ids)
521     {
522         $id = $ids[0];
523         $item = $this->dataModel->getItemByDn($id);
524         $this->setCurrentContainer($item['path']);
525         return;
526     }
530     /*! \brief  Removes an entry from the listing.
531      */
532     function removeEntry($ids)
533     {
534         foreach($ids as $id){
535             $item = $this->dataModel->getItemByDn($id);
537             // Is an config item.
538             if($this->cfgItemMap[$item['type']] != 'root'){
539                 $release = $this->getReleasePart($item['path']);
540                 $path = $this->getItemPath($item['path']);
541                 $rpc = $this->config->getRpcHandle();
542                 $rpc->removeConfigItem($release, $path);
543                 if(!$rpc->success()){
544                     msg_dialog::display(_("Error"), sprintf(_("Failed to remove: %s"), $rpc->get_error()),ERROR_DIALOG);
545                     return(NULL);
546                 }else{
547                     $this->dataModel->removeItem($item['path']);
548                 }
549             }else{
551                 // Remove distribution
552                 if($item['type'] == 'Distribution'){
554                     $dist = $this->getDistributionPart($item['path']);
555                     $rpc = $this->config->getRpcHandle();
556                     $rpc->removeDistribution($dist, array('recursive' => TRUE));
557                     if(!$rpc->success()){
558                         msg_dialog::display(_("Error"), sprintf(_("Failed to remove the distribution: %s. Error was: %s"), 
559                                     $dist, $rpc->get_error()), ERROR_DIALOG);
560                         return(NULL);
561                     }else{
562                         $this->dataModel->removeItem($item['path']);
563                     }
564                 }elseif($item['type'] == 'Release'){
566                     // Remove release
567                     $release = preg_replace("/^.*\//","", $this->getReleasePart($item['path']));
568                     $rpc = $this->config->getRpcHandle();
569                     $rpc->removeRelease($release, array('recursive' => TRUE));
570                     if(!$rpc->success()){
571                         msg_dialog::display(_("Error"), sprintf(_("Failed to remove the release: %s. Error was: %s"), 
572                                     $release, $rpc->get_error()),ERROR_DIALOG);
573                         return(NULL);
574                     }else{
575                         $this->dataModel->removeItem($item['path']);
576                     }
578                 }elseif($item['type'] == 'Template'){
580                     // Remove Template
581                     $rpc = $this->config->getRpcHandle();
582                     $rpc->installRemoveTemplate($item['name']);
583                     if(!$rpc->success()){
584                         msg_dialog::display(_("Error"), sprintf(_("Failed to remove the template: %s. Error was: %s"), 
585                                     $release, $rpc->get_error()),ERROR_DIALOG);
586                         return(NULL);
587                     }else{
588                         $this->dataModel->removeItem($item['path']);
589                     }
590                 }else{
591                     trigger_error($item['type']." - are not handled yet!");
592                 }
593             }
594         }
595     }
598     /*! \brief  Returns a list of used item names for a given path.
599      */
600     function getUsedNamesForPath($path)
601     {
602         $item = $this->dataModel->getItemByPath($path);
603         $names = array();
604         foreach($item['children'] as $path => $data){
605             $names[] = $data['name'];
606         }
607         return($names);
608     }
611     /*! \brief      Edits a selected list item.
612      */
613     function editEntry($ids)
614     {
615         $item = $this->dataModel->getItemByDn($ids[0]);
617         if(!$item) return;
619         $release = $this->getReleasePart($item['path']);
620         $path = $this->getItemPath($item['path']);
621         $method = $this->cfgItemMap[$item['type']];
623         // Load item values on demand
624         if($this->cfgItemMap[$item['type']] != 'root'){
625             if($item['status'] == '-'){
626                 $rpc = $this->config->getRpcHandle();
627                 $res = $rpc->getConfigItem($release, $path);
628                 if(!$rpc->success()){
629                     msg_dialog::display(_("Error"), sprintf(_("Failed to load config item details: %s"), $rpc->get_error()),ERROR_DIALOG);
630                     return;
631                 }else{
632                     $item['values'] = $res;
633                     $this->dataModel->setItemStatus($item['path'], 'fetched');
634                     $this->dataModel->setItemValues($item['path'], $item['values']);
635                 }
636             }
637         }elseif($item['type'] == 'Template'){
638             if($item['status'] == '-'){
639                 $rpc = $this->config->getRpcHandle();
640                 $res = $rpc->installGetTemplate($item['name']);
641                 if(!$rpc->success()){
642                     msg_dialog::display(_("Error"), sprintf(_("Failed to load template details: %s"), $rpc->get_error()),ERROR_DIALOG);
643                     return;
644                 }else{
645                     $item['values'] = $res;
646                     $this->dataModel->setItemStatus($item['path'], 'fetched');
647                     $this->dataModel->setItemValues($item['path'], $item['values']);
648                 }
649             }
650         }
652         $this->TemplateEngine->load($this->itemConfig);
653         $this->TemplateEngine->setTemplate($method.".tpl");
654         $this->TemplateEngine->editItem($item['type'],$item['values']);
655         $this->listing->setDialogObject($this->TemplateEngine);
656         $this->currentObject = $item;
657     }
660     /*! \brief  Initiates the creation of a new item
661      */
662     function newEntry($type)
663     {
664         // We've to add a config item
665         $this->TemplateEngine->load($this->itemConfig);
666         if($this->cfgItemMap[$type] != 'root'){
667             $method = $this->cfgItemMap[$type];
668             $this->TemplateEngine->setTemplate($method.".tpl");
669             $this->TemplateEngine->createItem($type,array());
670             $this->listing->setDialogObject($this->TemplateEngine);
671             $this->currentObject = NULL;
672         }else{
673             $this->TemplateEngine->setTemplate("root.tpl");
674             $this->TemplateEngine->createItem($type,array());
675             $this->listing->setDialogObject($this->TemplateEngine);
676             $this->currentObject = NULL;
677         }
678     }
681     /*! \brief  Extracts the item-path out of a path.
682      *          e.g. /debian/squeeze/test/module -> /test/module
683      */
684     function getItemPath($fullPath)
685     {
686         $fPath = $fullPath.'/';
687         while(preg_match("/\//", $fPath)){
688             $fPath = preg_replace("/\/[^\/]*$/","", $fPath);
689             $item = $this->dataModel->getItemByPath($fPath);
690             if(in_array($item['type'], array('Release', 'Distribution', 'root'))){
691                 return(preg_replace("/".preg_quote($item['path'],'/')."/", "", $fullPath));
692             }
693         }
694         return(NULL);
695     }
698     /*! \brief  Extracts the releaes path out of a path.
699      *          e.g. /debian/squeeze/test/module -> /debian/squeeze
700      */
701     function getReleasePath($fullPath)
702     {
703         $fullPath.='/';
704         while(preg_match("/\//", $fullPath)){
705             $fullPath = preg_replace("/\/[^\/]*$/","", $fullPath);
706             $item = $this->dataModel->getItemByPath($fullPath);
707             if($item['type'] == 'Release'){
708                 return($fullPath);
709             }
710         }
711         return(NULL);
712     }
713   
714     
715     /*! \brief  Extracts the distribution path out of a path.
716      *          e.g. /root/debian/squeeze/test/module -> /root/debian
717      */
718     function getDistributionPath($fullPath)
719     {
720         $fullPath.='/';
721         while(preg_match("/\//", $fullPath)){
722             $fullPath = preg_replace("/\/[^\/]*$/","", $fullPath);
723             $item = $this->dataModel->getItemByPath($fullPath);
724             if($item['type'] == 'Distribution'){
725                 return($fullPath);
726             }
727         }
728         return(NULL);
729     }
732     /*! \brief  Extracts the distribution-part out of a path.
733      *          e.g. /root/debian/squeeze/test/module -> debian
734      */
735     function getDistributionPart($fullPath)
736     {
737         return(trim(preg_replace("#^/root/#","", $this->getDistributionPath($fullPath)), '/'));
738     }
739     
740     
741     /*! \brief  Extracts the release-part out of a path.
742      *          e.g. /root/debian/squeeze/test/module -> squeeze/test
743      */
744     function getReleasePart($path)
745     {
746         $rPath = $this->getReleasePath($path);
747         $dPath = $this->getDistributionPath($path);
748         return(preg_replace("/^".preg_quote($dPath, '/')."\/?/", "", $rPath));
749     }
750  
751  
752     function saveItemChanges()
753     {
754         // Save template engine modifications and validate values.
755         $this->TemplateEngine->save_object();
756         $msgs = $this->TemplateEngine->check();
758         // Get values to be saved
759         $values = array();
760         foreach($this->TemplateEngine->getWidgets() as $w){
761             $values[$w->getName()] = $w->getValue();
762         }
763            
764         // No input error were found, now check that we do not use the same name twice
765         //  and that it is valid.
766         if(!count($msgs)){
768             // Get used item names for the current path
769             if($this->currentObject){
770     
771                 // Get used item names in the parent path.
772                 $usedNames = $this->getUsedNamesForPath($this->currentObject['parentPath']);
773             }else{
775                 // Get used items for the selected path.
776                 $usedNames = $this->getUsedNamesForPath($this->selectedContainer);
777             }
779             // Allow the item to keep its name.
780             if($this->currentObject != NULL && isset($this->currentObject['values']['name'])){
781                 $usedNames = array_remove_entries(array($this->currentObject['values']['name']), $usedNames);
782             }
783             if(in_array($values['name'],$usedNames)){
784                 $msgs[] = msgPool::duplicated(_("Name"));
785             }
786         }
788         // Display errors
789         if(count($msgs)){
790             msg_dialog::displayChecks($msgs);
791             return;
792         }
794         // Get the item type to be saved
795         $item = $this->currentObject;
796         $type = $this->TemplateEngine->getItemType();
797         if($this->cfgItemMap[$type] == 'root'){
799             // We've to create a new distribution
800             if($type == 'Distribution'){
801                 
802                 // Distributions cannot be renamed!
803                 if(isset($item['name']) && $item['name'] != $values['name']){
804                     msg_dialog::displayChecks(array("Distributions cannot be renamed!"));
805                     return;
806                 }
808                 // Create a new distribution 
809                 if(!$item){
810                     $name = $values['name'];
811                     $itype = $values['installation_type'];
812                     $imethod = $values['installation_method'];
813                     $origin = $values['origin'];
815                     // Initiate the rpc request.
816                     $rpc = $this->config->getRpcHandle();
817                     $res = $rpc->createDistribution($name, $itype, array('mirror'=>$origin, 'install_method' => $imethod));
818                     if(!$rpc->success()){
819                         msg_dialog::display(_("Error"), sprintf(_("Failed to save distributions: %s"), 
820                             $rpc->get_error()),ERROR_DIALOG);
821                         return(NULL);
822                     }
823                 }
825                 // Collect distribution properties
826                 $data = array();
827                 $data['distribution'] = $values['name'];
828                 $data['arch'] = $values['architectures'];
829                 $data['component'] = $values['components'];
830                 $data['mirror_sources'] = $values['mirror_sources'];
832                 // Set distribution properties
833                 $rpc = $this->config->getRpcHandle();
834                 $rpc->setDistribution($data);
835                 if(!$rpc->success()){
836                     msg_dialog::display(_("Error"), sprintf(_("Failed to save distribution properties: %s"), 
837                                 $rpc->get_error()),ERROR_DIALOG);
838                     return(NULL);
839                 }
841                 // We've successfully added the item, now add it to the tree.
842                 $this->dataModel->addItem($type, $this->selectedContainer, $values['name'],$values, '-' );
844                 // Finally - close the dialog. 
845                 $this->listing->clearDialogObject();
847             }elseif($type == 'Release'){
848            
849                 // We've to update a release. 
850                 if($item){
852                     // Check if we've to rename the item.
853                     $path = $this->getReleasePart($item['parentPath']);
854                     $curPath = $this->getReleasePart($item['path']);
855                     $newPath = trim($path."/".$values['name'], '/');
856                     if($curPath != $newPath){
857                         $rpc = $this->config->getRpcHandle();
858                         $res = $rpc->renameRelease($curPath, $newPath);
859                         if(!$rpc->success()){
860                             msg_dialog::display(_("Error"), sprintf(_("Failed to save release: %s"), $rpc->get_error()),ERROR_DIALOG);
861                             return(NULL);
862                         }else{
863                             $nP = $item['parentPath'].'/'.$values['name'];
864                             $this->dataModel->moveItem($item['path'], $nP);
865                             $this->dataModel->setItemValues($nP, $values);
866                             $this->listing->clearDialogObject();
867                         }
868                     }else{
869                         $this->listing->clearDialogObject();
870                     }
871                 
872  
873                 }else{
875                     // Build up the new release path.
876                     $name = $values['name'];
877                     $rPath = $this->getReleasePart($this->selectedContainer);
878                     $newPath = trim($rPath."/".$name, '/');
880                     // Detect the parent distribution
881                     $dist = $this->getDistributionPart($this->selectedContainer);
883                     // Initiate the rpc request.
884                     $rpc = $this->config->getRpcHandle();
885                     $res = $rpc->createRelease($dist, $newPath);
886                     if(!$rpc->success()){
887                         msg_dialog::display(_("Error"), sprintf(_("Failed to save release: %s"), $rpc->get_error()),ERROR_DIALOG);
888                         return(NULL);
889                     }else{
891                         // We've successfully added/saved the item, now add it to the tree.
892                         $this->dataModel->addItem($type, $this->selectedContainer, $values['name'],$values, '-' );
893                         $this->listing->clearDialogObject();
894                     }
895                 }
896             }elseif($type == "Template"){
898                     // Initiate the rpc request.
899                     $rpc = $this->config->getRpcHandle();
900                     $res = $rpc->installSetTemplate($values['name'], $values);
901                     if(!$rpc->success()){
902                         msg_dialog::display(_("Error"), sprintf(_("Failed to save template: %s"), $rpc->get_error()),ERROR_DIALOG);
903                         return(NULL);
904                     }else{
905                         
906                         // We've successfully added/saved the item, now add it to the tree.
907                         if(!$item){
908                             $this->dataModel->addItem($type, $this->selectedContainer, $values['name'],$values, '-' );
909                             $this->listing->clearDialogObject();
910                         }else{
912                             // Update the model and clear the dialogs 
913                             $path = $item['path'];
914                             $this->dataModel->setItemValues($path, $values);
915                             $this->listing->clearDialogObject();
916                         }
917                     }
918                 
919             }else{
920                 echo "{$type} Cannot be saved yet";
921                 $this->listing->clearDialogObject();
922                 return;
923             }
924         }
926         // Save a CONFIG-ITEM object.
927         if($this->cfgItemMap[$type] != 'root'){
929             // Get paths 
930             $release =  $this->getReleasePart($this->selectedContainer);
932             if($item){
933                 $oldPath = $item['path'];
934                 $oldItemPath = $this->getItemPath($item['path']);
935                 $newPath = $item['parentPath']."/".$values['name'];
936                 $newItemPath = $this->getItemPath($newPath);
937             }else{
938                 $newPath = $this->selectedContainer."/".$values['name'];
939                 $newItemPath = $this->getItemPath($this->selectedContainer)."/".$values['name'];
940             }
942             // If this is a new item, then create it now.
943             if($item == NULL){
945                 // Add the new item
946                 $rpc = $this->config->getRpcHandle();
947                 $res = $rpc->setConfigItem($release, $newItemPath, $type, $values);
948                 if(!$rpc->success()){
949                     msg_dialog::display(_("Error"), sprintf(_("Failed to save %s: %s"),$type, $rpc->get_error()),ERROR_DIALOG);
950                     return(NULL);
951                 }else{
953                     // We've successfully added the item, now add it to the tree.
954                     $this->dataModel->addItem($type, $this->selectedContainer, $values['name'],array(), '-' );
956                     // Finally - close the dialog. 
957                     $this->listing->clearDialogObject();
958                 }
959             }else{
961                 // Write the modifications back to the server.
962                 $rpc = $this->config->getRpcHandle();
963                 $res = $rpc->setConfigItem($release, $oldItemPath, $type, $values);
964                 if(!$rpc->success()){
965                     msg_dialog::display(_("Error"), sprintf(_("Failed to save config item: %s"), $rpc->get_error()),ERROR_DIALOG);
966                     return(NULL);
967                 }else{
968             
969                     // Update the data model
970                     $this->dataModel->setItemValues($oldPath, $values);
971                     if($oldPath != $newPath){
972                         $this->dataModel->moveItem($oldPath, $newPath);
973                     }
974                     $this->listing->clearDialogObject();
975                 }
976             }
977         }
978     }
979     function remove_lock() {}
983 ?>