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 // Create statistic table entry
98 stats::log('management', $class = get_class($this), $this->getAclCategories(), $action = 'open',
99 $amount = 1, $duration = (microtime(TRUE) - $this->initTime));
101 if($this->cpHandler) $this->headpage->setCopyPasteHandler($this->cpHandler);
102 if($this->snapHandler) $this->headpage->setSnapshotHandler($this->snapHandler);
104 if(empty($this->plIcon)){
105 $this->plIcon = "plugins/".$plugname."/images/plugin.png";
106 }
108 // Register default actions
109 $this->registerAction("new", "newEntry");
110 $this->registerAction("edit", "editEntry");
111 $this->registerAction("apply", "applyChanges");
112 $this->registerAction("save", "saveChanges");
113 $this->registerAction("cancel", "cancelEdit");
114 $this->registerAction("cancelDelete", "cancelEdit");
115 $this->registerAction("remove", "removeEntryRequested");
116 $this->registerAction("removeConfirmed", "removeEntryConfirmed");
118 $this->registerAction("copy", "copyPasteHandler");
119 $this->registerAction("cut", "copyPasteHandler");
120 $this->registerAction("paste", "copyPasteHandler");
122 $this->registerAction("snapshot", "createSnapshotDialog");
123 $this->registerAction("restore", "restoreSnapshotDialog");
124 $this->registerAction("saveSnapshot","saveSnapshot");
125 $this->registerAction("restoreSnapshot","restoreSnapshot");
126 $this->registerAction("removeSnapshotConfirmed","removeSnapshotConfirmed");
127 $this->registerAction("cancelSnapshot","closeDialogs");
129 $this->registerAction("config-filter","editFilter");
130 $this->registerAction("saveFilter","saveFilter");
131 $this->registerAction("cancelFilter","cancelFilter");
133 // To temporay disable the filter caching UNcomment this line.
134 #session::global_un_set(get_class($this)."_filter");
135 }
138 /*! \brief Returns an array with all ACL-Categories we are responsible for.
139 */
140 function getAclCategories()
141 {
142 $ret= $this->aclCategory;
143 if(!is_array($ret)) $ret = array($ret);
144 return($ret);
145 }
148 /*! \brief Execute this plugin
149 * Handle actions/events, locking, snapshots, dialogs, tabs,...
150 */
151 function execute()
152 {
153 // Ensure that html posts and gets are kept even if we see a 'Entry islocked' dialog.
154 $vars = array('/^act$/','/^listing/','/^PID$/','/^FILTER_PID$/');
155 session::set('LOCK_VARS_TO_USE',$vars);
157 pathNavigator::registerPlugin($this);
159 /* Display the copy & paste dialog, if it is currently open */
160 $ret = $this->copyPasteHandler("",array());
161 if($ret){
162 return($this->getHeader().$ret);
163 }
165 // Update filter
166 if ($this->filter) {
167 $this->filter->update();
168 session::global_set(get_class($this)."_filter", $this->filter);
169 session::set('autocomplete', $this->filter);
170 }
172 // Handle actions (POSTs and GETs)
173 $str = $this->handleActions($this->detectPostActions());
174 if($str) return($this->getHeader().$str);
176 // Open single dialog objects
177 if(is_object($this->dialogObject)){
178 if(method_exists($this->dialogObject,'save_object')) $this->dialogObject->save_object();
179 if(method_exists($this->dialogObject,'execute')){
180 $display = $this->dialogObject->execute();
181 $display.= $this->_getTabFooter();
182 return($this->getHeader().$display);
183 }
184 }
186 // Display tab object.
187 if($this->tabObject instanceOf tabs || $this->tabObject instanceOf multi_plug){
188 # $this->tabObject->save_object();
189 $display = $this->tabObject->execute();
190 $display.= $this->_getTabFooter();
191 return($this->getHeader().$display);
192 }
194 // Set current restore base for snapshot handling.
195 if(is_object($this->snapHandler)){
196 $bases = array();
197 foreach($this->storagePoints as $sp){
198 $bases[] = $sp.$this->headpage->getBase();
199 }
201 // No bases specified? Try base
202 if(!count($bases)) $bases[] = $this->headpage->getBase();
204 $this->snapHandler->setSnapshotBases($bases);
205 }
207 // Create statistic table entry
208 stats::log('management', $class = get_class($this), $this->getAclCategories(), $action = 'view',
209 $amount = 1, $duration = (microtime(TRUE) - $this->initTime));
211 // Display list
212 return($this->renderList());
213 }
215 function editFilter()
216 {
217 $this->dialogObject = new userFilter($this->config,$this->getHeadpage());
218 }
220 function renderList()
221 {
222 $this->headpage->update();
223 $display = $this->headpage->render();
224 return($this->getHeader().$display);
225 }
227 function getHeadpage()
228 {
229 return($this->headpage);
230 }
232 function getFilter()
233 {
234 return($this->filter);
235 }
237 /*! \brief Generates the plugin header which is displayed whenever a tab object is
238 * opened.
239 */
240 protected function getHeader()
241 {
242 // We do not display any headers right now.
243 if(1 || $this->skipHeader) return("");
244 }
247 /*! \brief Generates the footer which is used whenever a tab object is
248 * displayed.
249 */
250 protected function _getTabFooter()
251 {
252 // Do not display tab footer for non tab objects
253 if(!($this->tabObject instanceOf tabs || $this->tabObject instanceOf multi_plug)){
254 return("");
255 }
257 // Check if there is a dialog opened - We don't need any buttons in this case.
258 if($this->tabObject->by_object[$this->tabObject->current]){
259 $current = $this->tabObject->by_object[$this->tabObject->current];
260 if(isset($current->dialog) && (is_object($current->dialog) || $current->dialog)){
261 return("");
262 }
263 }
265 // Skip footer if requested;
266 if($this->skipFooter) return("");
268 // In case an of locked entry, we may have opened a read-only tab.
269 $str = "";
270 if(isset($this->tabObject->read_only) && $this->tabObject->read_only == TRUE){
271 $str.= "
272 <p style=\"text-align:right\">
273 <button type=submit name=\"edit_cancel\">".msgPool::cancelButton()."</button>
274 </p>";
275 return($str);
276 }else{
278 // Display ok, (apply) and cancel buttons
279 $str.= "<p style=\"text-align:right\">\n";
280 $str.= "<button type=\"submit\" name=\"edit_finish\">".msgPool::okButton()."</button>\n";
281 $str.= " \n";
282 if($this->displayApplyBtn){
283 $str.= "<button type=\"submit\" name=\"edit_apply\">".msgPool::applyButton()."</button>\n";
284 $str.= " \n";
285 }
286 $str.= "<button type=\"submit\" name=\"edit_cancel\">".msgPool::cancelButton()."</button>\n";
287 $str.= "</p>";
288 }
289 return($str);
290 }
293 /*! \brief Initiates the removal for the given entries
294 * and displays a confirmation dialog.
295 *
296 * @param String 'action' The name of the action which was the used as trigger.
297 * @param Array 'target' A list of object dns, which should be affected by this method.
298 * @param Array 'all' A combination of both 'action' and 'target'.
299 */
300 protected function removeEntryRequested($action="",$target=array(),$all=array())
301 {
302 // Close dialogs and remove locks for currently handled dns
303 $this->cancelEdit();
305 $disallowed = array();
306 $this->dns = array();
308 @DEBUG (DEBUG_TRACE, __LINE__, __FUNCTION__, __FILE__,$target,"Entry removel requested!");
310 // Check permissons for each target
311 $h = $this->getHeadpage();
312 $oTypes = array_reverse($h->objectTypes);
313 foreach($target as $dn){
314 $entry = $h->getEntry($dn);
315 $obj = $h->getObjectType($oTypes, $entry['objectClass']);
316 $acl = $this->ui->get_permissions($dn, $obj['category']."/".$obj['class']);
317 if(preg_match("/d/",$acl)){
318 $this->dns[] = $dn;
319 }else{
320 $disallowed[] = $dn;
321 }
322 }
323 if(count($disallowed)){
324 msg_dialog::display(_("Permission"),msgPool::permDelete($disallowed),INFO_DIALOG);
325 }
327 // We've at least one entry to delete.
328 if(count($this->dns)){
330 // check locks
331 if ($user= get_multiple_locks($this->dns)){
332 return(gen_locked_message($user,$this->dns));
333 }
335 // Add locks
336 $dns_names = array();
337 $types = array();
339 // Build list of object -labels
340 foreach($h->objectTypes as $type){
341 $map[$type['objectClass']]= $type['label'];
342 }
344 foreach($this->dns as $dn){
345 $tmp = $h->getType($dn);
346 if(isset($map[$tmp])){
347 $dns_names[LDAP::fix($dn)] = _($map[$tmp]);
348 }else{
349 $dns_names[] =LDAP::fix($dn);
350 }
351 }
352 add_lock ($this->dns, $this->ui->dn);
354 // Display confirmation dialog.
355 $smarty = get_smarty();
356 $smarty->assign("info", msgPool::deleteInfo($dns_names));
357 $smarty->assign("multiple", true);
358 return($smarty->fetch(get_template_path('removeEntries.tpl')));
359 }
360 }
363 /*! \brief Object removal was confirmed, now remove the requested entries.
364 *
365 * @param String 'action' The name of the action which was the used as trigger.
366 * @param Array 'target' A list of object dns, which should be affected by this method.
367 * @param Array 'all' A combination of both 'action' and 'target'.
368 */
369 function removeEntryConfirmed($action="",$target=array(),$all=array(),
370 $altTabClass="",$altTabType="", $altAclCategory="",$altAclPlugin="")
371 {
372 $tabType = $this->tabType;
373 $tabClass = $this->tabClass;
374 $aclCategory = $this->aclCategory;
375 $aclPlugin = $this->aclPlugin;
376 if(!empty($altTabClass)) $tabClass = $altTabClass;
377 if(!empty($altTabType)) $tabType = $altTabType;
378 if(!empty($altAclCategory)) $aclCategory = $altAclCategory;
379 if(!empty($altAclPlugin)) $aclPlugin = $altAclPlugin;
381 @DEBUG (DEBUG_TRACE, __LINE__, __FUNCTION__, __FILE__,$target,"Entry removel confirmed!");
383 // Check permissons for each target
384 $h = $this->getHeadpage();
385 $oTypes = array_reverse($h->objectTypes);
386 foreach($this->dns as $key => $dn){
387 $entry = $h->getEntry($dn);
388 $obj = $h->getObjectType($oTypes, $entry['objectClass']);
389 $acl = $this->ui->get_permissions($dn, $obj['category']."/".$obj['class']);
391 // Check permissions, are we allowed to remove this object?
392 if(preg_match("/d/",$acl)){
394 // Delete the object
395 $this->dn = $dn;
396 $this->tabObject= new $tabClass($this->config,$this->config->data['TABS'][$tabType], $this->dn,
397 $aclCategory, true, true);
398 $this->tabObject->set_acl_base($this->dn);
399 $this->tabObject->parent = &$this;
400 $this->tabObject->delete ();
402 // Remove the lock for the current object.
403 del_lock($this->dn);
404 } else {
405 msg_dialog::display(_("Permission error"), msgPool::permDelete(), ERROR_DIALOG);
406 new log("security","groups/".get_class($this),$dn,array(),"Tried to trick deletion.");
407 }
408 }
410 // Cleanup
411 $this->remove_lock();
412 $this->closeDialogs();
413 }
416 /*! \brief Detects actions/events send by the ui
417 * and the corresponding targets.
418 */
419 function detectPostActions()
420 {
421 if(!is_object($this->headpage)){
422 trigger_error("No valid headpage given....!");
423 return(array());
424 }
425 $action= $this->headpage->getAction();
426 if(isset($_POST['edit_apply'])) $action['action'] = "apply";
427 if(isset($_POST['edit_finish'])) $action['action'] = "save";
428 if(isset($_POST['edit_cancel'])) $action['action'] = "cancel";
429 if(isset($_POST['delete_confirmed'])) $action['action'] = "removeConfirmed";
430 if(isset($_POST['delete_snapshot_confirm'])) $action['action'] = "removeSnapshotConfirmed";
431 if(isset($_POST['delete_cancel'])) $action['action'] = "cancelDelete";
432 if(isset($_POST['saveFilter'])) $action['action'] = "saveFilter";
433 if(isset($_POST['cancelFilter'])) $action['action'] = "cancelFilter";
435 // Detect Snapshot actions
436 if(isset($_POST['CreateSnapshot'])) $action['action'] = "saveSnapshot";
437 if(isset($_POST['CancelSnapshot'])) $action['action'] = "cancelSnapshot";
438 foreach($_POST as $name => $value){
439 $once =TRUE;
440 if(preg_match("/^RestoreSnapShot_/",$name) && $once){
441 $once = FALSE;
442 $entry = base64_decode(preg_replace("/^RestoreSnapShot_(.*)$/i","\\1",$name));
443 $action['action'] = "restoreSnapshot";
444 $action['targets'] = array($entry);
445 }
446 }
448 return($action);
449 }
452 /*! \brief Calls the registered method for a given action/event.
453 */
454 function handleActions($action)
455 {
456 // Start action
457 if(isset($this->actions[$action['action']])){
458 $func = $this->actions[$action['action']];
459 if(!isset($action['targets']))$action['targets']= array();
461 // Create statistic table entry
462 stats::log('management', $class = get_class($this), $this->getAclCategories(), $action['action'],
463 $amount = count($action['targets']), $duration = (microtime(TRUE) - $this->initTime));
465 return($this->$func($action['action'],$action['targets'],$action));
466 }
467 }
470 /*! \brief Opens the snapshot creation dialog for the given target.
471 *
472 * @param String 'action' The name of the action which was the used as trigger.
473 * @param Array 'target' A list of object dns, which should be affected by this method.
474 * @param Array 'all' A combination of both 'action' and 'target'.
475 */
476 function createSnapshotDialog($action="",$target=array(),$all=array())
477 {
478 @DEBUG (DEBUG_TRACE, __LINE__, __FUNCTION__, __FILE__,$target,"Snaptshot creation initiated!");
480 foreach($target as $entry){
481 if(!empty($entry) && $this->ui->allow_snapshot_create($entry,$this->aclCategory)){
482 $this->dialogObject = new SnapShotDialog($this->config,$entry,$this);
483 $this->dialogObject->aclCategories = array($this->aclCategory);
484 $this->dialogObject->parent = &$this;
486 }else{
487 msg_dialog::display(_("Permission"),sprintf(_("You are not allowed to create a snapshot for %s!"), bold($entry)),
488 ERROR_DIALOG);
489 }
490 }
491 }
494 /*! \brief Creates a snapshot new entry - This method is called when the somebody
495 * clicks 'save' in the "Create snapshot dialog" (see ::createSnapshotDialog).
496 *
497 * @param String 'action' The name of the action which was the used as trigger.
498 * @param Array 'target' A list of object dns, which should be affected by this method.
499 * @param Array 'all' A combination of both 'action' and 'target'.
500 */
501 function saveSnapshot($action="",$target=array(),$all=array())
502 {
503 if(!is_object($this->dialogObject)) return;
504 $this->dialogObject->save_object();
505 $msgs = $this->dialogObject->check();
506 if(count($msgs)){
507 foreach($msgs as $msg){
508 msg_dialog::display(_("Error"), $msg, ERROR_DIALOG);
509 }
510 }else{
511 $this->dn = $this->dialogObject->dn;
512 $this->snapHandler->create_snapshot( $this->dn,$this->dialogObject->CurrentDescription);
513 @DEBUG (DEBUG_TRACE, __LINE__, __FUNCTION__, __FILE__,$this->dn,"Snaptshot created!");
514 $this->closeDialogs();
515 }
516 }
519 /*! \brief Restores a snapshot object.
520 * The dn of the snapshot entry has to be given as ['target'] parameter.
521 *
522 * @param String 'action' The name of the action which was the used as trigger.
523 * @param Array 'target' A list of object dns, which should be affected by this method.
524 * @param Array 'all' A combination of both 'action' and 'target'.
525 */
526 function restoreSnapshot($action="",$target=array(),$all=array())
527 {
528 $entry = array_pop($target);
529 if(!empty($entry) && $this->ui->allow_snapshot_restore($entry,$this->aclCategory)){
530 $this->snapHandler->restore_snapshot($entry);
531 @DEBUG (DEBUG_TRACE, __LINE__, __FUNCTION__, __FILE__,$this->dn,"Snaptshot restored!");
532 $this->closeDialogs();
533 }else{
534 msg_dialog::display(_("Permission"),sprintf(_("You are not allowed to restore a snapshot for %s!"), bold($entry)),
535 ERROR_DIALOG);
536 }
537 }
540 /*! \brief Removes a snapshot object.
541 */
542 function removeSnapshotConfirmed($action="",$target=array(),$all=array())
543 {
544 $entry = $this->dialogObject->del_dn;
545 if(!empty($entry) && $this->ui->allow_snapshot_create($entry,$this->aclCategory)){
546 $this->snapHandler->remove_snapshot($entry);
547 @DEBUG (DEBUG_TRACE, __LINE__, __FUNCTION__, __FILE__,$entry,"Snaptshot removed!");
548 }else{
549 msg_dialog::display(_("Permission"),sprintf(_("You are not allowed to remove a snapshot for %s!"), bold($entry)),
550 ERROR_DIALOG);
551 }
552 }
555 /*! \brief Displays the "Restore snapshot dialog" for a given target.
556 * If no target is specified, open the restore removed object
557 * dialog.
558 * @param String 'action' The name of the action which was the used as trigger.
559 * @param Array 'target' A list of object dns, which should be affected by this method.
560 * @param Array 'all' A combination of both 'action' and 'target'.
561 */
562 function restoreSnapshotDialog($action="",$target=array(),$all=array())
563 {
564 // Set current restore base for snapshot handling.
565 if(is_object($this->snapHandler)){
566 $bases = array();
567 foreach($this->storagePoints as $sp){
568 $bases[] = $sp.$this->headpage->getBase();
569 }
570 }
572 // No bases specified? Try base
573 if(!count($bases)) $bases[] = $this->headpage->getBase();
575 // No target, open the restore removed object dialog.
576 if(!count($target)){
577 $entry = $this->headpage->getBase();
578 if(!empty($entry) && $this->ui->allow_snapshot_restore($entry,$this->aclCategory)){
579 @DEBUG (DEBUG_TRACE, __LINE__, __FUNCTION__, __FILE__,$entry,"Snaptshot restoring initiated!");
580 $this->dialogObject = new SnapShotDialog($this->config,$entry,$this);
581 $this->dialogObject->set_snapshot_bases($bases);
582 $this->dialogObject->display_all_removed_objects = true;
583 $this->dialogObject->display_restore_dialog = true;
584 $this->dialogObject->parent = &$this;
585 }else{
586 msg_dialog::display(_("Permission"),sprintf(_("You are not allowed to restore a snapshot for %s!"), bold($entry)),
587 ERROR_DIALOG);
588 }
589 }else{
591 // Display the restore points for a given object.
592 $entry = array_pop($target);
593 if(!empty($entry) && $this->ui->allow_snapshot_restore($entry,$this->aclCategory)){
594 @DEBUG (DEBUG_TRACE, __LINE__, __FUNCTION__, __FILE__,$entry,"Snaptshot restoring initiated!");
595 $this->dialogObject = new SnapShotDialog($this->config,$entry,$this);
596 $this->dialogObject->set_snapshot_bases($bases);
597 $this->dialogObject->display_restore_dialog = true;
598 $this->dialogObject->parent = &$this;
599 }else{
600 msg_dialog::display(_("Permission"),sprintf(_("You are not allowed to restore a snapshot for %s!"), bold($entry)),
601 ERROR_DIALOG);
602 }
603 }
604 }
607 /*! \brief This method intiates the object creation.
608 *
609 * @param String 'action' The name of the action which was the used as trigger.
610 * @param Array 'target' A list of object dns, which should be affected by this method.
611 * @param Array 'all' A combination of both 'action' and 'target'.
612 */
613 function newEntry($action="",$target=array(),$all=array(), $altTabClass ="", $altTabType = "", $altAclCategory="")
614 {
615 /* To handle mutliple object types overload this method.
616 * ...
617 * registerAction('newUser', 'newEntry');
618 * registerAction('newGroup','newEntry');
619 * ...
620 *
621 * function newEntry($action="",$target=array(),$all=array(), $altTabClass ="", $altTabType = "", $altAclCategory)
622 * {
623 * switch($action){
624 * case 'newUser' : {
625 * mangement::newEntry($action,$target,$all,"usertabs","USERTABS","users");
626 * }
627 * case 'newGroup' : {
628 * mangement::newEntry($action,$target,$all,"grouptabs","GROUPTABS","groups");
629 * }
630 * }
631 * }
632 **/
633 $tabType = $this->tabType;
634 $tabClass = $this->tabClass;
635 $aclCategory = $this->aclCategory;
636 if(!empty($altTabClass)) $tabClass = $altTabClass;
637 if(!empty($altTabType)) $tabType = $altTabType;
638 if(!empty($altAclCategory)) $aclCategory = $altAclCategory;
640 // Check locking & lock entry if required
641 $this->displayApplyBtn = FALSE;
642 $this->dn = "new";
643 $this->is_new = TRUE;
644 $this->is_single_edit = FALSE;
645 $this->is_multiple_edit = FALSE;
647 set_object_info($this->dn);
649 // Open object.
650 if(empty($tabClass) || empty($tabType)){
651 // No tab type defined
652 }else{
654 if (isset($this->config->data['TABS'][$tabType])) {
656 // Check if the base plugin is available - it is mostly responsible for object creation and removal.
657 $first = $this->config->data['TABS'][$tabType][0];
658 if(!class_available($first['CLASS'])){
659 msg_dialog::display(_("Internal error"),
660 sprintf(_("Cannot instantiate tabbed-plug-in, the base plugin (%s) is not available!"), $first['CLASS']),
661 ERROR_DIALOG);
662 }else{
663 $this->tabObject= new $tabClass($this->config,$this->config->data['TABS'][$tabType], $this->dn, $aclCategory);
664 $this->tabObject->set_acl_base($this->headpage->getBase());
665 $this->tabObject->parent = &$this;
666 @DEBUG (DEBUG_TRACE, __LINE__, __FUNCTION__, __FILE__,$this->dn,"Create new entry initiated!");
667 }
668 } else {
669 msg_dialog::display(_("Error"), sprintf(_("No tab definition for %s found in configuration file: cannot create plugin instance!"), bold($tabType)), ERROR_DIALOG);
670 }
671 }
672 }
675 /*! \brief This method opens an existing object or a list of existing objects to be edited.
676 *
677 *
678 * @param String 'action' The name of the action which was the used as trigger.
679 * @param Array 'target' A list of object dns, which should be affected by this method.
680 * @param Array 'all' A combination of both 'action' and 'target'.
681 */
682 function editEntry($action="",$target=array(),$all=array(), $altTabClass ="", $altTabType = "", $altAclCategory="")
683 {
684 /* To handle mutliple object types overload this method.
685 * ...
686 * registerAction('editUser', 'editEntry');
687 * registerAction('editGroup','editEntry');
688 * ...
689 *
690 * function editEntry($action="",$target=array(),$all=array(), $altTabClass ="", $altTabType = "", $altAclCategory)
691 * {
692 * switch($action){
693 * case 'editUser' : {
694 * mangement::editEntry($action,$target,$all,"usertabs","USERTABS","users");
695 * }
696 * case 'editGroup' : {
697 * mangement::editEntry($action,$target,$all,"grouptabs","GROUPTABS","groups");
698 * }
699 * }
700 * }
701 **/
703 // Do not create a new tabObject while there is already one opened,
704 // the user may have just pressed F5 to reload the page.
705 if(is_object($this->tabObject)){
706 return;
707 }
709 $tabType = $this->tabType;
710 $tabClass = $this->tabClass;
711 $aclCategory = $this->aclCategory;
712 if(!empty($altTabClass)) $tabClass = $altTabClass;
713 if(!empty($altTabType)) $tabType = $altTabType;
714 if(!empty($altAclCategory)) $aclCategory = $altAclCategory;
716 $this->displayApplyBtn = count($target) == 1;
718 // Single edit - we only got one object dn.
719 if(count($target) == 1){
720 $this->is_new = FALSE;
721 $this->is_single_edit = TRUE;
722 $this->is_multiple_edit = FALSE;
724 // Get the dn of the object and creates lock
725 $this->dn = array_pop($target);
726 set_object_info($this->dn);
727 $user = get_lock($this->dn);
728 if ($user != ""){
729 return(gen_locked_message ($user, array($this->dn),TRUE));
730 }
731 add_lock ($this->dn, $this->ui->dn);
733 // Open object.
734 if(empty($tabClass) || empty($tabType)){
735 trigger_error("We can't edit any object(s). 'tabClass' or 'tabType' is empty!");
736 }else{
738 $tab = $tabClass;
740 // Check if the base plugin is available - it is mostly responsible for object creation and removal.
741 $first = $this->config->data['TABS'][$tabType][0];
742 if(!class_available($first['CLASS'])){
743 msg_dialog::display(_("Internal error"),
744 sprintf(_("Cannot instantiate tabbed-plug-in, the base plugin (%s) is not available!"), $first['CLASS']),
745 ERROR_DIALOG);
746 }else{
747 $this->tabObject= new $tab($this->config,$this->config->data['TABS'][$tabType], $this->dn,$aclCategory);
748 @DEBUG (DEBUG_TRACE, __LINE__, __FUNCTION__, __FILE__,$this->dn,"Edit entry initiated!");
749 $this->tabObject->set_acl_base($this->dn);
750 $this->tabObject->parent = &$this;
751 }
752 }
753 }else{
755 // We've multiple entries to edit.
756 $this->is_new = FALSE;
757 $this->is_singel_edit = FALSE;
758 $this->is_multiple_edit = TRUE;
760 // Open multiple edit handler.
761 if(empty($tabClass) || empty($tabType)){
762 trigger_error("We can't edit any object(s). 'tabClass' or 'tabType' is empty!");
763 }else{
764 $this->dns = $target;
765 $tmp = new multi_plug($this->config,$tabClass,$this->config->data['TABS'][$tabType],
766 $this->dns,$this->headpage->getBase(),$aclCategory);
768 // Check for locked entries
769 if ($tmp->entries_locked()){
770 return($tmp->display_lock_message());
771 }
773 @DEBUG (DEBUG_TRACE, __LINE__, __FUNCTION__, __FILE__,$this->dns,"Edit entry initiated!");
775 // Now lock entries.
776 if($tmp->multiple_available()){
777 $tmp->lock_entries($this->ui->dn);
778 $this->tabObject = $tmp;
779 set_object_info($this->tabObject->get_object_info());
780 }
781 }
782 }
783 }
786 /*! \brief Close filter dialog
787 */
788 protected function cancelFilter()
789 {
790 if($this->dialogObject instanceOf userFilter){
791 $this->remove_lock();
792 $this->closeDialogs();
793 }
794 }
797 /*! \brief Save filter modifcations.
798 */
799 protected function saveFilter()
800 {
801 if($this->dialogObject instanceOf userFilter){
802 $msgs = $this->dialogObject->check();
803 if(count($msgs)){
804 msg_dialog::displayChecks($msgs);
805 return("");
806 }else{
807 $this->dialogObject->save();
808 @DEBUG (DEBUG_TRACE, __LINE__, __FUNCTION__, __FILE__,$this->dns,"Entry saved!");
809 $this->remove_lock();
810 $this->closeDialogs();
812 // Ask filter to reload information
813 $this->filter->reloadFilters();
814 }
815 }
816 }
819 /*! \brief Save object modifications and closes dialogs (returns to object listing).
820 * - Calls '::check' to validate the given input.
821 * - Calls '::save' to save back object modifications (e.g. to ldap).
822 * - Calls '::remove_locks' to remove eventually created locks.
823 * - Calls '::closeDialogs' to return to the object listing.
824 */
825 protected function saveChanges()
826 {
827 if($this->tabObject instanceOf tabs || $this->tabObject instanceOf multi_plug){
828 $this->tabObject->save_object();
829 $msgs = $this->tabObject->check();
830 if(count($msgs)){
831 msg_dialog::displayChecks($msgs);
832 return("");
833 }else{
834 $this->tabObject->save();
835 @DEBUG (DEBUG_TRACE, __LINE__, __FUNCTION__, __FILE__,$this->dns,"Entry saved!");
836 $this->remove_lock();
837 $this->closeDialogs();
838 }
839 }elseif($this->dialogObject instanceOf plugin){
840 $this->dialogObject->save_object();
841 $msgs = $this->dialogObject->check();
842 if(count($msgs)){
843 msg_dialog::displayChecks($msgs);
844 return("");
845 }else{
846 $this->dialogObject->save();
847 @DEBUG (DEBUG_TRACE, __LINE__, __FUNCTION__, __FILE__,$this->dns,"Entry saved!");
848 $this->remove_lock();
849 $this->closeDialogs();
850 }
851 }
852 }
855 /*! \brief Save object modifications and keep dialogs opened.
856 * - Calls '::check' to validate the given input.
857 * - Calls '::save' to save back object modifications (e.g. to ldap).
858 */
859 protected function applyChanges()
860 {
861 if($this->tabObject instanceOf tabs || $this->tabObject instanceOf multi_plug){
862 $this->tabObject->save_object();
863 $msgs = $this->tabObject->check();
864 if(count($msgs)){
865 msg_dialog::displayChecks($msgs);
866 return("");
867 }else{
868 $this->tabObject->save();
869 @DEBUG (DEBUG_TRACE, __LINE__, __FUNCTION__, __FILE__,$this->dns,"Modifications applied!");
870 $this->tabObject->re_init();
871 }
872 }
873 }
876 /*! \brief This method closes dialogs
877 * and cleans up the cached object info and the ui.
878 */
879 protected function closeDialogs()
880 {
881 $this->last_dn = $this->dn;
882 $this->last_dns = $this->dns;
883 $this->last_tabObject = $this->tabObject;
884 $this->last_dialogObject = $this->dialogObject;
885 $this->dn = "";
886 $this->dns = array();
887 $this->tabObject = null;
888 $this->dialogObject = null;
889 $this->skipFooter = FALSE;
890 set_object_info();
891 }
894 /*! \brief Editing an object was caneled.
895 * Close dialogs/tabs and remove locks.
896 */
897 protected function cancelEdit()
898 {
899 $this->remove_lock();
900 $this->closeDialogs();
901 }
904 /*! \brief Every click in the list user interface sends an event
905 * here can we connect those events to a method.
906 * eg. ::registerEvent('new','createUser')
907 * When the action/event new is send, the method 'createUser'
908 * will be called.
909 */
910 function registerAction($action,$target)
911 {
912 $this->actions[$action] = $target;
913 }
916 /*! \brief Removes ldap object locks created by this class.
917 * Whenever an object is edited, we create locks to avoid
918 * concurrent modifications.
919 * This locks will automatically removed here.
920 */
921 function remove_lock()
922 {
923 if(!empty($this->dn) && $this->dn != "new"){
924 del_lock($this->dn);
925 }
926 if(count($this->dns)){
927 del_lock($this->dns);
928 }
929 }
932 /*! \brief This method is used to queue and process copy&paste actions.
933 * Allows to copy, cut and paste mutliple entries at once.
934 * @param String 'action' The name of the action which was the used as trigger.
935 * @param Array 'target' A list of object dns, which should be affected by this method.
936 * @param Array 'all' A combination of both 'action' and 'target'.
937 */
938 function copyPasteHandler($action="",$target=array(),$all=array(),
939 $altTabClass ="", $altTabType = "", $altAclCategory="",$altAclPlugin="")
940 {
941 // Return without any actions while copy&paste handler is disabled.
942 if(!is_object($this->cpHandler)) return("");
944 $tabType = $this->tabType;
945 $tabClass = $this->tabClass;
946 $aclCategory = $this->aclCategory;
947 $aclPlugin = $this->aclPlugin;
948 if(!empty($altTabClass)) $tabClass = $altTabClass;
949 if(!empty($altTabType)) $tabType = $altTabType;
950 if(!empty($altAclCategory)) $aclCategory = $altAclCategory;
951 if(!empty($altAclPlugin)) $aclPlugin = $altAclPlugin;
953 // Save user input
954 $this->cpHandler->save_object();
956 // Add entries to queue
957 if($action == "copy" || $action == "cut"){
958 $this->cpHandler->cleanup_queue();
959 foreach($target as $dn){
960 if($action == "copy" && $this->ui->is_copyable($dn,$aclCategory,$aclPlugin)){
961 $this->cpHandler->add_to_queue($dn,"copy",$tabClass,$tabType,$aclCategory,$this);
962 @DEBUG (DEBUG_TRACE, __LINE__, __FUNCTION__, __FILE__,$dn,"Entry copied!");
963 }
964 if($action == "cut" && $this->ui->is_cutable($dn,$aclCategory,$aclPlugin)){
965 $this->cpHandler->add_to_queue($dn,"cut",$tabClass,$tabType,$aclCategory,$this);
966 @DEBUG (DEBUG_TRACE, __LINE__, __FUNCTION__, __FILE__,$dn,"Entry cutted!");
967 }
968 }
969 }
971 // Initiate pasting
972 if($action == "paste"){
973 $this->cpPastingStarted = TRUE;
974 }
976 // Display any c&p dialogs, eg. object modifications required before pasting.
977 if($this->cpPastingStarted && $this->cpHandler->entries_queued()){
978 $this->cpHandler->SetVar("base",$this->headpage->getBase());
979 $data = $this->cpHandler->execute();
980 if(!empty($data)){
981 return($data);
982 }
983 }
985 // Automatically disable pasting process since there is no entry left to paste.
986 if(!$this->cpHandler->entries_queued()){
987 $this->cpPastingStarted = FALSE;
988 }
989 return("");
990 }
993 function setFilter($str) {
994 $this->filter = $str;
995 }
998 function postcreate() {
999 $this->handle_post_events('add');
1000 }
1001 function postmodify(){
1002 $this->handle_post_events('modify');
1003 }
1004 function postremove(){
1005 $this->handle_post_events('remove');
1006 }
1008 function is_modal_dialog()
1009 {
1010 return(is_object($this->tabObject) || is_object($this->dialogObject));
1011 }
1014 /*! \brief Forward command execution request
1015 * to the correct method.
1016 */
1017 function handle_post_events($mode, $addAttrs= array())
1018 {
1019 if(!in_array($mode, array('add','remove','modify'))){
1020 trigger_error(sprintf("Invalid post event type given %s! Valid types are [add,modify,remove].", bold($mode)));
1021 return;
1022 }
1023 switch ($mode){
1024 case "add":
1025 plugin::callHook($this,"POSTCREATE", $addAttrs);
1026 break;
1028 case "modify":
1029 plugin::callHook($this,"POSTMODIFY", $addAttrs);
1030 break;
1032 case "remove":
1033 plugin::callHook($this,"POSTREMOVE", $addAttrs);
1034 break;
1035 }
1036 }
1037 }
1039 // vim:tabstop=2:expandtab:shiftwidth=2:filetype=php:syntax:ruler:
1040 ?>