5b7b3698cadde75db443b768d9a707a1a0805ed9
[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-2012 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         if (Tinebase_User::getConfiguredBackend() == Tinebase_User::ACTIVEDIRECTORY) {
58            $this->_manageSAM = array(); 
59         }
60         
61         // manage email user settings
62         if (Tinebase_EmailUser::manages(Tinebase_Config::IMAP)) {
63             $this->_manageImapEmailUser = TRUE;
64         }
65         if (Tinebase_EmailUser::manages(Tinebase_Config::SMTP)) {
66             $this->_manageSmtpEmailUser = TRUE;
67         }
68     }
69     
70     /**
71      * Returns registry data of admin.
72      * @see Tinebase_Application_Json_Abstract
73      * 
74      * @return mixed array 'variable name' => 'data'
75      */
76     public function getRegistryData()
77     {
78         $appConfigDefaults = Admin_Controller::getInstance()->getConfigSettings();
79         $smtpConfig = Tinebase_Config::getInstance()->get(Tinebase_Config::SMTP, new Tinebase_Config_Struct())->toArray();
80         
81         $registryData = array(
82             'manageSAM'                     => $this->_manageSAM,
83             'manageImapEmailUser'           => $this->_manageImapEmailUser,
84             'manageSmtpEmailUser'           => $this->_manageSmtpEmailUser,
85             'primarydomain'                 => ((isset($smtpConfig['primarydomain']) || array_key_exists('primarydomain', $smtpConfig)))     ? $smtpConfig['primarydomain'] : '',
86             'secondarydomains'              => ((isset($smtpConfig['secondarydomains']) || array_key_exists('secondarydomains', $smtpConfig)))  ? $smtpConfig['secondarydomains'] : '',
87             'defaultPrimaryGroup'           => Tinebase_Group::getInstance()->getDefaultGroup()->toArray(),
88             'defaultInternalAddressbook'    => ($appConfigDefaults[Admin_Model_Config::DEFAULTINTERNALADDRESSBOOK] !== NULL) 
89                 ? Tinebase_Container::getInstance()->get($appConfigDefaults[Admin_Model_Config::DEFAULTINTERNALADDRESSBOOK])->toArray() 
90                 : NULL,
91         );
92         return $registryData;
93     }
94     
95     /******************************* Access Log *******************************/
96     
97     /**
98      * delete access log entries
99      *
100      * @param array $ids list of logIds to delete
101      * @return array with success flag
102      */
103     public function deleteAccessLogs($ids)
104     {
105         return $this->_delete($ids, Admin_Controller_AccessLog::getInstance());
106     }
107     
108     /**
109      * Search for records matching given arguments
110      *
111      * @param array $filter 
112      * @param array $paging 
113      * @return array
114      */
115     public function searchAccessLogs($filter, $paging)
116     {
117         $result = $this->_search($filter, $paging, Admin_Controller_AccessLog::getInstance(), 'Tinebase_Model_AccessLogFilter');
118         
119         return $result;
120     }
121
122     /****************************** Applications ******************************/
123     
124     /**
125      * get application
126      *
127      * @param   int $applicationId application id to get
128      * @return  array with application data
129      * 
130      */
131     public function getApplication($applicationId)
132     {
133         $application = Admin_Controller_Application::getInstance()->get($applicationId);
134         
135         return $application->toArray();
136     }
137     
138     /**
139      * get list of applications
140      *
141      * @param string $filter
142      * @param string $sort
143      * @param string $dir
144      * @param int $start
145      * @param int $limit
146      * @return array with results array & totalcount (int)
147      * 
148      * @todo switch to new api with only filter and paging params
149      */
150     public function getApplications($filter, $sort, $dir, $start, $limit)
151     {
152         if (empty($filter)) {
153             $filter = NULL;
154         }
155         
156         $result = array(
157             'results'     => array(),
158             'totalcount'  => 0
159         );
160         
161         $applicationSet = Admin_Controller_Application::getInstance()->search($filter, $sort, $dir, $start, $limit);
162
163         $result['results']    = $applicationSet->toArray();
164         if ($start == 0 && count($result['results']) < $limit) {
165             $result['totalcount'] = count($result['results']);
166         } else {
167             $result['totalcount'] = Admin_Controller_Application::getInstance()->getTotalApplicationCount($filter);
168         }
169         
170         return $result;
171     }
172
173     /**
174      * set application state
175      *
176      * @param   array  $applicationIds  array of application ids
177      * @param   string $state           state to set
178      * @return  array with success flag
179      */
180     public function setApplicationState($applicationIds, $state)
181     {
182         Admin_Controller_Application::getInstance()->setApplicationState($applicationIds, $state);
183
184         $result = array(
185             'success' => TRUE
186         );
187         
188         return $result;
189     }
190             
191     /********************************** Users *********************************/
192     
193     /**
194      * returns a fullUser
195      *
196      * @param string $id
197      * @return array
198      */
199     public function getUser($id)
200     {
201         if (!empty($id)) {
202             $user = Admin_Controller_User::getInstance()->get($id);
203             $userArray = $this->_recordToJson($user);
204             
205             // don't send some infos to the client: unset email uid+gid
206             if ((isset($userArray['emailUser']) || array_key_exists('emailUser', $userArray))) {
207                 $unsetFields = array('emailUID', 'emailGID');
208                 foreach ($unsetFields as $field) {
209                     unset($userArray['emailUser'][$field]);
210                 }
211             }
212             
213             // add primary group to account for the group selection combo box
214             $group = Tinebase_Group::getInstance()->getGroupById($user->accountPrimaryGroup);
215             
216             $userGroups = Tinebase_Group::getInstance()->getMultiple(Tinebase_Group::getInstance()->getGroupMemberships($user->accountId))->toArray();
217             
218             try {
219                 $roleMemberships = Tinebase_Acl_Roles::getInstance()->getRoleMemberships($user->accountId);
220                 $userRoles = Tinebase_Acl_Roles::getInstance()->getMultiple($roleMemberships)->toArray();
221             } catch (Tinebase_Exception_NotFound $tenf) {
222                 if (Tinebase_Core::isLogLevel(Zend_Log::CRIT)) Tinebase_Core::getLogger()->crit(__METHOD__ . '::' . __LINE__ . 
223                     ' Failed to fetch role memberships for user ' . $user->accountFullName . ': ' . $tenf->getMessage()
224                 );
225                 $userRoles = array();
226             }
227             
228             
229         } else {
230             $userArray = array('accountStatus' => 'enabled', 'visibility' => 'displayed');
231             
232             // get default primary group for the group selection combo box
233             $group = Tinebase_Group::getInstance()->getDefaultGroup();
234             
235             // no user groups by default
236             $userGroups = array();
237             
238             // no user roles by default
239             $userRoles = array();
240         }
241         
242         // encode the account array
243         $userArray['accountPrimaryGroup'] = $group->toArray();
244         
245         // encode the groups array
246         $userArray['groups'] = array(
247             'results'         => $userGroups,
248             'totalcount'     => count($userGroups)
249         );
250         
251         // encode the roles array
252         $userArray['accountRoles'] = array(
253             'results'         => $userRoles,
254             'totalcount'     => count($userRoles)
255         );
256         
257         return $userArray;
258     }
259     
260     /**
261      * get list of accounts
262      *
263      * @param string $_filter
264      * @param string $_sort
265      * @param string $_dir
266      * @param int $_start
267      * @param int $_limit
268      * @return array with results array & totalcount (int)
269      * 
270      * @todo switch to new api with only filter and paging params
271      */
272     public function getUsers($filter, $sort, $dir, $start, $limit)
273     {
274         $accounts = Admin_Controller_User::getInstance()->searchFullUsers($filter, $sort, $dir, $start, $limit);
275
276         $result = array(
277             'results'     => $this->_multipleRecordsToJson($accounts),
278             'totalcount'  => Admin_Controller_User::getInstance()->searchCount($filter)
279         );
280         
281         return $result;
282     }
283
284     /**
285      * search for users/accounts
286      * 
287      * @param array $filter
288      * @param array $paging
289      * @return array with results array & totalcount (int)
290      */
291     public function searchUsers($filter, $paging)
292     {
293         $sort = (isset($paging['sort']))    ? $paging['sort']   : 'accountDisplayName';
294         $dir  = (isset($paging['dir']))     ? $paging['dir']    : 'ASC';
295         
296         $result = $this->getUsers($filter[0]['value'], $sort, $dir, $paging['start'], $paging['limit']);
297         $result['filter'] = $filter[0];
298         
299         return $result;
300     }
301     
302     /**
303      * Search for groups matching given arguments
304      *
305      * @param  array $_filter
306      * @param  array $_paging
307      * @return array
308      * 
309      * @todo replace this by Admin.searchGroups / getGroups (without acl check)? or add getGroupCount to Tinebase_Group
310      */
311     public function searchGroups($filter, $paging)
312     {
313         $result = array(
314             'results'     => array(),
315             'totalcount'  => 0
316         );
317         
318         // old fn style yet
319         $sort = (isset($paging['sort']))    ? $paging['sort']   : 'name';
320         $dir  = (isset($paging['dir']))     ? $paging['dir']    : 'ASC';
321         $groups = Tinebase_Group::getInstance()->getGroups($filter[0]['value'], $sort, $dir, $paging['start'], $paging['limit']);
322
323         $result['results'] = $groups->toArray();
324         $result['totalcount'] = Admin_Controller_Group::getInstance()->searchCount($filter[0]['value']);
325         
326         return $result;
327     }
328     
329     /**
330      * save user
331      *
332      * @param  array $recordData data of Tinebase_Model_FullUser
333      * @return array  
334      */
335     public function saveUser($recordData)
336     {
337         $password = (isset($recordData['accountPassword'])) ? $recordData['accountPassword'] : '';
338         
339         $account = new Tinebase_Model_FullUser();
340         
341         // always re-evaluate fullname
342         unset($recordData['accountFullName']);
343         
344         try {
345             $account->setFromJsonInUsersTimezone($recordData);
346             if (isset($recordData['sambaSAM'])) {
347                 $account->sambaSAM = new Tinebase_Model_SAMUser($recordData['sambaSAM']);
348             }
349             
350             if (isset($recordData['emailUser'])) {
351                 $account->emailUser = new Tinebase_Model_EmailUser($recordData['emailUser']);
352                 $account->imapUser  = new Tinebase_Model_EmailUser($recordData['emailUser']);
353                 $account->smtpUser  = new Tinebase_Model_EmailUser($recordData['emailUser']);
354             }
355         } catch (Tinebase_Exception_Record_Validation $e) {
356             // invalid data in some fields sent from client
357             $result = array(
358                 'errors'            => $account->getValidationErrors(),
359                 'errorMessage'      => 'invalid data for some fields',
360                 'status'            => 'failure'
361             );
362
363             return $result;
364         }
365         
366         // this needs long 3execution time because cache invalidation may take long
367         // @todo remove this when "0007266: make groups / group memberships cache cleaning more efficient" is resolved 
368         $oldMaxExcecutionTime = Tinebase_Core::setExecutionLifeTime(300); // 5 minutes
369         
370         if ($account->getId() == NULL) {
371             $account = Admin_Controller_User::getInstance()->create($account, $password, $password);
372         } else {
373             $account = Admin_Controller_User::getInstance()->update($account, $password, $password);
374         }
375         
376         $result = $this->_recordToJson($account);
377         
378         // add primary group to account for the group selection combo box
379         $group = Tinebase_Group::getInstance()->getGroupById($account->accountPrimaryGroup);
380         
381         // add user groups
382         $userGroups = Tinebase_Group::getInstance()->getMultiple(Tinebase_Group::getInstance()->getGroupMemberships($account->accountId))->toArray();
383         
384         // add user roles
385         $userRoles = Tinebase_Acl_Roles::getInstance()->getMultiple(Tinebase_Acl_Roles::getInstance()->getRoleMemberships($account->accountId))->toArray();
386         
387         // encode the account array
388         $result['accountPrimaryGroup'] = $group->toArray();
389         
390         // encode the groups array
391         $result['groups'] = array(
392             'results'         => $userGroups,
393             'totalcount'     => count($userGroups)
394         );
395         
396         // encode the roles array
397         $result['accountRoles'] = array(
398             'results'         => $userRoles,
399             'totalcount'     => count($userRoles)
400         );
401         
402         Tinebase_Core::setExecutionLifeTime($oldMaxExcecutionTime);
403         
404         return $result;
405     }
406     
407     /**
408      * delete users
409      *
410      * @param   array $ids array of account ids
411      * @return  array with success flag
412      */
413     public function deleteUsers($ids)
414     {
415         Admin_Controller_User::getInstance()->delete($ids);
416         
417         $result = array(
418             'success' => TRUE
419         );
420         return $result;
421     }
422
423     /**
424      * set account state
425      *
426      * @param   array  $accountIds  array of account ids
427      * @param   string $state      state to set
428      * @return  array with success flag
429      */
430     public function setAccountState($accountIds, $status)
431     {
432         $controller = Admin_Controller_User::getInstance();
433         foreach ($accountIds as $accountId) {
434             $controller->setAccountStatus($accountId, $status);
435         }
436
437         $result = array(
438             'success' => TRUE
439         );
440         
441         return $result;
442     }
443     
444     /**
445      * reset password for given account
446      *
447      * @param array|string $account Tinebase_Model_FullUser data or account id
448      * @param string $password the new password
449      * @param bool $mustChange
450      * @return array
451      */
452     public function resetPassword($account, $password, $mustChange)
453     {
454         if (is_array($account)) {
455             $account = new Tinebase_Model_FullUser($account);
456         } else {
457             $account = Tinebase_User::factory(Tinebase_User::getConfiguredBackend())->getFullUserById($account);
458         }
459         
460         $controller = Admin_Controller_User::getInstance();
461         $controller->setAccountPassword($account, $password, $password, (bool)$mustChange);
462         
463         $result = array(
464             'success' => TRUE
465         );
466         return $result;
467     }
468     
469     /**
470      * adds the name of the account to each item in the name property
471      * 
472      * @param  array  &$_items array of arrays which contain a type and id property
473      * @param  bool   $_hasAccountPrefix
474      * @param  bool   $_removePrefix
475      * @return array  items with appended name 
476      * @throws UnexpectedValueException
477      * 
478      * @todo    remove all this prefix stuff? why did we add this?
479      * @todo    use a resolveMultiple function here
480      */
481     public static function resolveAccountName(array $_items, $_hasAccountPrefix = FALSE, $_removePrefix = FALSE)
482     {
483         $prefix = $_hasAccountPrefix ? 'account_' : '';
484         
485         $return = array();
486         foreach ($_items as $num => $item) {
487             switch ($item[$prefix . 'type']) {
488                 case Tinebase_Acl_Rights::ACCOUNT_TYPE_USER:
489                     try {
490                         $item[$prefix . 'name'] = Tinebase_User::getInstance()->getUserById($item[$prefix . 'id'])->accountDisplayName;
491                     } catch (Tinebase_Exception_NotFound $tenf) {
492                         $item[$prefix . 'name'] = 'Unknown user';
493                     }
494                     break;
495                 case Tinebase_Acl_Rights::ACCOUNT_TYPE_GROUP:
496                     try {
497                         $item[$prefix . 'name'] = Tinebase_Group::getInstance()->getGroupById($item[$prefix . 'id'])->name;
498                     } catch (Tinebase_Exception_Record_NotDefined $ternd) {
499                         $item[$prefix . 'name'] = 'Unknown group';
500                     }
501                     break;
502                 case Tinebase_Acl_Rights::ACCOUNT_TYPE_ANYONE:
503                     $item[$prefix . 'name'] = 'Anyone';
504                     break;
505                 default:
506                     throw new UnexpectedValueException('Unsupported accountType: ' . $item[$prefix . 'type']);
507                     break;
508             }
509             if ($_removePrefix) {
510                 $return[$num] = array(
511                     'id'    => $item[$prefix . 'id'],
512                     'name'  => $item[$prefix . 'name'], 
513                     'type'  => $item[$prefix . 'type'],
514                 );
515             } else {
516                 $return[$num] = $item;
517             }
518         }
519         return $return;
520     }
521     
522     /**
523      * search for shared addressbook containers
524      * 
525      * @param array $filter unused atm
526      * @param array $paging unused atm
527      * @return array
528      * 
529      * @todo add test
530      */
531     public function searchSharedAddressbooks($filter, $paging)
532     {
533         $sharedAddressbooks = Admin_Controller_User::getInstance()->searchSharedAddressbooks();
534         $result = $this->_multipleRecordsToJson($sharedAddressbooks);
535         
536         return array(
537             'results'       => $result,
538             'totalcount'    => count($result),
539         );
540     }
541     
542     /********************************* Groups *********************************/
543     
544     /**
545      * gets a single group
546      *
547      * @param int $groupId
548      * @return array
549      */
550     public function getGroup($groupId)
551     {
552         $groupArray = array();
553         
554         if ($groupId) {
555             $group = Admin_Controller_Group::getInstance()->get($groupId);
556             
557             $groupArray = $group->toArray();
558             
559             if (!empty($group->container_id)) {
560                 $groupArray['container_id'] = Tinebase_Container::getInstance()->getContainerById($group->container_id)->toArray();
561             }
562             
563         }
564         
565         $groupArray['groupMembers'] = $this->getGroupMembers($groupId);
566         
567         return $groupArray;
568     }
569     
570     /**
571      * get list of groups
572      *
573      * @param string $_filter
574      * @param string $_sort
575      * @param string $_dir
576      * @param int $_start
577      * @param int $_limit
578      * @return array with results array & totalcount (int)
579      * 
580      * @todo switch to new api with only filter and paging params
581      */
582     public function getGroups($filter, $sort, $dir, $start, $limit)
583     {
584         $groups = Admin_Controller_Group::getInstance()->search($filter, $sort, $dir, $start, $limit);
585         
586         $result = array(
587             'results'     => $this->_multipleRecordsToJson($groups),
588             'totalcount'  => Admin_Controller_Group::getInstance()->searchCount($filter)
589         );
590         
591         return $result;
592     }
593
594     /**
595      * get list of groupmembers
596      *
597      * @param int $groupId
598      * @return array with results / totalcount
599      * 
600      * @todo use Account Model?
601      */
602     public function getGroupMembers($groupId)
603     {
604         $result = array(
605             'results'     => array(),
606             'totalcount'  => 0
607         );
608         
609         if ($groupId) {
610             $accountIds = Admin_Controller_Group::getInstance()->getGroupMembers($groupId);
611     
612             $result['results'] = array();
613             foreach ($accountIds as $accountId) {
614                 $account = Tinebase_User::getInstance()->getUserById($accountId);
615                 $result['results'][] = array(
616                     'id'        => $accountId,
617                     'type'      => Tinebase_Acl_Rights::ACCOUNT_TYPE_USER,
618                     'name'      => $account->accountDisplayName,
619                 );
620             }
621                     
622             $result['totalcount'] = count($result['results']);
623         }
624         
625         return $result;
626     }
627         
628     /**
629      * save group data from edit form
630      *
631      * @param   array $groupData        group data
632      * @param   array $groupMembers     group members
633      * 
634      * @return  array
635      */
636     public function saveGroup($groupData, $groupMembers)
637     {
638         // unset if empty
639         if (empty($groupData['id'])) {
640             unset($groupData['id']);
641         }
642         
643         $group = new Tinebase_Model_Group($groupData);
644         $group->members = $groupMembers;
645         
646         // this needs long 3execution time because cache invalidation may take long
647         // @todo remove this when "0007266: make groups / group memberships cache cleaning more efficient" is resolved 
648         $oldMaxExcecutionTime = Tinebase_Core::setExecutionLifeTime(300); // 5 minutes
649         
650         if ( empty($group->id) ) {
651             $group = Admin_Controller_Group::getInstance()->create($group);
652         } else {
653             $group = Admin_Controller_Group::getInstance()->update($group);
654         }
655         
656         Tinebase_Core::setExecutionLifeTime($oldMaxExcecutionTime);
657         
658         return $this->getGroup($group->getId());
659     }
660    
661     /**
662      * delete multiple groups
663      *
664      * @param array $groupIds list of contactId's to delete
665      * @return array with success flag
666      */
667     public function deleteGroups($groupIds)
668     {
669         $result = array(
670             'success'   => TRUE
671         );
672         
673         Admin_Controller_Group::getInstance()->delete($groupIds);
674
675         return $result;
676     }
677     
678     /********************************** Samba Machines **********************************/
679     
680     /**
681      * Search for records matching given arguments
682      *
683      * @param array $filter 
684      * @param array $paging 
685      * @return array
686      */
687     public function searchSambaMachines($filter, $paging)
688     {
689         try {
690             $result = $this->_search($filter, $paging, Admin_Controller_SambaMachine::getInstance(), 'Admin_Model_SambaMachineFilter');
691         } catch (Admin_Exception $ae) {
692             // no samba settings defined
693             Tinebase_Core::getLogger()->warn(__METHOD__ . '::' . __LINE__ . ' ' . $ae->getMessage());
694             $result = array(
695                 'results'       => array(),
696                 'totalcount'    => 0
697             );
698         }
699         
700         return $result;
701     }
702
703     /**
704      * Return a single record
705      *
706      * @param   string $id
707      * @return  array record data
708      */
709     public function getSambaMachine($id)
710     {
711         return $this->_get($id, Admin_Controller_SambaMachine::getInstance());
712     }
713     
714     /**
715      * creates/updates a record
716      *
717      * @param  array $recordData
718      * @return array created/updated record
719      */
720     public function saveSambaMachine($recordData)
721     {
722         try {
723             $result = $this->_save($recordData, Admin_Controller_SambaMachine::getInstance(), 'SambaMachine', 'accountId');
724         } catch (Admin_Exception $ae) {
725             Tinebase_Core::getLogger()->warn(__METHOD__ . '::' . __LINE__ . ' Error while saving samba machine: ' . $ae->getMessage());
726             $result = array('success' => FALSE);
727         }
728         
729         return $result;
730     }
731     
732     /**
733      * deletes existing records
734      *
735      * @param  array $ids 
736      * @return string
737      */
738     public function deleteSambaMachines($ids)
739     {
740         return $this->_delete($ids, Admin_Controller_SambaMachine::getInstance());
741     }
742     
743
744     /********************************** Tags **********************************/
745     
746     /**
747      * gets a single tag
748      *
749      * @param int $tagId
750      * @return array
751      */
752     public function getTag($tagId)
753     {
754         $tag = array();
755         
756         if ($tagId) {
757             $tag = Admin_Controller_Tags::getInstance()->get($tagId)->toArray();
758             //$tag->rights = $tag->rights->toArray();
759             $tag['rights'] = self::resolveAccountName($tag['rights'] , true);
760         }
761         $tag['appList'] = Tinebase_Application::getInstance()->getApplications('%')->toArray();
762         
763         return $tag;
764     }
765     
766     /**
767      * get list of tags
768      *
769      * @param string $_filter
770      * @param string $_sort
771      * @param string $_dir
772      * @param int $_start
773      * @param int $_limit
774      * @return array with results array & totalcount (int)
775      */
776     public function getTags($query, $sort, $dir, $start, $limit)
777     {
778         $filter = new Tinebase_Model_TagFilter(array(
779             'name'        => '%' . $query . '%',
780             'description' => '%' . $query . '%',
781             'type'        => Tinebase_Model_Tag::TYPE_SHARED
782         ));
783         $paging = new Tinebase_Model_Pagination(array(
784             'start' => $start,
785             'limit' => $limit,
786             'sort'  => $sort,
787             'dir'   => $dir
788         ));
789         
790         $tags = Admin_Controller_Tags::getInstance()->search_($filter, $paging);
791         
792         $result = array(
793             'results'     => $this->_multipleRecordsToJson($tags),
794             'totalcount'  => Admin_Controller_Tags::getInstance()->searchCount_($filter)
795         );
796         
797         return $result;
798     }
799         
800     /**
801      * save tag data from edit form
802      *
803      * @param   array $tagData
804      * 
805      * @return  array with success, message, tag data and tag members
806      */
807     public function saveTag($tagData)
808     {
809         // unset if empty
810         if (empty($tagData['id'])) {
811             unset($tagData['id']);
812         }
813         
814         $tag = new Tinebase_Model_FullTag($tagData);
815         $tag->rights = new Tinebase_Record_RecordSet('Tinebase_Model_TagRight', $tagData['rights']);
816         
817         if ( empty($tag->id) ) {
818             $tag = Admin_Controller_Tags::getInstance()->create($tag);
819         } else {
820             $tag = Admin_Controller_Tags::getInstance()->update($tag);
821         }
822         
823         return $this->getTag($tag->getId());
824         
825     }    
826         
827     /**
828      * delete multiple tags
829      *
830      * @param array $tagIds list of contactId's to delete
831      * @return array with success flag
832      */
833     public function deleteTags($tagIds)
834     {
835         return $this->_delete($tagIds, Admin_Controller_Tags::getInstance());
836     }
837     
838     /********************************* Roles **********************************/
839     
840     /**
841      * get a single role with all related data
842      *
843      * @param int $roleId
844      * @return array
845      */
846     public function getRole($roleId)
847     {
848         $role = array();
849         if ($roleId) {
850             $role = Admin_Controller_Role::getInstance()->get($roleId)->toArray();
851         }
852
853         $role['roleMembers'] = $this->getRoleMembers($roleId);
854         $role['roleRights'] = $this->getRoleRights($roleId);
855         $role['allRights'] = $this->getAllRoleRights();
856         return $role;
857     }
858     
859     /**
860      * get list of roles
861      *
862      * @param string $query
863      * @param string $sort
864      * @param string $dir
865      * @param int $start
866      * @param int $limit
867      * @return array with results array & totalcount (int)
868      */
869     public function getRoles($query, $sort, $dir, $start, $limit)
870     {
871         $filter = new Tinebase_Model_RoleFilter(array(
872             'name'        => '%' . $query . '%',
873             'description' => '%' . $query . '%'
874         ));
875         $paging = new Tinebase_Model_Pagination(array(
876             'start' => $start,
877             'limit' => $limit,
878             'sort'  => $sort,
879             'dir'   => $dir
880         ));
881         
882         $roles = Admin_Controller_Role::getInstance()->search($filter, $paging);
883         
884         $result = array(
885             'results'     => $this->_multipleRecordsToJson($roles),
886             'totalcount'  => Admin_Controller_Role::getInstance()->searchCount($filter)
887         );
888         
889         return $result;
890     }
891
892     /**
893      * save role data from edit form
894      *
895      * @param   array $roleData        role data
896      * @param   array $roleMembers     role members
897      * @param   array $roleMembers     role rights
898      * @return  array
899      */
900     public function saveRole($roleData, $roleMembers, $roleRights)
901     {
902         // unset if empty
903         if (empty($roleData['id'])) {
904             unset($roleData['id']);
905         }
906         
907         $role = new Tinebase_Model_Role($roleData);
908         
909         if (empty($role->id) ) {
910             $role = Admin_Controller_Role::getInstance()->create($role, $roleMembers, $roleRights);
911         } else {
912             $role = Admin_Controller_Role::getInstance()->update($role, $roleMembers, $roleRights);
913         }
914         
915         return $this->getRole($role->getId());
916     }    
917
918     /**
919      * delete multiple roles
920      *
921      * @param array $roleIds list of roleId's to delete
922      * @return array with success flag
923      */
924     public function deleteRoles($roleIds)
925     {
926         $result = array(
927             'success'   => TRUE
928         );
929         
930         Admin_Controller_Role::getInstance()->delete($roleIds);
931
932         return $result;
933     }
934
935     /**
936      * get list of role members
937      *
938      * @param int $roleId
939      * @return array with results / totalcount
940      * 
941      * @todo    move group/user resolution to new accounts class
942      */
943     public function getRoleMembers($roleId)
944     {
945         $result = array(
946             'results'     => array(),
947             'totalcount'  => 0
948         );
949         
950         if (!empty($roleId)) {
951             $members = Admin_Controller_Role::getInstance()->getRoleMembers($roleId);
952     
953             $result['results'] = self::resolveAccountName($members, TRUE, TRUE);
954             $result['totalcount'] = count($result['results']);
955         }
956         return $result;
957     }
958
959     /**
960      * get list of role rights
961      *
962      * @param int $roleId
963      * @return array with results / totalcount
964      */
965     public function getRoleRights($roleId)
966     {
967         $result = array(
968             'results'     => array(),
969             'totalcount'  => 0
970         );
971         
972         if (!empty($roleId)) {
973             $rights = Admin_Controller_Role::getInstance()->getRoleRights($roleId);
974         
975             $result['results'] = $rights;
976             $result['totalcount'] = count($rights);
977         }    
978         return $result;
979     }
980     
981     /**
982      * get list of all role rights for all applications
983      *
984      * @return array with all rights for applications
985      * 
986      * @todo    get only rights of active applications?
987      */
988     public function getAllRoleRights()
989     {
990         if (Tinebase_Core::isLogLevel(Zend_Log::TRACE)) Tinebase_Core::getLogger()->debug(__METHOD__ . '::' . __LINE__ . ' Get all rights of all apps.');
991         
992         $result = array();
993         
994         $applications = Admin_Controller_Application::getInstance()->search(NULL, 'name', 'ASC', NULL, NULL);
995         
996         if (Tinebase_Core::isLogLevel(Zend_Log::TRACE)) Tinebase_Core::getLogger()->trace(__METHOD__ . '::' . __LINE__ . ' ' . print_r($applications->toArray(), TRUE));
997         
998         foreach ($applications as $application) {
999             $appId = $application->getId();
1000             $rightsForApplication = array(
1001                 "application_id"    => $appId,
1002                 "text"              => $application->name,
1003                 "children"          => array()
1004             );
1005             
1006             $allAplicationRights = Tinebase_Application::getInstance()->getAllRightDescriptions($appId);
1007             
1008             if (Tinebase_Core::isLogLevel(Zend_Log::TRACE)) Tinebase_Core::getLogger()->trace(__METHOD__ . '::' . __LINE__ . ' ' . print_r($allAplicationRights, TRUE));
1009             
1010             foreach ($allAplicationRights as $right => $description) {
1011                 $rightsForApplication["children"][] = array(
1012                     "text"      => $description['text'],
1013                     "qtip"      => $description['description'],
1014                     "right"     => $right,
1015                 );
1016             }
1017
1018             $result[] = $rightsForApplication;
1019         }
1020         
1021         return $result;
1022     }
1023     
1024     /****************************** Container ******************************/
1025
1026     /**
1027      * Search for records matching given arguments
1028      *
1029      * @param array $filter 
1030      * @param array $paging 
1031      * @return array
1032      */
1033     public function searchContainers($filter, $paging)
1034     {
1035         $result = $this->_search($filter, $paging, Admin_Controller_Container::getInstance(), 'Tinebase_Model_ContainerFilter');
1036         
1037         // remove acl (app) filter
1038         foreach ($result['filter'] as $id => $filter) {
1039             if ($filter['field'] === 'application_id' && $filter['operator'] === 'in') {
1040                 unset($result['filter'][$id]);
1041             }
1042         }
1043         
1044         return $result;
1045     }
1046     
1047     /**
1048      * Return a single record
1049      *
1050      * @param   string $id
1051      * @return  array record data
1052      */
1053     public function getContainer($id)
1054     {
1055         return $this->_get($id, Admin_Controller_Container::getInstance());
1056     }
1057
1058     /**
1059      * creates/updates a record
1060      *
1061      * @param  array $recordData
1062      * @return array created/updated record
1063      */
1064     public function saveContainer($recordData)
1065     {
1066         $application = Tinebase_Application::getInstance()->getApplicationById($recordData['application_id'])->name;
1067         if (empty($recordData['model'])) {
1068             $recordData['model'] = Tinebase_Core::getApplicationInstance($application)->getDefaultModel();
1069         } else {
1070             $recordData['model'] = strstr($recordData['model'], '_Model_') ? $recordData['model'] : $application . '_Model_' . $recordData['model'];
1071         }
1072         $additionalArguments = ((isset($recordData['note']) || array_key_exists('note', $recordData))) ? array(array('note' => $recordData['note'])) : array();
1073         return $this->_save($recordData, Admin_Controller_Container::getInstance(), 'Tinebase_Model_Container', 'id', $additionalArguments);
1074     }
1075     
1076     /**
1077      * deletes existing records
1078      *
1079      * @param  array  $ids 
1080      * @return string
1081      */
1082     public function deleteContainers($ids)
1083     {
1084         return $this->_delete($ids, Admin_Controller_Container::getInstance());
1085     }    
1086     
1087     /****************************** Customfield ******************************/
1088
1089     /**
1090      * Search for records matching given arguments
1091      *
1092      * @param array $filter 
1093      * @param array $paging 
1094      * @return array
1095      */
1096     public function searchCustomfields($filter, $paging)
1097     {
1098         $result = $this->_search($filter, $paging, Admin_Controller_Customfield::getInstance(), 'Tinebase_Model_CustomField_ConfigFilter');
1099         
1100         return $result;
1101     }
1102     
1103     /**
1104      * Return a single record
1105      *
1106      * @param   string $id
1107      * @return  array record data
1108      */
1109     public function getCustomfield($id)
1110     {
1111         return $this->_get($id, Admin_Controller_Customfield::getInstance());
1112     }
1113
1114     /**
1115      * creates/updates a record
1116      *
1117      * @param  array $recordData
1118      * @return array created/updated record
1119      */
1120     public function saveCustomfield($recordData)
1121     {
1122         return $this->_save($recordData, Admin_Controller_Customfield::getInstance(), 'Tinebase_Model_CustomField_Config', 'id');
1123     }
1124     
1125     /**
1126      * deletes existing records
1127      *
1128      * @param  array  $ids 
1129      * @return array
1130      */
1131     public function deleteCustomfields($ids)
1132     {
1133         return $this->_delete($ids, Admin_Controller_Customfield::getInstance());
1134     }   
1135
1136     /****************************** other *******************************/
1137     
1138     /**
1139      * returns phpinfo() output
1140      * 
1141      * @return array
1142      */
1143     public function getServerInfo()
1144     {
1145         if (! Tinebase_Core::getUser()->hasRight('Admin', Admin_Acl_Rights::RUN)) {
1146             return FALSE;
1147         }
1148         
1149         ob_start();
1150         phpinfo();
1151         $out = ob_get_clean();
1152         
1153         // only return body
1154         $dom = new DOMDocument('1.0', 'UTF-8');
1155         try {
1156             $dom->loadHTML($out);
1157             $body = $dom->getElementsByTagName('body');
1158             $phpinfo = $dom->saveXml($body->item(0));
1159         } catch (Exception $e) {
1160             // no html (CLI)
1161             $phpinfo = $out;
1162         }
1163         
1164         return array(
1165             'html' => $phpinfo
1166         );
1167     }
1168     
1169     /****************************** common ******************************/
1170     
1171     /**
1172      * returns record prepared for json transport
1173      *
1174      * @param Tinebase_Record_Interface $_record
1175      * @return array record data
1176      */
1177     protected function _recordToJson($_record)
1178     {
1179         $result = parent::_recordToJson($_record);
1180
1181         if ($_record instanceof Tinebase_Model_Container) {
1182             $result['account_grants'] = Tinebase_Frontend_Json_Container::resolveAccounts($result['account_grants']);
1183         }
1184         
1185         return $result;
1186     }
1187     
1188     /**
1189      * returns multiple records prepared for json transport
1190      *
1191      * @param Tinebase_Record_RecordSet $_records Tinebase_Record_Abstract
1192      * @param Tinebase_Model_Filter_FilterGroup $_filter
1193      * @param Tinebase_Model_Pagination $_pagination
1194      * @return array data
1195      */
1196     protected function _multipleRecordsToJson(Tinebase_Record_RecordSet $_records, $_filter = NULL, $_pagination = NULL)
1197     {
1198         switch ($_records->getRecordClassName()) {
1199             case 'Tinebase_Model_AccessLog':
1200                 // TODO use _resolveUserFields and remove this
1201                 foreach ($_records as $record) {
1202                     if (! empty($record->account_id)) {
1203                         try {
1204                             $record->account_id = Admin_Controller_User::getInstance()->get($record->account_id)->toArray();
1205                         } catch (Tinebase_Exception_NotFound $e) {
1206                             $record->account_id = Tinebase_User::getInstance()->getNonExistentUser('Tinebase_Model_FullUser')->toArray();
1207                         }
1208                     }
1209                 }
1210                 break;
1211             case 'Tinebase_Model_Container':
1212             case 'Tinebase_Model_CustomField_Config':
1213                 $applications = Tinebase_Application::getInstance()->getApplications();
1214                 foreach ($_records as $record) {
1215                     $idx = $applications->getIndexById($record->application_id);
1216                     if ($idx !== FALSE) {
1217                         $record->application_id = $applications[$idx];
1218                     }
1219                 }
1220                 break;
1221         }
1222         
1223         return parent::_multipleRecordsToJson($_records, $_filter, $_pagination);
1224     }
1225 }