class_management.inc 41.76 KiB
<?php
/*
  This code is part of FusionDirectory (http://www.fusiondirectory.org/)
  Copyright (C) 2017-2020  FusionDirectory
  This program is free software; you can redistribute it and/or modify
  it under the terms of the GNU General Public License as published by
  the Free Software Foundation; either version 2 of the License, or
  (at your option) any later version.
  This program is distributed in the hope that it will be useful,
  but WITHOUT ANY WARRANTY; without even the implied warranty of
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  GNU General Public License for more details.
  You should have received a copy of the GNU General Public License
  along with this program; if not, write to the Free Software
  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
/*!
 * \brief Management base class
class management implements FusionDirectoryDialog
  /* Object types we are currently managing */
  public $objectTypes;
  /* managementListing instance which manages the entries */
  public $listing;
  /* managementFilter instance which manages the filters */
  public $filter;
  /* Copy&Paste */
  protected $cpHandler = NULL;
  protected $cpPastingStarted = FALSE;
  protected $skipCpHandler = FALSE;
  /* Snapshots */
  protected $snapHandler = NULL;
  public static $skipSnapshots = FALSE;
  // The currently used object(s) (e.g. in edit, removal)
  protected $currentDn = '';
  protected $currentDns = [];
  // The last used object(s).
  protected $previousDn = '';
  protected $previousDns = [];
  // The opened object.
  /**
   * @var ?simpleTabs
  protected $tabObject = NULL;
  protected $dialogObject = NULL;
  // The last opened object.
  protected $last_tabObject = NULL;
  protected $last_dialogObject = NULL;
  protected $renderCache;
  public $headline;
  public $title;
  public $icon;
  protected $actions = [];
7172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140
protected $actionHandlers = []; protected $exporters = []; public $neededAttrs = []; public static $skipTemplates = TRUE; /* Disable and hide configuration system */ protected $skipConfiguration = FALSE; protected $columnConfiguration; /* Default columns */ public static $columns = [ ['ObjectTypeColumn', []], ['LinkColumn', ['attributes' => 'nameAttr', 'label' => 'Name']], ['LinkColumn', ['attributes' => 'description', 'label' => 'Description']], ['ActionsColumn', ['label' => 'Actions']], ]; function __construct ( $objectTypes = FALSE, array $filterElementDefinitions = [ ['TabFilterElement', []], ] ) { global $config, $class_mapping; if ($objectTypes === FALSE) { $plInfos = pluglist::pluginInfos(get_class($this)); $objectTypes = $plInfos['plManages']; } if (!preg_match('/^geticon/', $this->icon)) { $this->icon = get_template_path($this->icon); } /* Ignore non existing objectTypes. This happens when an optional plugin is missing. */ foreach ($objectTypes as $key => $type) { try { objects::infos($type); $objectTypes[$key] = strtoupper($type); } catch (NonExistingObjectTypeException $e) { unset($objectTypes[$key]); } } $this->objectTypes = array_values($objectTypes); $this->setUpHeadline(); $this->setUpListing(); $this->setUpFilter($filterElementDefinitions); // Add copy&paste and snapshot handler. if (!$this->skipCpHandler) { $this->cpHandler = new CopyPasteHandler(); } if (!static::$skipSnapshots && ($config->get_cfg_value('enableSnapshots') == 'TRUE')) { $this->snapHandler = new SnapshotHandler(); } // Load exporters foreach (array_keys($class_mapping) as $class) { if (preg_match('/Exporter$/', $class)) { $info = call_user_func([$class, 'getInfo']); if ($info != NULL) { $this->exporters = array_merge($this->exporters, $info); }
141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210
} } $this->configureActions(); } protected function setUpListing () { $this->listing = new managementListing($this); } protected function setUpFilter (array $filterElementDefinitions) { $this->filter = new managementFilter($this, NULL, $filterElementDefinitions); } protected function setUpHeadline () { $plInfos = pluglist::pluginInfos(get_class($this)); $this->headline = $plInfos['plShortName']; $this->title = $plInfos['plTitle']; $this->icon = $plInfos['plIcon']; } protected function configureActions () { global $config; // Register default actions $createMenu = []; if (!static::$skipTemplates) { $templateMenu = []; $fromTemplateMenu = []; } foreach ($this->objectTypes as $type) { $infos = objects::infos($type); $img = 'geticon.php?context=actions&icon=document-new&size=16'; if (isset($infos['icon'])) { $img = $infos['icon']; } $createMenu[] = new Action( 'new_' . $type, $infos['name'], $img, '0', 'newEntry', [$infos['aclCategory'] . '/' . $infos['mainTab'] . '/c'] ); if (!static::$skipTemplates) { $templateMenu[] = new Action( 'new_template_' . $type, $infos['name'], $img, '0', 'newEntryTemplate', [$infos['aclCategory'] . '/template/c'] ); $fromTemplateMenu[] = new Action( 'template_apply_' . $type, $infos['name'], $img, '0', 'newEntryFromTemplate', [$infos['aclCategory'] . '/template/r', $infos['aclCategory'] . '/' . $infos['mainTab'] . '/c'] ); } } if (!static::$skipTemplates) { $createMenu = array_merge( [ new SubMenuAction( 'template', _('Template'), 'geticon.php?context=devices&icon=template&size=16', $templateMenu ),
211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280
new SubMenuAction( 'fromtemplate', _('From template'), 'geticon.php?context=actions&icon=document-new&size=16', $fromTemplateMenu ), ], $createMenu ); } $this->registerAction( new SubMenuAction( 'new', _('Create'), 'geticon.php?context=actions&icon=document-new&size=16', $createMenu ) ); // Add export actions $exportMenu = []; foreach ($this->exporters as $action => $exporter) { $exportMenu[] = new Action( $action, $exporter['label'], $exporter['image'], '0', 'export' ); } $this->registerAction( new SubMenuAction( 'export', _('Export list'), 'geticon.php?context=actions&icon=document-export&size=16', $exportMenu ) ); $this->registerAction( new Action( 'edit', _('Edit'), 'geticon.php?context=actions&icon=document-edit&size=16', '+', 'editEntry' ) ); $this->actions['edit']->setSeparator(TRUE); if (!$this->skipCpHandler) { $this->registerAction( new Action( 'cut', _('Cut'), 'geticon.php?context=actions&icon=edit-cut&size=16', '+', 'copyPasteHandler', ['dr'] ) ); $this->registerAction( new Action( 'copy', _('Copy'), 'geticon.php?context=actions&icon=edit-copy&size=16', '+', 'copyPasteHandler', ['r'] ) ); $this->registerAction( new Action( 'paste', _('Paste'), 'geticon.php?context=actions&icon=edit-paste&size=16', '0', 'copyPasteHandler', ['w'] ) ); $this->actions['paste']->setEnableFunction([$this, 'enablePaste']); } if (!static::$skipTemplates) { $this->registerAction( new Action( 'template_apply_to', _('Apply template'), 'geticon.php?context=actions&icon=tools-wizard&size=16', '+', 'applyTemplateToEntry', ['/template/r', 'c'],
281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350
TRUE, FALSE ) ); } if (class_available('archivedObject')) { $action = archivedObject::getManagementAction($this->objectTypes, 'archiveRequested'); if ($action !== NULL) { $this->registerAction($action); $this->registerAction(new HiddenAction('archiveConfirmed', 'archiveConfirmed')); $this->registerAction(new HiddenAction('archiveCancel', 'cancelEdit')); } } $this->registerAction( new Action( 'remove', _('Remove'), 'geticon.php?context=actions&icon=edit-delete&size=16', '+', 'removeRequested', ['d'] ) ); if (!static::$skipSnapshots && ($config->get_cfg_value('enableSnapshots') == 'TRUE')) { $this->registerAction( new Action( 'snapshot', _('Create snapshot'), 'geticon.php?context=actions&icon=snapshot&size=16', '1', 'createSnapshotDialog', ['/SnapshotHandler/c'] ) ); $this->registerAction( new Action( 'restore', _('Restore snapshot'), 'geticon.php?context=actions&icon=document-restore&size=16', '*', 'restoreSnapshotDialog', ['w', '/SnapshotHandler/r'] ) ); $this->actions['snapshot']->setSeparator(TRUE); $this->actions['restore']->setEnableFunction([$this, 'enableSnapshotRestore']); } if (!static::$skipTemplates) { $this->registerAction( new Action( 'template_apply', _('Create an object from this template'), 'geticon.php?context=actions&icon=document-new&size=16', '1', 'newEntryFromTemplate', ['/template/r', 'c'], FALSE, TRUE, ['template'] ) ); } /* Actions from footer are not in any menus and do not need a label */ $this->registerAction(new HiddenAction('apply', 'applyChanges')); $this->registerAction(new HiddenAction('save', 'saveChanges')); $this->registerAction(new HiddenAction('cancel', 'cancelEdit')); $this->registerAction(new HiddenAction('cancelDelete', 'cancelEdit')); $this->registerAction(new HiddenAction('removeConfirmed', 'removeConfirmed')); if (!$this->skipConfiguration) { $this->registerAction(new HiddenAction('configure', 'configureDialog')); } } /*! * \brief Register an action to show in the action menu and/or the action column */ function registerAction (Action $action)
351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420
{ $action->setParent($this); $this->actions[$action->getName()] = $action; foreach ($action->listActions() as $actionName) { $this->actionHandlers[$actionName] = $action; } } public function getColumnConfiguration (): array { global $config; if (!isset($this->columnConfiguration)) { // LDAP configuration $this->columnConfiguration = $config->getManagementConfig(get_class($this)); } if (!isset($this->columnConfiguration)) { // Default configuration $this->columnConfiguration = static::$columns; } // Session configuration return $this->columnConfiguration; } public function setColumnConfiguration ($columns) { $this->columnConfiguration = $columns; $this->listing->reloadColumns(); } /*! * \brief Detects actions/events send by the ui * and the corresponding targets. */ function detectPostActions (): array { if (!is_object($this->listing)) { throw new FusionDirectoryException('No valid listing object'); } $action = ['targets' => [], 'action' => '', 'subaction' => NULL]; if ($this->showTabFooter()) { if (isset($_POST['edit_cancel'])) { $action['action'] = 'cancel'; } elseif (isset($_POST['edit_finish'])) { $action['action'] = 'save'; } elseif (isset($_POST['edit_apply'])) { $action['action'] = 'apply'; } } elseif (!$this->dialogOpened()) { if (isset($_POST['delete_confirmed'])) { $action['action'] = 'removeConfirmed'; } elseif (isset($_POST['delete_cancel'])) { $action['action'] = 'cancelDelete'; } elseif (isset($_POST['archive_confirmed'])) { $action['action'] = 'archiveConfirmed'; } elseif (isset($_POST['archive_cancel'])) { $action['action'] = 'archiveCancel'; } else { $action = $this->listing->getAction(); } } return $action; } /*! * \brief Calls the registered method for a given action/event. */
421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490
function handleAction (array $action) { // Start action if (isset($action['subaction']) && isset($this->actionHandlers[$action['action'] . '_' . $action['subaction']])) { return $this->actionHandlers[$action['action'] . '_' . $action['subaction']]->execute($this, $action); } elseif (isset($this->actionHandlers[$action['action']])) { return $this->actionHandlers[$action['action']]->execute($this, $action); } } protected function handleSubAction (array $action): bool { if (preg_match('/^tab_/', $action['subaction'])) { $tab = preg_replace('/^tab_/', '', $action['subaction']); if (isset($this->tabObject->by_object[$tab])) { $this->tabObject->current = $tab; } else { trigger_error('Unknown tab: ' . $tab); } return TRUE; } return FALSE; } /* For management we have to render directly in readPost in some cases */ public function readPost () { $this->renderCache = $this->execute(); } public function update (): bool { if ($this->renderCache === NULL) { if (!$this->dialogOpened()) { // Update list $this->listing->update(); // Init snapshot list for renderSnapshotActions if (is_object($this->snapHandler)) { $this->snapHandler->initSnapshotCache($this->listing->getBase()); } } } return TRUE; } public function render (): string { if ($this->renderCache === NULL) { if ($this->tabObject instanceof simpleTabs) { /* Display tab object */ $display = $this->tabObject->render(); $display .= $this->getTabFooter(); $this->renderCache = $this->getHeader() . $display; } elseif (is_object($this->dialogObject)) { /* Display dialog object */ $display = $this->dialogObject->render(); $display .= $this->getTabFooter(); $this->renderCache = $this->getHeader() . $display; } else { /* Display list */ $this->renderCache = $this->renderList(); } } return $this->renderCache; } /*! * \brief Execute this plugin * Handle actions/events, locking, snapshots, dialogs, tabs,...
491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560
*/ protected function execute () { // Ensure that html posts and gets are kept even if we see a 'Entry islocked' dialog. session::set('LOCK_VARS_TO_USE', ['/^act$/', '/^listing/', '/^PID$/']); /* Display the copy & paste dialog, if it is currently open */ $ret = $this->copyPasteHandler(); if ($ret) { return $this->getHeader() . $ret; } // Handle actions (POSTs and GETs) $action = $this->detectPostActions(); if (!empty($action['action'])) { logging::debug(DEBUG_TRACE, __LINE__, __FUNCTION__, __FILE__, $action, 'Action'); try { $str = $this->handleAction($action); if (!empty($str)) { return $this->getHeader() . $str; } } catch (FusionDirectoryException $e) { $error = new FusionDirectoryError(htmlescape($e->getMessage()), 0, $e); $error->display(); } } /* Save tab or dialog object */ if ($this->tabObject instanceof simpleTabs) { $this->tabObject->readPost(); $this->tabObject->update(); } elseif (is_object($this->dialogObject)) { try { $this->dialogObject->readPost(); if (is_object($this->dialogObject)) { /* Check again as readPost might close it */ if (!$this->dialogObject->update()) { $this->closeDialogs(); } } } catch (FusionDirectoryException $e) { $error = new FusionDirectoryError(htmlescape($e->getMessage()), 0, $e); $error->display(); $this->closeDialogs(); } } return NULL; } function renderList (): string { global $config, $ui; // Rendering things using smarty themselves first $listRender = $this->listing->render(); $filterRender = $this->renderFilter(); $actionMenu = $this->renderActionMenu(); $smarty = get_smarty(); $smarty->assign('usePrototype', 'true'); $smarty->assign('LIST', $listRender); $smarty->assign('FILTER', $filterRender); $smarty->assign('ACTIONS', $actionMenu); $smarty->assign('SIZELIMIT', $ui->getSizeLimitHandler()->renderWarning()); $smarty->assign('NAVIGATION', $this->listing->renderNavigation($this->skipConfiguration)); $smarty->assign('BASE', $this->listing->renderBase()); $smarty->assign('HEADLINE', $this->headline); return $this->getHeader() . $smarty->fetch(get_template_path('management/management.tpl'));
561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630
} protected function renderFilter (): string { return $this->filter->render(); } protected function renderActionMenu (): string { $menuActions = []; foreach ($this->actions as $action) { // Build ul/li list $action->fillMenuItems($menuActions); } if (empty($menuActions)) { return ''; } $smarty = get_smarty(); $smarty->assign('actions', $menuActions); return $smarty->fetch(get_template_path('management/actionmenu.tpl')); } function renderActionColumn (ListingEntry $entry): string { // Go thru all actions $result = ''; foreach ($this->actions as $action) { $result .= $action->renderColumnIcons($entry); } return $result; } function fillActionRowClasses (&$classes, ListingEntry $entry) { foreach ($this->actions as $action) { $action->fillRowClasses($classes, $entry); } } /*! * \brief Removes ldap object locks created by this class. * Whenever an object is edited, we create locks to avoid * concurrent modifications. * This locks will automatically removed here. */ public function removeLocks () { if (!empty($this->currentDn) && ($this->currentDn != 'new')) { Lock::deleteByObject($this->currentDn); } if (count($this->currentDns)) { Lock::deleteByObject($this->currentDns); } } function dialogOpened (): bool { return (is_object($this->tabObject) || is_object($this->dialogObject)); } /*! * \brief Sets smarty headline and returns the plugin header which is displayed whenever a tab object is opened. */ protected function getHeader (): string { global $smarty;
631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700
$smarty->assign('headline', $this->title); $smarty->assign('headline_image', $this->icon); if (is_object($this->tabObject) && ($this->currentDn != '')) { return '<div class="pluginfo">' . $this->currentDn . "</div>\n"; } return ''; } function openTabObject ($object) { $this->tabObject = $object; $this->tabObject->parent = &$this; } /*! * \brief This method closes dialogs * and cleans up the cached object info and the ui. */ public function closeDialogs () { $this->previousDn = $this->currentDn; $this->currentDn = ''; $this->previousDns = $this->currentDns; $this->currentDns = []; $this->last_tabObject = $this->tabObject; $this->tabObject = NULL; $this->last_dialogObject = $this->dialogObject; $this->dialogObject = NULL; } protected function listAclCategories (): array { $cat = []; foreach ($this->objectTypes as $type) { $infos = objects::infos($type); $cat[] = $infos['aclCategory']; } return array_unique($cat); } /*! * \brief Whether footer buttons should appear */ protected function showTabFooter (): bool { // Do not display tab footer for non tab objects if (!($this->tabObject instanceof simpleTabs)) { return FALSE; } // Check if there is a dialog opened - We don't need any buttons in this case. if ($this->tabObject->dialogOpened()) { return FALSE; } return TRUE; } /*! * \brief Generates the footer which is used whenever a tab object is displayed. */ protected function getTabFooter (): string { // Do not display tab footer for non tab objects if (!$this->showTabFooter()) { return ''; }
701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770
$smarty = get_smarty(); $smarty->assign('readOnly', $this->tabObject->readOnly()); $smarty->assign('showApply', ($this->currentDn != 'new')); return $smarty->fetch(get_template_path('management/tabfooter.tpl')); } function handleTemplateApply ($cancel = FALSE) { if (static::$skipTemplates) { return; } if ($cancel) { $msgs = []; } else { $msgs = $this->tabObject->save(); } if (count($msgs)) { msg_dialog::displayChecks($msgs); return; } else { if (!$cancel) { logging::debug(DEBUG_TRACE, __LINE__, __FUNCTION__, __FILE__, $this->currentDn, 'Template applied!'); } Lock::deleteByObject($this->currentDn); if (empty($this->currentDns)) { $this->closeDialogs(); } else { $this->last_tabObject = $this->tabObject; $this->tabObject = NULL; $this->currentDn = array_shift($this->currentDns); $this->dialogObject->setNextTarget($this->currentDn); $this->dialogObject->readPost(); } } } function enablePaste ($action, ListingEntry $entry = NULL): bool { if ($entry === NULL) { return $this->cpHandler->entries_queued(); } else { return FALSE; } } /* Action handlers */ /*! * \brief This method intiates the object creation. * * \param array $action A combination of both 'action' and 'target': * action: The name of the action which was the used as trigger. * target: A list of object dns, which should be affected by this method. */ function newEntry (array $action) { $type = $action['subaction']; $this->currentDn = 'new'; // Open object $this->openTabObject(objects::create($type)); logging::debug(DEBUG_TRACE, __LINE__, __FUNCTION__, __FILE__, $this->currentDn, 'Create entry initiated'); } function newEntryTemplate (array $action) { if (static::$skipTemplates) { return; }
771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840
$type = preg_replace('/^template_/', '', $action['subaction']); $this->currentDn = 'new'; // Open object $this->openTabObject(objects::createTemplate($type)); logging::debug(DEBUG_TRACE, __LINE__, __FUNCTION__, __FILE__, $this->currentDn, 'Create template entry initiated'); } function newEntryFromTemplate (array $action) { if (static::$skipTemplates) { return; } if (isset($action['targets'][0])) { $dn = $action['targets'][0]; } else { $dn = NULL; } if ($action['subaction'] == 'apply') { if ($dn === NULL) { return; } $type = $this->listing->getEntry($dn)->getTemplatedType(); } else { $type = preg_replace('/^apply_/', '', $action['subaction']); } $this->dialogObject = new templateDialog($this, $type, $dn); } function applyTemplateToEntry (array $action) { global $ui; if (static::$skipTemplates) { return; } if (empty($action['targets'])) { return; } $this->currentDns = $action['targets']; // check locks if ($locks = Lock::get($this->currentDns)) { return Lock::genLockedMessage($locks, FALSE, _('Apply anyway')); } // Add locks Lock::add($this->currentDns); // Detect type and check that all targets share the same type $type = NULL; foreach ($this->currentDns as $dn) { $entry = $this->listing->getEntry($dn); if ($entry === NULL) { trigger_error('Could not find ' . $dn . ', action canceled'); $this->currentDns = []; return; } if ($entry->isTemplate()) { $error = new FusionDirectoryError(htmlescape(_('Applying a template to a template is not possible'))); $error->display(); $this->currentDns = []; return; } if (!isset($type)) { $type = $entry->type; } elseif ($entry->type != $type) {
841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910
$error = new FusionDirectoryError(htmlescape(_('All selected entries need to share the same type to be able to apply a template to them'))); $error->display(); $this->currentDns = []; return; } } $this->currentDn = array_shift($this->currentDns); $this->dialogObject = new templateDialog($this, $type, NULL, $this->currentDn); } /*! \brief Queue selected objects to be archived. * Checks Locks and ask for confirmation. */ public function archiveRequested (array $action) { global $ui; if (empty($action['targets'])) { return; } $this->currentDns = $action['targets']; logging::debug(DEBUG_TRACE, __LINE__, __FUNCTION__, __FILE__, $action['targets'], 'Entry archive requested'); // Check locks if ($locks = Lock::get($this->currentDns)) { return Lock::genLockedMessage($locks, FALSE, _('Archive anyway')); } // Add locks Lock::add($this->currentDns); $objects = []; foreach ($this->currentDns as $dn) { $entry = $this->listing->getEntry($dn); if ($entry->isTemplate()) { $error = new FusionDirectoryError(htmlescape(_('Archiving a template is not possible'))); $error->display(); $this->removeLocks(); $this->currentDns = []; return; } $infos = objects::infos($entry->getTemplatedType()); $objects[] = [ 'name' => $entry[$infos['nameAttr']][0], 'dn' => $dn, 'icon' => $infos['icon'], 'type' => $infos['name'] ]; } $smarty = get_smarty(); $smarty->assign('objects', $objects); return $smarty->fetch(get_template_path('simple-archive.tpl')); } public function archiveConfirmed (array $action) { logging::debug(DEBUG_TRACE, __LINE__, __FUNCTION__, __FILE__, $this->currentDns, 'Archiving'); $success = 0; foreach ($this->currentDns as $dn) { $entry = $this->listing->getEntry($dn); $errors = archivedObject::archiveObject($entry->type, $dn); if (empty($errors)) { $success++; } else {
911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980
msg_dialog::displayChecks($errors); } Lock::deleteByObject($dn); } if ($success > 0) { msg_dialog::display( _('Archive success'), htmlescape(sprintf(_('%d entries were successfully archived'), $success)), INFO_DIALOG ); } $this->currentDns = []; } /*! * \brief This method opens an existing object to be edited. * * \param array $action A combination of both 'action' and 'targets': * action: The name of the action which was the used as trigger. * targets: A list of object dns, which should be affected by this method. */ function editEntry (array $action) { global $ui; // Do not create a new tabObject while there is already one opened, // the user may have just pressed F5 to reload the page. if (is_object($this->tabObject)) { return; } $target = array_pop($action['targets']); $entry = $this->listing->getEntry($target); if ($entry === NULL) { trigger_error('Could not find ' . $target . ', open canceled'); return; } // Get the dn of the object and create lock $this->currentDn = $target; if ($locks = Lock::get($this->currentDn, TRUE)) { return Lock::genLockedMessage($locks, TRUE); } Lock::add($this->currentDn); // Open object $this->openTabObject(objects::open($this->currentDn, $entry->getTemplatedType())); logging::debug(DEBUG_TRACE, __LINE__, __FUNCTION__, __FILE__, $this->currentDn, 'Edit entry initiated'); if (isset($action['subaction']) && ($this->handleSubAction($action) === FALSE)) { trigger_error('Was not able to handle subaction: ' . $action['subaction']); } } /*! * \brief Editing an object was canceled. * Close dialogs/tabs and remove locks. */ function cancelEdit () { if (($this->tabObject instanceof simpleTabs) && ($this->dialogObject instanceof templateDialog)) { $this->handleTemplateApply(TRUE); return; } $this->removeLocks(); $this->closeDialogs(); }
981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050
/*! * \brief Save object modifications and closes dialogs (returns to object listing). * - Calls 'simpleTabs::save' to save back object modifications (e.g. to ldap). * - Calls 'management::closeDialogs' to return to the object listing. */ function saveChanges () { if ($this->tabObject instanceof simpleTabs) { $this->tabObject->readPost(); $this->tabObject->update(); if ($this->dialogObject instanceof templateDialog) { $this->handleTemplateApply(); } else { $msgs = $this->tabObject->save(); if (count($msgs)) { msg_dialog::displayChecks($msgs); } else { logging::debug(DEBUG_TRACE, __LINE__, __FUNCTION__, __FILE__, $this->currentDns, 'Entry saved'); $this->removeLocks(); $this->closeDialogs(); } } } } /*! * \brief Save object modifications and keep dialogs opened */ function applyChanges () { if ($this->tabObject instanceof simpleTabs) { $this->tabObject->readPost(); $this->tabObject->update(); $msgs = $this->tabObject->save(); if (count($msgs)) { msg_dialog::displayChecks($msgs); } else { logging::debug(DEBUG_TRACE, __LINE__, __FUNCTION__, __FILE__, $this->currentDns, 'Modifications applied'); $this->tabObject->re_init(); /* Avoid applying the POST a second time */ $_POST = []; } } } /*! \brief Queue selected objects to be removed. * Checks ACLs, Locks and ask for confirmation. */ function removeRequested (array $action) { global $ui; $disallowed = []; $this->currentDns = []; logging::debug(DEBUG_TRACE, __LINE__, __FUNCTION__, __FILE__, $action['targets'], 'Entry deletion requested'); // Check permissons for each target foreach ($action['targets'] as $dn) { $entry = $this->listing->getEntry($dn); try { if ($entry->checkAcl('d')) { $this->currentDns[] = $dn; } else { $disallowed[] = $dn; } } catch (NonExistingObjectTypeException $e) { trigger_error('Unknown object type received :' . $e->getMessage()); } }
1051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120
if (count($disallowed)) { $error = new FusionDirectoryPermissionError(msgPool::permDelete($disallowed)); $error->display(); } // We've at least one entry to delete. if (count($this->currentDns)) { // Check locks if ($locks = Lock::get($this->currentDns)) { return Lock::genLockedMessage($locks, FALSE, _('Delete anyway')); } // Add locks Lock::add($this->currentDns); $objects = []; foreach ($this->currentDns as $dn) { $entry = $this->listing->getEntry($dn); $infos = objects::infos($entry->getTemplatedType()); if ($entry->isTemplate()) { $infos['nameAttr'] = 'cn'; } $objects[] = [ 'name' => $entry[$infos['nameAttr']][0], 'dn' => $dn, 'icon' => $infos['icon'], 'type' => $infos['name'] ]; } return $this->removeConfirmationDialog($objects); } } /*! \brief Display confirmation dialog */ protected function removeConfirmationDialog (array $objects) { $smarty = get_smarty(); $smarty->assign('objects', $objects); $smarty->assign('multiple', TRUE); return $smarty->fetch(get_template_path('simple-remove.tpl')); } /*! \brief Deletion was confirmed, delete the objects queued. * Checks ACLs just in case. */ function removeConfirmed (array $action) { global $ui; logging::debug(DEBUG_TRACE, __LINE__, __FUNCTION__, __FILE__, $this->currentDns, 'Entry deletion confirmed'); $snapshotHandler = new SnapshotHandler(); foreach ($this->currentDns as $dn) { $entry = $this->listing->getEntry($dn); if (empty($entry)) { continue; } if ($entry->checkAcl('d')) { // Delete the object $this->currentDn = $dn; $this->openTabObject(objects::open($this->currentDn, $entry->getTemplatedType())); $errors = $this->tabObject->delete(); msg_dialog::displayChecks($errors); // Remove the lock for the current object. Lock::deleteByObject($this->currentDn); // Remove related snapshots $dnSnapshotsList = $snapshotHandler->getSnapshots($this->currentDn, TRUE);
1121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190
foreach ($dnSnapshotsList as $snap) { $snapshotHandler->removeSnapshot($snap['dn']); } } else { $error = new FusionDirectoryPermissionError(msgPool::permDelete($dn)); $error->display(); logging::log('security', 'management/' . get_class($this), $dn, [], 'Tried to trick deletion.'); } } // Cleanup $this->removeLocks(); $this->closeDialogs(); } function configureDialog (array $action) { if (!$this->skipConfiguration) { $this->dialogObject = new ManagementConfigurationDialog($this); } } /*! \brief This method is used to queue and process copy&paste actions. * Allows to copy, cut and paste mutliple entries at once. */ function copyPasteHandler (array $action = ['action' => '']) { global $ui; // Exit if copy&paste handler is disabled. if (!is_object($this->cpHandler)) { return FALSE; } // Save user input $this->cpHandler->readPost(); // Add entries to queue if (($action['action'] == 'copy') || ($action['action'] == 'cut')) { $this->cpHandler->cleanup_queue(); foreach ($action['targets'] as $dn) { $entry = $this->listing->getEntry($dn); if (($action['action'] == 'copy') && $entry->checkAcl('r')) { $this->cpHandler->add_to_queue($dn, 'copy', $entry->getTemplatedType()); logging::debug(DEBUG_TRACE, __LINE__, __FUNCTION__, __FILE__, $dn, 'Entry copied!'); } if (($action['action'] == 'cut') && $entry->checkAcl('rd')) { $this->cpHandler->add_to_queue($dn, 'cut', $entry->getTemplatedType()); logging::debug(DEBUG_TRACE, __LINE__, __FUNCTION__, __FILE__, $dn, 'Entry cut!'); } } } // Initiate pasting if ($action['action'] == 'paste') { $this->cpPastingStarted = TRUE; } // Display any c&p dialogs, eg. object modifications required before pasting. if ($this->cpPastingStarted && $this->cpHandler->entries_queued()) { $this->cpHandler->update(); $data = $this->cpHandler->render(); if (!empty($data)) { return $data; } } // Automatically disable pasting process since there is no entry left to paste. if (!$this->cpHandler->entries_queued()) { $this->cpPastingStarted = FALSE;
1191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260
$this->cpHandler->resetPaste(); } return ''; } /*! * \brief Opens the snapshot creation dialog for the given target. */ function createSnapshotDialog (array $action) { global $config, $ui; logging::debug(DEBUG_TRACE, __LINE__, __FUNCTION__, __FILE__, $action['targets'], 'Snapshot creation initiated!'); $this->currentDn = array_pop($action['targets']); if (empty($this->currentDn)) { return; } $entry = $this->listing->getEntry($this->currentDn); if ($entry->snapshotCreationAllowed()) { $this->dialogObject = new SnapshotCreateDialog($this->currentDn, $this, ''); } else { $error = new FusionDirectoryError( htmlescape(sprintf( _('You are not allowed to create a snapshot for %s.'), $this->currentDn )) ); $error->display(); } } /*! * \brief Displays the "Restore snapshot dialog" for a given target. * If no target is specified, open the restore removed object dialog. */ function restoreSnapshotDialog (array $action) { global $config, $ui; if (empty($action['targets'])) { // No target, open the restore removed object dialog. $this->currentDn = $this->listing->getBase(); $aclCategories = $this->listAclCategories(); } else { // Display the restore points for a given object. $this->currentDn = $action['targets'][0]; if (empty($this->currentDn)) { return; } $aclCategories = [objects::infos($this->listing->getEntry($this->currentDn)->getTemplatedType())['aclCategory']]; } if ($ui->allow_snapshot_restore($this->currentDn, $aclCategories, empty($action['targets']))) { logging::debug(DEBUG_TRACE, __LINE__, __FUNCTION__, __FILE__, $this->currentDn, 'Snapshot restoring initiated!'); $this->dialogObject = new SnapshotRestoreDialog($this->currentDn, $this, empty($action['targets']), $aclCategories); } else { $error = new FusionDirectoryError( htmlescape(sprintf( _('You are not allowed to restore a snapshot for %s.'), $this->currentDn )) ); $error->display(); } } function export (array $action) {
1261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330
if (!isset($this->exporters[$action['action']])) { trigger_error('Unknown exporter ' . $action['action']); return; } $exporter = $this->exporters[$action['action']]; $file = $exporter['class']::export($this->listing); send_binary_content($file, $exporter['filename'], $exporter['mime']); } /* End of action handlers */ /* Methods related to Snapshots */ function getSnapshotBases (): array { $bases = []; foreach ($this->objectTypes as $type) { $infos = objects::infos($type); $bases[] = $infos['ou'] . $this->listing->getBase(); } // No bases specified? Try base if (!count($bases)) { $bases[] = $this->listing->getBase(); } return array_unique($bases); } /*! * \brief Get all deleted snapshots */ function getAllDeletedSnapshots (): array { $bases = $this->getSnapshotBases(); $tmp = []; foreach ($bases as $base) { $tmp = array_merge($tmp, $this->snapHandler->getAllDeletedSnapshots($base)); } return $tmp; } /* * \brief Return available snapshots for the given base * * \param string $dn The DN */ function getAvailableSnapsShots (string $dn): array { return $this->snapHandler->getAvailableSnapsShots($dn); } /* * \brief Whether snapshot restore action should be enabled for an entry */ function enableSnapshotRestore ($action, ListingEntry $entry = NULL): bool { if ($entry !== NULL) { /* For entries */ return $this->snapHandler->hasSnapshots($entry->dn); } else { /* For action menu */ return $this->snapHandler->hasDeletedSnapshots($this->getSnapshotBases()); } } /*! * \brief Creates a new snapshot entry * If source arg is not set, default to 'FD'. */
1331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400
function createSnapshot (string $dn, string $description, string $snapshotSource = 'FD') { global $ui; if (empty($dn) || ($this->currentDn !== $dn)) { trigger_error('There was a problem with the snapshot workflow'); return; } $entry = $this->listing->getEntry($dn); if ($entry->snapshotCreationAllowed()) { $this->snapHandler->createSnapshot($dn, $description, $entry->type, $snapshotSource); logging::debug(DEBUG_TRACE, __LINE__, __FUNCTION__, __FILE__, $dn, 'Snapshot created!'); } else { $error = new FusionDirectoryPermissionError(htmlescape(sprintf(_('You are not allowed to restore a snapshot for %s.'), $dn))); $error->display(); } } /*! * \brief Restores a snapshot object. * * \param String $dn The DN of the snapshot */ function restoreSnapshot (string $dn) { global $ui; if (!empty($dn) && $ui->allow_snapshot_restore($dn, $this->dialogObject->aclCategory, $this->dialogObject->global)) { $dn = $this->snapHandler->restoreSnapshot($dn); logging::debug(DEBUG_TRACE, __LINE__, __FUNCTION__, __FILE__, $dn, 'Snapshot restored'); $this->closeDialogs(); if ($dn !== FALSE) { $this->listing->focusDn($dn); $entry = $this->listing->getEntry($dn); $this->currentDn = $dn; Lock::add($this->currentDn); // Open object $this->openTabObject(objects::open($this->currentDn, $entry->getTemplatedType())); $this->saveChanges(); } } else { $error = new FusionDirectoryPermissionError(htmlescape(sprintf(_('You are not allowed to restore a snapshot for %s.'), $dn))); $error->display(); } } /*! * \brief Delete a snapshot * * \param string $dn DN of the snapshot */ function removeSnapshot (string $dn) { global $ui; if (!empty($dn) && $ui->allow_snapshot_delete($dn, $this->dialogObject->aclCategory)) { $this->snapHandler->removeSnapshot($dn); logging::debug(DEBUG_TRACE, __LINE__, __FUNCTION__, __FILE__, $dn, 'Snapshot deleted'); } else { $error = new FusionDirectoryPermissionError(htmlescape(sprintf(_('You are not allowed to delete a snapshot for %s.'), $dn))); $error->display(); } } static function mainInc ($classname = NULL, $objectTypes = FALSE) { global $remove_lock, $cleanup, $display; if ($classname === NULL) { $classname = get_called_class(); }
14011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429
/* Remove locks */ if ($remove_lock && session::is_set($classname)) { $macl = session::get($classname); $macl->removeLocks(); } if ($cleanup) { /* Clean up */ session::un_set($classname); } else { if (!session::is_set($classname) || (isset($_GET['reset']) && $_GET['reset'] == 1)) { /* Create the object if missing or reset requested */ $managementObject = new $classname($objectTypes); } else { /* Retrieve the object from session */ $managementObject = session::get($classname); } /* Execute and display */ $managementObject->readPost(); $managementObject->update(); $display = $managementObject->render(); /* Store the object in the session */ session::set($classname, $managementObject); } } }