/** * appends custom/acl filters to a given select object * * @param Zend_Db_Select $_select * @param Tinebase_Backend_Sql_Abstract $_backend * @return void */ public function appendFilterSql($_select, $_backend) { if (Timetracker_Controller_Timesheet::getInstance()->checkRight(Timetracker_Acl_Rights::MANAGE_TIMEACCOUNTS, FALSE, FALSE)) { return; } if (!$this->_isResolved) { if (Tinebase_Core::isLogLevel(Zend_Log::DEBUG)) { Tinebase_Core::getLogger()->debug(__METHOD__ . '::' . __LINE__ . " Get all timeaccounts for user with required grants: " . print_r($this->_requiredGrants, TRUE)); } $result = Timetracker_Model_TimeaccountGrants::getTimeaccountsByAcl($this->_requiredGrants, TRUE); $this->_validTimeaccounts = $result; $this->_isResolved = TRUE; if (Tinebase_Core::isLogLevel(Zend_Log::DEBUG)) { Tinebase_Core::getLogger()->debug(__METHOD__ . '::' . __LINE__ . " Got " . count($this->_validTimeaccounts) . ' valid timeaccounts'); } } $db = Tinebase_Core::getDb(); $field = $db->quoteIdentifier('id'); $where = $db->quoteInto("{$field} IN (?)", empty($this->_validTimeaccounts) ? array('') : $this->_validTimeaccounts); $_select->where($where); }
/** * resolve timeaccount ids */ protected function _resolve() { if ($this->_isResolved) { //if (Tinebase_Core::isLogLevel(Zend_Log::DEBUG)) Tinebase_Core::getLogger()->debug(__METHOD__ . '::' . __LINE__ . ' already resolved'); return; } $this->_value = (array) $this->_value; // we only need to resolve the timaccount ids if user has no MANAGE_TIMEACCOUNTS grant if (!Timetracker_Controller_Timesheet::getInstance()->checkRight(Timetracker_Acl_Rights::MANAGE_TIMEACCOUNTS, FALSE, FALSE)) { // get all timeaccounts user has required grants for $result = array(); foreach ($this->_requiredGrants as $grant) { //if (Tinebase_Core::isLogLevel(Zend_Log::DEBUG)) Tinebase_Core::getLogger()->debug(__METHOD__ . '::' . __LINE__ . ' value:' . $this->_value); $result = array_merge($result, Timetracker_Model_TimeaccountGrants::getTimeaccountsByAcl($grant, TRUE)); } $result = array_unique($result); //if (Tinebase_Core::isLogLevel(Zend_Log::DEBUG)) Tinebase_Core::getLogger()->debug(__METHOD__ . '::' . __LINE__ . ' ' . print_r($result, TRUE)); // finally compute timeaccount_ids which match the filter and required grants switch ($this->_operator) { case 'equals': case 'in': $this->_value = array_intersect($this->_value, $result); break; case 'all': $this->_value = $result; break; } } $this->_isResolved = TRUE; }
/** * check grant for action (CRUD) * * @param Timetracker_Model_Timeaccount $_record * @param string $_action * @param boolean $_throw * @param string $_errorMessage * @param Timetracker_Model_Timeaccount $_oldRecord * @return boolean * @throws Tinebase_Exception_AccessDenied */ protected function _checkGrant($_record, $_action, $_throw = TRUE, $_errorMessage = 'No Permission.', $_oldRecord = NULL) { if ($_action == 'create' || $this->_doGrantChecks == FALSE) { // no check here because the MANAGE_TIMEACCOUNTS right has been already checked before return TRUE; } $hasGrant = Timetracker_Model_TimeaccountGrants::hasGrant($_record->getId(), Tinebase_Model_Grants::GRANT_ADMIN); switch ($_action) { case 'get': $hasGrant = $hasGrant || Timetracker_Model_TimeaccountGrants::hasGrant($_record->getId(), array(Timetracker_Model_TimeaccountGrants::VIEW_ALL, Timetracker_Model_TimeaccountGrants::BOOK_OWN, Timetracker_Model_TimeaccountGrants::BOOK_ALL, Timetracker_Model_TimeaccountGrants::MANAGE_BILLABLE)); case 'delete': case 'update': $hasGrant = $hasGrant || $this->checkRight(Timetracker_Acl_Rights::MANAGE_TIMEACCOUNTS, FALSE); break; } if ($_throw && !$hasGrant) { throw new Tinebase_Exception_AccessDenied($_errorMessage); } return $hasGrant; }
/** * returns multiple records prepared for json transport * * NOTE: we can't use parent::_multipleRecordsToJson here because of the different container handling * * @param Tinebase_Record_RecordSet $_leads Crm_Model_Lead * @return array data */ protected function _multipleRecordsToJson(Tinebase_Record_RecordSet $_records, $_filter = NULL) { if (count($_records) == 0) { return array(); } switch ($_records->getRecordClassName()) { case 'Timetracker_Model_Timesheet': // resolve timeaccounts $timeaccountIds = $_records->timeaccount_id; $timeaccounts = $this->_timeaccountController->getMultiple(array_unique(array_values($timeaccountIds))); Timetracker_Model_TimeaccountGrants::getGrantsOfRecords($timeaccounts, Tinebase_Core::get('currentAccount')); foreach ($_records as $record) { $idx = $timeaccounts->getIndexById($record->timeaccount_id); if ($idx !== FALSE) { $record->timeaccount_id = $timeaccounts[$idx]; $record->timeaccount_id->account_grants = $this->_resolveTimesheetGrantsByTimeaccountGrants($record->timeaccount_id->account_grants, $record->account_id); } else { Tinebase_Core::getLogger()->warn(__METHOD__ . '::' . __LINE__ . ' Could not resolve timeaccount (id: ' . $record->timeaccount_id . '). No permission?'); } } // resolve user afterwards because we compare ids in _resolveTimesheetGrantsByTimeaccountGrants() Tinebase_User::getInstance()->resolveMultipleUsers($_records, array('account_id', 'created_by', 'last_modified_by'), true); break; case 'Timetracker_Model_Timeaccount': // resolve timeaccounts grants Timetracker_Model_TimeaccountGrants::getGrantsOfRecords($_records, Tinebase_Core::get('currentAccount')); $this->_resolveTimeaccountGrants($_records); break; } Tinebase_Tags::getInstance()->getMultipleTagsOfRecords($_records); $_records->setTimezone(Tinebase_Core::get('userTimeZone')); $_records->convertDates = true; $result = $_records->toArray(); return $result; }
/** * returns account_grants of given timeaccount * - this function caches its result (with cache tag 'container') * * @param Tinebase_Model_User|int $_accountId * @param Timetracker_Model_Timeaccount|string $_timeaccountId * @param bool $_ignoreAcl * @return array */ public static function getGrantsOfAccount($_accountId, $_timeaccountId, $_ignoreAcl = FALSE) { $cache = Tinebase_Core::getCache(); $cacheId = convertCacheId('getGrantsOfAccount' . Tinebase_Model_User::convertUserIdToInt($_accountId) . ($_timeaccountId instanceof Timetracker_Model_Timeaccount ? $_timeaccountId->getId() : $_timeaccountId) . $_ignoreAcl); $result = $cache->load($cacheId); if ($result === FALSE) { $timeaccount = $_timeaccountId instanceof Timetracker_Model_Timeaccount ? $_timeaccountId : Timetracker_Controller_Timeaccount::getInstance()->get($_timeaccountId); $containerGrantsArray = Tinebase_Container::getInstance()->getGrantsOfAccount($_accountId, $timeaccount->container_id, 'Timetracker_Model_TimeaccountGrants')->toArray(); $account_grants = new Timetracker_Model_TimeaccountGrants($containerGrantsArray); $result = $account_grants->toArray(); $cache->save($result, $cacheId, array('container')); } return $result; }
/** * check grant for action * * @param Timetracker_Model_Timeaccount $_record * @param string $_action * @param boolean $_throw * @param string $_errorMessage * @param Timetracker_Model_Timesheet $_oldRecord * @return boolean * @throws Tinebase_Exception_AccessDenied * * @todo think about just setting the default values when user * hasn't the required grant to change the field (instead of throwing exception) */ protected function _checkGrant($_record, $_action, $_throw = TRUE, $_errorMessage = 'No Permission.', $_oldRecord = NULL) { // users with MANAGE_TIMEACCOUNTS have all grants here if ($this->checkRight(Timetracker_Acl_Rights::MANAGE_TIMEACCOUNTS, FALSE) || Timetracker_Model_TimeaccountGrants::hasGrant($_record->timeaccount_id, Tinebase_Model_Grants::GRANT_ADMIN)) { return TRUE; } // only TA managers are allowed to alter TS of closed TAs if ($_action != 'get') { $timeaccount = Timetracker_Controller_Timeaccount::getInstance()->get($_record->timeaccount_id); if (!$timeaccount->is_open) { return FALSE; } // check if timeaccount->is_billable is false => set default in fieldGrants to 0 and allow only managers to change it if (!$timeaccount->is_billable) { $this->_fieldGrants['is_billable']['default'] = 0; $this->_fieldGrants['is_billable']['requiredGrant'] = Tinebase_Model_Grants::GRANT_ADMIN; } } $hasGrant = FALSE; switch ($_action) { case 'get': $hasGrant = Timetracker_Model_TimeaccountGrants::hasGrant($_record->timeaccount_id, array(Timetracker_Model_TimeaccountGrants::VIEW_ALL, Timetracker_Model_TimeaccountGrants::BOOK_ALL)) || $_record->account_id == $this->_currentAccount->getId() && Timetracker_Model_TimeaccountGrants::hasGrant($_record->timeaccount_id, Timetracker_Model_TimeaccountGrants::BOOK_OWN); break; case 'create': $hasGrant = $_record->account_id == $this->_currentAccount->getId() && Timetracker_Model_TimeaccountGrants::hasGrant($_record->timeaccount_id, Timetracker_Model_TimeaccountGrants::BOOK_OWN) || Timetracker_Model_TimeaccountGrants::hasGrant($_record->timeaccount_id, Timetracker_Model_TimeaccountGrants::BOOK_ALL); if ($hasGrant) { foreach ($this->_fieldGrants as $field => $config) { if (isset($_record->{$field}) && $_record->{$field} != $config['default']) { $hasGrant &= Timetracker_Model_TimeaccountGrants::hasGrant($_record->timeaccount_id, $config['requiredGrant']); } } } break; case 'update': $hasGrant = $_record->account_id == $this->_currentAccount->getId() && Timetracker_Model_TimeaccountGrants::hasGrant($_record->timeaccount_id, Timetracker_Model_TimeaccountGrants::BOOK_OWN) || Timetracker_Model_TimeaccountGrants::hasGrant($_record->timeaccount_id, Timetracker_Model_TimeaccountGrants::BOOK_ALL); if ($hasGrant) { foreach ($this->_fieldGrants as $field => $config) { if (isset($_record->{$field}) && $_record->{$field} != $_oldRecord->{$field}) { $hasGrant &= Timetracker_Model_TimeaccountGrants::hasGrant($_record->timeaccount_id, $config['requiredGrant']); } } } break; case 'delete': $hasGrant = $_record->account_id == $this->_currentAccount->getId() && Timetracker_Model_TimeaccountGrants::hasGrant($_record->timeaccount_id, Timetracker_Model_TimeaccountGrants::BOOK_OWN) || Timetracker_Model_TimeaccountGrants::hasGrant($_record->timeaccount_id, Timetracker_Model_TimeaccountGrants::BOOK_ALL); break; } if ($_throw && !$hasGrant) { throw new Tinebase_Exception_AccessDenied($_errorMessage); } return $hasGrant; }
/** * append acl filter * * @param Zend_Db_Select $_select */ protected function _appendAclSqlFilter($_select) { if ($this->getCondition() === self::CONDITION_OR) { // ACL filter with OR condition is useless and delivers wrong results! if (Tinebase_Core::isLogLevel(Zend_Log::DEBUG)) { Tinebase_Core::getLogger()->debug(__METHOD__ . '::' . __LINE__ . ' ' . ' No ACL filter for OR condition!'); } return; } if (Timetracker_Controller_Timesheet::getInstance()->checkRight(Timetracker_Acl_Rights::MANAGE_TIMEACCOUNTS, FALSE, FALSE)) { if (Tinebase_Core::isLogLevel(Zend_Log::DEBUG)) { Tinebase_Core::getLogger()->debug(__METHOD__ . '::' . __LINE__ . ' ' . ' No ACL filter for MANAGE_TIMEACCOUNTS right!'); } return; } if (!$this->_isResolved) { // get all timeaccounts user has required grants for $result = array(); foreach ($this->_requiredGrants as $grant) { if ($grant != Timetracker_Model_TimeaccountGrants::BOOK_OWN) { $result = array_merge($result, Timetracker_Model_TimeaccountGrants::getTimeaccountsByAcl($grant, TRUE)); } } $this->_validTimeaccounts = array_unique($result); if (Tinebase_Core::isLogLevel(Zend_Log::TRACE)) { Tinebase_Core::getLogger()->trace(__METHOD__ . '::' . __LINE__ . ' valid timeaccounts' . print_r($this->_validTimeaccounts, TRUE) . ' for required grants: ' . print_r($this->_requiredGrants, TRUE)); } $this->_isResolved = TRUE; } $db = Tinebase_Core::getDb(); $field = $db->quoteIdentifier('timeaccount_id'); $where = $db->quoteInto("{$field} IN (?)", empty($this->_validTimeaccounts) ? array('') : $this->_validTimeaccounts); // get timeaccounts with BOOK_OWN right (get only if no manual filter is set) $bookOwnTS = Timetracker_Model_TimeaccountGrants::getTimeaccountsByAcl(Timetracker_Model_TimeaccountGrants::BOOK_OWN, TRUE); if (!empty($bookOwnTS)) { $where .= ' OR (' . $db->quoteInto($field . ' IN (?)', $bookOwnTS) . ' AND ' . $db->quoteInto($db->quoteIdentifier('account_id') . ' = ?', Tinebase_Core::getUser()->getId()) . ')'; } $_select->where($where); if (Tinebase_Core::isLogLevel(Zend_Log::TRACE)) { Tinebase_Core::getLogger()->trace(__METHOD__ . '::' . __LINE__ . ' ACL filter: ' . $where); } }
/** * try to add a Timesheet with different grants * * @param Tinebase_Record_RecordSet $_grants * @param string $_action * @param mixed $_expect * @param Timetracker_Model_Timesheet */ protected function _grantTestHelper($_grants, $_action = 'create', $_expect = NULL, $_ts = NULL) { // take default ts? $ts = $_ts ? $_ts : $this->_objects['timesheet']; // remove BOOK_OWN + BOOK_ALL + ADMIN grant Timetracker_Model_TimeaccountGrants::setTimeaccountGrants($this->_objects['timeaccount'], $_grants, TRUE); // try to create timesheet switch ($_action) { case 'create': if ($_expect === 'Exception') { $this->setExpectedException('Tinebase_Exception_AccessDenied'); $this->_timesheetController->create($ts); } else { $ts = $this->_timesheetController->create($ts); $this->assertEquals(Tinebase_Core::getUser()->getId(), $ts->created_by); } break; case 'create_deadline': // date is before deadline $date = new Tinebase_DateTime(); $date->sub(8, Tinebase_DateTime::MODIFIER_DAY); $ts->start_date = $date->toString('Y-m-d'); $this->setExpectedException('Timetracker_Exception_Deadline'); $this->_timesheetController->create($ts); break; case 'search_bookable': $filter = $this->_getTimeaccountFilter(TRUE); $result = $this->_timeaccountController->search($filter); $this->assertEquals($_expect, count($result)); break; case 'searchTA': $filter = $this->_getTimeaccountFilter(); $result = $this->_timeaccountController->search($filter); $this->assertEquals($_expect, count($result)); break; case 'searchTS': $filter = $this->_getTimesheetFilter(); $ts = $this->_timesheetController->create($ts); $result = $this->_timesheetController->search($filter); $this->assertEquals($_expect, count($result)); break; case 'searchTSExport': $filter = $this->_getTimesheetFilter(); $result = $this->_timesheetController->search($filter, NULL, FALSE, FALSE, 'export'); $this->assertEquals($_expect, count($result)); break; default: echo "nothing tested."; } // delete (set delete grant first) $grants = new Tinebase_Record_RecordSet('Timetracker_Model_TimeaccountGrants', array(array('account_id' => Tinebase_Core::getUser()->getId(), 'account_type' => 'user', Timetracker_Model_TimeaccountGrants::MANAGE_BILLABLE => TRUE, Tinebase_Model_Grants::GRANT_ADMIN => TRUE, Timetracker_Model_TimeaccountGrants::BOOK_ALL => TRUE, Timetracker_Model_TimeaccountGrants::BOOK_OWN => TRUE, Timetracker_Model_TimeaccountGrants::VIEW_ALL => TRUE, Tinebase_Model_Grants::GRANT_EXPORT => TRUE))); Timetracker_Model_TimeaccountGrants::setTimeaccountGrants($this->_objects['timeaccount'], $grants, TRUE); }
/** * check grant for action * * @param Timetracker_Model_Timeaccount $_record * @param string $_action * @param boolean $_throw * @param string $_errorMessage * @param Timetracker_Model_Timesheet $_oldRecord * @return boolean * @throws Tinebase_Exception_AccessDenied * * @todo think about just setting the default values when user * hasn't the required grant to change the field (instead of throwing exception) */ protected function _checkGrant($_record, $_action, $_throw = TRUE, $_errorMessage = 'No Permission.', $_oldRecord = NULL) { $isAdmin = false; // users with MANAGE_TIMEACCOUNTS have all grants here if ($this->checkRight(Timetracker_Acl_Rights::MANAGE_TIMEACCOUNTS, FALSE) || Timetracker_Model_TimeaccountGrants::hasGrant($_record->timeaccount_id, Tinebase_Model_Grants::GRANT_ADMIN)) { $isAdmin = true; } // only TA managers are allowed to alter TS of closed TAs, but they have to confirm first that they really want to do it if ($_action != 'get') { $timeaccount = Timetracker_Controller_Timeaccount::getInstance()->get($_record->timeaccount_id); if (!$timeaccount->is_open) { if (Tinebase_Core::isLogLevel(Zend_Log::DEBUG)) { Tinebase_Core::getLogger()->debug(__METHOD__ . '::' . __LINE__ . ' This Timeaccount is already closed!'); } if ($isAdmin === true) { if (is_array($this->_requestContext) && isset($this->_requestContext['skipClosedCheck']) && $this->_requestContext['skipClosedCheck']) { return true; } } if ($_throw) { throw new Timetracker_Exception_ClosedTimeaccount(); } return FALSE; } // check if timeaccount->is_billable is false => set default in fieldGrants to 0 and allow only managers to change it if (!$timeaccount->is_billable) { $this->_fieldGrants['is_billable']['default'] = 0; $this->_fieldGrants['is_billable']['requiredGrant'] = Tinebase_Model_Grants::GRANT_ADMIN; } } if ($isAdmin === true) { return true; } $hasGrant = FALSE; switch ($_action) { case 'get': $hasGrant = Timetracker_Model_TimeaccountGrants::hasGrant($_record->timeaccount_id, array(Timetracker_Model_TimeaccountGrants::VIEW_ALL, Timetracker_Model_TimeaccountGrants::BOOK_ALL)) || $_record->account_id == Tinebase_Core::getUser()->getId() && Timetracker_Model_TimeaccountGrants::hasGrant($_record->timeaccount_id, Timetracker_Model_TimeaccountGrants::BOOK_OWN); break; case 'create': $hasGrant = $_record->account_id == Tinebase_Core::getUser()->getId() && Timetracker_Model_TimeaccountGrants::hasGrant($_record->timeaccount_id, Timetracker_Model_TimeaccountGrants::BOOK_OWN) || Timetracker_Model_TimeaccountGrants::hasGrant($_record->timeaccount_id, Timetracker_Model_TimeaccountGrants::BOOK_ALL); if ($hasGrant) { foreach ($this->_fieldGrants as $field => $config) { if (isset($_record->{$field}) && $_record->{$field} != $config['default']) { $hasGrant &= Timetracker_Model_TimeaccountGrants::hasGrant($_record->timeaccount_id, $config['requiredGrant']); } } } break; case 'update': $hasGrant = $_record->account_id == Tinebase_Core::getUser()->getId() && Timetracker_Model_TimeaccountGrants::hasGrant($_record->timeaccount_id, Timetracker_Model_TimeaccountGrants::BOOK_OWN) || Timetracker_Model_TimeaccountGrants::hasGrant($_record->timeaccount_id, Timetracker_Model_TimeaccountGrants::BOOK_ALL); if ($hasGrant) { foreach ($this->_fieldGrants as $field => $config) { if (isset($_record->{$field}) && $_record->{$field} != $_oldRecord->{$field}) { $hasGrant &= Timetracker_Model_TimeaccountGrants::hasGrant($_record->timeaccount_id, $config['requiredGrant']); } } } break; case 'delete': $hasGrant = $_record->account_id == Tinebase_Core::getUser()->getId() && Timetracker_Model_TimeaccountGrants::hasGrant($_record->timeaccount_id, Timetracker_Model_TimeaccountGrants::BOOK_OWN) || Timetracker_Model_TimeaccountGrants::hasGrant($_record->timeaccount_id, Timetracker_Model_TimeaccountGrants::BOOK_ALL); break; } if ($_throw && !$hasGrant) { throw new Tinebase_Exception_AccessDenied($_errorMessage); } return $hasGrant; }
/** * append acl filter * * @param Zend_Db_Select $_select */ protected function _appendAclSqlFilter($_select) { if (Timetracker_Controller_Timesheet::getInstance()->checkRight(Timetracker_Acl_Rights::MANAGE_TIMEACCOUNTS, FALSE, FALSE)) { return; } if (!$this->_isResolved) { // get all timeaccounts user has required grants for $result = array(); foreach ($this->_requiredGrants as $grant) { $result = array_merge($result, Timetracker_Model_TimeaccountGrants::getTimeaccountsByAcl($grant, TRUE)); } $this->_validTimeaccounts = array_unique($result); $this->_isResolved = TRUE; } $db = Tinebase_Core::getDb(); $field = $db->quoteIdentifier('id'); $where = $db->quoteInto("{$field} IN (?)", empty($this->_validTimeaccounts) ? array('') : $this->_validTimeaccounts); $_select->where($where); }