• Côme Chilliet's avatar
    :sparkles: feat(core) Big refactor of dialog system · 94eaa6ba
    Côme Chilliet authored
    This replaces save_object and execute methods by 3 methods:
    readPost - Reads POST data
    update - Update object state
    render - Render HTML UI
    
    The point is to avoid reading POST and rendering HTML when this is not
     needed (when doing stuff through the webservice for instance).
    
    It’s also more consisent across FD with all classes handling some kind
     of dialog implementing the new interface FusionDirectoryDialog which
     makes sure these 3 methods are implemented.
    
    issue #6072
    Unverified
    94eaa6ba
class_CopyPasteHandler.inc 9.57 KiB
<?php
/*
  This code is part of FusionDirectory (http://www.fusiondirectory.org/)
  Copyright (C) 2003-2010  Cajus Pollmeier
  Copyright (C) 2011-2017  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.
/*!
 * \file class_CopyPasteHandler.inc
 * Source code for class CopyPasteHandle
/*!
 * \brief This class contains all function to copy and paste
class CopyPasteHandler implements FusionDirectoryDialog
  var $current = FALSE;
  /*!
   * \brief This array contains all dns of the currently copied objects
  protected $objectList = [];
  /*!
   * \brief This array contains all remaining objects to paste
  protected $queue = [];
  /*!
   *  \brief The dn of the last edited object
  protected $lastdn = '';
  protected $disallowed_objects = [];
  protected $objects_to_fix     = [];
  protected $clean_objects      = [];
  protected $require_update     = FALSE;
  /*!
   * \brief Create CP handler
  function __construct ()
  /*!
   * \brief Entry entry to Copy & Paste queue.
   * A Queue entry is represented as follows.
   *  array['method']     - 'copy' or 'cut'
   *  array['dn']         - the dn of the object added to the queue
   *  array['type']       - Object type
   * \param String $dn The dn of the object added to the queue
   * \param String $action Copy or Cut
7172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140
* \param String $type the type of the object */ function add_to_queue ($dn, $action, $type) { logging::debug(DEBUG_TRACE, __LINE__, __FUNCTION__, __FILE__, $dn, 'add_to_queue'); if (!in_array($action, ['cut','copy'])) { trigger_error(sprintf('Specified action "%s" does not exists for copy & paste.', $action)); return FALSE; } $tmp = []; $tmp['method'] = $action; $tmp['dn'] = $dn; $tmp['type'] = $type; $infos = objects::infos($type); $tmp['aclCategory'] = $infos['aclCategory']; $tmp['mainTab'] = $infos['mainTab']; $tmp['parent'] = NULL; $this->queue[] = $tmp; if ($action == 'copy') { $this->objectList[] = $tmp; } $this->require_update = TRUE; return TRUE; } /*! * \brief This removes all objects from queue. * Remove hdd dumps of current entries too. * Remove entries older than 24 hours. */ function cleanup_queue () { $this->current = FALSE; $this->require_update = TRUE; $this->queue = []; $this->objectList = []; } /*! * \brief This resets the queue to allow pasting again. */ function resetPaste () { $this->current = FALSE; $this->require_update = TRUE; $this->queue = $this->objectList; } /*! * \brief Check if there are still entries the object queue */ function entries_queued () { return ((count($this->queue) > 0) || ($this->current !== FALSE)); } /*! * \brief Paste one entry from LDAP */ protected function load_entry_from_ldap ($entry) { logging::debug(DEBUG_TRACE, __LINE__, __FUNCTION__, __FILE__, $entry['dn'], 'load_entry_from_ldap'); if (!isset($entry['tab_class']) && !isset($entry['type'])) {
141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210
return []; } $entry['object'] = objects::open($entry['dn'], $entry['type']); if ($entry['parent'] !== NULL) { $entry['object']->parent = $entry['parent']; } if ($entry['method'] == 'copy') { $entry['object']->resetCopyInfos(); } logging::log('copy', $entry['method'], $entry['dn'], [], ''); $entry['object']->resetBase(); return $entry; } public function update(): bool { $ui = get_userinfo(); /* Check which entries can be pasted directly. * Create a list of all entries that can be pasted directly. */ if ($this->require_update) { $this->clean_objects = []; $this->objects_to_fix = []; $this->disallowed_objects = []; /* Put each queued object in one of the above arrays */ foreach ($this->queue as $key => $entry) { /* Update entries on demand */ if (!isset($entry['object'])) { $entry = $this->load_entry_from_ldap($entry); $this->queue[$key] = $entry; } /* Retrieve ACL infos */ $copy_acl = $ui->is_copyable($entry['dn'], $entry['aclCategory']); $cut_acl = $ui->is_cutable($entry['dn'], $entry['aclCategory'], $entry['mainTab']); /* Check permissions */ if ((($entry['method'] == 'copy') && !$copy_acl) || (($entry['method'] == 'cut') && !$cut_acl)) { $this->disallowed_objects[$key] = $entry; } else { $this->clean_objects[$key] = $entry; } } if (count($this->disallowed_objects)) { $dns = []; foreach ($this->disallowed_objects as $entry) { $dns[] = $entry['dn']; } $error = new FusionDirectoryPermissionError(msgPool::permCreate($dns)); $error->display(); } $this->require_update = FALSE; } /* Save objects that can be pasted directly */ if (count($this->clean_objects)) { foreach ($this->clean_objects as $key => $entry) { $this->current = $entry; $errors = $this->current['object']->save();
211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280
if (empty($errors)) { $this->current_saved(); /* Remove from queue -> avoid saving twice */ unset($this->queue[$key]); } else { $this->objects_to_fix[$key] = $entry; } unset($this->clean_objects[$key]); } $this->current = FALSE; } /* Save edited entry and force loading new one */ if (isset($this->current['object'])) { $this->current['object']->readPost(); $this->current['object']->update(); /* Save current object if edition is finished */ if (!$this->current['object']->dialogOpened() && isset($_POST['edit_finish'])) { $errors = $this->current['object']->save(); if (empty($errors)) { $this->current_saved(); } else { msg_dialog::displayChecks($errors); } } } return TRUE; } /*! * \brief Displays a dialog which allows the user to fix all dependencies of this object. * Create unique names, ids, or what ever */ public function render (): string { /* Display a list of all pastable entries */ if ($this->current || count($this->objects_to_fix)) { if (!$this->current) { $key = key($this->objects_to_fix); if ($key !== NULL) { $this->current = $this->objects_to_fix[$key]; unset($this->objects_to_fix[$key]); unset($this->queue[$key]); } } if ($this->current) { $display = $this->current['object']->render(); if (!$this->current['object']->dialogOpened()) { // Display ok, (apply) and cancel buttons $display .= '<p class="plugbottom">'."\n"; $display .= '<input type="submit" name="edit_finish" style="width:80px" value="'.msgPool::okButton().'"/>'."\n"; $display .= "&nbsp;\n"; $display .= '<input type="submit" formnovalidate="formnovalidate" name="abort_current_cut-copy_operation" value="'.msgPool::cancelButton().'"/>'."\n"; $display .= '<input type="submit" formnovalidate="formnovalidate" name="abort_all_cut-copy_operations" value="'._('Cancel all').'"/>'."\n"; $display .= '</p>'; } return $display; } } return ''; } private function current_saved () { $this->lastdn = $this->current['object']->dn; logging::log('copy', 'paste', $this->lastdn); $this->handleReferences(); $this->current = FALSE;
281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337
} /*! * \brief Get the last endited entry * * \return the dn of the last edited entry */ function last_entry () { return $this->lastdn; } /*! * \brief Save new values posted by copy & paste dialog */ public function readPost () { if (isset($_POST['abort_current_cut-copy_operation'])) { $this->current = FALSE; } if (isset($_POST['abort_all_cut-copy_operations'])) { $this->cleanup_queue(); $this->current = FALSE; } } function handleReferences () { $dst_dn = $this->current['object']->dn; $src_dn = $this->current['dn']; $this->current['object']->getBaseObject()->handleForeignKeys( $src_dn, $dst_dn, ($this->current['method'] == 'cut' ? 'move' : 'copy') ); } /*! * \brief Generate the paste icon for headpages * * \return the paste icon for headpages */ function generatePasteIcon () { $Copy_Paste = "&nbsp;<img class='center' src='images/lists/seperator.png' alt='' height='16' width='1'>&nbsp;"; if ($this->entries_queued()) { $Copy_Paste .= "<input type='image' name='editPaste' class='center' src='geticon.php?context=actions&amp;icon=edit-paste&amp;size=16' alt='"._("Paste")."'>&nbsp;"; } else { $Copy_Paste .= "<img class='center' src='geticon.php?context=actions&amp;icon=edit-paste&amp;size=16&amp;disabled=1' alt=\""._("Cannot paste")."\">&nbsp;"; } return $Copy_Paste; } }