"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.

    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 }