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