1 <?php
3 /*! \brief A GOsa plugin which generates a device configuration dialog
4 */
5 class ConfigManagement extends management
6 {
8 // Used to render the item-configuration dialog
9 private $TemplateEngine = NULL;
11 // A list of all configured items for this device.
12 private $allConfiguredItems = array();
14 // The currently active item
15 // Add add and remove action will be performed on this item
16 private $currentItem = array();
18 // A baseSelector which will be fed with a simulated
19 // department list. All entries will get a fake base
20 // which can then be used to fill the baseSelector widget.
21 private $itemContainerSelector = NULL;
23 // The currently selected base within management list.
24 private $base ;
26 // This array contains a list of all item-types we can add
27 // to the currently selected item (currentItem)
28 private $addableContainerItems = array();
30 // Due to the fakt that we use a fake 'base/dn' for all items
31 // we've to map this 'base/dn' to the items 'id'.
32 private $mappingBaseToID = array();
34 private $rootItemID;
35 private $itemConfig = array();
36 private $lastItemID = 1;
38 private $rpcError = FALSE;
39 private $initFailed = FALSE;
40 private $invalidInstallMethod = FALSE;
41 private $errorMessage = "";
43 // Some plugin related memebers which are not member of
44 // the management class. See class plugin.
45 public $initTime;
46 public $ignore_account = FALSE;
47 public $pl_notify;
48 public $read_only;
50 public $allItemConfigurations = NULL;
52 /*! \brief Constructs the device configuration plugin
53 * @param Config The GOsa configuration object.
54 */
55 function __construct(&$config, $dn)
56 {
57 // Load the template engine and tell her what template
58 // to use for the HTML it produces.
59 $this->TemplateEngine = new TemplateEngine($config);
60 $this->TemplateEngine->setTemplate('puppet.tpl');
61 $this->config = $config;
63 // Set storage points - We do not have any - We just create a fake list which lists all items
64 $this->storagePoints = array("");
66 // Try to initialize
67 $this->init();
68 $this->setInstallMethod('puppet');
69 $this->rebuildListing();
70 }
73 /*! \brief Sets the installation method to the given method.
74 * Updates the template engine and adds the initial root
75 * object for the selected method.
76 * @param The method to use.
77 * @return TRUE on success else FALSE.
78 */
79 function setInstallMethod($str)
80 {
81 if(!isset($this->allItemConfigurations[$str])){
82 $this->itemConfig = array();
83 $this->invalidInstallMethod =TRUE;
84 $this->errorMessage = sprintf(_("Invalid installation method %s selected!"), bold($str));
85 msg_dialog::display(_("Setup"), $this->errorMessage, ERROR_DIALOG);
86 return(FALSE);
87 }else{
89 $this->itemConfig = $this->allItemConfigurations[$str]['items'];
90 $this->invalidInstallMethod =FALSE;
91 $this->TemplateEngine->load($this->itemConfig);
93 // Detect root item, its name is /
94 $root = NULL;
95 foreach($this->itemConfig as $key => $item){
96 if($item['name'] == '/') {
97 $root = $key;
98 break;
99 }
100 }
101 if(!$root){
102 $this->errorMessage = sprintf(_("Installation method %s is invalid: no root object found!"), bold($str));
103 msg_dialog::display(_("Setup"), $this->errorMessage , ERROR_DIALOG);
104 $this->initFailed = TRUE;
105 $this->itemConfig = array();
106 return(FALSE);
107 }
109 // Set current item to 'root', this is the minimum to get things running.
110 $idRoot = $this->addItem($root,'root',array());
111 $this->rootItemID = $idRoot;
112 $this->setCurrentItem($idRoot);
113 $this->setSelectedListItemID($idRoot);
114 $this->rebuildListing();
115 return(TRUE);
116 }
117 }
120 /*! \brief Intializes this plugin
121 * All available installation methods will be loaded
122 * and populated.
123 */
124 function init()
125 {
126 // Reset erros
127 $this->rpcError = $this->initFailed = FALSE;
129 // Load configuration via rpc.
130 $rpc = $this->config->getRpcHandle();
132 // Populate install methods on success.
133 $res = $rpc->getSupportedInstallMethods();
134 if(!$rpc->success()){
135 $this->rpcError = TRUE;
136 $this->errorMessage = $rpc->get_error();;
137 return;
138 }
139 $this->allItemConfigurations = $res;
140 if(!count($this->allItemConfigurations)){
141 $this->errorMessage = _("No selectable install methods available!");
142 msg_dialog::display(_("Setup"), $this->errorMessage , ERROR_DIALOG);
143 $this->initFailed = TRUE;
144 return;
145 }
146 }
149 /*! \brief Add a new child-item to the currently selected one.
150 *
151 * @param String type The 'type' of the new object, eg. 'KickstartTemplate'
152 * @param String name The 'name' of the new object.
153 * @param Array values The initial values for this object.
154 * @return
155 */
156 function addItem($type,$name, $values = array())
157 {
158 if(!isset($this->itemConfig[$type])){
159 echo "Invalid type {$type}, skipping item!<br>";
160 return;
161 }
163 // Add missing values with the item-type defaults.
164 $allValuesSet = TRUE;
165 foreach($this->itemConfig[$type]['options'] as $oName => $oValue){
166 if(!isset($values[$oName])){
167 $values[$oName] = (isset($oValue['default']))?$oValue['default']:"";
168 }
169 }
171 // Get the currently selected entry, its the parent for the newly
172 // added one.
173 $current = &$this->currentItem;
175 // Create a FAKE base to be able to use the management lists
176 // which are currently ldap and thus dn based.
177 $base = (isset($current['base']))? ",".$current['base'] : '';
178 $base = "{$type}={$name}{$base}";
181 if(isset($this->mappingBaseToID[$base])){
182 echo "Cannot add entry, dn already in use! {$base}<br>";
183 return(null);
184 }
186 // Get next free item slot.
187 $id = ($this->lastItemID ++);
188 $new = array(
189 'base' => $base,
190 'children' => array(),
191 'id' => $id,
192 'type' => $type,
193 'name' => $name,
194 'values' => $values);
196 // Append the entry to the list of all items.
197 $this->allConfiguredItems[$id] = $new;
199 // Create a child referenc, this creates some kind of entry tree.
200 $current['children'][$id] = &$this->allConfiguredItems[$id];
202 // Add entries to the list of base and id mappings
203 // this allows us to easily detect the base for an id and vice versa.
204 $this->mappingBaseToID[$id] = $base;
205 $this->mappingBaseToID[$base] = $id;
206 return($id);
207 }
210 /*! \brief Selects an item as active.
211 * All further add and remove actions will be performed
212 * on the obejcts children.
213 * @param String The 'id' of the item we want to select.
214 * @return
215 */
216 function setCurrentItem($item)
217 {
218 if(!isset($this->allConfiguredItems[$item])){
219 echo "Invalid item name {$name}! Skipping selection!";
220 return;
221 }
223 // Set the new item info.
224 $this->currentItem = &$this->allConfiguredItems[$item];
225 $this->currentItemType = $this->currentItem['type'];
226 $this->currentItemDescriptor = $this->itemConfig[$this->currentItem['type']];
227 }
230 /*! \brief Removes a given item ID.
231 * @param String The 'id' of the item we want to remove.
232 * @return
233 */
234 function removeItem($id, &$data = NULL)
235 {
236 if($data === NULL){
237 $data = &$this->allConfiguredItems;
238 }
240 // Remove the item and its children
241 if(isset($data[$id])){
242 foreach($data[$id]['children'] as $cid => $item){
243 $this->removeItem($cid, $data);
244 }
245 unset($data[$id]);
246 }
248 // Remove to current id from sub entries
249 foreach($data as $key => $item){
250 $this->removeItem($id, $data[$key]['children']);
251 }
252 }
255 /*! \brief Initiate item edit.
256 * An action send from the management list.
257 * @param See management::editEntry
258 * @return
259 */
260 function editEntry($action="",$target=array(),$all=array(),
261 $altTabClass ="", $altTabType = "", $altAclCategory="")
262 {
263 $this->setCurrentItem($target[0]);
264 $this->dialogObject = $this->TemplateEngine;
265 $this->skipFooter = TRUE;
266 $this->dialog = TRUE;
268 // Update the template engine to use another type of item and
269 // some other values.
270 $this->TemplateEngine->setValues($this->currentItemType,$this->currentItem['values']);
271 }
274 /*! \brief Save changes for the currently edited item.
275 */
276 function saveItemChanges()
277 {
278 // Save eventually changed values
279 if($this->currentItem){
281 // Check if everything is fine.
282 $msgs = $this->TemplateEngine->save_object();
283 $msgs = $this->TemplateEngine->check();
284 if(count($msgs)){
285 msg_dialog::displayChecks($msgs);
286 }else{
287 foreach($this->TemplateEngine->getWidgets() as $widget){
288 $this->currentItem['values'][$widget->getName()] = $widget->getValue();
289 }
290 $this->closeDialogs();
291 }
292 }
293 }
296 /*! \brief React on open requests from the management list
297 */
298 function openEntry($action="",$target=array(),$all=array(),
299 $altTabClass ="", $altTabType = "", $altAclCategory="")
300 {
301 $this->setSelectedListItemID($target[0]);
302 }
305 /*! \brief Overridden render method of class mangement.
306 * this allows us to add a release selection box.
307 */
308 function renderList()
309 {
310 // In case of an error abort here.
311 if($this->rpcError || $this->initFailed || $this->invalidInstallMethod){
312 $smarty = get_smarty();
313 $smarty->assign('initFailed', $this->initFailed);
314 $smarty->assign('rpcError', $this->rpcError);
315 $smarty->assign('invalidInstallMethod', $this->invalidInstallMethod);
316 $smarty->assign('error', $this->errorMessage);
317 return($smarty->fetch(get_template_path('failed.tpl', TRUE)));
318 }
320 // Collect item container list to be able to render the fake-base selector
321 if(!$this->itemContainerSelector){
322 $this->itemContainerSelector = new releaseSelector(
323 $this->getContainerList(),
324 $this->base,
325 $this->allConfiguredItems[$this->rootItemID]['base']);
326 }else{
327 $this->itemContainerSelector->setBases($this->getContainerList());
328 }
329 $this->itemContainerSelector->update(true);
330 $this->itemContainerSelector->setBase($this->base);
332 session::set('DEVICE_ITEMS', $this->allConfiguredItems);
333 $this->rebuildListing();
334 $filter = $this->getFilter();
335 $headpage = $this->getHeadpage();
337 $headpage->update();
338 $smarty = get_smarty();
339 $smarty->assign("RELEASE", $this->itemContainerSelector->render());
340 $display = $headpage->render();
341 return($this->getHeader().$display);
342 }
345 /*! \brief Build up a list of items useable for the itemSelector.
346 */
347 function getContainerList($array = NULL)
348 {
349 $array = ($array == NULL)?$this->allConfiguredItems[$this->rootItemID]: $array;
350 $ret[$array['base']] = $array['type'];
351 if(count($array['children'])){
352 foreach($array['children'] as $subItem){
353 $ret = array_merge($ret, $this->getContainerList($subItem));
354 }
355 }
356 return($ret);
357 }
360 /*! \brief Update the management class and tell her which
361 * items are available for the itemSelector (baseSelector).
362 */
363 function rebuildListing()
364 {
365 // Build filter
366 if (session::global_is_set(get_class($this)."_filter")){
367 $filter= session::global_get(get_class($this)."_filter");
368 } else {
369 $filter = new filter(get_template_path("DeviceConfig-filter.xml", true));
370 $filter->setObjectStorage($this->storagePoints);
371 }
372 $this->setFilter($filter);
374 // Load service xml file and fill in placeholders
375 $contents =file_get_contents(get_template_path("DeviceConfig-list.xml", true));
377 // Build up device-list configuration
378 $types ="";
379 $images = array();
380 $images[] = 'images/lists/edit.png';
381 $images[] = 'images/caps.png';
382 $images[] = 'images/lists/trash.png';
383 $images[] = 'images/filter.png';
384 $images[] = 'images/find.png';
385 $i = 0;
386 foreach($this->itemConfig as $type => $item){
387 $desc = $item['description'];
388 $img = $images[$i++];
389 $types .=
390 " <objectType>".
391 " <label>{$desc}</label>".
392 " <objectClass>{$type}</objectClass>".
393 " <category>Device</category>".
394 " <class>dummy</class>".
395 " <image>{$img}</image>".
396 " </objectType>";
397 }
398 $contents = preg_replace("/%TYPES%/", $types, $contents);
401 $items = "";
402 $i = 0;
403 foreach($this->addableContainerItems as $item){
404 $desc = $this->itemConfig[$item]['description'];
405 $img = $images[$i++];
406 $items .=
407 "<action>".
408 " <name>add_{$item}</name>".
409 " <type>entry</type>".
410 " <image>{$img}</image>".
411 " <label>{$desc}</label>".
412 "</action>";
413 }
415 if(!empty($items)){
416 $items =
418 "<action>".
419 " <type>sub</type>".
420 " <image>images/lists/element.png[new]</image>".
421 " <label>Create</label>".
422 " {$items}".
423 "</action>";
424 }
426 $contents = preg_replace("/%ITEMS%/", $items, $contents);
428 $headpage = new listing($contents,TRUE);
429 $headpage->setBase($this->base);
430 $headpage->setFilter($filter);
432 parent::__construct($this->config, $this->ui, "services", $headpage);
434 // Register default actions
435 $this->registerAction("new", "newEntry");
436 $this->registerAction("edit", "openEntry"); // !! We forward 'edit' to 'open' to have a department like navigation.
437 $this->registerAction("editEntry", "editEntry");
439 $this->registerAction("saveItemChanges", "saveItemChanges");
440 $this->registerAction("cancelItemEdit", "closeDialogs");
441 $this->registerAction("cancelItemAdd", "closeDialogs");
442 $this->registerAction("saveItemAdd", "saveItemAdd");
443 foreach($this->itemConfig as $name => $item){
444 $this->registerAction("add_{$name}", "newEntry");
445 }
446 }
449 /*! \brief This method intiates the object creation.
450 *
451 * @param String 'action' The name of the action which was the used as trigger.
452 * @param Array 'target' A list of object dns, which should be affected by this method.
453 * @param Array 'all' A combination of both 'action' and 'target'.
454 */
455 function newEntry($action="",$target=array(),$all=array(),
456 $altTabClass ="", $altTabType = "", $altAclCategory="")
457 {
458 $toAdd = preg_replace("/^add_/", "",$action);
459 $itemToAdd = $this->itemConfig[$toAdd];
461 $this->dialogObject = new AddItemDialog($this->config,$toAdd,$itemToAdd);
462 $this->dialog = true;
463 }
466 /*! \brief Saves newly created items and adds them as child to
467 * the currently selected item.
468 */
469 function saveItemAdd()
470 {
471 if(!$this->dialogObject instanceOf AddItemDialog) return;
473 $msgs = $this->dialogObject->save_object();
474 $msgs = $this->dialogObject->check();
475 if(count($msgs)){
476 msg_dialog::displayChecks($msgs);
477 }else{
478 $itemName = $this->dialogObject->getName();
479 $itemCfg = $this->dialogObject->getItemCfg();
480 $itemType = $this->dialogObject->getItemType();
482 $this->setCurrentItem($this->mappingBaseToID[$this->base]);
484 $this->addItem($itemType, $itemName);
485 $this->closeDialogs();
487 # $this->setCurrentItem($itemName);
488 # $this->dialogObject = $this->TemplateEngine;
489 # $this->skipFooter = TRUE;
490 # $this->dialog = TRUE;
492 }
493 }
496 /*! \brief Keep track of posted values, some may be interesting for us.
497 * Tell the template engine to take care of posted values too.
498 * @param String
499 * @return
500 */
501 function save_object()
502 {
503 if(isset($_POST['retryInit'])){
504 $this->init();
505 return;
506 }
508 // Do nothing else in case of an error
509 if($this->rpcError || $this->initFailed) return;
511 // Add sub-module requested.
512 if(isset($_POST['addSubModule']) && isset($_POST['subModule'])){
513 $sub = get_post('subModule');
514 if(in_array_strict($sub, $this->currentItemDescriptor['container'])){
516 // Check if this is a valid item
517 if(!isset($this->itemConfig[$sub])) {
518 echo "Invalid item type '{$sub}'!";
519 $values = array();
520 }else{
521 $values = $this->itemConfig[$sub]['options'];
522 }
523 $name = 'test'.rand(0,99999);
524 $this->addItem($sub,$name,$values);
525 }
526 }
528 // Get the selected item-id from the item list and populate it.
529 if($this->itemContainerSelector){
530 $this->itemContainerSelector->update();
531 $id = $this->mappingBaseToID[$this->itemContainerSelector->getBase()];
532 $this->setSelectedListItemID($id);
533 }
534 }
537 /* \brief Updates the currenlty seleted item in the management list
538 */
539 function setSelectedListItemID($id)
540 {
541 $this->base = $this->mappingBaseToID[$id];
542 $type = $this->allConfiguredItems[$id]['type'];
543 $this->addableContainerItems = $this->itemConfig[$type]['container'];
544 }
547 /*! \brief Forward plugin acls
548 */
549 function set_acl_base($base)
550 {
551 $this->acl_base = $base;
552 }
555 /*! \brief Forward plugin acls
556 */
557 function set_acl_category($category)
558 {
559 $this->acl_category = $category;
560 }
562 function save()
563 {
564 foreach($this->allConfiguredItems as $name => $item){
565 foreach($item['values'] as $oName => $oValue){
566 if(!is_array($oValue)) $oValue = array($oValue);
567 foreach($oValue as $val){
568 echo "<br>{$name} -- <i>{$item['type']}</i>: <b>{$oName}</b>: {$val}";
569 }
570 }
571 }
572 }
575 /*! \brief Initiates the removal for the given entries
576 * and displays a confirmation dialog.
577 *
578 * @param String 'action' The name of the action which was the used as trigger.
579 * @param Array 'target' A list of object dns, which should be affected by this method.
580 * @param Array 'all' A combination of both 'action' and 'target'.
581 */
582 protected function removeEntryRequested($action="",$target=array(),$all=array())
583 {
584 foreach($target as $id){
585 $this->removeItem($id);
586 }
587 }
590 // Inject user actions
591 function detectPostActions()
592 {
593 if($this->rpcError || $this->initFailed) return(array('action' => ''));
595 $action = management::detectPostActions();
596 if(isset($_POST['saveItemEdit'])) $action['action'] = "saveItemChanges";
597 if(isset($_POST['saveItemAdd'])) $action['action'] = "saveItemAdd";
598 if(isset($_POST['cancelItemEdit'])) $action['action'] = "cancelItemEdit";
599 if(isset($_POST['cancelItemAdd'])) $action['action'] = "cancelItemAdd";
600 return($action);
601 }
604 function closeDialogs()
605 {
606 parent::closeDialogs();
607 $this->dialog = false;
608 }
611 function check()
612 {
613 return(array());
614 }
616 function getRootItemId()
617 {
618 return($this->rootItemID);
619 }
622 public static function plInfo()
623 {
624 return (array(
625 "plShortName" => _("Config management"),
626 "plDescription" => _("Config management"),
627 "plSelfModify" => FALSE,
628 "plDepends" => array(),
629 "plPriority" => 0,
630 "plSection" => array("administration"),
631 "plCategory" => array(
632 "ConfigManagement" => array("description" => _("Config management"),
633 "objectClass" => "FAKE_OC_ConfigManagement")),
634 "plProvidedAcls"=> array()
635 ));
636 }
637 }
638 ?>