3c7edee5ccc7718a34ee4527bc5003329a116b0f
[tine20] / tine20 / Admin / Frontend / Json.php
1 <?php
2 /**
3  * Tine 2.0
4  *
5  * @package     Admin
6  * @subpackage  Frontend
7  * @license     http://www.gnu.org/licenses/agpl.html AGPL Version 3
8  * @author      Lars Kneschke <l.kneschke@metaways.de>
9  * @copyright   Copyright (c) 2007-2017 Metaways Infosystems GmbH (http://www.metaways.de)
10  * 
11  * @todo        try to split this into smaller parts (record proxy should support 'nested' json frontends first)
12  * @todo        use functions from Tinebase_Frontend_Json_Abstract
13  */
14
15 /**
16  * backend class for Zend_Json_Server
17  *
18  * This class handles all Json requests for the admin application
19  *
20  * @package     Admin
21  * @subpackage  Frontend
22  */
23 class Admin_Frontend_Json extends Tinebase_Frontend_Json_Abstract
24 {
25     /**
26      * the application name
27      *
28      * @var string
29      */
30     protected $_applicationName = 'Admin';
31     
32     /**
33      * @var bool
34      */
35     protected $_manageSAM = false;
36     
37     /**
38      * @var bool
39      */
40     protected $_manageImapEmailUser = FALSE;
41     
42     /**
43      * @var bool
44      */
45     protected $_manageSmtpEmailUser = FALSE;
46     
47     /**
48      * constructs Admin_Frontend_Json
49      */
50     public function __construct()
51     {
52         // manage samba sam?
53         if (isset(Tinebase_Core::getConfig()->samba)) {
54             $this->_manageSAM = Tinebase_Core::getConfig()->samba->get('manageSAM', false);
55         }
56
57         // manage email user settings
58         if (Tinebase_EmailUser::manages(Tinebase_Config::IMAP)) {
59             $this->_manageImapEmailUser = TRUE;
60         }
61         if (Tinebase_EmailUser::manages(Tinebase_Config::SMTP)) {
62             $this->_manageSmtpEmailUser = TRUE;
63         }
64     }
65     
66     /**
67      * Returns registry data of admin.
68      * @see Tinebase_Application_Json_Abstract
69      * 
70      * @return mixed array 'variable name' => 'data'
71      */
72     public function getRegistryData()
73     {
74         $appConfigDefaults = Admin_Controller::getInstance()->getConfigSettings();
75         $smtpConfig = ($this->_manageSmtpEmailUser) ? Tinebase_EmailUser::getConfig(Tinebase_Config::SMTP) : $smtpConfig = array();
76
77         $registryData = array(
78             'manageSAM'                     => $this->_manageSAM,
79             'manageImapEmailUser'           => $this->_manageImapEmailUser,
80             'manageSmtpEmailUser'           => $this->_manageSmtpEmailUser,
81             'primarydomain'                 => isset($smtpConfig['primarydomain']) ? $smtpConfig['primarydomain'] : '',
82             'secondarydomains'              => isset($smtpConfig['secondarydomains']) ? $smtpConfig['secondarydomains'] : '',
83             'defaultPrimaryGroup'           => Tinebase_Group::getInstance()->getDefaultGroup()->toArray(),
84             'defaultInternalAddressbook'    => ($appConfigDefaults[Admin_Model_Config::DEFAULTINTERNALADDRESSBOOK] !== NULL) 
85                 ? Tinebase_Container::getInstance()->get($appConfigDefaults[Admin_Model_Config::DEFAULTINTERNALADDRESSBOOK])->toArray() 
86                 : NULL,
87         );
88
89         return $registryData;
90     }
91     
92     /******************************* Access Log *******************************/
93     
94     /**
95      * delete access log entries
96      *
97      * @param array $ids list of logIds to delete
98      * @return array with success flag
99      */
100     public function deleteAccessLogs($ids)
101     {
102         return $this->_delete($ids, Admin_Controller_AccessLog::getInstance());
103     }
104     
105     /**
106      * Search for records matching given arguments
107      *
108      * @param array $filter 
109      * @param array $paging 
110      * @return array
111      */
112     public function searchAccessLogs($filter, $paging)
113     {
114         $result = $this->_search($filter, $paging, Admin_Controller_AccessLog::getInstance(), 'Tinebase_Model_AccessLogFilter');
115         
116         return $result;
117     }
118
119     /****************************** Applications ******************************/
120     
121     /**
122      * get application
123      *
124      * @param   int $applicationId application id to get
125      * @return  array with application data
126      * 
127      */
128     public function getApplication($applicationId)
129     {
130         $application = Admin_Controller_Application::getInstance()->get($applicationId);
131         
132         return $application->toArray();
133     }
134     
135     /**
136      * get list of applications
137      *
138      * @param string $filter
139      * @param string $sort
140      * @param string $dir
141      * @param int $start
142      * @param int $limit
143      * @return array with results array & totalcount (int)
144      * 
145      * @todo switch to new api with only filter and paging params
146      */
147     public function getApplications($filter, $sort, $dir, $start, $limit)
148     {
149         if (empty($filter)) {
150             $filter = NULL;
151         }
152         
153         $result = array(
154             'results'     => array(),
155             'totalcount'  => 0
156         );
157         
158         $applicationSet = Admin_Controller_Application::getInstance()->search($filter, $sort, $dir, $start, $limit);
159
160         $result['results']    = $applicationSet->toArray();
161         if ($start == 0 && count($result['results']) < $limit) {
162             $result['totalcount'] = count($result['results']);
163         } else {
164             $result['totalcount'] = Admin_Controller_Application::getInstance()->getTotalApplicationCount($filter);
165         }
166         
167         return $result;
168     }
169
170     /**
171      * set application state
172      *
173      * @param   array  $applicationIds  array of application ids
174      * @param   string $state           state to set
175      * @return  array with success flag
176      */
177     public function setApplicationState($applicationIds, $state)
178     {
179         Admin_Controller_Application::getInstance()->setApplicationState($applicationIds, $state);
180
181         $result = array(
182             'success' => TRUE
183         );
184         
185         return $result;
186     }
187             
188     /********************************** Users *********************************/
189     
190     /**
191      * returns a fullUser
192      *
193      * @param string $id
194      * @return array
195      */
196     public function getUser($id)
197     {
198         if (!empty($id)) {
199             $user = Admin_Controller_User::getInstance()->get($id);
200             $userArray = $this->_recordToJson($user);
201             
202             // don't send some infos to the client: unset email uid+gid
203             if ((isset($userArray['emailUser']) || array_key_exists('emailUser', $userArray))) {
204                 $unsetFields = array('emailUID', 'emailGID');
205                 foreach ($unsetFields as $field) {
206                     unset($userArray['emailUser'][$field]);
207                 }
208
209                 if(isset($userArray['imapUser']['emailMailSize']) && ($userArray['imapUser']['emailMailQuota'] !== null)) {
210                     $userArray['emailUser']['emailMailSize'] = $userArray['imapUser']['emailMailSize'];
211                     $userArray['emailUser']['emailMailQuota'] = $userArray['imapUser']['emailMailQuota'];
212                 }
213             }
214             
215             // add primary group to account for the group selection combo box
216             $group = Tinebase_Group::getInstance()->getGroupById($user->accountPrimaryGroup);
217             
218             $userGroups = Tinebase_Group::getInstance()->getMultiple(Tinebase_Group::getInstance()->getGroupMemberships($user->accountId))->toArray();
219             
220             try {
221                 $roleMemberships = Tinebase_Acl_Roles::getInstance()->getRoleMemberships($user->accountId);
222                 $userRoles = Tinebase_Acl_Roles::getInstance()->getMultiple($roleMemberships)->toArray();
223             } catch (Tinebase_Exception_NotFound $tenf) {
224                 if (Tinebase_Core::isLogLevel(Zend_Log::CRIT)) Tinebase_Core::getLogger()->crit(__METHOD__ . '::' . __LINE__ . 
225                     ' Failed to fetch role memberships for user ' . $user->accountFullName . ': ' . $tenf->getMessage()
226                 );
227                 $userRoles = array();
228             }
229             
230             
231         } else {
232             $userArray = array('accountStatus' => 'enabled', 'visibility' => 'displayed');
233             
234             // get default primary group for the group selection combo box
235             $group = Tinebase_Group::getInstance()->getDefaultGroup();
236             
237             // no user groups by default
238             $userGroups = array();
239             
240             // no user roles by default
241             $userRoles = array();
242         }
243         
244         // encode the account array
245         $userArray['accountPrimaryGroup'] = $group->toArray();
246         
247         // encode the groups array
248         $userArray['groups'] = array(
249             'results'         => $userGroups,
250             'totalcount'     => count($userGroups)
251         );
252         
253         // encode the roles array
254         $userArray['accountRoles'] = array(
255             'results'         => $userRoles,
256             'totalcount'     => count($userRoles)
257         );
258         
259         return $userArray;
260     }
261     
262     /**
263      * get list of accounts
264      *
265      * @param string $_filter
266      * @param string $_sort
267      * @param string $_dir
268      * @param int $_start
269      * @param int $_limit
270      * @return array with results array & totalcount (int)
271      * 
272      * @todo switch to new api with only filter and paging params
273      */
274     public function getUsers($filter, $sort, $dir, $start, $limit)
275     {
276         $accounts = Admin_Controller_User::getInstance()->searchFullUsers($filter, $sort, $dir, $start, $limit);
277
278         $result = array(
279             'results'     => $this->_multipleRecordsToJson($accounts),
280             'totalcount'  => Admin_Controller_User::getInstance()->searchCount($filter)
281         );
282         
283         return $result;
284     }
285
286     /**
287      * search for users/accounts
288      * 
289      * @param array $filter
290      * @param array $paging
291      * @return array with results array & totalcount (int)
292      */
293     public function searchUsers($filter, $paging)
294     {
295         $sort = (isset($paging['sort']))    ? $paging['sort']   : 'accountDisplayName';
296         $dir  = (isset($paging['dir']))     ? $paging['dir']    : 'ASC';
297         
298         $result = $this->getUsers($filter[0]['value'], $sort, $dir, $paging['start'], $paging['limit']);
299         $result['filter'] = $filter[0];
300         
301         return $result;
302     }
303     
304     /**
305      * Search for groups matching given arguments
306      *
307      * @param  array $_filter
308      * @param  array $_paging
309      * @return array
310      * 
311      * @todo replace this by Admin.searchGroups / getGroups (without acl check)? or add getGroupCount to Tinebase_Group
312      */
313     public function searchGroups($filter, $paging)
314     {
315         $result = array(
316             'results'     => array(),
317             'totalcount'  => 0
318         );
319         
320         // old fn style yet
321         $sort = (isset($paging['sort']))    ? $paging['sort']   : 'name';
322         $dir  = (isset($paging['dir']))     ? $paging['dir']    : 'ASC';
323         $groups = Tinebase_Group::getInstance()->getGroups($filter[0]['value'], $sort, $dir, $paging['start'], $paging['limit']);
324
325         $result['results'] = $groups->toArray();
326         $result['totalcount'] = Admin_Controller_Group::getInstance()->searchCount($filter[0]['value']);
327         
328         return $result;
329     }
330     
331     /**
332      * save user
333      *
334      * @param  array $recordData data of Tinebase_Model_FullUser
335      * @return array  
336      */
337     public function saveUser($recordData)
338     {
339         $password = (isset($recordData['accountPassword'])) ? $recordData['accountPassword'] : '';
340         
341         $account = new Tinebase_Model_FullUser();
342         
343         // always re-evaluate fullname
344         unset($recordData['accountFullName']);
345         
346         try {
347             $account->setFromJsonInUsersTimezone($recordData);
348             if (isset($recordData['sambaSAM'])) {
349                 $account->sambaSAM = new Tinebase_Model_SAMUser($recordData['sambaSAM']);
350             }
351             
352             if (isset($recordData['emailUser'])) {
353                 $account->emailUser = new Tinebase_Model_EmailUser($recordData['emailUser']);
354                 $account->imapUser  = new Tinebase_Model_EmailUser($recordData['emailUser']);
355                 $account->smtpUser  = new Tinebase_Model_EmailUser($recordData['emailUser']);
356             }
357         } catch (Tinebase_Exception_Record_Validation $e) {
358             // invalid data in some fields sent from client
359             $result = array(
360                 'errors'            => $account->getValidationErrors(),
361                 'errorMessage'      => 'invalid data for some fields',
362                 'status'            => 'failure'
363             );
364             
365             return $result;
366         }
367         
368         // this needs long 3execution time because cache invalidation may take long
369         // @todo remove this when "0007266: make groups / group memberships cache cleaning more efficient" is resolved 
370         $oldMaxExcecutionTime = Tinebase_Core::setExecutionLifeTime(300); // 5 minutes
371         
372         if ($account->getId() == NULL) {
373             $account = Admin_Controller_User::getInstance()->create($account, $password, $password);
374         } else {
375             $account = Admin_Controller_User::getInstance()->update($account, $password, $password);
376         }
377         
378         $result = $this->_recordToJson($account);
379         
380         // add primary group to account for the group selection combo box
381         $group = Tinebase_Group::getInstance()->getGroupById($account->accountPrimaryGroup);
382         
383         // add user groups
384         $userGroups = Tinebase_Group::getInstance()->getMultiple(Tinebase_Group::getInstance()->getGroupMemberships($account->accountId))->toArray();
385         
386         // add user roles
387         $userRoles = Tinebase_Acl_Roles::getInstance()->getMultiple(Tinebase_Acl_Roles::getInstance()->getRoleMemberships($account->accountId))->toArray();
388         
389         // encode the account array
390         $result['accountPrimaryGroup'] = $group->toArray();
391         
392         // encode the groups array
393         $result['groups'] = array(
394             'results'         => $userGroups,
395             'totalcount'     => count($userGroups)
396         );
397         
398         // encode the roles array
399         $result['accountRoles'] = array(
400             'results'         => $userRoles,
401             'totalcount'     => count($userRoles)
402         );
403         
404         Tinebase_Core::setExecutionLifeTime($oldMaxExcecutionTime);
405         
406         return $result;
407     }
408     
409     /**
410      * delete users
411      *
412      * @param   array $ids array of account ids
413      * @return  array with success flag
414      */
415     public function deleteUsers($ids)
416     {
417         Admin_Controller_User::getInstance()->delete($ids);
418         
419         $result = array(
420             'success' => TRUE
421         );
422         return $result;
423     }
424
425     /**
426      * set account state
427      *
428      * @param   array  $accountIds  array of account ids
429      * @param   string $state      state to set
430      * @return  array with success flag
431      */
432     public function setAccountState($accountIds, $status)
433     {
434         $controller = Admin_Controller_User::getInstance();
435         foreach ($accountIds as $accountId) {
436             $controller->setAccountStatus($accountId, $status);
437         }
438
439         $result = array(
440             'success' => TRUE
441         );
442         
443         return $result;
444     }
445     
446     /**
447      * reset password for given account
448      *
449      * @param array|string $account Tinebase_Model_FullUser data or account id
450      * @param string $password the new password
451      * @param bool $mustChange
452      * @return array
453      */
454     public function resetPassword($account, $password, $mustChange)
455     {
456         if (is_array($account)) {
457             $account = new Tinebase_Model_FullUser($account);
458         } else {
459             $account = Tinebase_User::factory(Tinebase_User::getConfiguredBackend())->getFullUserById($account);
460         }
461         
462         $controller = Admin_Controller_User::getInstance();
463         $controller->setAccountPassword($account, $password, $password, (bool)$mustChange);
464         
465         $result = array(
466             'success' => TRUE
467         );
468         return $result;
469     }
470
471     /**
472      * reset password for given account
473      *
474      * @param array|string $account Tinebase_Model_FullUser data or account id
475      * @param string $password the new password
476      * @return array
477      */
478     public function resetPin($account, $password)
479     {
480         if (is_array($account)) {
481             $account = new Tinebase_Model_FullUser($account);
482         } else {
483             $account = Tinebase_User::factory(Tinebase_User::getConfiguredBackend())->getFullUserById($account);
484         }
485
486         $controller = Admin_Controller_User::getInstance();
487         $controller->setAccountPin($account, $password);
488
489         $result = array(
490             'success' => TRUE
491         );
492         return $result;
493     }
494
495     /**
496      * adds the name of the account to each item in the name property
497      * 
498      * @param  array  &$_items array of arrays which contain a type and id property
499      * @param  bool   $_hasAccountPrefix
500      * @param  bool   $_removePrefix
501      * @return array  items with appended name 
502      * @throws UnexpectedValueException
503      * 
504      * @todo    remove all this prefix stuff? why did we add this?
505      * @todo    use a resolveMultiple function here
506      */
507     public static function resolveAccountName(array $_items, $_hasAccountPrefix = FALSE, $_removePrefix = FALSE)
508     {
509         $prefix = $_hasAccountPrefix ? 'account_' : '';
510         
511         $return = array();
512         foreach ($_items as $num => $item) {
513             switch ($item[$prefix . 'type']) {
514                 case Tinebase_Acl_Rights::ACCOUNT_TYPE_USER:
515                     try {
516                         $item[$prefix . 'name'] = Tinebase_User::getInstance()->getUserById($item[$prefix . 'id'])->accountDisplayName;
517                     } catch (Tinebase_Exception_NotFound $tenf) {
518                         $item[$prefix . 'name'] = 'Unknown user';
519                     }
520                     break;
521                 case Tinebase_Acl_Rights::ACCOUNT_TYPE_GROUP:
522                     try {
523                         $item[$prefix . 'name'] = Tinebase_Group::getInstance()->getGroupById($item[$prefix . 'id'])->name;
524                     } catch (Tinebase_Exception_Record_NotDefined $ternd) {
525                         $item[$prefix . 'name'] = 'Unknown group';
526                     }
527                     break;
528                 case Tinebase_Acl_Rights::ACCOUNT_TYPE_ROLE:
529                     try {
530                         $item[$prefix . 'name'] = Tinebase_Acl_Roles::getInstance()->getRoleById($item[$prefix . 'id'])->name;
531                     } catch(Tinebase_Exception_NotFound $tenf) {
532                         $item[$prefix . 'name'] = 'Unknown role';
533                     }
534                     break;
535                 case Tinebase_Acl_Rights::ACCOUNT_TYPE_ANYONE:
536                     $item[$prefix . 'name'] = 'Anyone';
537                     break;
538                 default:
539                     throw new UnexpectedValueException('Unsupported accountType: ' . $item[$prefix . 'type']);
540                     break;
541             }
542             if ($_removePrefix) {
543                 $return[$num] = array(
544                     'id'    => $item[$prefix . 'id'],
545                     'name'  => $item[$prefix . 'name'], 
546                     'type'  => $item[$prefix . 'type'],
547                 );
548             } else {
549                 $return[$num] = $item;
550             }
551         }
552         return $return;
553     }
554     
555     /**
556      * search for shared addressbook containers
557      * 
558      * @param array $filter unused atm
559      * @param array $paging unused atm
560      * @return array
561      * 
562      * @todo add test
563      */
564     public function searchSharedAddressbooks($filter, $paging)
565     {
566         $sharedAddressbooks = Admin_Controller_User::getInstance()->searchSharedAddressbooks();
567         $result = $this->_multipleRecordsToJson($sharedAddressbooks);
568         
569         return array(
570             'results'       => $result,
571             'totalcount'    => count($result),
572         );
573     }
574     
575     /********************************* Groups *********************************/
576     
577     /**
578      * gets a single group
579      *
580      * @param int $groupId
581      * @return array
582      */
583     public function getGroup($groupId)
584     {
585         $groupArray = array();
586         
587         if ($groupId) {
588             $group = Admin_Controller_Group::getInstance()->get($groupId);
589             
590             $groupArray = $group->toArray();
591             
592             if (!empty($group->container_id)) {
593                 $groupArray['container_id'] = Tinebase_Container::getInstance()->getContainerById($group->container_id)->toArray();
594             }
595             
596         }
597         
598         $groupArray['groupMembers'] = $this->getGroupMembers($groupId);
599         
600         return $groupArray;
601     }
602     
603     /**
604      * get list of groups
605      *
606      * @param string $_filter
607      * @param string $_sort
608      * @param string $_dir
609      * @param int $_start
610      * @param int $_limit
611      * @return array with results array & totalcount (int)
612      * 
613      * @todo switch to new api with only filter and paging params
614      */
615     public function getGroups($filter, $sort, $dir, $start, $limit)
616     {
617         $groups = Admin_Controller_Group::getInstance()->search($filter, $sort, $dir, $start, $limit);
618         
619         $result = array(
620             'results'     => $this->_multipleRecordsToJson($groups),
621             'totalcount'  => Admin_Controller_Group::getInstance()->searchCount($filter)
622         );
623         
624         return $result;
625     }
626
627     /**
628      * get list of groupmembers
629      *
630      * @param int $groupId
631      * @return array with results / totalcount
632      * 
633      * @todo use Account Model?
634      */
635     public function getGroupMembers($groupId)
636     {
637         $result = array(
638             'results'     => array(),
639             'totalcount'  => 0
640         );
641         
642         if ($groupId) {
643             $accountIds = Admin_Controller_Group::getInstance()->getGroupMembers($groupId);
644             $users = Tinebase_User::getInstance()->getMultiple($accountIds);
645             $result['results'] = array();
646             foreach ($users as $user) {
647                 $result['results'][] = array(
648                     'id'        => $user->getId(),
649                     'type'      => Tinebase_Acl_Rights::ACCOUNT_TYPE_USER,
650                     'name'      => $user->accountDisplayName,
651                 );
652             }
653             
654             $result['totalcount'] = count($result['results']);
655         }
656         
657         return $result;
658     }
659         
660     /**
661      * save group data from edit form
662      *
663      * @param   array $groupData        group data
664      * @param   array $groupMembers     group members (array of ids)
665      * 
666      * @return  array
667      */
668     public function saveGroup($groupData, $groupMembers)
669     {
670         // unset if empty
671         if (empty($groupData['id'])) {
672             unset($groupData['id']);
673         }
674         
675         $group = new Tinebase_Model_Group($groupData);
676         $group->members = $groupMembers;
677         
678         // this needs long execution time because cache invalidation may take long
679         $oldMaxExcecutionTime = Tinebase_Core::setExecutionLifeTime(60); // 1 minute
680         
681         if ( empty($group->id) ) {
682             $group = Admin_Controller_Group::getInstance()->create($group);
683         } else {
684             $group = Admin_Controller_Group::getInstance()->update($group);
685         }
686         
687         Tinebase_Core::setExecutionLifeTime($oldMaxExcecutionTime);
688         
689         return $this->getGroup($group->getId());
690     }
691    
692     /**
693      * delete multiple groups
694      *
695      * @param array $groupIds list of contactId's to delete
696      * @return array with success flag
697      */
698     public function deleteGroups($groupIds)
699     {
700         $result = array(
701             'success'   => TRUE
702         );
703         
704         Admin_Controller_Group::getInstance()->delete($groupIds);
705
706         return $result;
707     }
708     
709     /********************************** Samba Machines **********************************/
710     
711     /**
712      * Search for records matching given arguments
713      *
714      * @param array $filter 
715      * @param array $paging 
716      * @return array
717      */
718     public function searchSambaMachines($filter, $paging)
719     {
720         try {
721             $result = $this->_search($filter, $paging, Admin_Controller_SambaMachine::getInstance(), 'Admin_Model_SambaMachineFilter');
722         } catch (Admin_Exception $ae) {
723             // no samba settings defined
724             Tinebase_Core::getLogger()->warn(__METHOD__ . '::' . __LINE__ . ' ' . $ae->getMessage());
725             $result = array(
726                 'results'       => array(),
727                 'totalcount'    => 0
728             );
729         }
730         
731         return $result;
732     }
733
734     /**
735      * Return a single record
736      *
737      * @param   string $id
738      * @return  array record data
739      */
740     public function getSambaMachine($id)
741     {
742         return $this->_get($id, Admin_Controller_SambaMachine::getInstance());
743     }
744     
745     /**
746      * creates/updates a record
747      *
748      * @param  array $recordData
749      * @return array created/updated record
750      */
751     public function saveSambaMachine($recordData)
752     {
753         try {
754             $result = $this->_save($recordData, Admin_Controller_SambaMachine::getInstance(), 'SambaMachine', 'accountId');
755         } catch (Admin_Exception $ae) {
756             Tinebase_Core::getLogger()->warn(__METHOD__ . '::' . __LINE__ . ' Error while saving samba machine: ' . $ae->getMessage());
757             $result = array('success' => FALSE);
758         }
759         
760         return $result;
761     }
762     
763     /**
764      * deletes existing records
765      *
766      * @param  array $ids 
767      * @return string
768      */
769     public function deleteSambaMachines($ids)
770     {
771         return $this->_delete($ids, Admin_Controller_SambaMachine::getInstance());
772     }
773     
774
775     /********************************** Tags **********************************/
776     
777     /**
778      * gets a single tag
779      *
780      * @param int $tagId
781      * @return array
782      */
783     public function getTag($tagId)
784     {
785         $tag = array();
786         
787         if ($tagId) {
788             $tag = Admin_Controller_Tags::getInstance()->get($tagId)->toArray();
789             //$tag->rights = $tag->rights->toArray();
790             $tag['rights'] = self::resolveAccountName($tag['rights'] , true);
791         }
792         $tag['appList'] = Tinebase_Application::getInstance()->getApplicationsByState(Tinebase_Application::ENABLED)->toArray();
793         
794         return $tag;
795     }
796     
797     /**
798      * get list of tags
799      *
800      * @param string $_filter
801      * @param string $_sort
802      * @param string $_dir
803      * @param int $_start
804      * @param int $_limit
805      * @return array with results array & totalcount (int)
806      */
807     public function getTags($query, $sort, $dir, $start, $limit)
808     {
809         $filter = new Tinebase_Model_TagFilter(array(
810             'name'        => '%' . $query . '%',
811             'description' => '%' . $query . '%',
812             'type'        => Tinebase_Model_Tag::TYPE_SHARED
813         ));
814         $paging = new Tinebase_Model_Pagination(array(
815             'start' => $start,
816             'limit' => $limit,
817             'sort'  => $sort,
818             'dir'   => $dir
819         ));
820         
821         $tags = Admin_Controller_Tags::getInstance()->search_($filter, $paging);
822         
823         $result = array(
824             'results'     => $this->_multipleRecordsToJson($tags),
825             'totalcount'  => Admin_Controller_Tags::getInstance()->searchCount_($filter)
826         );
827         
828         return $result;
829     }
830         
831     /**
832      * save tag data from edit form
833      *
834      * @param   array $tagData
835      * 
836      * @return  array with success, message, tag data and tag members
837      */
838     public function saveTag($tagData)
839     {
840         // unset if empty
841         if (empty($tagData['id'])) {
842             unset($tagData['id']);
843         }
844         
845         $tag = new Tinebase_Model_FullTag($tagData);
846         $tag->rights = new Tinebase_Record_RecordSet('Tinebase_Model_TagRight', $tagData['rights']);
847         
848         if ( empty($tag->id) ) {
849             $tag = Admin_Controller_Tags::getInstance()->create($tag);
850         } else {
851             $tag = Admin_Controller_Tags::getInstance()->update($tag);
852         }
853         
854         return $this->getTag($tag->getId());
855         
856     }    
857         
858     /**
859      * delete multiple tags
860      *
861      * @param array $tagIds list of contactId's to delete
862      * @return array with success flag
863      */
864     public function deleteTags($tagIds)
865     {
866         return $this->_delete($tagIds, Admin_Controller_Tags::getInstance());
867     }
868     
869     /********************************* Roles **********************************/
870     
871     /**
872      * get a single role with all related data
873      *
874      * @param int $roleId
875      * @return array
876      */
877     public function getRole($roleId)
878     {
879         $role = array();
880         if ($roleId) {
881             $role = Admin_Controller_Role::getInstance()->get($roleId)->toArray();
882         }
883
884         $role['roleMembers'] = $this->getRoleMembers($roleId);
885         $role['roleRights'] = $this->getRoleRights($roleId);
886         $role['allRights'] = $this->getAllRoleRights();
887         return $role;
888     }
889     
890     /**
891      * get list of roles
892      *
893      * @param string $query
894      * @param string $sort
895      * @param string $dir
896      * @param int $start
897      * @param int $limit
898      * @return array with results array & totalcount (int)
899      */
900     public function getRoles($query, $sort, $dir, $start, $limit)
901     {
902         $filter = new Tinebase_Model_RoleFilter(array(
903             array('field' => 'query', 'operator' => 'contains', 'value' => $query),
904         ));
905         $paging = new Tinebase_Model_Pagination(array(
906             'start' => $start,
907             'limit' => $limit,
908             'sort'  => $sort,
909             'dir'   => $dir
910         ));
911         
912         $roles = Admin_Controller_Role::getInstance()->search($filter, $paging);
913         
914         $result = array(
915             'results'     => $this->_multipleRecordsToJson($roles),
916             'totalcount'  => Admin_Controller_Role::getInstance()->searchCount($filter)
917         );
918         
919         return $result;
920     }
921
922     /**
923      * save role data from edit form
924      *
925      * @param   array $roleData        role data
926      * @param   array $roleMembers     role members
927      * @param   array $roleRights      role rights
928      * @return  array
929      */
930     public function saveRole($roleData, $roleMembers, $roleRights)
931     {
932         // unset if empty
933         if (empty($roleData['id'])) {
934             unset($roleData['id']);
935         }
936         
937         $role = new Tinebase_Model_Role($roleData);
938         
939         if (empty($role->id) ) {
940             $role = Admin_Controller_Role::getInstance()->create($role, $roleMembers, $roleRights);
941         } else {
942             $role = Admin_Controller_Role::getInstance()->update($role, $roleMembers, $roleRights);
943         }
944         
945         return $this->getRole($role->getId());
946     }    
947
948     /**
949      * delete multiple roles
950      *
951      * @param array $roleIds list of roleId's to delete
952      * @return array with success flag
953      */
954     public function deleteRoles($roleIds)
955     {
956         $result = array(
957             'success'   => TRUE
958         );
959         
960         Admin_Controller_Role::getInstance()->delete($roleIds);
961
962         return $result;
963     }
964
965     /**
966      * get list of role members
967      *
968      * @param int $roleId
969      * @return array with results / totalcount
970      * 
971      * @todo    move group/user resolution to new accounts class
972      */
973     public function getRoleMembers($roleId)
974     {
975         $result = array(
976             'results'     => array(),
977             'totalcount'  => 0
978         );
979         
980         if (!empty($roleId)) {
981             $members = Admin_Controller_Role::getInstance()->getRoleMembers($roleId);
982     
983             $result['results'] = self::resolveAccountName($members, TRUE, TRUE);
984             $result['totalcount'] = count($result['results']);
985         }
986         return $result;
987     }
988
989     /**
990      * get list of role rights
991      *
992      * @param int $roleId
993      * @return array with results / totalcount
994      */
995     public function getRoleRights($roleId)
996     {
997         $result = array(
998             'results'     => array(),
999             'totalcount'  => 0
1000         );
1001         
1002         if (!empty($roleId)) {
1003             $rights = Admin_Controller_Role::getInstance()->getRoleRights($roleId);
1004         
1005             $result['results'] = $rights;
1006             $result['totalcount'] = count($rights);
1007         }    
1008         return $result;
1009     }
1010     
1011     /**
1012      * get list of all role rights for all applications
1013      *
1014      * @return array with all rights for applications
1015      * 
1016      * @todo    get only rights of active applications?
1017      */
1018     public function getAllRoleRights()
1019     {
1020         if (Tinebase_Core::isLogLevel(Zend_Log::TRACE)) Tinebase_Core::getLogger()->debug(__METHOD__ . '::' . __LINE__ . ' Get all rights of all apps.');
1021         
1022         $result = array();
1023         
1024         $applications = Admin_Controller_Application::getInstance()->search(NULL, 'name', 'ASC', NULL, NULL);
1025         
1026         if (Tinebase_Core::isLogLevel(Zend_Log::TRACE)) Tinebase_Core::getLogger()->trace(__METHOD__ . '::' . __LINE__ . ' ' . print_r($applications->toArray(), TRUE));
1027         
1028         foreach ($applications as $application) {
1029             $appId = $application->getId();
1030             $rightsForApplication = array(
1031                 "application_id"    => $appId,
1032                 "text"              => $application->name,
1033                 "children"          => array()
1034             );
1035             
1036             $allAplicationRights = Tinebase_Application::getInstance()->getAllRightDescriptions($appId);
1037             
1038             if (Tinebase_Core::isLogLevel(Zend_Log::TRACE)) Tinebase_Core::getLogger()->trace(__METHOD__ . '::' . __LINE__ . ' ' . print_r($allAplicationRights, TRUE));
1039             
1040             foreach ($allAplicationRights as $right => $description) {
1041                 $rightsForApplication["children"][] = array(
1042                     "text"      => $description['text'],
1043                     "qtip"      => $description['description'],
1044                     "right"     => $right,
1045                 );
1046             }
1047
1048             $result[] = $rightsForApplication;
1049         }
1050         
1051         return $result;
1052     }
1053     
1054     /****************************** Container ******************************/
1055
1056     /**
1057      * Search for records matching given arguments
1058      *
1059      * @param array $filter 
1060      * @param array $paging 
1061      * @return array
1062      */
1063     public function searchContainers($filter, $paging)
1064     {
1065         $result = $this->_search($filter, $paging, Admin_Controller_Container::getInstance(), 'Tinebase_Model_ContainerFilter');
1066         
1067         // remove acl (app) filter
1068         foreach ($result['filter'] as $id => $filter) {
1069             if ($filter['field'] === 'application_id' && $filter['operator'] === 'in') {
1070                 unset($result['filter'][$id]);
1071             }
1072         }
1073         
1074         return $result;
1075     }
1076     
1077     /**
1078      * Return a single record
1079      *
1080      * @param   string $id
1081      * @return  array record data
1082      */
1083     public function getContainer($id)
1084     {
1085         return $this->_get($id, Admin_Controller_Container::getInstance());
1086     }
1087
1088     /**
1089      * creates/updates a record
1090      *
1091      * @param  array $recordData
1092      * @return array created/updated record
1093      */
1094     public function saveContainer($recordData)
1095     {
1096         $application = Tinebase_Application::getInstance()->getApplicationById($recordData['application_id'])->name;
1097         if (empty($recordData['model'])) {
1098             $recordData['model'] = Tinebase_Core::getApplicationInstance($application)->getDefaultModel();
1099         } else {
1100             $applicationModelParts = \explode('.', $recordData['model']);
1101
1102             if (0 === \count($applicationModelParts) && false === \strpos($recordData['model'], '_Model_')) {
1103                 throw new \InvalidArgumentException('Invalid model specified.');
1104             }
1105             // Handling if a model is either in php format like Application_Model_Foobar or Application.Model.Foobar
1106             $recordData['model'] = \strstr($recordData['model'], '_Model_') ? $recordData['model'] : $application . '_Model_' . \end($applicationModelParts);
1107             \reset($applicationModelParts);
1108         }
1109         $additionalArguments = ((isset($recordData['note']) || array_key_exists('note', $recordData))) ? array(array('note' => $recordData['note'])) : array();
1110         return $this->_save($recordData, Admin_Controller_Container::getInstance(), 'Tinebase_Model_Container', 'id', $additionalArguments);
1111     }
1112     
1113     /**
1114      * deletes existing records
1115      *
1116      * @param  array  $ids 
1117      * @return string
1118      */
1119     public function deleteContainers($ids)
1120     {
1121         return $this->_delete($ids, Admin_Controller_Container::getInstance());
1122     }    
1123     
1124     /****************************** Customfield ******************************/
1125
1126     /**
1127      * Search for records matching given arguments
1128      *
1129      * @param array $filter 
1130      * @param array $paging 
1131      * @return array
1132      */
1133     public function searchCustomfields($filter, $paging)
1134     {
1135         $result = $this->_search($filter, $paging, Admin_Controller_Customfield::getInstance(), 'Tinebase_Model_CustomField_ConfigFilter');
1136         
1137         return $result;
1138     }
1139     
1140     /**
1141      * Return a single record
1142      *
1143      * @param   string $id
1144      * @return  array record data
1145      */
1146     public function getCustomfield($id)
1147     {
1148         return $this->_get($id, Admin_Controller_Customfield::getInstance());
1149     }
1150
1151     /**
1152      * creates/updates a record
1153      *
1154      * @param  array $recordData
1155      * @return array created/updated record
1156      */
1157     public function saveCustomfield($recordData)
1158     {
1159         return $this->_save($recordData, Admin_Controller_Customfield::getInstance(), 'Tinebase_Model_CustomField_Config', 'id');
1160     }
1161     
1162     /**
1163      * deletes existing records
1164      *
1165      * @param  array $ids
1166      * @param  array $context
1167      * @return array
1168      */
1169     public function deleteCustomfields($ids, array $context = array())
1170     {
1171         $controller = Admin_Controller_Customfield::getInstance();
1172         $controller->setRequestContext($context);
1173
1174         return $this->_delete($ids, $controller);
1175     }
1176
1177     /****************************** Config ******************************/
1178 //
1179 //    /**
1180 //     * gets all config which is available via admin module
1181 //     *
1182 //     * @param string $appname
1183 //     * @return array
1184 //     */
1185 //    public function getConfig($appname)
1186 //    {
1187 //        if (! Tinebase_Core::getUser()->hasRight($appname, 'admin')) {
1188 //            throw new Tinebase_Exception_AccessDenied("You do not have admin rights for $appname");
1189 //        }
1190 //
1191 //        $config = Tinebase_Config::getAppConfig($appname);
1192 //        $properties = $config->getProperties();
1193 //
1194 //        $result = array();
1195 //
1196 //        foreach ($properties as $name => $definition) {
1197 //            if (array_key_exists('setByAdminModule', $definition) && $definition['setByAdminModule']) {
1198 //                $value = $config::getInstance()->get($name);
1199 //                if (is_object($value) && method_exists($value, 'toArray')) {
1200 //                    $value = $value->toArray();
1201 //                }
1202 //                if (is_object($value) && method_exists($value, 'toString')) {
1203 //                    $value = $value->toString();
1204 //                }
1205 //
1206 //                $result[$name] = $value;
1207 //            }
1208 //        }
1209 //
1210 //        return $result;
1211 //    }
1212 //
1213 //    /**
1214 //     * sets given config.
1215 //     *
1216 //     * NOTE: configs which got overwritten per config file have no effect here
1217 //     *
1218 //     * @param   string $appname
1219 //     * @param   string $key
1220 //     * @param   string $value
1221 //     * @return  array
1222 //     */
1223 //    public function setConfig($appname, $key, $value)
1224 //    {
1225 //        if (! Tinebase_Core::getUser()->hasRight($appname, 'admin')) {
1226 //            throw new Tinebase_Exception_AccessDenied("You do not have admin rights for $appname");
1227 //        }
1228 //
1229 //        $config = Tinebase_Config::getAppConfig($appname);
1230 //        $definition = $config->getDefinition($key);
1231 //
1232 //        if (! $definition) {
1233 //            throw new Tinebase_Exception_InvalidArgument('no such config setting');
1234 //        }
1235 //
1236 //        if (! array_key_exists('setByAdminModule', $definition) || $definition['setByAdminModule'] !== TRUE) {
1237 //            throw new Tinebase_Exception_InvalidArgument("setting of $key via admin module is not allowed");
1238 //        }
1239 //
1240 //        $config->set($key, $value);
1241 //    }
1242
1243     /**
1244      * Search for records matching given arguments
1245      *
1246      * @param array $filter
1247      * @param array $paging
1248      * @return array
1249      */
1250     public function searchConfigs($filter, $paging)
1251     {
1252         $result = $this->_search($filter, $paging, Admin_Controller_Config::getInstance(), 'Tinebase_Model_ConfigFilter', false, self::TOTALCOUNT_COUNTRESULT);
1253
1254         return $result;
1255     }
1256
1257     /**
1258      * Return a single record
1259      *
1260      * @param   string $id
1261      * @return  array record data
1262      */
1263     public function getConfig($id)
1264     {
1265         return $this->_get($id, Admin_Controller_Config::getInstance());
1266     }
1267
1268     /**
1269      * creates/updates a record
1270      *
1271      * @param  array $recordData
1272      * @return array created/updated record
1273      */
1274     public function saveConfig($recordData)
1275     {
1276         return $this->_save($recordData, Admin_Controller_Config::getInstance(), 'Tinebase_Model_Config', 'id');
1277     }
1278
1279     /**
1280      * deletes existing records
1281      *
1282      * @param  array  $ids
1283      * @return array
1284      */
1285     public function deleteConfigs($ids)
1286     {
1287         return $this->_delete($ids, Admin_Controller_Config::getInstance());
1288     }
1289
1290
1291     /****************************** other *******************************/
1292     
1293     /**
1294      * returns phpinfo() output
1295      * 
1296      * @return array
1297      */
1298     public function getServerInfo()
1299     {
1300         if (! Tinebase_Core::getUser()->hasRight('Admin', Admin_Acl_Rights::RUN)) {
1301             return FALSE;
1302         }
1303         
1304         ob_start();
1305         phpinfo();
1306         $out = ob_get_clean();
1307         
1308         // only return body
1309         $dom = new DOMDocument('1.0', 'UTF-8');
1310         try {
1311             $dom->loadHTML($out);
1312             $body = $dom->getElementsByTagName('body');
1313             $phpinfo = $dom->saveXml($body->item(0));
1314         } catch (Exception $e) {
1315             // no html (CLI)
1316             $phpinfo = $out;
1317         }
1318         
1319         return array(
1320             'html' => $phpinfo
1321         );
1322     }
1323
1324     public function searchQuotaNodes($filter = null)
1325     {
1326         if (! Tinebase_Core::getUser()->hasRight('Admin', Admin_Acl_Rights::VIEW_QUOTA_USAGE)) {
1327             return FALSE;
1328         }
1329
1330         $path = '';
1331         if (null !== $filter) {
1332             array_walk($filter, function ($val) use (&$path) {
1333                 if ('path' === $val['field']) {
1334                     $path = $val['value'];
1335                 }
1336             });
1337         }
1338         $filter = $this->_decodeFilter($filter, 'Tinebase_Model_Tree_Node_Filter');
1339         // ATTENTION sadly the pathfilter to Array does path magic, returns the flatpath and not the statpath
1340         // etc. this is Filemanager path magic. We don't want that here!
1341         $filterArray = $filter->toArray();
1342         array_walk($filterArray, function (&$val) use($path) {
1343             if('path' === $val['field']) {
1344                 $val['value'] = $path;
1345             }
1346         });
1347         $filter = new Tinebase_Model_Tree_Node_Filter($filterArray, '', array('ignoreAcl' => true));
1348
1349         $pathFilters = $filter->getFilter('path', TRUE);
1350         if (count($pathFilters) !== 1) {
1351             if (Tinebase_Core::isLogLevel(Zend_Log::NOTICE)) Tinebase_Core::getLogger()->notice(__METHOD__ . '::' . __LINE__
1352                 . 'Exactly one path filter required.');
1353             $pathFilter = $filter->createFilter(array(
1354                     'field'     => 'path',
1355                     'operator'  => 'equals',
1356                     'value'     => '/',)
1357             );
1358             $filter->removeFilter('path');
1359             $filter->addFilter($pathFilter);
1360             $path = '/';
1361         }
1362
1363         $filter->removeFilter('type');
1364         $filter->addFilter($filter->createFilter(array(
1365                     'field'     => 'type',
1366                     'operator'  => 'equals',
1367                     'value'     => Tinebase_Model_Tree_FileObject::TYPE_FOLDER,
1368                 )));
1369
1370         $records = Tinebase_FileSystem::getInstance()->search($filter);
1371
1372         $result = $this->_multipleRecordsToJson($records, $filter);
1373
1374         $filterArray = $filter->toArray();
1375         array_walk($filterArray, function (&$val) use($path) {
1376             if('path' === $val['field']) {
1377                 $val['value'] = $path;
1378             }
1379         });
1380         return array(
1381             'results'       => array_values($result),
1382             'totalcount'    => count($result),
1383             'filter'        => $filterArray
1384         );
1385     }
1386
1387     /****************************** common ******************************/
1388     
1389     /**
1390      * returns record prepared for json transport
1391      *
1392      * @param Tinebase_Record_Interface $_record
1393      * @return array record data
1394      */
1395     protected function _recordToJson($_record)
1396     {
1397         $result = parent::_recordToJson($_record);
1398
1399         if ($_record instanceof Tinebase_Model_Container) {
1400             $result['account_grants'] = Tinebase_Frontend_Json_Container::resolveAccounts($_record['account_grants']->toArray());
1401         }
1402
1403         return $result;
1404     }
1405     
1406     /**
1407      * returns multiple records prepared for json transport
1408      *
1409      * @param Tinebase_Record_RecordSet $_records Tinebase_Record_Abstract
1410      * @param Tinebase_Model_Filter_FilterGroup $_filter
1411      * @param Tinebase_Model_Pagination $_pagination
1412      * @return array data
1413      */
1414     protected function _multipleRecordsToJson(Tinebase_Record_RecordSet $_records, $_filter = NULL, $_pagination = NULL)
1415     {
1416         switch ($_records->getRecordClassName()) {
1417             case 'Tinebase_Model_AccessLog':
1418                 // TODO use _resolveUserFields and remove this
1419                 foreach ($_records as $record) {
1420                     if (! empty($record->account_id)) {
1421                         try {
1422                             $record->account_id = Admin_Controller_User::getInstance()->get($record->account_id)->toArray();
1423                         } catch (Tinebase_Exception_NotFound $e) {
1424                             $record->account_id = Tinebase_User::getInstance()->getNonExistentUser('Tinebase_Model_FullUser')->toArray();
1425                         }
1426                     }
1427                 }
1428                 break;
1429             case 'Tinebase_Model_Container':
1430             case 'Tinebase_Model_CustomField_Config':
1431                 $applications = Tinebase_Application::getInstance()->getApplications();
1432                 foreach ($_records as $record) {
1433                     $idx = $applications->getIndexById($record->application_id);
1434                     if ($idx !== FALSE) {
1435                         $record->application_id = $applications[$idx];
1436                     }
1437                 }
1438                 break;
1439         }
1440         
1441         return parent::_multipleRecordsToJson($_records, $_filter, $_pagination);
1442     }
1443 }