0011522: improve handling of group-lists
[tine20] / tine20 / Admin / Controller / Group.php
1 <?php
2 /**
3  * Tine 2.0
4  *
5  * @package     Admin
6  * @subpackage  Controller
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-2009 Metaways Infosystems GmbH (http://www.metaways.de)
10  * 
11  * @todo        make it possible to change default groups
12  * @todo        extend abstract record controller
13  */
14
15 /**
16  * Group Controller for Admin application
17  *
18  * @package     Admin
19  * @subpackage  Controller
20  */
21 class Admin_Controller_Group extends Tinebase_Controller_Abstract
22 {
23     /**
24      * holds the instance of the singleton
25      *
26      * @var Admin_Controller_Group
27      */
28     private static $_instance = NULL;
29         
30     /**
31      * @var Tinebase_SambaSAM_Ldap
32      */
33     protected $_samBackend = NULL;
34
35     /**
36      * the constructor
37      *
38      * don't use the constructor. use the singleton 
39      */
40     private function __construct() 
41     {
42         $this->_applicationName = 'Admin';
43     }
44
45     /**
46      * don't clone. Use the singleton.
47      *
48      */
49     private function __clone() 
50     {
51     }
52
53     /**
54      * the singleton pattern
55      *
56      * @return Admin_Controller_Group
57      */
58     public static function getInstance() 
59     {
60         if (self::$_instance === NULL) {
61             self::$_instance = new Admin_Controller_Group;
62         }
63         
64         return self::$_instance;
65     }
66     
67     /**
68      * get list of groups
69      *
70      * @param string $_filter
71      * @param string $_sort
72      * @param string $_dir
73      * @param int $_start
74      * @param int $_limit
75      * @return Tinebase_Record_RecordSet with record class Tinebase_Model_Group
76      */
77     public function search($filter = NULL, $sort = 'name', $dir = 'ASC', $start = NULL, $limit = NULL)
78     {
79         $this->checkRight('VIEW_ACCOUNTS');
80         
81         return Tinebase_Group::getInstance()->getGroups($filter, $sort, $dir, $start, $limit);
82     }
83    
84     /**
85      * count groups
86      *
87      * @param string $_filter string to search groups for
88      * @return int total group count
89      * 
90      * @todo add checkRight again / but first fix Tinebase_Frontend_Json::searchGroups
91      */
92     public function searchCount($_filter)
93     {
94         //$this->checkRight('VIEW_ACCOUNTS');
95         
96         $groups = Tinebase_Group::getInstance()->getGroups($_filter);
97         $result = count($groups);
98         
99         return $result;
100     }
101     
102     /**
103      * set all groups an user is member of
104      *
105      * @param  mixed  $_userId   the account as integer or Tinebase_Model_User
106      * @param  mixed  $_groupIds
107      * @return array
108      */
109     public function setGroupMemberships($_userId, $_groupIds)
110     {
111         $this->checkRight('MANAGE_ACCOUNTS');
112         
113         if ($_groupIds instanceof Tinebase_Record_RecordSet) {
114             $_groupIds = $_groupIds->getArrayOfIds();
115         }
116         
117         if (count($_groupIds) === 0) {
118             throw new Tinebase_Exception_InvalidArgument('user must belong to at least one group');
119         }
120         
121         $userId = Tinebase_Model_User::convertUserIdToInt($_userId);
122         
123         $groupMemberships = Tinebase_Group::getInstance()->getGroupMemberships($userId);
124         
125         $removeGroupMemberships = array_diff($groupMemberships, $_groupIds);
126         $addGroupMemberships    = array_diff($_groupIds, $groupMemberships);
127         
128         if (Tinebase_Core::isLogLevel(Zend_Log::TRACE)) Tinebase_Core::getLogger()->trace(__METHOD__ . '::' . __LINE__ . ' current groupmemberships: ' . print_r($groupMemberships, true));
129         if (Tinebase_Core::isLogLevel(Zend_Log::TRACE)) Tinebase_Core::getLogger()->trace(__METHOD__ . '::' . __LINE__ . ' new groupmemberships: ' . print_r($_groupIds, true));
130         if (Tinebase_Core::isLogLevel(Zend_Log::TRACE)) Tinebase_Core::getLogger()->trace(__METHOD__ . '::' . __LINE__ . ' added groupmemberships: ' . print_r($addGroupMemberships, true));
131         if (Tinebase_Core::isLogLevel(Zend_Log::TRACE)) Tinebase_Core::getLogger()->trace(__METHOD__ . '::' . __LINE__ . ' removed groupmemberships: ' . print_r($removeGroupMemberships, true));
132         
133         foreach ($addGroupMemberships as $groupId) {
134             $this->addGroupMember($groupId, $userId);
135         }
136         
137         foreach ($removeGroupMemberships as $groupId) {
138             try {
139                 $this->removeGroupMember($groupId, $userId);
140             } catch (Tinebase_Exception_Record_NotDefined $tern) {
141                 if (Tinebase_Core::isLogLevel(Zend_Log::WARN)) Tinebase_Core::getLogger()->warn(__METHOD__ . '::' . __LINE__ 
142                     . ' Could not remove group member from group ' . $groupId . ': ' . $tern);
143             }
144         }
145         
146         return Tinebase_Group::getInstance()->getGroupMemberships($userId);
147     }
148     
149     /**
150      * fetch one group identified by groupid
151      *
152      * @param int $_groupId
153      * @return Tinebase_Model_Group
154      */
155     public function get($_groupId)
156     {
157         $this->checkRight('VIEW_ACCOUNTS');
158         
159         $group = Tinebase_Group::getInstance()->getGroupById($_groupId);
160
161         return $group;
162     }  
163
164    /**
165      * add new group
166      *
167      * @param Tinebase_Model_Group $_group
168      * @param array $_groupMembers
169      * 
170      * @return Tinebase_Model_Group
171      */
172     public function create(Tinebase_Model_Group $_group)
173     {
174         $this->checkRight('MANAGE_ACCOUNTS');
175         
176         // avoid forging group id, get's created in backend
177         unset($_group->id);
178         
179         if (Tinebase_Application::getInstance()->isInstalled('Addressbook') === true) {
180             $list = $this->createOrUpdateList($_group);
181             $_group->list_id = $list->getId();
182         }
183         
184         Tinebase_Timemachine_ModificationLog::setRecordMetaData($_group, 'create');
185         
186         try {
187             $group = Tinebase_Group::getInstance()->addGroup($_group);
188         } catch (Exception $e) {
189             // remove list again, if group creation fails
190             if (isset($list)) {
191                 $listsBackend = new Addressbook_Backend_List();
192                 $listsBackend->delete($list);
193             }
194             throw $e;
195         }
196         
197         if (!empty($_group['members']) ) {
198             Tinebase_Group::getInstance()->setGroupMembers($group->getId(), $_group['members']);
199         }
200         
201         $event = new Admin_Event_CreateGroup();
202         $event->group = $group;
203         Tinebase_Event::fireEvent($event);
204         
205         return $group;
206     }  
207
208    /**
209      * update existing group
210      *
211      * @param Tinebase_Model_Group $_group
212      * @param boolean $_updateList
213      * @return Tinebase_Model_Group
214      */
215     public function update(Tinebase_Model_Group $_group, $_updateList = true)
216     {
217         $this->checkRight('MANAGE_ACCOUNTS');
218         
219         // update default user group if name has changed
220         $oldGroup = Tinebase_Group::getInstance()->getGroupById($_group->getId());
221         
222         $defaultGroupName = Tinebase_User::getBackendConfiguration(Tinebase_User::DEFAULT_USER_GROUP_NAME_KEY);
223         if ($oldGroup->name == $defaultGroupName && $oldGroup->name != $_group->name) {
224             Tinebase_Core::getLogger()->info(__METHOD__ . '::' . __LINE__ 
225                 . ' Updated default group name: ' . $oldGroup->name . ' -> ' . $_group->name
226             );
227             Tinebase_User::setBackendConfiguration($_group->name, Tinebase_User::DEFAULT_USER_GROUP_NAME_KEY);
228             Tinebase_User::saveBackendConfiguration();
229         }
230         
231         $transactionId = Tinebase_TransactionManager::getInstance()->startTransaction(Tinebase_Core::getDb());
232         
233         if (true === $_updateList && Tinebase_Application::getInstance()->isInstalled('Addressbook') === true) {
234             $_group->list_id = $oldGroup->list_id;
235             $list = $this->createOrUpdateList($_group);
236             $_group->list_id = $list->getId();
237         }
238         
239         Tinebase_Timemachine_ModificationLog::setRecordMetaData($_group, 'update', $oldGroup);
240         
241         $group = Tinebase_Group::getInstance()->updateGroup($_group);
242         
243         Tinebase_Group::getInstance()->setGroupMembers($group->getId(), $_group->members);
244         
245         Tinebase_TransactionManager::getInstance()->commitTransaction($transactionId);
246         
247         $event = new Admin_Event_UpdateGroup();
248         $event->group = $group;
249         Tinebase_Event::fireEvent($event);
250         
251         return $group;
252     }
253     
254     /**
255      * add a new groupmember to a group
256      *
257      * @param int $_groupId
258      * @param int $_accountId
259      * @param  boolean $_addToList
260      * @return void
261      */
262     public function addGroupMember($_groupId, $_userId, $_addToList = true)
263     {
264         $this->checkRight('MANAGE_ACCOUNTS');
265         
266         Tinebase_Group::getInstance()->addGroupMember($_groupId, $_userId);
267         
268         if (true === $_addToList && Tinebase_Application::getInstance()->isInstalled('Addressbook') === true) {
269             $group = $this->get($_groupId);
270             $user  = Tinebase_User::getInstance()->getUserById($_userId);
271             
272             if (! empty($user->contact_id) && ! empty($group->list_id)) {
273                 if (! Addressbook_Controller_List::getInstance()->exists($group->list_id)) {
274                     if (Tinebase_Core::isLogLevel(Zend_Log::WARN)) Tinebase_Core::getLogger()->warn(__METHOD__ . '::' . __LINE__ 
275                         . ' Could not add member to list ' . $group->list_id . ' (it does not exist)');
276                 } else {
277                     $aclChecking = Addressbook_Controller_List::getInstance()->doContainerACLChecks(FALSE);
278                     Addressbook_Controller_List::getInstance()->addListMember($group->list_id, $user->contact_id, false);
279                     Addressbook_Controller_List::getInstance()->doContainerACLChecks($aclChecking);
280                 }
281             }
282         }
283         
284         $event = new Admin_Event_AddGroupMember();
285         $event->groupId = $_groupId;
286         $event->userId  = $_userId;
287         Tinebase_Event::fireEvent($event);
288     }
289     
290     /**
291      * remove one groupmember from the group
292      *
293      * @param int $_groupId
294      * @param int $_accountId
295      * @param  boolean $_removeFromList
296      * @return void
297      */
298     public function removeGroupMember($_groupId, $_userId, $_removeFromList = true)
299     {
300         $this->checkRight('MANAGE_ACCOUNTS');
301         
302         Tinebase_Group::getInstance()->removeGroupMember($_groupId, $_userId);
303         
304         if (true === $_removeFromList && Tinebase_Application::getInstance()->isInstalled('Addressbook') === true) {
305             $group = $this->get($_groupId);
306             $user  = Tinebase_User::getInstance()->getUserById($_userId);
307             
308             if (!empty($user->contact_id) && !empty($group->list_id)) {
309                 try {
310                     $aclChecking = Addressbook_Controller_List::getInstance()->doContainerACLChecks(FALSE);
311                     Addressbook_Controller_List::getInstance()->removeListMember($group->list_id, $user->contact_id, false);
312                     Addressbook_Controller_List::getInstance()->doContainerACLChecks($aclChecking);
313                 } catch (Tinebase_Exception_NotFound $tenf) {
314                     if (Tinebase_Core::isLogLevel(Zend_Log::WARN)) 
315                         Tinebase_Core::getLogger()->warn(__METHOD__ . '::' . __LINE__ . ' catched exception: ' . get_class($tenf));
316                     if (Tinebase_Core::isLogLevel(Zend_Log::WARN)) 
317                         Tinebase_Core::getLogger()->warn(__METHOD__ . '::' . __LINE__ . ' ' . $tenf->getMessage());
318                     if (Tinebase_Core::isLogLevel(Zend_Log::INFO)) 
319                         Tinebase_Core::getLogger()->info(__METHOD__ . '::' . __LINE__ . ' ' . $tenf->getTraceAsString());
320                 }
321             }
322         }
323         
324         $event = new Admin_Event_RemoveGroupMember();
325         $event->groupId = $_groupId;
326         $event->userId  = $_userId;
327         Tinebase_Event::fireEvent($event);
328         
329     }
330     
331     /**
332      * delete multiple groups
333      *
334      * @param   array $_groupIds
335      * @return  void
336      */
337     public function delete($_groupIds)
338     {
339         $this->checkRight('MANAGE_ACCOUNTS');
340         
341         // check default user group / can't delete this group
342         $defaultUserGroup = Tinebase_Group::getInstance()->getDefaultGroup();
343         
344         if (in_array($defaultUserGroup->getId(), $_groupIds)) {
345             Tinebase_Core::getLogger()->info(__METHOD__ . '::' . __LINE__ 
346                 . ' Can\'t delete default group: ' . $defaultUserGroup->name
347             );
348             foreach ($_groupIds as $key => $value) {
349                 if ($value == $defaultUserGroup->getId()) {
350                     unset($_groupIds[$key]);
351                 }
352             }
353         }
354         
355         if (empty($_groupIds)) {
356             return;
357         }
358         
359         $eventBefore = new Admin_Event_BeforeDeleteGroup();
360         $eventBefore->groupIds = $_groupIds;
361         Tinebase_Event::fireEvent($eventBefore);
362         
363         if (Tinebase_Application::getInstance()->isInstalled('Addressbook') === true) {
364             $listIds = array();
365             
366             foreach ($_groupIds as $groupId) {
367                 $group = $this->get($groupId);
368                 if (!empty($group->list_id)) {
369                     $listIds[] = $group->list_id;
370                 }
371             }
372             
373             if (!empty($listIds)) {
374                 $listBackend = new Addressbook_Backend_List();
375                 $listBackend->delete($listIds);
376             }
377         }
378         
379         Tinebase_Group::getInstance()->deleteGroups($_groupIds);
380         
381         $event = new Admin_Event_DeleteGroup();
382         $event->groupIds = $_groupIds;
383         Tinebase_Event::fireEvent($event);
384     }
385     
386     /**
387      * get list of groupmembers
388      *
389      * @param int $_groupId
390      * @return array with Tinebase_Model_User arrays
391      */
392     public function getGroupMembers($_groupId)
393     {
394         $result = Tinebase_Group::getInstance()->getGroupMembers($_groupId);
395         
396         return $result;
397     }
398     
399     /**
400      * return all groups an account is member of
401      *
402      * @param mixed $_accountId the account as integer or Tinebase_Model_User
403      * @return array
404      */
405     public function getGroupMemberships($_accountId)
406     {
407         $this->checkRight('VIEW_ACCOUNTS');
408         
409         $result = Tinebase_Group::getInstance()->getGroupMemberships($_accountId);
410         
411         return $result;
412     }
413     
414     /**
415      * create or update list in addressbook sql backend
416      * 
417      * @param  Tinebase_Model_Group  $group
418      * @return Addressbook_Model_List
419      */
420     public function createOrUpdateList(Tinebase_Model_Group $group)
421     {
422         return Addressbook_Controller_List::getInstance()->createOrUpdateByGroup($group);
423     }
424 }