1 <?php
2 /*
3 * This code is part of GOsa (http://www.gosa-project.org)
4 * Copyright (C) 2003-2008 GONICUS GmbH
5 *
6 * ID: $$Id$$
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
21 */
23 class management
24 {
25 // Public
26 public $config = null;
27 public $ui = null;
29 // The plugin description
30 public $plugname = "unconfigured";
31 public $plIcon = "unconfigured";
32 public $plDescription = "unconfigured";
33 public $plHeadline = "unconfigured";
35 // The currently used object(s) (e.g. in edit, removal)
36 public $dn = ""; // this is public due to some compatibility problems with class plugin..
37 protected $dns = array();
39 // The last used object(s).
40 protected $last_dn = "";
41 protected $last_dns = array();
43 // The common places the displayed objects are stored in. (e.g. array("ou=groups,",".."))
44 protected $storagePoints = array();
46 // The tab definitions to use for the current object.
47 protected $tabClass = ""; // e.g. usertabs
48 protected $tabType = ""; // e.g. USERTABS
49 protected $aclPlugin = ""; // e.g. generic
50 protected $aclCategory = ""; // e.g. users
51 protected $objectName = ""; // e.g. users
53 // The opened object.
54 protected $tabObject = null;
55 protected $dialogObject = null;
57 // The last opened object.
58 protected $last_tabObject = null;
59 protected $last_dialogObject = null;
61 // Whether to display the apply button or not
62 protected $displayApplyBtn = FALSE;
64 // Whether to display a header or not.
65 protected $skipHeader = false;
67 // Whether to display a footer or not.
68 protected $skipFooter = false;
70 // Copy&Paste handler
71 protected $cpHandler = null;
73 // Indicates that we want to paste objects right now.
74 protected $cpPastingStarted = FALSE;
76 // The Snapshot handler class.
77 protected $snapHandler = null;
79 // The listing handlers
80 private $headpage = null;
81 private $filter = null;
83 // A list of configured actions/events
84 protected $actions = array();
86 // Attributes managed by this plugin, can be used in post events;
87 public $attributes = array();
89 function __construct(&$config,$ui,$plugname, $headpage)
90 {
91 $this->plugname = $plugname;
92 $this->headpage = $headpage;
93 $this->ui = $ui;
94 $this->config = $config;
95 $this->initTime = microtime(TRUE);
97 stats::log('management', $class = get_class($this), $action = __FUNCTION__, $amount = 1,
98 $duration = (microtime(TRUE) - $this->initTime));
100 if($this->cpHandler) $this->headpage->setCopyPasteHandler($this->cpHandler);
101 if($this->snapHandler) $this->headpage->setSnapshotHandler($this->snapHandler);
103 if(empty($this->plIcon)){
104 $this->plIcon = "plugins/".$plugname."/images/plugin.png";
105 }
107 // Register default actions
108 $this->registerAction("new", "newEntry");
109 $this->registerAction("edit", "editEntry");
110 $this->registerAction("apply", "applyChanges");
111 $this->registerAction("save", "saveChanges");
112 $this->registerAction("cancel", "cancelEdit");
113 $this->registerAction("cancelDelete", "cancelEdit");
114 $this->registerAction("remove", "removeEntryRequested");
115 $this->registerAction("removeConfirmed", "removeEntryConfirmed");
117 $this->registerAction("copy", "copyPasteHandler");
118 $this->registerAction("cut", "copyPasteHandler");
119 $this->registerAction("paste", "copyPasteHandler");
121 $this->registerAction("snapshot", "createSnapshotDialog");
122 $this->registerAction("restore", "restoreSnapshotDialog");
123 $this->registerAction("saveSnapshot","saveSnapshot");
124 $this->registerAction("restoreSnapshot","restoreSnapshot");
125 $this->registerAction("removeSnapshotConfirmed","removeSnapshotConfirmed");
126 $this->registerAction("cancelSnapshot","closeDialogs");
128 $this->registerAction("config-filter","editFilter");
129 $this->registerAction("saveFilter","saveFilter");
130 $this->registerAction("cancelFilter","cancelFilter");
132 // To temporay disable the filter caching UNcomment this line.
133 #session::global_un_set(get_class($this)."_filter");
134 }
136 /*! \brief Execute this plugin
137 * Handle actions/events, locking, snapshots, dialogs, tabs,...
138 */
139 function execute()
140 {
141 // Ensure that html posts and gets are kept even if we see a 'Entry islocked' dialog.
142 $vars = array('/^act$/','/^listing/','/^PID$/','/^FILTER_PID$/');
143 session::set('LOCK_VARS_TO_USE',$vars);
145 pathNavigator::registerPlugin($this);
147 /* Display the copy & paste dialog, if it is currently open */
148 $ret = $this->copyPasteHandler("",array());
149 if($ret){
150 return($this->getHeader().$ret);
151 }
153 // Update filter
154 if ($this->filter) {
155 $this->filter->update();
156 session::global_set(get_class($this)."_filter", $this->filter);
157 session::set('autocomplete', $this->filter);
158 }
160 // Handle actions (POSTs and GETs)
161 $str = $this->handleActions($this->detectPostActions());
162 if($str) return($this->getHeader().$str);
164 // Open single dialog objects
165 if(is_object($this->dialogObject)){
166 if(method_exists($this->dialogObject,'save_object')) $this->dialogObject->save_object();
167 if(method_exists($this->dialogObject,'execute')){
168 $display = $this->dialogObject->execute();
169 $display.= $this->_getTabFooter();
170 return($this->getHeader().$display);
171 }
172 }
174 // Display tab object.
175 if($this->tabObject instanceOf tabs || $this->tabObject instanceOf multi_plug){
176 # $this->tabObject->save_object();
177 $display = $this->tabObject->execute();
178 $display.= $this->_getTabFooter();
179 return($this->getHeader().$display);
180 }
182 // Set current restore base for snapshot handling.
183 if(is_object($this->snapHandler)){
184 $bases = array();
185 foreach($this->storagePoints as $sp){
186 $bases[] = $sp.$this->headpage->getBase();
187 }
189 // No bases specified? Try base
190 if(!count($bases)) $bases[] = $this->headpage->getBase();
192 $this->snapHandler->setSnapshotBases($bases);
193 }
195 // Display list
196 return($this->renderList());
197 }
199 function editFilter()
200 {
201 $this->dialogObject = new userFilter($this->config,$this->getHeadpage());
202 }
204 function renderList()
205 {
206 $this->headpage->update();
207 $display = $this->headpage->render();
208 return($this->getHeader().$display);
209 }
211 function getHeadpage()
212 {
213 return($this->headpage);
214 }
216 function getFilter()
217 {
218 return($this->filter);
219 }
221 /*! \brief Generates the plugin header which is displayed whenever a tab object is
222 * opened.
223 */
224 protected function getHeader()
225 {
226 // We do not display any headers right now.
227 if(1 || $this->skipHeader) return("");
228 }
231 /*! \brief Generates the footer which is used whenever a tab object is
232 * displayed.
233 */
234 protected function _getTabFooter()
235 {
236 // Do not display tab footer for non tab objects
237 if(!($this->tabObject instanceOf tabs || $this->tabObject instanceOf multi_plug)){
238 return("");
239 }
241 // Check if there is a dialog opened - We don't need any buttons in this case.
242 if($this->tabObject->by_object[$this->tabObject->current]){
243 $current = $this->tabObject->by_object[$this->tabObject->current];
244 if(isset($current->dialog) && (is_object($current->dialog) || $current->dialog)){
245 return("");
246 }
247 }
249 // Skip footer if requested;
250 if($this->skipFooter) return("");
252 // In case an of locked entry, we may have opened a read-only tab.
253 $str = "";
254 if(isset($this->tabObject->read_only) && $this->tabObject->read_only == TRUE){
255 $str.= "
256 <p style=\"text-align:right\">
257 <button type=submit name=\"edit_cancel\">".msgPool::cancelButton()."</button>
258 </p>";
259 return($str);
260 }else{
262 // Display ok, (apply) and cancel buttons
263 $str.= "<p style=\"text-align:right\">\n";
264 $str.= "<button type=\"submit\" name=\"edit_finish\">".msgPool::okButton()."</button>\n";
265 $str.= " \n";
266 if($this->displayApplyBtn){
267 $str.= "<button type=\"submit\" name=\"edit_apply\">".msgPool::applyButton()."</button>\n";
268 $str.= " \n";
269 }
270 $str.= "<button type=\"submit\" name=\"edit_cancel\">".msgPool::cancelButton()."</button>\n";
271 $str.= "</p>";
272 }
273 return($str);
274 }
277 /*! \brief Initiates the removal for the given entries
278 * and displays a confirmation dialog.
279 *
280 * @param String 'action' The name of the action which was the used as trigger.
281 * @param Array 'target' A list of object dns, which should be affected by this method.
282 * @param Array 'all' A combination of both 'action' and 'target'.
283 */
284 protected function removeEntryRequested($action="",$target=array(),$all=array())
285 {
286 // Close dialogs and remove locks for currently handled dns
287 $this->cancelEdit();
289 $disallowed = array();
290 $this->dns = array();
292 @DEBUG (DEBUG_TRACE, __LINE__, __FUNCTION__, __FILE__,$target,"Entry removel requested!");
294 // Check permissons for each target
295 $h = $this->getHeadpage();
296 $oTypes = array_reverse($h->objectTypes);
297 foreach($target as $dn){
298 $entry = $h->getEntry($dn);
299 $obj = $h->getObjectType($oTypes, $entry['objectClass']);
300 $acl = $this->ui->get_permissions($dn, $obj['category']."/".$obj['class']);
301 if(preg_match("/d/",$acl)){
302 $this->dns[] = $dn;
303 }else{
304 $disallowed[] = $dn;
305 }
306 }
307 if(count($disallowed)){
308 msg_dialog::display(_("Permission"),msgPool::permDelete($disallowed),INFO_DIALOG);
309 }
311 // We've at least one entry to delete.
312 if(count($this->dns)){
314 // check locks
315 if ($user= get_multiple_locks($this->dns)){
316 return(gen_locked_message($user,$this->dns));
317 }
319 // Add locks
320 $dns_names = array();
321 $types = array();
323 // Build list of object -labels
324 foreach($h->objectTypes as $type){
325 $map[$type['objectClass']]= $type['label'];
326 }
328 foreach($this->dns as $dn){
329 $tmp = $h->getType($dn);
330 if(isset($map[$tmp])){
331 $dns_names[LDAP::fix($dn)] = _($map[$tmp]);
332 }else{
333 $dns_names[] =LDAP::fix($dn);
334 }
335 }
336 add_lock ($this->dns, $this->ui->dn);
338 // Display confirmation dialog.
339 $smarty = get_smarty();
340 $smarty->assign("info", msgPool::deleteInfo($dns_names));
341 $smarty->assign("multiple", true);
342 return($smarty->fetch(get_template_path('removeEntries.tpl')));
343 }
344 }
347 /*! \brief Object removal was confirmed, now remove the requested entries.
348 *
349 * @param String 'action' The name of the action which was the used as trigger.
350 * @param Array 'target' A list of object dns, which should be affected by this method.
351 * @param Array 'all' A combination of both 'action' and 'target'.
352 */
353 function removeEntryConfirmed($action="",$target=array(),$all=array(),
354 $altTabClass="",$altTabType="", $altAclCategory="",$altAclPlugin="")
355 {
356 $tabType = $this->tabType;
357 $tabClass = $this->tabClass;
358 $aclCategory = $this->aclCategory;
359 $aclPlugin = $this->aclPlugin;
360 if(!empty($altTabClass)) $tabClass = $altTabClass;
361 if(!empty($altTabType)) $tabType = $altTabType;
362 if(!empty($altAclCategory)) $aclCategory = $altAclCategory;
363 if(!empty($altAclPlugin)) $aclPlugin = $altAclPlugin;
365 @DEBUG (DEBUG_TRACE, __LINE__, __FUNCTION__, __FILE__,$target,"Entry removel confirmed!");
367 // Check permissons for each target
368 $h = $this->getHeadpage();
369 $oTypes = array_reverse($h->objectTypes);
370 foreach($this->dns as $key => $dn){
371 $entry = $h->getEntry($dn);
372 $obj = $h->getObjectType($oTypes, $entry['objectClass']);
373 $acl = $this->ui->get_permissions($dn, $obj['category']."/".$obj['class']);
375 // Check permissions, are we allowed to remove this object?
376 if(preg_match("/d/",$acl)){
378 // Delete the object
379 $this->dn = $dn;
380 $this->tabObject= new $tabClass($this->config,$this->config->data['TABS'][$tabType], $this->dn,
381 $aclCategory, true, true);
382 $this->tabObject->set_acl_base($this->dn);
383 $this->tabObject->parent = &$this;
384 $this->tabObject->delete ();
386 // Remove the lock for the current object.
387 del_lock($this->dn);
388 } else {
389 msg_dialog::display(_("Permission error"), msgPool::permDelete(), ERROR_DIALOG);
390 new log("security","groups/".get_class($this),$dn,array(),"Tried to trick deletion.");
391 }
392 }
394 // Cleanup
395 $this->remove_lock();
396 $this->closeDialogs();
397 }
400 /*! \brief Detects actions/events send by the ui
401 * and the corresponding targets.
402 */
403 function detectPostActions()
404 {
405 if(!is_object($this->headpage)){
406 trigger_error("No valid headpage given....!");
407 return(array());
408 }
409 $action= $this->headpage->getAction();
410 if(isset($_POST['edit_apply'])) $action['action'] = "apply";
411 if(isset($_POST['edit_finish'])) $action['action'] = "save";
412 if(isset($_POST['edit_cancel'])) $action['action'] = "cancel";
413 if(isset($_POST['delete_confirmed'])) $action['action'] = "removeConfirmed";
414 if(isset($_POST['delete_snapshot_confirm'])) $action['action'] = "removeSnapshotConfirmed";
415 if(isset($_POST['delete_cancel'])) $action['action'] = "cancelDelete";
416 if(isset($_POST['saveFilter'])) $action['action'] = "saveFilter";
417 if(isset($_POST['cancelFilter'])) $action['action'] = "cancelFilter";
419 // Detect Snapshot actions
420 if(isset($_POST['CreateSnapshot'])) $action['action'] = "saveSnapshot";
421 if(isset($_POST['CancelSnapshot'])) $action['action'] = "cancelSnapshot";
422 foreach($_POST as $name => $value){
423 $once =TRUE;
424 if(preg_match("/^RestoreSnapShot_/",$name) && $once){
425 $once = FALSE;
426 $entry = base64_decode(preg_replace("/^RestoreSnapShot_(.*)$/i","\\1",$name));
427 $action['action'] = "restoreSnapshot";
428 $action['targets'] = array($entry);
429 }
430 }
432 return($action);
433 }
436 /*! \brief Calls the registered method for a given action/event.
437 */
438 function handleActions($action)
439 {
440 // Start action
441 if(isset($this->actions[$action['action']])){
442 $func = $this->actions[$action['action']];
443 if(!isset($action['targets']))$action['targets']= array();
444 stats::log('management', $class = get_class($this), $action['action'], $amount = count($action['targets']),
445 $duration = (microtime(TRUE) - $this->initTime));
447 return($this->$func($action['action'],$action['targets'],$action));
448 }
449 }
452 /*! \brief Opens the snapshot creation dialog for the given target.
453 *
454 * @param String 'action' The name of the action which was the used as trigger.
455 * @param Array 'target' A list of object dns, which should be affected by this method.
456 * @param Array 'all' A combination of both 'action' and 'target'.
457 */
458 function createSnapshotDialog($action="",$target=array(),$all=array())
459 {
460 @DEBUG (DEBUG_TRACE, __LINE__, __FUNCTION__, __FILE__,$target,"Snaptshot creation initiated!");
462 foreach($target as $entry){
463 if(!empty($entry) && $this->ui->allow_snapshot_create($entry,$this->aclCategory)){
464 $this->dialogObject = new SnapShotDialog($this->config,$entry,$this);
465 $this->dialogObject->aclCategories = array($this->aclCategory);
466 $this->dialogObject->parent = &$this;
468 }else{
469 msg_dialog::display(_("Permission"),sprintf(_("You are not allowed to create a snapshot for %s!"), bold($entry)),
470 ERROR_DIALOG);
471 }
472 }
473 }
476 /*! \brief Creates a snapshot new entry - This method is called when the somebody
477 * clicks 'save' in the "Create snapshot dialog" (see ::createSnapshotDialog).
478 *
479 * @param String 'action' The name of the action which was the used as trigger.
480 * @param Array 'target' A list of object dns, which should be affected by this method.
481 * @param Array 'all' A combination of both 'action' and 'target'.
482 */
483 function saveSnapshot($action="",$target=array(),$all=array())
484 {
485 if(!is_object($this->dialogObject)) return;
486 $this->dialogObject->save_object();
487 $msgs = $this->dialogObject->check();
488 if(count($msgs)){
489 foreach($msgs as $msg){
490 msg_dialog::display(_("Error"), $msg, ERROR_DIALOG);
491 }
492 }else{
493 $this->dn = $this->dialogObject->dn;
494 $this->snapHandler->create_snapshot( $this->dn,$this->dialogObject->CurrentDescription);
495 @DEBUG (DEBUG_TRACE, __LINE__, __FUNCTION__, __FILE__,$this->dn,"Snaptshot created!");
496 $this->closeDialogs();
497 }
498 }
501 /*! \brief Restores a snapshot object.
502 * The dn of the snapshot entry has to be given as ['target'] parameter.
503 *
504 * @param String 'action' The name of the action which was the used as trigger.
505 * @param Array 'target' A list of object dns, which should be affected by this method.
506 * @param Array 'all' A combination of both 'action' and 'target'.
507 */
508 function restoreSnapshot($action="",$target=array(),$all=array())
509 {
510 $entry = array_pop($target);
511 if(!empty($entry) && $this->ui->allow_snapshot_restore($entry,$this->aclCategory)){
512 $this->snapHandler->restore_snapshot($entry);
513 @DEBUG (DEBUG_TRACE, __LINE__, __FUNCTION__, __FILE__,$this->dn,"Snaptshot restored!");
514 $this->closeDialogs();
515 }else{
516 msg_dialog::display(_("Permission"),sprintf(_("You are not allowed to restore a snapshot for %s!"), bold($entry)),
517 ERROR_DIALOG);
518 }
519 }
522 /*! \brief Removes a snapshot object.
523 */
524 function removeSnapshotConfirmed($action="",$target=array(),$all=array())
525 {
526 $entry = $this->dialogObject->del_dn;
527 if(!empty($entry) && $this->ui->allow_snapshot_create($entry,$this->aclCategory)){
528 $this->snapHandler->remove_snapshot($entry);
529 @DEBUG (DEBUG_TRACE, __LINE__, __FUNCTION__, __FILE__,$entry,"Snaptshot removed!");
530 }else{
531 msg_dialog::display(_("Permission"),sprintf(_("You are not allowed to remove a snapshot for %s!"), bold($entry)),
532 ERROR_DIALOG);
533 }
534 }
537 /*! \brief Displays the "Restore snapshot dialog" for a given target.
538 * If no target is specified, open the restore removed object
539 * dialog.
540 * @param String 'action' The name of the action which was the used as trigger.
541 * @param Array 'target' A list of object dns, which should be affected by this method.
542 * @param Array 'all' A combination of both 'action' and 'target'.
543 */
544 function restoreSnapshotDialog($action="",$target=array(),$all=array())
545 {
546 // Set current restore base for snapshot handling.
547 if(is_object($this->snapHandler)){
548 $bases = array();
549 foreach($this->storagePoints as $sp){
550 $bases[] = $sp.$this->headpage->getBase();
551 }
552 }
554 // No bases specified? Try base
555 if(!count($bases)) $bases[] = $this->headpage->getBase();
557 // No target, open the restore removed object dialog.
558 if(!count($target)){
559 $entry = $this->headpage->getBase();
560 if(!empty($entry) && $this->ui->allow_snapshot_restore($entry,$this->aclCategory)){
561 @DEBUG (DEBUG_TRACE, __LINE__, __FUNCTION__, __FILE__,$entry,"Snaptshot restoring initiated!");
562 $this->dialogObject = new SnapShotDialog($this->config,$entry,$this);
563 $this->dialogObject->set_snapshot_bases($bases);
564 $this->dialogObject->display_all_removed_objects = true;
565 $this->dialogObject->display_restore_dialog = true;
566 $this->dialogObject->parent = &$this;
567 }else{
568 msg_dialog::display(_("Permission"),sprintf(_("You are not allowed to restore a snapshot for %s!"), bold($entry)),
569 ERROR_DIALOG);
570 }
571 }else{
573 // Display the restore points for a given object.
574 $entry = array_pop($target);
575 if(!empty($entry) && $this->ui->allow_snapshot_restore($entry,$this->aclCategory)){
576 @DEBUG (DEBUG_TRACE, __LINE__, __FUNCTION__, __FILE__,$entry,"Snaptshot restoring initiated!");
577 $this->dialogObject = new SnapShotDialog($this->config,$entry,$this);
578 $this->dialogObject->set_snapshot_bases($bases);
579 $this->dialogObject->display_restore_dialog = true;
580 $this->dialogObject->parent = &$this;
581 }else{
582 msg_dialog::display(_("Permission"),sprintf(_("You are not allowed to restore a snapshot for %s!"), bold($entry)),
583 ERROR_DIALOG);
584 }
585 }
586 }
589 /*! \brief This method intiates the object creation.
590 *
591 * @param String 'action' The name of the action which was the used as trigger.
592 * @param Array 'target' A list of object dns, which should be affected by this method.
593 * @param Array 'all' A combination of both 'action' and 'target'.
594 */
595 function newEntry($action="",$target=array(),$all=array(), $altTabClass ="", $altTabType = "", $altAclCategory="")
596 {
597 /* To handle mutliple object types overload this method.
598 * ...
599 * registerAction('newUser', 'newEntry');
600 * registerAction('newGroup','newEntry');
601 * ...
602 *
603 * function newEntry($action="",$target=array(),$all=array(), $altTabClass ="", $altTabType = "", $altAclCategory)
604 * {
605 * switch($action){
606 * case 'newUser' : {
607 * mangement::newEntry($action,$target,$all,"usertabs","USERTABS","users");
608 * }
609 * case 'newGroup' : {
610 * mangement::newEntry($action,$target,$all,"grouptabs","GROUPTABS","groups");
611 * }
612 * }
613 * }
614 **/
615 $tabType = $this->tabType;
616 $tabClass = $this->tabClass;
617 $aclCategory = $this->aclCategory;
618 if(!empty($altTabClass)) $tabClass = $altTabClass;
619 if(!empty($altTabType)) $tabType = $altTabType;
620 if(!empty($altAclCategory)) $aclCategory = $altAclCategory;
622 // Check locking & lock entry if required
623 $this->displayApplyBtn = FALSE;
624 $this->dn = "new";
625 $this->is_new = TRUE;
626 $this->is_single_edit = FALSE;
627 $this->is_multiple_edit = FALSE;
629 set_object_info($this->dn);
631 // Open object.
632 if(empty($tabClass) || empty($tabType)){
633 // No tab type defined
634 }else{
636 if (isset($this->config->data['TABS'][$tabType])) {
638 // Check if the base plugin is available - it is mostly responsible for object creation and removal.
639 $first = $this->config->data['TABS'][$tabType][0];
640 if(!class_available($first['CLASS'])){
641 msg_dialog::display(_("Internal error"),
642 sprintf(_("Cannot instantiate tabbed-plug-in, the base plugin (%s) is not available!"), $first['CLASS']),
643 ERROR_DIALOG);
644 }else{
645 $this->tabObject= new $tabClass($this->config,$this->config->data['TABS'][$tabType], $this->dn, $aclCategory);
646 $this->tabObject->set_acl_base($this->headpage->getBase());
647 $this->tabObject->parent = &$this;
648 @DEBUG (DEBUG_TRACE, __LINE__, __FUNCTION__, __FILE__,$this->dn,"Create new entry initiated!");
649 }
650 } else {
651 msg_dialog::display(_("Error"), sprintf(_("No tab definition for %s found in configuration file: cannot create plugin instance!"), bold($tabType)), ERROR_DIALOG);
652 }
653 }
654 }
657 /*! \brief This method opens an existing object or a list of existing objects to be edited.
658 *
659 *
660 * @param String 'action' The name of the action which was the used as trigger.
661 * @param Array 'target' A list of object dns, which should be affected by this method.
662 * @param Array 'all' A combination of both 'action' and 'target'.
663 */
664 function editEntry($action="",$target=array(),$all=array(), $altTabClass ="", $altTabType = "", $altAclCategory="")
665 {
666 /* To handle mutliple object types overload this method.
667 * ...
668 * registerAction('editUser', 'editEntry');
669 * registerAction('editGroup','editEntry');
670 * ...
671 *
672 * function editEntry($action="",$target=array(),$all=array(), $altTabClass ="", $altTabType = "", $altAclCategory)
673 * {
674 * switch($action){
675 * case 'editUser' : {
676 * mangement::editEntry($action,$target,$all,"usertabs","USERTABS","users");
677 * }
678 * case 'editGroup' : {
679 * mangement::editEntry($action,$target,$all,"grouptabs","GROUPTABS","groups");
680 * }
681 * }
682 * }
683 **/
685 // Do not create a new tabObject while there is already one opened,
686 // the user may have just pressed F5 to reload the page.
687 if(is_object($this->tabObject)){
688 return;
689 }
691 $tabType = $this->tabType;
692 $tabClass = $this->tabClass;
693 $aclCategory = $this->aclCategory;
694 if(!empty($altTabClass)) $tabClass = $altTabClass;
695 if(!empty($altTabType)) $tabType = $altTabType;
696 if(!empty($altAclCategory)) $aclCategory = $altAclCategory;
698 $this->displayApplyBtn = count($target) == 1;
700 // Single edit - we only got one object dn.
701 if(count($target) == 1){
702 $this->is_new = FALSE;
703 $this->is_single_edit = TRUE;
704 $this->is_multiple_edit = FALSE;
706 // Get the dn of the object and creates lock
707 $this->dn = array_pop($target);
708 set_object_info($this->dn);
709 $user = get_lock($this->dn);
710 if ($user != ""){
711 return(gen_locked_message ($user, array($this->dn),TRUE));
712 }
713 add_lock ($this->dn, $this->ui->dn);
715 // Open object.
716 if(empty($tabClass) || empty($tabType)){
717 trigger_error("We can't edit any object(s). 'tabClass' or 'tabType' is empty!");
718 }else{
720 $tab = $tabClass;
722 // Check if the base plugin is available - it is mostly responsible for object creation and removal.
723 $first = $this->config->data['TABS'][$tabType][0];
724 if(!class_available($first['CLASS'])){
725 msg_dialog::display(_("Internal error"),
726 sprintf(_("Cannot instantiate tabbed-plug-in, the base plugin (%s) is not available!"), $first['CLASS']),
727 ERROR_DIALOG);
728 }else{
729 $this->tabObject= new $tab($this->config,$this->config->data['TABS'][$tabType], $this->dn,$aclCategory);
730 @DEBUG (DEBUG_TRACE, __LINE__, __FUNCTION__, __FILE__,$this->dn,"Edit entry initiated!");
731 $this->tabObject->set_acl_base($this->dn);
732 $this->tabObject->parent = &$this;
733 }
734 }
735 }else{
737 // We've multiple entries to edit.
738 $this->is_new = FALSE;
739 $this->is_singel_edit = FALSE;
740 $this->is_multiple_edit = TRUE;
742 // Open multiple edit handler.
743 if(empty($tabClass) || empty($tabType)){
744 trigger_error("We can't edit any object(s). 'tabClass' or 'tabType' is empty!");
745 }else{
746 $this->dns = $target;
747 $tmp = new multi_plug($this->config,$tabClass,$this->config->data['TABS'][$tabType],
748 $this->dns,$this->headpage->getBase(),$aclCategory);
750 // Check for locked entries
751 if ($tmp->entries_locked()){
752 return($tmp->display_lock_message());
753 }
755 @DEBUG (DEBUG_TRACE, __LINE__, __FUNCTION__, __FILE__,$this->dns,"Edit entry initiated!");
757 // Now lock entries.
758 if($tmp->multiple_available()){
759 $tmp->lock_entries($this->ui->dn);
760 $this->tabObject = $tmp;
761 set_object_info($this->tabObject->get_object_info());
762 }
763 }
764 }
765 }
768 /*! \brief Close filter dialog
769 */
770 protected function cancelFilter()
771 {
772 if($this->dialogObject instanceOf userFilter){
773 $this->remove_lock();
774 $this->closeDialogs();
775 }
776 }
779 /*! \brief Save filter modifcations.
780 */
781 protected function saveFilter()
782 {
783 if($this->dialogObject instanceOf userFilter){
784 $msgs = $this->dialogObject->check();
785 if(count($msgs)){
786 msg_dialog::displayChecks($msgs);
787 return("");
788 }else{
789 $this->dialogObject->save();
790 @DEBUG (DEBUG_TRACE, __LINE__, __FUNCTION__, __FILE__,$this->dns,"Entry saved!");
791 $this->remove_lock();
792 $this->closeDialogs();
794 // Ask filter to reload information
795 $this->filter->reloadFilters();
796 }
797 }
798 }
801 /*! \brief Save object modifications and closes dialogs (returns to object listing).
802 * - Calls '::check' to validate the given input.
803 * - Calls '::save' to save back object modifications (e.g. to ldap).
804 * - Calls '::remove_locks' to remove eventually created locks.
805 * - Calls '::closeDialogs' to return to the object listing.
806 */
807 protected function saveChanges()
808 {
809 if($this->tabObject instanceOf tabs || $this->tabObject instanceOf multi_plug){
810 $this->tabObject->save_object();
811 $msgs = $this->tabObject->check();
812 if(count($msgs)){
813 msg_dialog::displayChecks($msgs);
814 return("");
815 }else{
816 $this->tabObject->save();
817 @DEBUG (DEBUG_TRACE, __LINE__, __FUNCTION__, __FILE__,$this->dns,"Entry saved!");
818 $this->remove_lock();
819 $this->closeDialogs();
820 }
821 }elseif($this->dialogObject instanceOf plugin){
822 $this->dialogObject->save_object();
823 $msgs = $this->dialogObject->check();
824 if(count($msgs)){
825 msg_dialog::displayChecks($msgs);
826 return("");
827 }else{
828 $this->dialogObject->save();
829 @DEBUG (DEBUG_TRACE, __LINE__, __FUNCTION__, __FILE__,$this->dns,"Entry saved!");
830 $this->remove_lock();
831 $this->closeDialogs();
832 }
833 }
834 }
837 /*! \brief Save object modifications and keep dialogs opened.
838 * - Calls '::check' to validate the given input.
839 * - Calls '::save' to save back object modifications (e.g. to ldap).
840 */
841 protected function applyChanges()
842 {
843 if($this->tabObject instanceOf tabs || $this->tabObject instanceOf multi_plug){
844 $this->tabObject->save_object();
845 $msgs = $this->tabObject->check();
846 if(count($msgs)){
847 msg_dialog::displayChecks($msgs);
848 return("");
849 }else{
850 $this->tabObject->save();
851 @DEBUG (DEBUG_TRACE, __LINE__, __FUNCTION__, __FILE__,$this->dns,"Modifications applied!");
852 $this->tabObject->re_init();
853 }
854 }
855 }
858 /*! \brief This method closes dialogs
859 * and cleans up the cached object info and the ui.
860 */
861 protected function closeDialogs()
862 {
863 $this->last_dn = $this->dn;
864 $this->last_dns = $this->dns;
865 $this->last_tabObject = $this->tabObject;
866 $this->last_dialogObject = $this->dialogObject;
867 $this->dn = "";
868 $this->dns = array();
869 $this->tabObject = null;
870 $this->dialogObject = null;
871 $this->skipFooter = FALSE;
872 set_object_info();
873 }
876 /*! \brief Editing an object was caneled.
877 * Close dialogs/tabs and remove locks.
878 */
879 protected function cancelEdit()
880 {
881 $this->remove_lock();
882 $this->closeDialogs();
883 }
886 /*! \brief Every click in the list user interface sends an event
887 * here can we connect those events to a method.
888 * eg. ::registerEvent('new','createUser')
889 * When the action/event new is send, the method 'createUser'
890 * will be called.
891 */
892 function registerAction($action,$target)
893 {
894 $this->actions[$action] = $target;
895 }
898 /*! \brief Removes ldap object locks created by this class.
899 * Whenever an object is edited, we create locks to avoid
900 * concurrent modifications.
901 * This locks will automatically removed here.
902 */
903 function remove_lock()
904 {
905 if(!empty($this->dn) && $this->dn != "new"){
906 del_lock($this->dn);
907 }
908 if(count($this->dns)){
909 del_lock($this->dns);
910 }
911 }
914 /*! \brief This method is used to queue and process copy&paste actions.
915 * Allows to copy, cut and paste mutliple entries at once.
916 * @param String 'action' The name of the action which was the used as trigger.
917 * @param Array 'target' A list of object dns, which should be affected by this method.
918 * @param Array 'all' A combination of both 'action' and 'target'.
919 */
920 function copyPasteHandler($action="",$target=array(),$all=array(),
921 $altTabClass ="", $altTabType = "", $altAclCategory="",$altAclPlugin="")
922 {
923 // Return without any actions while copy&paste handler is disabled.
924 if(!is_object($this->cpHandler)) return("");
926 $tabType = $this->tabType;
927 $tabClass = $this->tabClass;
928 $aclCategory = $this->aclCategory;
929 $aclPlugin = $this->aclPlugin;
930 if(!empty($altTabClass)) $tabClass = $altTabClass;
931 if(!empty($altTabType)) $tabType = $altTabType;
932 if(!empty($altAclCategory)) $aclCategory = $altAclCategory;
933 if(!empty($altAclPlugin)) $aclPlugin = $altAclPlugin;
935 // Save user input
936 $this->cpHandler->save_object();
938 // Add entries to queue
939 if($action == "copy" || $action == "cut"){
940 $this->cpHandler->cleanup_queue();
941 foreach($target as $dn){
942 if($action == "copy" && $this->ui->is_copyable($dn,$aclCategory,$aclPlugin)){
943 $this->cpHandler->add_to_queue($dn,"copy",$tabClass,$tabType,$aclCategory,$this);
944 @DEBUG (DEBUG_TRACE, __LINE__, __FUNCTION__, __FILE__,$dn,"Entry copied!");
945 }
946 if($action == "cut" && $this->ui->is_cutable($dn,$aclCategory,$aclPlugin)){
947 $this->cpHandler->add_to_queue($dn,"cut",$tabClass,$tabType,$aclCategory,$this);
948 @DEBUG (DEBUG_TRACE, __LINE__, __FUNCTION__, __FILE__,$dn,"Entry cutted!");
949 }
950 }
951 }
953 // Initiate pasting
954 if($action == "paste"){
955 $this->cpPastingStarted = TRUE;
956 }
958 // Display any c&p dialogs, eg. object modifications required before pasting.
959 if($this->cpPastingStarted && $this->cpHandler->entries_queued()){
960 $this->cpHandler->SetVar("base",$this->headpage->getBase());
961 $data = $this->cpHandler->execute();
962 if(!empty($data)){
963 return($data);
964 }
965 }
967 // Automatically disable pasting process since there is no entry left to paste.
968 if(!$this->cpHandler->entries_queued()){
969 $this->cpPastingStarted = FALSE;
970 }
971 return("");
972 }
975 function setFilter($str) {
976 $this->filter = $str;
977 }
980 function postcreate() {
981 $this->handle_post_events('add');
982 }
983 function postmodify(){
984 $this->handle_post_events('modify');
985 }
986 function postremove(){
987 $this->handle_post_events('remove');
988 }
990 function is_modal_dialog()
991 {
992 return(is_object($this->tabObject) || is_object($this->dialogObject));
993 }
996 /*! \brief Forward command execution request
997 * to the correct method.
998 */
999 function handle_post_events($mode, $addAttrs= array())
1000 {
1001 if(!in_array($mode, array('add','remove','modify'))){
1002 trigger_error(sprintf("Invalid post event type given %s! Valid types are [add,modify,remove].", bold($mode)));
1003 return;
1004 }
1005 switch ($mode){
1006 case "add":
1007 plugin::callHook($this,"POSTCREATE", $addAttrs);
1008 break;
1010 case "modify":
1011 plugin::callHook($this,"POSTMODIFY", $addAttrs);
1012 break;
1014 case "remove":
1015 plugin::callHook($this,"POSTREMOVE", $addAttrs);
1016 break;
1017 }
1018 }
1019 }
1021 // vim:tabstop=2:expandtab:shiftwidth=2:filetype=php:syntax:ruler:
1022 ?>