0009768: Use ModelConfig for Timetracker models
[tine20] / tine20 / Timetracker / Frontend / Json.php
1 <?php
2 /**
3  * Tine 2.0
4  * @package     Timetracker
5  * @subpackage  Frontend
6  * @license     http://www.gnu.org/licenses/agpl.html AGPL Version 3
7  * @author      Philipp Schüle <p.schuele@metaways.de>
8  * @copyright   Copyright (c) 2007-2011 Metaways Infosystems GmbH (http://www.metaways.de)
9  *
10  */
11
12 /**
13  *
14  * This class handles all Json requests for the Timetracker application
15  *
16  * @package     Timetracker
17  * @subpackage  Frontend
18  */
19 class Timetracker_Frontend_Json extends Tinebase_Frontend_Json_Abstract
20 {
21     /**
22      * timesheet controller
23      *
24      * @var Timetracker_Controller_Timesheet
25      */
26     protected $_timesheetController = NULL;
27
28     /**
29      * timesheet controller
30      *
31      * @var Timetracker_Controller_Timeaccount
32      */
33     protected $_timeaccountController = NULL;
34
35     /**
36      * @see Tinebase_Frontend_Json_Abstract
37      */
38     protected $_relatableModels = array('Timetracker_Model_Timeaccount');
39
40     /**
41      * default model (needed for application starter -> defaultContentType)
42      * @var string
43      */
44     protected $_defaultModel = 'Timesheet';
45
46     /**
47      * All configured models
48      * @var array
49      */
50         protected $_configuredModels = array('Timesheet', 'Timeaccount');
51
52     /**
53      * the constructor
54      *
55      */
56     public function __construct()
57     {
58         $this->_applicationName = 'Timetracker';
59         $this->_timesheetController = Timetracker_Controller_Timesheet::getInstance();
60         $this->_timeaccountController = Timetracker_Controller_Timeaccount::getInstance();
61     }
62
63     /************************************** protected helper functions **************************************/
64
65     /**
66      * returns record prepared for json transport
67      *
68      * @param Tinebase_Record_Interface $_record
69      * @return array record data
70      */
71     protected function _recordToJson($_record)
72     {
73         switch (get_class($_record)) {
74             case 'Timetracker_Model_Timesheet':
75                 $_record['timeaccount_id'] = $_record['timeaccount_id'] ? $this->_timeaccountController->get($_record['timeaccount_id']) : $_record['timeaccount_id'];
76                 $_record['timeaccount_id']['account_grants'] = Timetracker_Model_TimeaccountGrants::getGrantsOfAccount(Tinebase_Core::get('currentAccount'), $_record['timeaccount_id']);
77                 $_record['timeaccount_id']['account_grants'] = $this->_resolveTimesheetGrantsByTimeaccountGrants($_record['timeaccount_id']['account_grants'], $_record['account_id']);
78                 Tinebase_User::getInstance()->resolveUsers($_record, 'account_id');
79
80                 if (Tinebase_Core::getUser()->hasRight('Sales', 'manage_invoices') && ! empty($_record['invoice_id'])) {
81                     try {
82                         $_record['invoice_id'] = Sales_Controller_Invoice::getInstance()->get($_record['invoice_id']);
83                     } catch (Tinebase_Exception_NotFound $nfe) {
84                         Tinebase_Core::getLogger()->warn(__METHOD__ . '::' . __LINE__ . ' Could not resolve invoice with id ' . $_record['invoice_id']);
85                     }
86                 }
87                 
88                 $recordArray = parent::_recordToJson($_record);
89                 break;
90
91             case 'Timetracker_Model_Timeaccount':
92
93                 $recordArray = parent::_recordToJson($_record);
94
95                 // When editing a single TA we send _ALL_ grants to the client
96                 $recordArray['grants'] = Timetracker_Model_TimeaccountGrants::getTimeaccountGrants($_record)->toArray();
97                 foreach($recordArray['grants'] as &$value) {
98                     switch($value['account_type']) {
99                         case Tinebase_Acl_Rights::ACCOUNT_TYPE_USER:
100                             $value['account_name'] = Tinebase_User::getInstance()->getUserById($value['account_id'])->toArray();
101                             break;
102                         case Tinebase_Acl_Rights::ACCOUNT_TYPE_GROUP:
103                             $value['account_name'] = Tinebase_Group::getInstance()->getGroupById($value['account_id'])->toArray();
104                             break;
105                         case Tinebase_Acl_Rights::ACCOUNT_TYPE_ANYONE:
106                             $value['account_name'] = array('accountDisplayName' => 'Anyone');
107                             break;
108                         default:
109                             throw new Tinebase_Exception_InvalidArgument('Unsupported accountType.');
110                             break;
111                     }
112                 }
113                 break;
114         }
115
116         return $recordArray;
117     }
118
119     /**
120      * returns multiple records prepared for json transport
121      * NOTE: we can't use parent::_multipleRecordsToJson here because of the different container handling
122      *
123      * @param Tinebase_Record_RecordSet $_records Tinebase_Record_Abstract
124      * @param Tinebase_Model_Filter_FilterGroup
125      * @param Tinebase_Model_Pagination $_pagination
126      * @return array data
127      * 
128      * @todo replace with Timetracker_Convert_*
129      */
130     protected function _multipleRecordsToJson(Tinebase_Record_RecordSet $_records, $_filter = NULL, $_pagination = NULL)
131     {
132         if (count($_records) == 0) {
133             return array();
134         }
135
136         switch ($_records->getRecordClassName()) {
137             case 'Timetracker_Model_Timesheet':
138                 // resolve timeaccounts
139                 $timeaccountIds = $_records->timeaccount_id;
140                 $timeaccounts = $this->_timeaccountController->getMultiple(array_unique(array_values($timeaccountIds)));
141                 
142                 $invoices = FALSE;
143                 
144                 Timetracker_Model_TimeaccountGrants::getGrantsOfRecords($timeaccounts, Tinebase_Core::get('currentAccount'));
145
146                 foreach ($_records as $record) {
147                     $idx = $timeaccounts->getIndexById($record->timeaccount_id);
148                     if ($idx !== FALSE) {
149                         $record->timeaccount_id = $timeaccounts[$idx];
150                         $record->timeaccount_id->account_grants = $this->_resolveTimesheetGrantsByTimeaccountGrants($record->timeaccount_id->account_grants, $record->account_id);
151                     } else {
152                         Tinebase_Core::getLogger()->warn(__METHOD__ . '::' . __LINE__ . ' Could not resolve timeaccount (id: ' . $record->timeaccount_id . '). No permission?');
153                     }
154                 }
155
156                 // resolve user afterwards because we compare ids in _resolveTimesheetGrantsByTimeaccountGrants()
157                 Tinebase_User::getInstance()->resolveMultipleUsers($_records, array('account_id', 'created_by', 'last_modified_by'), true);
158
159                 break;
160             case 'Timetracker_Model_Timeaccount':
161                 // resolve timeaccounts grants
162                 Timetracker_Model_TimeaccountGrants::getGrantsOfRecords($_records, Tinebase_Core::get('currentAccount'));
163                 $this->_resolveTimeaccountGrants($_records);
164                 break;
165         }
166         
167         if (Tinebase_Core::getUser()->hasRight('Sales', 'manage_invoices')) {
168             $invoiceIds = array_unique(array_values($_records->invoice_id));
169             $invoices   = Sales_Controller_Invoice::getInstance()->getMultiple($invoiceIds);
170             
171             foreach ($_records as $record) {
172                 if ($invoices && $record->invoice_id) {
173                     $record->invoice_id = $invoices->getById($record->invoice_id);
174                 }
175             }
176         }
177         
178
179         Tinebase_Tags::getInstance()->getMultipleTagsOfRecords($_records);
180         $_records->setTimezone(Tinebase_Core::getUserTimezone());
181         $_records->convertDates = true;
182         $result = $_records->toArray();
183
184         return $result;
185     }
186
187     /**
188      * calculate effective ts grants so the client doesn't need to calculate them
189      *
190      * @param  array  $TimeaccountGrantsArray
191      * @param  int    $timesheetOwnerId
192      * @return array
193      */
194     protected function _resolveTimesheetGrantsByTimeaccountGrants($timeaccountGrantsArray, $timesheetOwnerId)
195     {
196         $manageAllRight = Timetracker_Controller_Timeaccount::getInstance()->checkRight(Timetracker_Acl_Rights::MANAGE_TIMEACCOUNTS, FALSE);
197         $currentUserId = Tinebase_Core::getUser()->getId();
198
199         $modifyGrant = $manageAllRight || ($timeaccountGrantsArray[Timetracker_Model_TimeaccountGrants::BOOK_OWN]
200             && $timesheetOwnerId == $currentUserId) || $timeaccountGrantsArray[Timetracker_Model_TimeaccountGrants::BOOK_ALL];
201
202         $timeaccountGrantsArray[Tinebase_Model_Grants::GRANT_READ]   = true;
203         $timeaccountGrantsArray[Tinebase_Model_Grants::GRANT_EDIT]   = $modifyGrant;
204         $timeaccountGrantsArray[Tinebase_Model_Grants::GRANT_DELETE] = $modifyGrant;
205
206         return $timeaccountGrantsArray;
207     }
208
209     /**
210      * calculate effective ta grants so the client doesn't need to calculate them
211      *
212      * @param  array  $_timesaccounts
213      */
214     protected function _resolveTimeaccountGrants(Tinebase_Record_RecordSet $_timesaccounts)
215     {
216          $manageAllRight = Timetracker_Controller_Timeaccount::getInstance()->checkRight(Timetracker_Acl_Rights::MANAGE_TIMEACCOUNTS, FALSE);
217          foreach ($_timesaccounts as $timeaccount) {
218              $timeaccountGrantsArray = $timeaccount->account_grants;
219              $modifyGrant = $manageAllRight || $timeaccountGrantsArray[Timetracker_Model_TimeaccountGrants::GRANT_ADMIN];
220
221              $timeaccountGrantsArray[Tinebase_Model_Grants::GRANT_READ]   = true;
222              $timeaccountGrantsArray[Tinebase_Model_Grants::GRANT_EDIT]   = $modifyGrant;
223              $timeaccountGrantsArray[Tinebase_Model_Grants::GRANT_DELETE] = $modifyGrant;
224              $timeaccount->account_grants = $timeaccountGrantsArray;
225
226              // also move the grants into the container_id property, as the clients expects records to
227              // be contained in some kind of container where it searches the grants in
228              $timeaccount->container_id = array(
229                 'account_grants' => $timeaccountGrantsArray
230              );
231          }
232     }
233
234     /************************************** public API **************************************/
235
236     /**
237      * Search for records matching given arguments
238      *
239      * @param  array $filter
240      * @param  array $paging
241      * @return array
242      */
243     public function searchTimesheets($filter, $paging)
244     {
245         $result = $this->_search($filter, $paging, $this->_timesheetController, 'Timetracker_Model_TimesheetFilter', true);
246         
247         $result['totalcountbillable'] = $result['totalcount']['sum_is_billable_combined'];
248         $result['totalsum']           = $result['totalcount']['sum_duration'];
249         $result['totalsumbillable']   = $result['totalcount']['sum_duration_billable'];
250         $result['totalcount']         = $result['totalcount']['count'];
251
252         return $result;
253     }
254
255     /**
256      * Return a single record
257      *
258      * @param   string $id
259      * @return  array record data
260      */
261     public function getTimesheet($id)
262     {
263         return $this->_get($id, $this->_timesheetController);
264     }
265
266     /**
267      * creates/updates a record
268      *
269      * @param  array $recordData
270      * @param  array $context
271      * @return array created/updated record
272      */
273     public function saveTimesheet($recordData, array $context = array())
274     {
275         $this->_timesheetController->setRequestContext($context);
276         return $this->_save($recordData, $this->_timesheetController, 'Timesheet');
277     }
278
279     /**
280      * deletes existing records
281      *
282      * @param  array $ids
283      * @return string
284      */
285     public function deleteTimesheets($ids)
286     {
287         return $this->_delete($ids, $this->_timesheetController);
288     }
289
290     /**
291      * Search for records matching given arguments
292      *
293      * @param  array $filter
294      * @param  array $paging
295      * @return array
296      */
297     public function searchTimeaccounts($filter, $paging)
298     {
299         return $this->_search($filter, $paging, $this->_timeaccountController, 'Timetracker_Model_TimeaccountFilter');
300     }
301
302     /**
303      * Return a single record
304      *
305      * @param   string $id
306      * @return  array record data
307      */
308     public function getTimeaccount($id)
309     {
310         return $this->_get($id, $this->_timeaccountController);
311     }
312
313     /**
314      * creates/updates a record
315      *
316      * @param  array $recordData
317      * @return array created/updated record
318      */
319     public function saveTimeaccount($recordData)
320     {
321         return $this->_save($recordData, $this->_timeaccountController, 'Timeaccount');
322     }
323
324     /**
325      * deletes existing records
326      *
327      * @param  array  $ids
328      * @return string
329      */
330     public function deleteTimeaccounts($ids)
331     {
332         return $this->_delete($ids, $this->_timeaccountController);
333     }
334 }