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