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