"Fossies" - the Fresh Open Source Software Archive

Member "PHProjekt-6.2.1/phprojekt/application/Default/Controllers/IndexController.php" (9 Oct 2012, 42886 Bytes) of package /linux/www/old/PHProjekt-6.2.1.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) PHP source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "IndexController.php" see the Fossies "Dox" file reference documentation and the latest Fossies "Diffs" side-by-side code changes report: 6.2.0_vs_6.2.1.

    1 <?php
    2 /**
    3  * This software is free software; you can redistribute it and/or
    4  * modify it under the terms of the GNU Lesser General Public
    5  * License version 3 as published by the Free Software Foundation
    6  *
    7  * This library is distributed in the hope that it will be useful,
    8  * but WITHOUT ANY WARRANTY; without even the implied warranty of
    9  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
   10  * Lesser General Public License for more details.
   11  *
   12  * @copyright  Copyright (c) 2010 Mayflower GmbH (http://www.mayflower.de)
   13  * @license    LGPL v3 (See LICENSE file)
   14  */
   15 
   16 /**
   17  * Default Controller.
   18  *
   19  * <pre>
   20  * The controller gets an action and runs the nessesary stuff for it.
   21  * The actions whose name starts with "json", returns the data in JSON format.
   22  * The actions whose name starts with csv, returns the data in CSV format.
   23  * The controller calls the class model of the module, for process all the data.
   24  * </pre>
   25  */
   26 class IndexController extends Zend_Controller_Action
   27 {
   28     /**
   29      * String to use on success in the action save for new items.
   30      */
   31     const ADD_TRUE_TEXT = "The Item was added correctly";
   32 
   33     /**
   34      * String to use on success in the action save for existing items.
   35      */
   36     const EDIT_TRUE_TEXT = "The Item was edited correctly";
   37 
   38     /**
   39      * String to use on success in the action save for many items together.
   40      */
   41     const EDIT_MULTIPLE_TRUE_TEXT = "The Items were edited correctly";
   42 
   43     /**
   44      * String to use on success in the action delete.
   45      */
   46     const DELETE_TRUE_TEXT = "The Item was deleted correctly";
   47 
   48     /**
   49      * String to use on error in the action delete.
   50      */
   51     const DELETE_FALSE_TEXT = "The Item can't be deleted";
   52 
   53     /**
   54      * String to use on success in the action delete for many items together.
   55      */
   56     const DELETE_MULTIPLE_TRUE_TEXT = "The Items were deleted correctly";
   57 
   58     /**
   59      * String for use if the item don't exists.
   60      */
   61     const NOT_FOUND = "The Item was not found";
   62 
   63     /**
   64      * String for use if the id is not in the request parameters.
   65      */
   66     const ID_REQUIRED_TEXT = "ID parameter required";
   67 
   68     /**
   69      * String for use if the nodeId is not in the request parameters.
   70      */
   71     const NODEID_REQUIRED_TEXT = "Node Id parameter required";
   72 
   73     /**
   74      * String for use if the nodeId is not in the request parameters.
   75      */
   76     const PROJECTID_REQUIRED_TEXT = "projectId parameter required";
   77 
   78     /**
   79      * Internal number for the root project.
   80      */
   81     const INVISIBLE_ROOT = 1;
   82 
   83     /**
   84      * The link will be executed using a normal POST and ajax.
   85      */
   86     const MODE_ACTION_XHR = 0;
   87 
   88     /**
   89      * The link will be executed in a new windows as a normal GET.
   90      */
   91     const MODE_ACTION_WINDOW = 1;
   92 
   93     /**
   94      * The action will be executed in the client.
   95      */
   96     const MODE_ACTION_CLIENT = 2;
   97 
   98     /**
   99      * The action is for one id,
  100      * used in the grid for one row.
  101      */
  102     const TARGET_ACTION_SINGLE = 0;
  103 
  104     /**
  105      * The action is for multiple ids,
  106      * used in the selectbox of the grid for all the checked rows.
  107      */
  108     const TARGET_ACTION_MULTIPLE = 1;
  109 
  110     /**
  111      * String to use on success in the action disableFrontendMessages.
  112      */
  113     const DISABLE_FRONTEND_MESSAGES_TRUE_TEXT = "All settings were disabled successfully!";
  114 
  115     /**
  116      * String to use on error in the action disableFrontendMessages.
  117      */
  118     const DISABLE_FRONTEND_MESSAGES_FALSE_TEXT = "No settings were disabled!";
  119 
  120     /**
  121      * Initialize our controller and disable the viewRenderer.
  122      *
  123      * Try to detect ajax requests and set the format so we can use json templates.
  124      *
  125      * @return void
  126      */
  127     public function init()
  128     {
  129         $this->_helper->viewRenderer->setNoRender();
  130         // check for ajax request, if ajax, send json, if not, send html page
  131         if ($this->getRequest()->getHeader('X-Requested-With') === 'XMLHttpRequest') {
  132             $this->getRequest()->setParam('format', 'json');
  133         }
  134     }
  135 
  136     /**
  137      * Init function.
  138      *
  139      * Checks if it is a logged user, if not,
  140      * is redirected to the login form or throws an exception.
  141      *
  142      * The function sets up the helper and cleans all the variables.
  143      *
  144      * @throws Zend_Controller_Action_Exception If the user is not logged in and the request is a POST.
  145      *
  146      * @return void
  147      */
  148     public function preDispatch()
  149     {
  150         $this->checkAuthentication();
  151     }
  152 
  153     /**
  154      * Check if the user is logged in and everything is fine.
  155      *
  156      * @return void
  157      */
  158     public function checkAuthentication()
  159     {
  160         $isLoggedIn = Phprojekt_Auth::isLoggedIn();
  161         if ($isLoggedIn) {
  162             // Check the CSRF token
  163             $this->checkCsrfToken();
  164         } else {
  165             // User not logged in, display login page
  166             // If is a GET, show the index page with isLogged false
  167             // If is a POST, send message in json format
  168             if ($this->getRequest()->getActionName() == 'index') {
  169                 $isLoggedIn = false;
  170                 if ($this->getRequest()->getModuleName() != 'Default') {
  171                     $this->_forward('index', 'Default', 'Default', null);
  172                 }
  173             } else {
  174                 $this->getResponse()->setRawHeader('HTTP/1.1 401 Authorization Required');
  175                 $this->getResponse()->sendHeaders();
  176                 exit;
  177             }
  178         }
  179 
  180         $this->view->clearVars();
  181         $this->view->isLoggedIn = $isLoggedIn;
  182 
  183        // Setting the domain selection
  184        $authMode = Phprojekt_Auth::getLoginMode();
  185        if ($authMode == 'ldap') {
  186            $conf = Phprojekt::getInstance()->getConfig();
  187            $ldapOptions = isset($conf->authentication->ldap) ? $conf->authentication->ldap->toArray() : array();
  188            $domains = array();
  189            foreach ($ldapOptions as $server => $opts) {
  190                $serverName = isset($opts['accountDomainNameShort']) ? trim($opts['accountDomainNameShort']) :
  191                                (isset($opts['accountDomainName']) ? trim($opts['accountDomainName']) : $server);
  192                $domains[$server] = $serverName;
  193            }
  194            if (sizeof($domains) > 0) {
  195                $this->view->domains = $domains;
  196            }
  197        }
  198     }
  199 
  200     /**
  201      * Check if a token is in the SESSION.
  202      *
  203      * @return boolean True for a valid one.
  204      */
  205     public function checkCsrfToken()
  206     {
  207         $error      = false;
  208         $controller = $this->getRequest()->getControllerName();
  209         $action     = $this->getRequest()->getActionName();
  210 
  211         // Skip initial request
  212         // and jsonGetConfigurations since is the action that returns
  213         // the valid token for use in the next request
  214         if ($controller == 'index' || $controller == 'Upgrade') {
  215             if ($action == 'index' || $action == 'jsonGetConfigurations') {
  216                 return true;
  217             }
  218         }
  219 
  220         $sessionName   = 'Phprojekt_CsrfToken';
  221         $csrfNamespace = new Zend_Session_Namespace($sessionName);
  222 
  223         if (!isset($csrfNamespace->token)) {
  224             $error = true;
  225         }
  226 
  227         $token = (string) $this->getRequest()->getParam('csrfToken', null);
  228         if (null === $token) {
  229             $error = true;
  230         }
  231 
  232         if (!$csrfNamespace->token == $token) {
  233             $error = true;
  234         }
  235 
  236         if ($error) {
  237             $this->getResponse()->setRawHeader('HTTP/1.1 403 Forbidden');
  238         }
  239 
  240         return true;
  241     }
  242 
  243     /**
  244      * Standard action.
  245      *
  246      * The function sets up the template index.phtml and renders it.
  247      *
  248      * @return void
  249      */
  250     public function indexAction()
  251     {
  252         $language = Phprojekt_Auth::getRealUser()->getSetting(
  253             "language",
  254             Phprojekt::getInstance()->getConfig()->language
  255         );
  256 
  257         $this->view->language       = $language;
  258         $this->view->compressedDojo = (bool) Phprojekt::getInstance()->getConfig()->compressedDojo;
  259         $this->view->frontendMsg    = (bool) Phprojekt::getInstance()->getConfig()->frontendMessages;
  260 
  261         // Since the time for re-starting a poll to the server is in milliseconds, a multiple of 1000 is needed here.
  262         $this->view->pollingLoop = Phprojekt::getInstance()->getConfig()->pollingLoop * 1000;
  263         if (Phprojekt_Auth::isLoggedIn()) {
  264             $this->render('index');
  265         } else {
  266             $this->render('login');
  267         }
  268     }
  269 
  270     /**
  271      * Return the model name for construct the class.
  272      *
  273      * @return string The path to the model in the class format.
  274      */
  275     public function getModelName()
  276     {
  277         return $this->getRequest()->getModuleName();
  278     }
  279 
  280     /**
  281      * Return the module name for construct the class.
  282      *
  283      * @return string The module name.
  284      */
  285     public function getModuleName()
  286     {
  287         return $this->getRequest()->getModuleName();
  288     }
  289 
  290     /**
  291      * Gets the class model of the module or the default one.
  292      *
  293      * @return Phprojekt_Model_Interface An instance of Phprojekt_Model_Interface.
  294      */
  295     public function getModelObject()
  296     {
  297         $modelName  = $this->getModelName();
  298         $moduleName = $this->getModuleName();
  299         $object     = Phprojekt_Loader::getModel($modelName, $moduleName);
  300         if (null === $object) {
  301             throw new Exception('No Model object could be found');
  302         }
  303 
  304         return $object;
  305     }
  306 
  307     /**
  308      * Sets some values depending on the parameters.
  309      * Each module can implement this function to change their values.
  310      *
  311      * The function needs at least one parameter
  312      * (The array of parameters itself for return it).
  313      *
  314      * @throws Zend_Controller_Action_Exception If the arguments are missing.
  315      *
  316      * @return array
  317      */
  318     public function setParams()
  319     {
  320         $args = func_get_args();
  321 
  322         if (1 > count($args)) {
  323             throw new InvalidArgumentException('Missing arguments in setParams function');
  324         }
  325 
  326         return $args[0];
  327     }
  328 
  329     /**
  330      * Keep in the registry the current project id.
  331      * Deprecated, do not use.
  332      *
  333      * @return void
  334      */
  335     public function setCurrentProjectId()
  336     {
  337         $projectId = (int) $this->getRequest()->getParam("nodeId");
  338 
  339         if (empty($projectId)) {
  340             throw new Zend_Controller_Action_Exception(self::NODEID_REQUIRED_TEXT, 400);
  341         } else {
  342             Phprojekt::setCurrentProjectId($projectId);
  343         }
  344     }
  345 
  346     /**
  347      * Keeps the project id in zend registry or reports an error if an empty value is supplied.
  348      *
  349      * @param int $projectId The project id to store.
  350      *
  351      * @return void
  352      */
  353     protected function _storeCurrentProjectId($projectId)
  354     {
  355         if (empty($projectId)) {
  356             throw new Zend_Controller_Action_Exception(self::PROJECTID_REQUIRED_TEXT, 400);
  357         } else {
  358             Phprojekt::setCurrentProjectId($projectId);
  359         }
  360     }
  361 
  362     /**
  363      * Add to the internal where, the filters set by the user.
  364      *
  365      * @param string $where Internal where clause.
  366      *
  367      * @return string Where clause.
  368      */
  369     public function getFilterWhere($where = null)
  370     {
  371         $filters = $this->getRequest()->getParam('filters', "[]");
  372 
  373         $filters = json_decode($filters);
  374 
  375         if (!empty($filters)) {
  376             $filterClass = new Phprojekt_Filter($this->getModelObject(), $where);
  377             foreach ($filters as $filter) {
  378                 list($filterOperator, $filterField, $filterRule, $filterValue) = $filter;
  379                 $filterOperator = Cleaner::sanitize('alpha', $filterOperator, null);
  380                 $filterField    = Cleaner::sanitize('alpha', $filterField, null);
  381                 $filterRule     = Cleaner::sanitize('alpha', $filterRule, null);
  382                 if (isset($filterOperator) && isset($filterField) &&  isset($filterRule) && isset($filterValue)) {
  383                     $filterClass->addFilter($filterField, $filterRule, $filterValue, $filterOperator);
  384                 }
  385             }
  386             $where = $filterClass->getWhere();
  387         }
  388 
  389         return $where;
  390     }
  391 
  392     /**
  393      * Returns the default extra actions to perform for multiple or singles ids.
  394      * (Delete and Export)
  395      *
  396      * Each action defines in the array:
  397      * <pre>
  398      *  - action: Name of the action that will process ids.
  399      *  - label:  Display for the action.
  400      *  - class:  Name of the class for display the icon.
  401      * </pre>
  402      *
  403      * @return array Array with 'target', 'action', 'label', 'mode' and 'class'.
  404      */
  405     public function getDefaultExtraActions()
  406     {
  407         $delete = array('target' => self::TARGET_ACTION_MULTIPLE,
  408                         'action' => 'jsonDeleteMultiple',
  409                         'label'  => Phprojekt::getInstance()->translate('Delete'),
  410                         'mode'   => self::MODE_ACTION_XHR,
  411                         'class'  => 'deleteOption');
  412 
  413         $export = array('target' => self::TARGET_ACTION_MULTIPLE,
  414                         'action' => 'csvExportMultiple',
  415                         'label'  => Phprojekt::getInstance()->translate('Export'),
  416                         'mode'   => self::MODE_ACTION_WINDOW,
  417                         'class'  => 'exportOption');
  418 
  419         return array($delete, $export);
  420     }
  421 
  422     /**
  423      * Returns the project tree.
  424      *
  425      * The return is a tree compatible format, with identifier, label,
  426      * and the list of items, each one with the name, id, parent, path and children�s id.
  427      *
  428      * The tree is stored as a file until a user add, edit or delete a project
  429      * (tmp/ZendCache/zend_cache---Phprojekt_Tree_Node_Database_setup).
  430      *
  431      * The return is in JSON format.
  432      *
  433      * @return void
  434      */
  435     public function jsonTreeAction()
  436     {
  437         $model = new Project_Models_Project();
  438         $tree  = new Phprojekt_Tree_Node_Database($model, 1);
  439 
  440         Phprojekt_Converter_Json::echoConvert($tree->setup());
  441     }
  442 
  443     /**
  444      * Returns the list of items for one model.
  445      *
  446      * The return have:
  447      *  - The metadata of each field.
  448      *  - The data of all the rows.
  449      *  - The number of rows.
  450      *
  451      * The function use Phprojekt_ModelInformation_Default::ORDERING_LIST for get and sort the fields.
  452      *
  453      * OPTIONAL request parameters:
  454      * <pre>
  455      *  - integer <b>id</b>     List only this id.
  456      *  - integer <b>nodeId</b> List all the items with projectId == nodeId.
  457      *  - integer <b>count</b>  Use for SQL LIMIT count.
  458      *  - integer <b>offset</b> Use for SQL LIMIT offset.
  459      *  - boolean <b>recursive</b> Include items of subprojects.
  460      * </pre>
  461      *
  462      * The return is in JSON format.
  463      *
  464      * @return void
  465      */
  466     public function jsonListAction()
  467     {
  468         $itemId    = (int) $this->getRequest()->getParam('id', null);
  469         $projectId = (int) $this->getRequest()->getParam('nodeId', null);
  470         $count     = (int) $this->getRequest()->getParam('count', null);
  471         $offset    = (int) $this->getRequest()->getParam('start', null);
  472         $recursive = $this->getRequest()->getParam('recursive', 'false');
  473         $this->setCurrentProjectId();
  474 
  475         if (!empty($itemId)) {
  476             $where = sprintf('id = %d', (int) $itemId);
  477         } else if (!empty($projectId) && $this->getModelObject()->hasField('projectId')) {
  478             $where  = sprintf('project_id = %d', (int) $projectId);
  479         } else {
  480             $where = null;
  481         }
  482 
  483         /* recursive is only supported if nodeId is specified */
  484         if (!empty($projectId) && $this->getModelObject()->hasField('projectId')
  485             && 'true' === $recursive) {
  486             $tree = new Phprojekt_Tree_Node_Database(
  487                 new Project_Models_Project(),
  488                 $projectId);
  489             $tree->setup();
  490             Phprojekt_Converter_Json::echoConvert(
  491                 $tree->getRecordsFor($this->getModelObject(), null, null, $this->getFilterWhere()),
  492                 Phprojekt_ModelInformation_Default::ORDERING_LIST);
  493         } else  {
  494             $where   = $this->getFilterWhere($where);
  495             $records = $this->getModelObject()->fetchAll($where, null, $count, $offset);
  496 
  497             Phprojekt_Converter_Json::echoConvert($records, Phprojekt_ModelInformation_Default::ORDERING_LIST);
  498         }
  499     }
  500 
  501     /**
  502      * Returns the metadata for this Module's default module.
  503      *
  504      * Mandatory parameters:
  505      *  - integer projectId The id of the project that the metadata should be based on.
  506      */
  507     public function metadataAction()
  508     {
  509         $projectId = $this->getRequest()->getParam('projectId', null);
  510         $this->_storeCurrentProjectId($projectId);
  511 
  512         $fieldDefinition  = $this->getModelObject()->getInformation()->getFieldDefinition();
  513         Phprojekt_CompressedSender::send(
  514             Zend_Json_Encoder::encode($fieldDefinition)
  515         );
  516     }
  517 
  518     /**
  519      * Returns the detail (fields and data) of one item from the model.
  520      *
  521      * The return have:
  522      *  - The metadata of each field.
  523      *  - The data of one item.
  524      *  - The number of rows.
  525      *
  526      * If the request parameter "id" is null or 0, the data will be all values of a "new item",
  527      * if the "id" is an existing item, the data will be all the values of the item.
  528      *
  529      * The function use Phprojekt_ModelInformation_Default::ORDERING_FORM for get and sort the fields.
  530      *
  531      * OPTIONAL request parameters:
  532      * <pre>
  533      *  - integer <b>id</b> id of the item to consult.
  534      * </pre>
  535      *
  536      * The return is in JSON format.
  537      *
  538      * @return void
  539      */
  540     public function jsonDetailAction()
  541     {
  542         $id = (int) $this->getRequest()->getParam('id');
  543         $this->setCurrentProjectId();
  544 
  545         if (empty($id)) {
  546             $record = $this->getModelObject();
  547         } else {
  548             $record = $this->getModelObject()->find($id);
  549         }
  550 
  551         Phprojekt_Converter_Json::echoConvert($record, Phprojekt_ModelInformation_Default::ORDERING_FORM);
  552     }
  553 
  554     /**
  555      * Saves the current item.
  556      *
  557      * If the request parameter "id" is null or 0, the function will add a new item,
  558      * if the "id" is an existing item, the function will update it.
  559      *
  560      * OPTIONAL request parameters:
  561      * <pre>
  562      *  - integer <b>id</b>                      id of the item to save.
  563      *  - mixed   <b>all other module fields</b> All the fields values to save.
  564      * </pre>
  565      *
  566      * If there is an error, the save will return a Zend_Controller_Action_Exception,
  567      * if not, it returns a string in JSON format with:
  568      * <pre>
  569      *  - type    => 'success'.
  570      *  - message => Success message.
  571      *  - id      => Id of the item.
  572      * </pre>
  573      *
  574      * @throws Zend_Controller_Action_Exception On error in the action save or wrong id.
  575      *
  576      * @return void
  577      */
  578     public function jsonSaveAction()
  579     {
  580         $id = (int) $this->getRequest()->getParam('id');
  581         $this->setCurrentProjectId();
  582 
  583         if (empty($id)) {
  584             $model   = $this->getModelObject();
  585             $message = Phprojekt::getInstance()->translate(self::ADD_TRUE_TEXT);
  586             $newItem = true;
  587         } else {
  588             $model   = $this->getModelObject()->find($id);
  589             $message = Phprojekt::getInstance()->translate(self::EDIT_TRUE_TEXT);
  590             $newItem = false;
  591         }
  592 
  593         if ($model instanceof Phprojekt_Model_Interface) {
  594             $params = $this->setParams($this->getRequest()->getParams(), $model, $newItem);
  595             Default_Helpers_Save::save($model, $params);
  596 
  597             $return = array('type'    => 'success',
  598                             'message' => $message,
  599                             'id'      => $model->id);
  600 
  601             Phprojekt_Converter_Json::echoConvert($return);
  602         } else {
  603             throw new Zend_Controller_Action_Exception(self::NOT_FOUND, 404);
  604         }
  605     }
  606 
  607     /**
  608      * Save some fields for many items.
  609      * Only edit existing items.
  610      *
  611      * OPTIONAL request parameters:
  612      * <pre>
  613      *  - array <b>data</b> Array with itemId and field as index, and the value.
  614      *    ($data[2]['title'] = 'new tittle')
  615      * </pre>
  616      *
  617      * The return is a string in JSON format with:
  618      * <pre>
  619      *  - type    => 'success' or 'error'.
  620      *  - message => Success or error message.
  621      *  - id      => Comma separated ids of the items.
  622      * </pre>
  623      *
  624      * @return void
  625      */
  626     public function jsonSaveMultipleAction()
  627     {
  628         $data    = (array) $this->getRequest()->getParam('data');
  629         $showId  = array();
  630         $model   = $this->getModelObject();
  631         $success = true;
  632         $this->setCurrentProjectId();
  633 
  634         foreach ($data as $id => $fields) {
  635             $model->find((int) $id);
  636             $params = $this->setParams($fields, $model);
  637             try {
  638                 Default_Helpers_Save::save($model, $params);
  639                 $showId[] = $id;
  640             } catch (Zend_Controller_Action_Exception $error) {
  641                 $message = sprintf("ID %d. %s", $id, $error->getMessage());
  642                 $success = false;
  643                 $showId  = array($id);
  644                 break;
  645             }
  646         }
  647 
  648         if ($success) {
  649             $message    = Phprojekt::getInstance()->translate(self::EDIT_MULTIPLE_TRUE_TEXT);
  650             $resultType = 'success';
  651         } else {
  652             $resultType = 'error';
  653         }
  654 
  655         $return = array('type'    => $resultType,
  656                         'message' => $message,
  657                         'id'      => implode(',', $showId));
  658 
  659         Phprojekt_Converter_Json::echoConvert($return);
  660     }
  661 
  662     /**
  663      * Deletes a certain item.
  664      *
  665      * REQUIRES request parameters:
  666      * <pre>
  667      *  - integer <b>id</b> id of the item to delete.
  668      * </pre>
  669      *
  670      * The return is a string in JSON format with:
  671      * <pre>
  672      *  - type    => 'success' or 'error'.
  673      *  - message => Success or error message.
  674      *  - id      => id of the deleted item.
  675      * </pre>
  676      *
  677      * @throws Zend_Controller_Action_Exception On missing or wrong id, or on error in the action delete.
  678      *
  679      * @return void
  680      */
  681     public function jsonDeleteAction()
  682     {
  683         $id = (int) $this->getRequest()->getParam('id');
  684 
  685         if (empty($id)) {
  686             throw new Zend_Controller_Action_Exception(self::ID_REQUIRED_TEXT, 400);
  687         }
  688 
  689         $model = $this->getModelObject()->find($id);
  690         if (empty($model)) {
  691             throw new Zend_Controller_Action_Exception(self::NOT_FOUND, 404);
  692         }
  693         if ($model->hasField('projectId')) {
  694             Phprojekt::setCurrentProjectId($model->projectId);
  695         }
  696 
  697         if ($model instanceof Phprojekt_ActiveRecord_Abstract) {
  698             $tmp = Default_Helpers_Delete::delete($model);
  699             if ($tmp === false) {
  700                 $message    = Phprojekt::getInstance()->translate(self::DELETE_FALSE_TEXT);
  701                 $resultType = 'error';
  702             } else {
  703                 $message    = Phprojekt::getInstance()->translate(self::DELETE_TRUE_TEXT);
  704                 $resultType = 'success';
  705             }
  706             $return = array('type'    => $resultType,
  707                             'message' => $message,
  708                             'id'      => $id);
  709 
  710             Phprojekt_Converter_Json::echoConvert($return);
  711         } else {
  712             throw new Zend_Controller_Action_Exception(self::NOT_FOUND, 404);
  713         }
  714     }
  715 
  716     /**
  717      * Deletes many items together.
  718      *
  719      * OPTIONAL request parameters:
  720      * <pre>
  721      *  - string <b>ids</b> Comma separated ids of the item to delete.
  722      * </pre>
  723      *
  724      * If there is an error, the delete will return a Zend_Controller_Action_Exception,
  725      * if not, it returns a string in JSON format with:
  726      * <pre>
  727      *  - type    => 'success'.
  728      *  - message => Success message.
  729      *  - id      => Comma separated ids of the items.
  730      * </pre>
  731      *
  732      * @throws Zend_Controller_Action_Exception On error in the action delete.
  733      *
  734      * @return void
  735      */
  736     public function jsonDeleteMultipleAction()
  737     {
  738         $ids = $this->getRequest()->getParam('ids');
  739         $this->setCurrentProjectId();
  740 
  741         if (!empty($ids)) {
  742             $message  = Phprojekt::getInstance()->translate(self::DELETE_MULTIPLE_TRUE_TEXT);
  743             $showId   = array();
  744             $model    = $this->getModelObject();
  745             $idsArray = explode(",", $ids);
  746 
  747             if ($model instanceof Phprojekt_ActiveRecord_Abstract) {
  748                 foreach ($idsArray as $id) {
  749                     $model->find((int) $id);
  750                     Default_Helpers_Delete::delete($model);
  751                     $showId[] = $id;
  752                 }
  753             }
  754 
  755             $return = array('type'    => 'success',
  756                             'message' => $message,
  757                             'id'      => implode(',', $showId));
  758 
  759             Phprojekt_Converter_Json::echoConvert($return);
  760         }
  761     }
  762 
  763     /**
  764      * Returns project-module && user-role-project permissions.
  765      *
  766      * Returns the permissions,
  767      * ("none", "read", "write", "access", "create", "copy", "delete", "download", "admin")
  768      * for each module that have the project,
  769      * for the current logged user,
  770      * depending on their role and access, in the project.
  771      *
  772      * REQUIRES request parameters:
  773      * <pre>
  774      *  - integer <b>nodeId</b> The projectId for consult.
  775      * </pre>
  776      *
  777      * The return is in JSON format.
  778      *
  779      * @return void
  780      */
  781     public function jsonGetModulesPermissionAction()
  782     {
  783         $projectId = (int) $this->getRequest()->getParam('nodeId');
  784         $relation  = new Project_Models_ProjectModulePermissions();
  785         $modules   = $relation->getProjectModulePermissionsById($projectId);
  786 
  787         if ($projectId == 0) {
  788             $data = array(); // there is no rights or invalid project
  789         } else {
  790             $allowedModules = array();
  791             $rights         = new Phprojekt_RoleRights($projectId);
  792             foreach ($modules['data'] as $module) {
  793                 if ($module['inProject']) {
  794                     $tmpPermission = Phprojekt_Acl::NONE;
  795                     if ($rights->hasRight('admin', $module['id'])) {
  796                         $tmpPermission = $tmpPermission | Phprojekt_Acl::ADMIN;
  797                     }
  798                     if ($rights->hasRight('create', $module['id'])) {
  799                         $tmpPermission = $tmpPermission | Phprojekt_Acl::CREATE;
  800                     }
  801                     if ($rights->hasRight('write', $module['id'])) {
  802                         $tmpPermission = $tmpPermission | Phprojekt_Acl::WRITE;
  803                     }
  804                     if ($rights->hasRight('read', $module['id'])) {
  805                         $tmpPermission = $tmpPermission | Phprojekt_Acl::READ;
  806                     }
  807 
  808                     // Return modules with at least one access
  809                     if ($tmpPermission != Phprojekt_Acl::NONE || Phprojekt_Auth::isAdminUser()) {
  810                         $module['rights'] = Phprojekt_Acl::convertBitmaskToArray($tmpPermission);
  811                         $allowedModules[] = $module;
  812                     }
  813                 }
  814             }
  815             $data = $allowedModules;
  816         }
  817 
  818         Phprojekt_Converter_Json::echoConvert($data);
  819     }
  820 
  821     /**
  822      * Returns all the words translated in each modules for the request language.
  823      *
  824      * REQUIRES request parameters:
  825      * <pre>
  826      *  - string <b>language</b> The current language for get the translations.
  827      * </pre>
  828      *
  829      * The return is in JSON format.
  830      *
  831      * @return void
  832      */
  833     public function jsonGetTranslatedStringsAction()
  834     {
  835         $language  = Cleaner::sanitize('alpha', $this->getRequest()->getParam('language', 'en'));
  836         $translate = Phprojekt::getInstance()->getTranslate();
  837 
  838         Phprojekt_Converter_Json::echoConvert($translate->getTranslatedStrings($language));
  839     }
  840 
  841     /**
  842      * Returns the front configurations from the configuration.php (front.xxx),
  843      * and some others Core Settings.
  844      *
  845      * The return is an array like ('name' => varName, 'value' => varValue')
  846      *
  847      * The return is in JSON format.
  848      *
  849      * @return void
  850      */
  851     public function jsonGetConfigurationsAction()
  852     {
  853         $fronVars = Phprojekt::getInstance()->getConfig()->front;
  854         $data     = array();
  855         if (null !== $fronVars) {
  856             foreach ($fronVars as $key => $value) {
  857                 $data[] = array('name'  => $key,
  858                                 'value' => $value);
  859             }
  860         }
  861 
  862         $user = Phprojekt_Auth_Proxy::getEffectiveUser();
  863         $settings = $user->settings->fetchAll();
  864 
  865         $tutorialDisplayed = "false";
  866         foreach ($settings as $setting) {
  867             if ($setting->keyValue == "tutorialDisplayed") {
  868                 $tutorialDisplayed = $setting->value;
  869                 break;
  870             }
  871         }
  872 
  873         // System info
  874         $data[] = array('name'  => 'phprojektVersion',
  875                         'value' => Phprojekt::getVersion());
  876         $data[] = array('name'  => 'currentUserId',
  877                         'value' => $user->id);
  878         $data[] = array('name'  => 'currentUserName',
  879                         'value' => $user->username);
  880         $data[] = array('name'  => 'csrfToken',
  881                         'value' => Phprojekt::createCsrfToken());
  882         $data[] = array('name'  => 'tutorialDisplayed',
  883                         'value' => $tutorialDisplayed);
  884 
  885         Phprojekt_Converter_Json::echoConvert($data);
  886     }
  887 
  888     /**
  889      * Returns the possible extra actions to perform for multiple or singles ids.
  890      *
  891      * Each action defines in the array:
  892      * <pre>
  893      *  - action: Name of the action that will process ids.
  894      *  - label:  Display for the action.
  895      *  - class:  Name of the class for display the icon.
  896      * </pre>
  897      *
  898      * The return is in JSON format.
  899      *
  900      * @return void
  901      */
  902     public function jsonGetExtraActionsAction()
  903     {
  904         $actions = $this->getDefaultExtraActions();
  905 
  906         Phprojekt_Converter_Json::echoConvert($actions);
  907     }
  908 
  909     /**
  910      * Returns the frontend (realtime) notification(s) to a user. The return format is JSON.
  911      *
  912      * Note:
  913      * At this point a Zend_Session::writeClose() is needed, to avoid blocking of other requests.
  914      * See http://www.php.net/manual/en/function.session-write-close.php for more details.
  915      *
  916      * @return void
  917      */
  918     public function jsonGetFrontendMessageAction()
  919     {
  920         try {
  921             Zend_Session::writeClose(false);
  922         } catch (Exception $error) {
  923             Phprojekt::getInstance()->getLog()->debug('Error: ' . $error->getMessage());
  924         }
  925 
  926         $notification = new Phprojekt_Notification_FrontendMessage();
  927         $userId       = (int) Phprojekt_Auth::getUserId();
  928         $data         = $notification->getFrontendMessage($userId);
  929 
  930         $return = array("data" => $data);
  931 
  932         Phprojekt_Converter_Json::echoConvert($return);
  933     }
  934 
  935     /**
  936      * Disables all frontend messages.
  937      *
  938      * @return void
  939      */
  940     public function jsonDisableFrontendMessagesAction()
  941     {
  942         $notification = new Phprojekt_Notification();
  943 
  944         try {
  945             $notification->disableFrontendMessages();
  946             $message    = Phprojekt::getInstance()->translate(self::DISABLE_FRONTEND_MESSAGES_TRUE_TEXT);
  947             $resultType = 'success';
  948         } catch (Exception $error) {
  949             Phprojekt::getInstance()->getLog()->debug('Error: ' . $error->getMessage());
  950             $message    = Phprojekt::getInstance()->translate(self::DISABLE_FRONTEND_MESSAGES_FALSE_TEXT);
  951             $resultType = 'error';
  952         }
  953 
  954         $return = array('type'    => $resultType,
  955                         'message' => $message,
  956                         'id'      => 0);
  957 
  958         Phprojekt_Converter_Json::echoConvert($return);
  959     }
  960 
  961     /**
  962      * Returns the ACL rights for all the users of one item.
  963      *
  964      * OPTIONAL request parameters:
  965      * <pre>
  966      *  - integer <b>id</b>     The id of the item to consult.
  967      *  - integer <b>nodeId</b> The id of the parent project.
  968      * </pre>
  969      *
  970      * The return is an array like ('#userID' => {'admin': true/false, 'read': true/false, etc})
  971      * The return is in JSON format.
  972      *
  973      * @return void
  974      */
  975     public function jsonGetUsersRightsAction()
  976     {
  977         $id        = (int) $this->getRequest()->getParam('id');
  978         $projectId = (int) $this->getRequest()->getParam('nodeId');
  979 
  980         if (empty($id)) {
  981             if (empty($projectId)) {
  982                 $record = $this->getModelObject();
  983             } else {
  984                 $model  = new Project_Models_Project();
  985                 $record = $model->find($projectId);
  986             }
  987         } else {
  988             $record = $this->getModelObject()->find($id);
  989         }
  990 
  991         if ($record instanceof Phprojekt_Model_Interface) {
  992             Phprojekt_Converter_Json::echoConvert($record->getUsersRights());
  993         } else {
  994             Phprojekt_Converter_Json::echoConvert(array());
  995         }
  996     }
  997 
  998     /**
  999      * Sets the tutorialDisplayed setting of the current user.
 1000      *
 1001      * Sets the tutorialDisplayed setting of the current user, indicating that the tutorial has been displayed.
 1002      * The request parameter "displayed" should either be true or false.
 1003      *
 1004      * @return void
 1005      */
 1006     public function jsonSetTutorialDisplayedAction()
 1007     {
 1008         $displayed = $this->getRequest()->getParam('displayed', "");
 1009         if ($displayed == "true") {
 1010             $displayed = "true";
 1011         } else {
 1012             $displayed = "false";
 1013         }
 1014 
 1015         $user = Phprojekt_Auth_Proxy::getEffectiveUser();
 1016         $settings = $user->settings->fetchAll();
 1017 
 1018         $found = false;
 1019         foreach ($settings as $setting) {
 1020             // Update
 1021             if ($setting->keyValue == "tutorialDisplayed") {
 1022                 $setting->value = $displayed;
 1023                 $setting->save();
 1024                 $found = true;
 1025                 break;
 1026             }
 1027         }
 1028         if (!$found) {
 1029             // Create
 1030             $record             = $user->settings->create();
 1031             $record->moduleId   = 0;
 1032             $record->keyValue   = "tutorialDisplayed";
 1033             $record->value      = $displayed;
 1034             $record->identifier = 'Core';
 1035             $record->save();
 1036         }
 1037 
 1038         Phprojekt_Converter_Json::echoConvert(array());
 1039     }
 1040 
 1041     /**
 1042      * Returns the list of items for one model.
 1043      *
 1044      * The function use Phprojekt_ModelInformation_Default::ORDERING_LIST for get and sort the fields.
 1045      *
 1046      * OPTIONAL request parameters:
 1047      * <pre>
 1048      *  - integer <b>id</b>     List only this id.
 1049      *  - integer <b>nodeId</b> List all the items with projectId == nodeId.
 1050      * </pre>
 1051      *
 1052      * The return is in CSV format.
 1053      *
 1054      * @return void
 1055      */
 1056     public function csvListAction()
 1057     {
 1058         $projectId = (int) $this->getRequest()->getParam('nodeId', null);
 1059         $itemId    = (int) $this->getRequest()->getParam('id', null);
 1060         $this->setCurrentProjectId();
 1061 
 1062         if (!empty($itemId)) {
 1063             $where = sprintf('id = %d', (int) $itemId);
 1064         } else if (!empty($projectId)) {
 1065             $where = sprintf('project_id = %d', (int) $projectId);
 1066         } else {
 1067             $where = null;
 1068         }
 1069 
 1070         $records = $this->getModelObject()->fetchAll($where);
 1071 
 1072         Phprojekt_Converter_Csv::echoConvert($records, Phprojekt_ModelInformation_Default::ORDERING_LIST);
 1073     }
 1074 
 1075     /**
 1076      * Returns the list of requested ids items.
 1077      *
 1078      * The function use Phprojekt_ModelInformation_Default::ORDERING_LIST for get and sort the fields.
 1079      *
 1080      * OPTIONAL request parameters:
 1081      * <pre>
 1082      *  - string <b>ids</b> Comma separated ids of the item to list.
 1083      * </pre>
 1084      *
 1085      * The return is in CSV format.
 1086      *
 1087      * @return void
 1088      */
 1089     public function csvExportMultipleAction()
 1090     {
 1091         $ids = $this->getRequest()->getParam('ids', null);
 1092         $this->setCurrentProjectId();
 1093 
 1094         if (!empty($ids)) {
 1095             $idsArray = explode(",", $ids);
 1096             $where    = "id IN (";
 1097             $i        = 0;
 1098             foreach ($idsArray as $id) {
 1099                 $i++;
 1100                 $where .= (int) $id;
 1101                 if ($i < count($idsArray)) {
 1102                     $where .= ", ";
 1103                 }
 1104             }
 1105             $where .= ")";
 1106 
 1107             $records = $this->getModelObject()->fetchAll($where, null, 0, 0);
 1108             Phprojekt_Converter_Csv::echoConvert($records, Phprojekt_ModelInformation_Default::ORDERING_LIST);
 1109         }
 1110     }
 1111 
 1112     /**
 1113      * The function init the upload field and call the render for draw it.
 1114      *
 1115      * OPTIONAL request parameters:
 1116      * <pre>
 1117      *  - integer <b>id</b>    Id of the current item.
 1118      *  - string  <b>field</b> Name of the field in the module.
 1119      * </pre>
 1120      *
 1121      * @return void
 1122      */
 1123     public function fileFormAction()
 1124     {
 1125         list($model, $field, $itemId) = $this->_getFileParameters();
 1126 
 1127         $value = Default_Helpers_Upload::initValue($model, $field, $itemId);
 1128 
 1129         $this->_fileRenderView($itemId, $field, $value);
 1130     }
 1131 
 1132     /**
 1133      * Upload the file and call the render for draw the upload field.
 1134      *
 1135      * OPTIONAL request parameters:
 1136      * <pre>
 1137      *  - integer <b>id</b>    Id of the current item.
 1138      *  - string  <b>field</b> Name of the field in the module.
 1139      * </pre>
 1140      *
 1141      * @return void
 1142      */
 1143     public function fileUploadAction()
 1144     {
 1145         list($model, $field, $itemId) = $this->_getFileParameters();
 1146 
 1147         try {
 1148             $value = Default_Helpers_Upload::uploadFile($model, $field, $itemId);
 1149         } catch (Exception $error) {
 1150             $this->view->errorMessage = $error->getMessage();
 1151             $value                    = Default_Helpers_Upload::getFiles($model, $field);
 1152         }
 1153 
 1154         $this->_fileRenderView($itemId, $field, $value);
 1155     }
 1156 
 1157     /**
 1158      * Retrieves the file from upload folder.
 1159      *
 1160      * OPTIONAL request parameters:
 1161      * <pre>
 1162      *  - integer <b>id</b>    Id of the current item.
 1163      *  - string  <b>field</b> Name of the field in the module.
 1164      *  - integer <b>order</b> Position of the file (Can be many uploaded files in the same field).
 1165      * </pre>
 1166      *
 1167      * @return void
 1168      */
 1169     public function fileDownloadAction()
 1170     {
 1171         $hash = (int) $this->getRequest()->getParam('hash', null);
 1172 
 1173         list($model, $field, $itemId) = $this->_getFileParameters();
 1174 
 1175         Default_Helpers_Upload::downloadFile($model, $field, $itemId, $hash);
 1176     }
 1177 
 1178     /**
 1179      * Set the file parameters needed by all the file actions.
 1180      *
 1181      * @return array A list with the file parameters.
 1182      */
 1183     private function _getFileParameters()
 1184     {
 1185         $model  = $this->getModelObject();
 1186         $field  = Cleaner::sanitize('alnum', $this->getRequest()->getParam('field', null));
 1187         $itemId = (int) $this->getRequest()->getParam('id', null);
 1188         $this->setCurrentProjectId();
 1189 
 1190         return array($model, $field, $itemId);
 1191     }
 1192 
 1193     /**
 1194      * Renders the upload.phtml template for display an upload field.
 1195      *
 1196      * This function draws the upload field in the form.
 1197      * All the uploaded files are displayed with a cross for delete it and a link for download it.
 1198      *
 1199      * @param integer $itemId Current item id.
 1200      * @param string  $field  Name of the field in the module.
 1201      * @param string  $value  Value of the field.
 1202      *
 1203      * @return void
 1204      */
 1205     private function _fileRenderView($itemId, $field, $files)
 1206     {
 1207         $this->getResponse()->clearHeaders();
 1208         $this->getResponse()->clearBody();
 1209 
 1210         $sessionName   = 'Phprojekt_CsrfToken';
 1211         $csrfNamespace = new Zend_Session_Namespace($sessionName);
 1212         $config        = Phprojekt::getInstance()->getConfig();
 1213         $linkBegin     = 'index.php/' . $this->getModuleName() . '/index/';
 1214         $fieldId       = $this->getRequest()->getParam('fieldId', '');
 1215 
 1216         // Add all the extra parameters that have the original URL
 1217         $linkData      = '';
 1218         $removeParams  = array('module', 'controller', 'field', 'id',
 1219                                'csrfToken', 'action', 'MAX_FILE_SIZE', 'order');
 1220         foreach ($this->getRequest()->getParams() as $paramName => $paramValue) {
 1221             if (!in_array($paramName, $removeParams)) {
 1222                 $linkData .= $paramName . '/' . $paramValue . '/';
 1223             }
 1224         }
 1225 
 1226         $this->view->compressedDojo = (bool) $config->compressedDojo;
 1227         $this->view->formPath       = $linkBegin . 'fileUpload/' . $linkData;
 1228         $this->view->downloadLink   = '';
 1229         $this->view->fileName       = null;
 1230         $this->view->itemId         = $itemId;
 1231         $this->view->field          = $field;
 1232         $this->view->fieldId        = $fieldId;
 1233         $this->view->csrfToken      = $csrfNamespace->token;
 1234         $this->view->maxUploadSize  = (isset($config->maxUploadSize)) ? (int) $config->maxUploadSize :
 1235             Phprojekt::DEFAULT_MAX_UPLOAD_SIZE;
 1236 
 1237         $model = $this->getModelObject();
 1238         $model->find($itemId);
 1239 
 1240         $filesForView         = array();
 1241         $hasDownloadRight     = $model->hasRight(Phprojekt_Auth_Proxy::getEffectiveUserId(), Phprojekt_Acl::DOWNLOAD);
 1242         $hasWriteRight        = $model->hasRight(Phprojekt_Auth_Proxy::getEffectiveUserId(), Phprojekt_Acl::WRITE);
 1243         $this->view->disabled = !$hasWriteRight;
 1244 
 1245         // Is there any file?
 1246         if (!empty($files)) {
 1247             $i = 0;
 1248 
 1249             foreach ($files as $file) {
 1250                 $fileName = $file['name'];
 1251                 $fileHash = $file['md5'];
 1252                 $fileData = 'id/' . $itemId . '/field/' . $field . '/hash/' . $fileHash . '/csrfToken/' . $csrfNamespace->token;
 1253 
 1254                 $filesForView[$i] = array(
 1255                     'fileName' => $fileName,
 1256                     'hash' => $fileHash
 1257                 );
 1258 
 1259                 if ($hasDownloadRight) {
 1260                     $filesForView[$i]['downloadLink'] = $linkBegin . 'fileDownload/' . $linkData . $fileData;
 1261                 }
 1262 
 1263                 $fileinfo = Default_Helpers_Upload::getInfosFromFile($file);
 1264 
 1265                 $filesForView[$i]['size'] = $fileinfo['size'];
 1266                 $filesForView[$i]['ctime'] = $fileinfo['ctime'];
 1267 
 1268                 $i++;
 1269             }
 1270         }
 1271         if (isset($this->view->errorMessage) && !empty($this->view->errorMessage)) {
 1272             $filesForView[] = array();
 1273         }
 1274 
 1275         $this->view->files = $filesForView;
 1276         $this->render('upload');
 1277     }
 1278 }