7 * @license http://www.gnu.org/licenses/agpl.html AGPL Version 3
8 * @copyright Copyright (c) 2007-2014 Metaways Infosystems GmbH (http://www.metaways.de)
9 * @author Lars Kneschke <l.kneschke@metaways.de>
14 * Json interface to Tinebase
19 class Tinebase_Frontend_Json extends Tinebase_Frontend_Json_Abstract
21 const REQUEST_TYPE = 'JSON-RPC';
27 protected $_hasCaptcha = null;
32 * @todo do we still need this?
34 public function ping()
36 Tinebase_Session::writeClose(true);
38 return array('changes' => 'contacts');
42 * get list of translated country names
44 * Wrapper for {@see Tinebase_Core::getCountrylist}
46 * @return array list of countrys
48 public function getCountryList()
50 return Tinebase_Translation::getCountryList();
54 * returns list of all available translations
56 * @return array list of all available translations
58 public function getAvailableTranslations()
60 $availableTranslations = Tinebase_Translation::getAvailableTranslations();
61 foreach($availableTranslations as &$info) {
66 'results' => array_values($availableTranslations),
67 'totalcount' => count($availableTranslations)
74 * @param string $localeString
75 * @param bool $saveaspreference
76 * @param bool $setcookie
79 public function setLocale($localeString, $saveaspreference, $setcookie)
81 Tinebase_Core::setupUserLocale($localeString);
83 if ($saveaspreference && is_object(Tinebase_Core::getUser())) {
84 if (Tinebase_Core::isLogLevel(Zend_Log::DEBUG)) Tinebase_Core::getLogger()->debug(__METHOD__ . '::' . __LINE__
85 . " Saving locale: " . $localeString);
86 Tinebase_Core::getPreference()->{Tinebase_Preference::LOCALE} = $localeString;
89 // save in cookie (expires in 365 days)
91 setcookie('TINE20LOCALE', $localeString, time()+60*60*24*365);
102 * @param string $timezoneString
103 * @param bool $saveaspreference
106 public function setTimezone($timezoneString, $saveaspreference)
108 $timezone = Tinebase_Core::setupUserTimezone($timezoneString, $saveaspreference);
116 * @param string $filter
117 * @param string $sort
121 * @return array with results array & totalcount (int)
123 public function getUsers($filter, $sort, $dir, $start, $limit)
126 'results' => array(),
130 if($rows = Tinebase_User::getInstance()->getUsers($filter, $sort, $dir, $start, $limit)) {
131 $result['results'] = $rows->toArray();
132 if($start == 0 && count($result['results']) < $limit) {
133 $result['totalcount'] = count($result['results']);
135 //$result['totalcount'] = $backend->getCountByAddressbookId($addressbookId, $filter);
145 * @param array $_filter
146 * @param array $_paging
149 public function searchRoles($filter, $paging)
152 'results' => array(),
156 $filter = new Tinebase_Model_RoleFilter(array(
157 'name' => '%' . $filter[0]['value'] . '%',
158 'description' => '%' . $filter[0]['value'] . '%'
161 $paging['sort'] = isset($paging['sort']) ? $paging['sort'] : 'name';
162 $paging['dir'] = isset($paging['dir']) ? $paging['dir'] : 'ASC';
164 $result['results'] = Tinebase_Acl_Roles::getInstance()->searchRoles($filter, new Tinebase_Model_Pagination($paging))->toArray();
165 $result['totalcount'] = Tinebase_Acl_Roles::getInstance()->searchCount($filter);
171 * change password of user
173 * @param string $oldPassword the old password
174 * @param string $newPassword the new password
177 public function changePassword($oldPassword, $newPassword)
184 Tinebase_Controller::getInstance()->changePassword($oldPassword, $newPassword);
185 } catch (Tinebase_Exception $e) {
188 'errorMessage' => "New password could not be set! Error: " . $e->getMessage()
198 * @param string $name
201 public function clearState($name)
203 Tinebase_State::getInstance()->clearState($name);
209 * @return array of name => value
211 public function loadState()
213 return Tinebase_State::getInstance()->loadStateInfo();
219 * @param string $name
220 * @param string $value
223 public function setState($name, $value)
225 if (Tinebase_Core::isLogLevel(Zend_Log::DEBUG)) Tinebase_Core::getLogger()->debug(__METHOD__ . '::' . __LINE__ . " Setting state: {$name} -> {$value}");
226 Tinebase_State::getInstance()->setState($name, $value);
230 * adds a new personal tag
235 public function saveTag($tag)
237 $inTag = new Tinebase_Model_Tag($tag);
239 if (strlen($inTag->getId()) < 40) {
240 if (Tinebase_Core::isLogLevel(Zend_Log::DEBUG)) Tinebase_Core::getLogger()->debug(__METHOD__ . '::' . __LINE__ . ' creating tag: ' . print_r($inTag->toArray(), true));
241 $outTag = Tinebase_Tags::getInstance()->createTag($inTag);
243 if (Tinebase_Core::isLogLevel(Zend_Log::DEBUG)) Tinebase_Core::getLogger()->debug(__METHOD__ . '::' . __LINE__ . ' updating tag: ' .print_r($inTag->toArray(), true));
244 $outTag = Tinebase_Tags::getInstance()->updateTag($inTag);
247 return $outTag->toArray();
251 * Used for updating multiple records
253 * @param string $appName
254 * @param string $modelName
255 * @param array $changes
256 * @param array $filter
258 public function updateMultipleRecords($appName, $modelName, $changes, $filter)
260 // increase execution time to 30 minutes
261 Tinebase_Core::setExecutionLifeTime(1800);
263 $filterModel = $appName . '_Model_' . $modelName . 'Filter';
265 foreach ($changes as $f) {
266 $data[preg_replace('/^customfield_/','#', $f['name'])] = $f['value'];
269 return $this->_updateMultiple($filter, $data, Tinebase_Core::getApplicationInstance($appName, $modelName), $filterModel);
275 * @param array $filter filter array
276 * @param array $paging pagination info
279 public function searchTags($filter, $paging)
281 $filter = new Tinebase_Model_TagFilter($filter);
282 $paging = new Tinebase_Model_Pagination($paging);
285 'results' => Tinebase_Tags::getInstance()->searchTags($filter, $paging)->toArray(),
286 // TODO we normally use 'totalcount' (all lower case) - this should be streamlined
287 'totalCount' => Tinebase_Tags::getInstance()->getSearchTagsCount($filter)
292 * search tags by foreign filter
294 * @param array $filterData
295 * @param string $filterName
298 public function searchTagsByForeignFilter($filterData, $filterName)
300 $filter = $this->_getFilterGroup($filterData, $filterName);
302 $result = Tinebase_Tags::getInstance()->searchTagsByForeignFilter($filter)->toArray();
304 'results' => $result,
305 'totalCount' => count($result)
310 * get filter group defined by filterName and filterData
312 * @param array $_filterData
313 * @param string $_filterName
314 * @return Tinebase_Model_Filter_FilterGroup
315 * @throws Tinebase_Exception_AccessDenied
317 protected function _getFilterGroup($_filterData, $_filterName)
319 // NOTE: this function makes a new instance of a class whose name is given by user input.
320 // we need to do some sanitising first!
321 /** @noinspection PhpUnusedLocalVariableInspection */
322 list($appName, $modelString, $filterGroupName) = explode('_', $_filterName);
323 if ($modelString !== 'Model') {
324 Tinebase_Core::getLogger()->warn(__METHOD__ . '::' . __LINE__ . ' spoofing attempt detected, affected account: ' . print_r(Tinebase_Core::getUser()->toArray(), TRUE));
328 if (! Tinebase_Core::getUser()->hasRight($appName, Tinebase_Acl_Rights_Abstract::RUN)) {
329 throw new Tinebase_Exception_AccessDenied('No right to access application');
332 $filterGroup = new $_filterName(array());
333 if (! $filterGroup instanceof Tinebase_Model_Filter_FilterGroup) {
334 Tinebase_Core::getLogger()->warn(__METHOD__ . '::' . __LINE__ . ' spoofing attempt detected, affected account: ' . print_r(Tinebase_Core::getUser()->toArray(), TRUE));
338 // at this point we are sure request is save ;-)
339 $filterGroup->setFromArray($_filterData);
345 * attach tag to multiple records identified by a filter
347 * @param array $filterData
348 * @param string $filterName
349 * @param mixed $tag string|array existing and non-existing tag
352 public function attachTagToMultipleRecords($filterData, $filterName, $tag)
354 $this->_longRunningRequest();
355 $filter = $this->_getFilterGroup($filterData, $filterName);
357 Tinebase_Tags::getInstance()->attachTagToMultipleRecords($filter, $tag);
358 return array('success' => true);
362 * attach multiple tags to multiple records identified by a filter
364 * @param array $filterData
365 * @param string $filterName
366 * @param mixed $tags array of existing and non-existing tags
369 public function attachMultipleTagsToMultipleRecords($filterData, $filterName, $tags)
371 $this->_longRunningRequest();
372 $filter = $this->_getFilterGroup($filterData, $filterName);
374 foreach ($tags as $tag) {
375 Tinebase_Tags::getInstance()->attachTagToMultipleRecords(clone $filter, $tag);
378 return array('success' => true);
382 * detach tags to multiple records identified by a filter
384 * @param array $filterData
385 * @param string $filterName
386 * @param mixed $tag string|array existing and non-existing tag
389 public function detachTagsFromMultipleRecords($filterData, $filterName, $tag)
391 $this->_longRunningRequest();
392 $filter = $this->_getFilterGroup($filterData, $filterName);
394 Tinebase_Tags::getInstance()->detachTagsFromMultipleRecords($filter, $tag);
395 return array('success' => true);
400 * - used by activities grid
402 * @param array $filter filter array
403 * @param array $paging pagination info
406 public function searchNotes($filter, $paging)
408 $filter = new Tinebase_Model_NoteFilter($filter);
409 $paging = new Tinebase_Model_Pagination($paging);
411 $records = Tinebase_Notes::getInstance()->searchNotes($filter, $paging, /* ignoreACL = */ false);
412 $result = $this->_multipleRecordsToJson($records);
415 'results' => $result,
416 'totalcount' => Tinebase_Notes::getInstance()->searchNotesCount($filter, /* ignoreACL = */ false)
424 public function getNoteTypes()
426 $noteTypes = Tinebase_Notes::getInstance()->getNoteTypes();
427 $noteTypes->translate();
430 'results' => $noteTypes->toArray(),
431 'totalcount' => count($noteTypes)
436 * deletes tags identified by an array of identifiers
441 public function deleteTags($ids)
443 Tinebase_Tags::getInstance()->deleteTags($ids);
444 return array('success' => true);
448 * authenticate user by username and password
450 * @param string $username the username
451 * @param string $password the password
454 public function authenticate($username, $password)
456 $authResult = Tinebase_Auth::getInstance()->authenticate($username, $password);
458 if ($authResult->isValid()) {
460 'status' => 'success',
461 'msg' => 'authentication succseed',
462 //'loginUrl' => 'someurl',
467 'msg' => 'authentication failed',
475 * login user with given username and password
477 * @param string $username the username
478 * @param string $password the password
479 * @param string $securitycode the security code(captcha)
480 * @param string $otp the second factor password
483 public function login($username, $password, $securitycode = null, $otp = null)
485 Tinebase_Core::startCoreSession();
487 if (is_array(($response = $this->_getCaptchaResponse($securitycode)))) {
491 // TODO move security code here and use params
492 Tinebase_Controller::getInstance()->setRequestContext(array(
497 $success = Tinebase_Controller::getInstance()->login(
500 Tinebase_Core::get(Tinebase_Core::REQUEST),
505 if ($success === true) {
506 return $this->_getLoginSuccessResponse($username);
508 return $this->_getLoginFailedResponse();
513 * Returns TRUE if there is a captcha
516 protected function _hasCaptcha()
518 if ($this->_hasCaptcha === null){
519 $this->_hasCaptcha = isset(Tinebase_Core::getConfig()->captcha->count) && Tinebase_Core::getConfig()->captcha->count != 0;
522 return $this->_hasCaptcha;
527 * @param string $securitycode
528 * @return array | NULL
530 protected function _getCaptchaResponse($securitycode)
532 if ($this->_hasCaptcha()) {
533 $config_count = Tinebase_Core::getConfig()->captcha->count;
535 $count = (isset(Tinebase_Session::getSessionNamespace()->captcha['count'])
536 ? Tinebase_Session::getSessionNamespace()->captcha['count']
540 if ($count >= $config_count) {
541 $aux = isset(Tinebase_Session::getSessionNamespace()->captcha['code'])
542 ? Tinebase_Session::getSessionNamespace()->captcha['code']
545 if ($aux != $securitycode) {
546 $rets = Tinebase_Controller::getInstance()->makeCaptcha();
549 'errorMessage' => "Wrong username or password!",
563 * @param string $username
566 protected function _getLoginSuccessResponse($username)
570 'account' => Tinebase_Core::getUser()->getPublicUser()->toArray(),
571 'jsonKey' => Tinebase_Core::get('jsonKey'),
572 'welcomeMessage' => "Welcome to Tine 2.0!"
575 if (Tinebase_Config::getInstance()->get(Tinebase_Config::REUSEUSERNAME_SAVEUSERNAME, 0)) {
576 // save in cookie (expires in 2 weeks)
577 setcookie('TINE20LASTUSERID', $username, time()+60*60*24*14);
579 setcookie('TINE20LASTUSERID', '', 0);
582 $this->_setCredentialCacheCookie();
591 protected function _getLoginFailedResponse()
595 'errorMessage' => "Wrong username or password!",
598 Tinebase_Auth_CredentialCache::getInstance()->getCacheAdapter()->resetCache();
600 if ($this->_hasCaptcha()) {
601 $config_count = Tinebase_Core::getConfig()->captcha->count;
603 if (!isset(Tinebase_Session::getSessionNamespace()->captcha['count'])) {
604 Tinebase_Session::getSessionNamespace()->captcha['count'] = 1;
606 Tinebase_Session::getSessionNamespace()->captcha['count'] = Tinebase_Session::getSessionNamespace()->captcha['count'] + 1;
609 if (Tinebase_Session::getSessionNamespace()->captcha['count'] >= $config_count) {
610 $rets = Tinebase_Controller::getInstance()->makeCaptcha();
613 'errorMessage' => "Wrong username or password!",
618 Tinebase_Session::destroyAndMantainCookie();
625 * set credential cache cookie
629 protected function _setCredentialCacheCookie()
631 if (!Tinebase_Core::isRegistered(Tinebase_Core::USERCREDENTIALCACHE)) {
632 Tinebase_Core::getLogger()->warn(__METHOD__ . '::' . __LINE__ . ' Something went wrong with the CredentialCache / no CC registered.');
637 Tinebase_Auth_CredentialCache::getInstance()->getCacheAdapter()->setCache(Tinebase_Core::getUserCredentialCache());
643 * update user credential cache
645 * - fires Tinebase_Event_User_ChangeCredentialCache
647 * @param string $password
650 public function updateCredentialCache($password)
652 $oldCredentialCache = Tinebase_Core::getUserCredentialCache();
653 $credentialCache = Tinebase_Auth_CredentialCache::getInstance()->cacheCredentials(Tinebase_Core::getUser()->accountLoginName, $password);
654 Tinebase_Core::set(Tinebase_Core::USERCREDENTIALCACHE, $credentialCache);
656 $success = $this->_setCredentialCacheCookie();
659 // close session to allow other requests
660 Tinebase_Session::writeClose(true);
661 $event = new Tinebase_Event_User_ChangeCredentialCache($oldCredentialCache);
662 Tinebase_Event::fireEvent($event);
666 'success' => $success
675 public function logout()
677 Tinebase_Controller::getInstance()->logout($_SERVER['REMOTE_ADDR']);
679 Tinebase_Auth_CredentialCache::getInstance()->getCacheAdapter()->resetCache();
681 if (Tinebase_Session::isStarted()) {
682 Tinebase_Session::destroyAndRemoveCookie();
693 * Returns registry data of tinebase.
694 * @see Tinebase_Application_Json_Abstract
696 * @return mixed array 'variable name' => 'data'
698 public function getRegistryData()
700 $registryData = $this->_getAnonymousRegistryData();
702 if (Tinebase_Core::isRegistered(Tinebase_Core::USER)) {
703 $userRegistryData = $this->_getUserRegistryData();
704 $registryData += $userRegistryData;
707 return $registryData;
711 * get anonymous registry
715 protected function _getAnonymousRegistryData()
717 $locale = Tinebase_Core::get('locale');
718 $tbFrontendHttp = new Tinebase_Frontend_Http();
720 // default credentials
721 if (isset(Tinebase_Core::getConfig()->login)) {
722 $loginConfig = Tinebase_Core::getConfig()->login;
723 $defaultUsername = (isset($loginConfig->username)) ? $loginConfig->username : '';
724 $defaultPassword = (isset($loginConfig->password)) ? $loginConfig->password : '';
726 $defaultUsername = '';
727 $defaultPassword = '';
730 $symbols = Zend_Locale::getTranslationList('symbols', $locale);
731 $secondFactorConfig = Tinebase_Config::getInstance()->get(Tinebase_Config::AUTHENTICATIONSECONDFACTOR);
733 $registryData = array(
734 'modSsl' => Tinebase_Auth::getConfiguredBackend() == Tinebase_Auth::MODSSL,
735 'secondFactor' => $secondFactorConfig && $secondFactorConfig->active,
736 'serviceMap' => $tbFrontendHttp->getServiceMap(),
738 'locale' => $locale->toString(),
739 'language' => Zend_Locale::getTranslation($locale->getLanguage(), 'language', $locale),
740 'region' => Zend_Locale::getTranslation($locale->getRegion(), 'country', $locale),
743 'buildType' => TINE20_BUILDTYPE,
744 'codeName' => TINE20_CODENAME,
745 'packageString' => TINE20_PACKAGESTRING,
746 'releaseTime' => TINE20_RELEASETIME,
747 'filesHash' => TINE20_BUILDTYPE != 'DEVELOPMENT' ? $tbFrontendHttp->getJsCssHash() : null
749 'defaultUsername' => $defaultUsername,
750 'defaultPassword' => $defaultPassword,
751 'denySurveys' => Tinebase_Core::getConfig()->denySurveys,
752 'titlePostfix' => Tinebase_Config::getInstance()->get(Tinebase_Config::PAGETITLEPOSTFIX),
753 'redirectUrl' => Tinebase_Config::getInstance()->get(Tinebase_Config::REDIRECTURL),
754 'helpUrl' => Tinebase_Core::getConfig()->helpUrl,
755 'maxFileUploadSize' => Tinebase_Helper::convertToBytes(ini_get('upload_max_filesize')),
756 'maxPostSize' => Tinebase_Helper::convertToBytes(ini_get('post_max_size')),
757 'thousandSeparator' => $symbols['group'],
758 'decimalSeparator' => $symbols['decimal'],
759 'filesystemAvailable' => Tinebase_Core::isFilesystemAvailable(),
760 'brandingWeburl' => Tinebase_Config::getInstance()->get(Tinebase_Config::BRANDING_WEBURL),
761 'brandingLogo' => Tinebase_Config::getInstance()->get(Tinebase_Config::BRANDING_LOGO),
762 'brandingFavicon' => Tinebase_Config::getInstance()->get(Tinebase_Config::BRANDING_FAVICON),
763 'brandingTitle' => Tinebase_Config::getInstance()->get(Tinebase_Config::BRANDING_TITLE),
766 if (Tinebase_Core::isLogLevel(Zend_Log::TRACE)) Tinebase_Core::getLogger()->trace(__METHOD__ . '::' . __LINE__
767 . ' Anonymous registry: ' . print_r($registryData, TRUE));
769 return $registryData;
777 protected function _getUserRegistryData()
779 $user = Tinebase_Core::getUser();
780 $userContactArray = array();
781 if (Tinebase_Application::getInstance()->isInstalled('Addressbook') === true) {
783 $userContactArray = Addressbook_Controller_Contact::getInstance()->getContactByUserId($user->getId(), TRUE)->toArray();
784 } catch (Addressbook_Exception_NotFound $aenf) {
785 if (Tinebase_Core::isLogLevel(Zend_Log::NOTICE)) /** @noinspection PhpUndefinedMethodInspection */
786 Tinebase_Core::getLogger()->notice(__METHOD__ . '::' . __LINE__
787 . ' User not found in Addressbook: ' . $user->accountDisplayName);
792 $persistentFilters = Tinebase_Frontend_Json_PersistentFilter::getAllPersistentFilters();
793 } catch (Tinebase_Exception_NotFound $tenf) {
794 if (Tinebase_Core::isLogLevel(Zend_Log::NOTICE)) Tinebase_Core::getLogger()->notice(__METHOD__ . '::' . __LINE__
795 . " Failed to fetch persistent filters. Exception: \n". $tenf);
796 $persistentFilters = array();
797 } catch (Exception $e) {
798 if (Tinebase_Core::isLogLevel(Zend_Log::NOTICE)) Tinebase_Core::getLogger()->notice(__METHOD__ . '::' . __LINE__
799 . " Failed to fetch persistent filters. Exception: \n". $e);
800 $persistentFilters = array();
804 $userRegistryData = array(
805 'timeZone' => Tinebase_Core::getUserTimezone(),
806 'currentAccount' => $user->toArray(),
807 'userContact' => $userContactArray,
808 'accountBackend' => Tinebase_User::getConfiguredBackend(),
809 'jsonKey' => Tinebase_Core::get('jsonKey'),
810 'userApplications' => $user->getApplications()->toArray(),
811 'NoteTypes' => $this->getNoteTypes(),
812 'stateInfo' => Tinebase_State::getInstance()->loadStateInfo(),
813 'mustchangepw' => $user->mustChangePassword(),
814 'confirmLogout' => Tinebase_Core::getPreference()->getValue(Tinebase_Preference::CONFIRM_LOGOUT, 1),
815 'advancedSearch' => Tinebase_Core::getPreference()->getValue(Tinebase_Preference::ADVANCED_SEARCH, 0),
816 'persistentFilters' => $persistentFilters,
817 'userAccountChanged' => Tinebase_Controller::getInstance()->userAccountChanged(),
820 if (Tinebase_Core::isLogLevel(Zend_Log::TRACE)) Tinebase_Core::getLogger()->trace(__METHOD__ . '::' . __LINE__
821 . ' User registry: ' . print_r($userRegistryData, TRUE));
823 return $userRegistryData;
827 * Returns registry data of all applications current user has access to
828 * @see Tinebase_Application_Json_Abstract
830 * @return mixed array 'variable name' => 'data'
832 public function getAllRegistryData()
834 $registryData = array();
836 if (Tinebase_Core::getUser()) {
837 $userApplications = Tinebase_Core::getUser()->getApplications(/* $_anyRight */ TRUE);
838 $clientConfig = Tinebase_Config::getInstance()->getClientRegistryConfig();
840 if (Tinebase_Core::isLogLevel(Zend_Log::TRACE))
841 /** @noinspection PhpUndefinedFieldInspection */
842 Tinebase_Core::getLogger()->trace(__METHOD__ . '::' . __LINE__
843 . ' User applications to fetch registry for: ' . print_r($userApplications->name, TRUE));
845 /** @noinspection PhpUndefinedFieldInspection */
846 if (! in_array('Tinebase', $userApplications->name)) {
847 Tinebase_Core::getLogger()->err(__METHOD__ . '::' . __LINE__ . ' User has no permissions to run Tinebase.');
849 throw new Tinebase_Exception_AccessDenied('User has no permissions to run Tinebase');
852 foreach ($userApplications as $application) {
853 $appRegistry = array();
854 $appRegistry['rights'] = Tinebase_Core::getUser()->getRights($application->name);
855 $appRegistry['allrights'] = Tinebase_Application::getInstance()->getAllRights($application->getId());
856 $appRegistry['config'] = isset($clientConfig[$application->name])
857 ? $clientConfig[$application->name]->toArray()
860 // @todo do we need this for all apps?
861 $exportDefinitions = Tinebase_ImportExportDefinition::getInstance()->getExportDefinitionsForApplication($application);
862 $appRegistry['exportDefinitions'] = array(
863 'results' => $exportDefinitions->toArray(),
864 'totalcount' => count($exportDefinitions),
867 $customfields = Tinebase_CustomField::getInstance()->getCustomFieldsForApplication($application);
868 Tinebase_CustomField::getInstance()->resolveConfigGrants($customfields);
869 $appRegistry['customfields'] = $customfields->toArray();
871 // add preferences for app
873 $prefRegistry = $this->_getAppPreferencesForRegistry($application);
874 $appRegistry = array_merge_recursive($appRegistry, $prefRegistry);
875 } catch (Tinebase_Exception_AccessDenied $tead) {
876 // do not add prefs if user has no run right
879 $customAppRegistry = $this->_getCustomAppRegistry($application);
880 if (empty($customAppRegistry)) {
881 // TODO always get this from app controller (and remove from _getCustomAppRegistry)
882 $appController = Tinebase_Core::getApplicationInstance($application->name);
883 $models = $appController->getModels();
884 $appRegistry['models'] = Tinebase_ModelConfiguration::getFrontendConfigForModels($models);
885 $appRegistry['defaultModel'] = $appController->getDefaultModel();
888 $appRegistry = array_merge_recursive($appRegistry, $customAppRegistry);
891 $registryData[$application->name] = $appRegistry;
894 $registryData['Tinebase'] = $this->getRegistryData();
897 return $registryData;
901 * get app preferences for registry
903 * @param Tinebase_Model_Application $application
905 * @throws Tinebase_Exception_NotFound
907 protected function _getAppPreferencesForRegistry(Tinebase_Model_Application $application)
909 $registryData = array();
910 $appPrefs = Tinebase_Core::getPreference($application->name);
911 if ($appPrefs !== NULL) {
912 $allPrefs = $appPrefs->getAllApplicationPreferences();
913 if (Tinebase_Core::isLogLevel(Zend_Log::TRACE)) Tinebase_Core::getLogger()->trace(__METHOD__ . '::' . __LINE__
914 . ' ' . print_r($allPrefs, TRUE));
916 foreach ($allPrefs as $pref) {
918 $registryData['preferences'][$pref] = $appPrefs->{$pref};
919 } catch (Exception $e) {
920 Tinebase_Core::getLogger()->warn(__METHOD__ . '::' . __LINE__ . ' Could not get ' . $pref . ' preference: ' . $e);
925 return $registryData;
929 * get registry data from application frontend json class
931 * @param Tinebase_Model_Application $application
933 * @throws Tinebase_Exception_InvalidArgument
935 protected function _getCustomAppRegistry(Tinebase_Model_Application $application)
937 $jsonAppName = $application->name . '_Frontend_Json';
938 if (! class_exists($jsonAppName)) {
942 if (Tinebase_Core::isLogLevel(Zend_Log::DEBUG)) {
943 Tinebase_Core::getLogger()->debug(__METHOD__ . '::' . __LINE__
944 . ' Getting registry data for app ' . $application->name);
948 $applicationJson = new $jsonAppName();
949 $registryData = $applicationJson->getRegistryData();
951 } catch (Exception $e) {
952 Tinebase_Exception::log($e);
953 if (! $e instanceof Tinebase_Exception_AccessDenied && ! in_array($application->name, array('Tinebase', 'Addressbook', 'Admin'))) {
954 Tinebase_Core::getLogger()->warn(__METHOD__ . '::' . __LINE__ . ' Disabling ' . $application->name . ': ' . $e);
955 Tinebase_Application::getInstance()->setApplicationState(array($application->getId()), Tinebase_Application::DISABLED);
960 // TODO get this from app controller / modelconfig
961 foreach ($applicationJson->getRelatableModels() as $relModel) {
962 $registryData['relatableModels'][] = $relModel;
964 $registryData['models'] = $applicationJson->getModelsConfiguration();
965 $registryData['defaultModel'] = $applicationJson->getDefaultModel();
967 return $registryData;
971 * search / get custom field values
973 * @param array $filter filter array
974 * @param array $paging pagination info
977 public function searchCustomFieldValues($filter, $paging)
979 $result = $this->_search($filter, $paging, Tinebase_CustomField::getInstance(), 'Tinebase_Model_CustomField_ValueFilter');
983 /************************ preferences functions ***************************/
988 * @param string $applicationName
989 * @param array $filter json encoded
992 public function searchPreferencesForApplication($applicationName, $filter)
994 $decodedFilter = $this->_prepareParameter($filter);
996 $filter = new Tinebase_Model_PreferenceFilter();
997 if (! empty($decodedFilter)) {
998 $filter->setFromArrayInUsersTimezone($decodedFilter);
1000 $appId = Tinebase_Application::getInstance()->getApplicationByName($applicationName)->getId();
1001 $filter->addFilter($filter->createFilter(array('field' => 'application_id', 'operator' => 'equals', 'value' => $appId)));
1003 $backend = Tinebase_Core::getPreference($applicationName);
1005 $records = $backend->search($filter);
1007 if (Tinebase_Core::isLogLevel(Zend_Log::DEBUG)) Tinebase_Core::getLogger()->debug(__METHOD__ . '::' . __LINE__
1008 . ' Got ' . count($records) . ' preferences for app ' . $applicationName);
1009 if (Tinebase_Core::isLogLevel(Zend_Log::TRACE)) Tinebase_Core::getLogger()->trace(__METHOD__ . '::' . __LINE__
1010 . ' ' . print_r($records->toArray(), TRUE));
1012 $result = $this->_multipleRecordsToJson($records, $filter);
1014 // add translated labels and descriptions
1015 $translations = $backend->getTranslatedPreferences();
1016 foreach ($result as $key => $prefArray) {
1017 if (isset($translations[$prefArray['name']])) {
1018 $result[$key] = array_merge($prefArray, $translations[$prefArray['name']]);
1020 $result[$key] = array_merge($prefArray, array('label' => $prefArray['name']));
1024 // sort prefs by definition
1025 $allPrefs = (array) $backend->getAllApplicationPreferences();
1026 usort($result, function($a, $b) use ($allPrefs) {
1027 $a = (int) array_search($a['name'], $allPrefs);
1028 $b = (int) array_search($b['name'], $allPrefs);
1033 return ($a < $b) ? -1 : 1;
1041 'results' => $result,
1042 'totalcount' => count($result)
1047 * save preferences for application
1049 * @param string $data json encoded preferences data
1050 * @param bool $adminMode submit in admin mode?
1051 * @return array with the changed prefs
1053 * @todo move saving of user values to preferences controller
1055 public function savePreferences($data, $adminMode)
1057 $decodedData = $this->_prepareParameter($data);
1060 foreach ($decodedData as $applicationName => $data) {
1062 if ($applicationName == 'Tinebase.UserProfile') {
1063 $userProfileData = array();
1064 foreach($data as $fieldName => $valueArray) {
1065 $userProfileData[$fieldName] = $valueArray['value'];
1067 $this->updateUserProfile($userProfileData);
1070 $backend = Tinebase_Core::getPreference($applicationName);
1071 if ($backend !== NULL) {
1073 $backend->saveAdminPreferences($data);
1074 // TODO return preference values?
1078 foreach ($data as $name => $value) {
1080 $backend->doSpecialJsonFrontendActions($this, $name, $value['value'], $applicationName);
1081 $backend->$name = $value['value'];
1082 $result[$applicationName][] = array('name' => $name, 'value' => $backend->$name);
1083 } catch (Exception $e) {
1084 if (Tinebase_Core::isLogLevel(Zend_Log::NOTICE))
1085 Tinebase_Core::getLogger()->notice(__METHOD__ . '::' . __LINE__ . ' '
1086 . 'Could not save preference '. $name . ' -> ' . $e->getMessage());
1095 'status' => 'success',
1096 'results' => $result
1101 * get profile of current user
1103 * @param string $userId
1106 public function getUserProfile($userId)
1108 // NOTE: $userProfile is a contact where non readable fields are clearad out!
1109 $userProfile = Tinebase_UserProfile::getInstance()->get($userId);
1111 // NOTE: This hurts! We don't have methods to call in our frontends yet which convert
1112 // a record to the json representaion :( Thus image link will be broken!
1113 $userProfile->setTimezone(Tinebase_Core::getUserTimezone());
1116 'userProfile' => $userProfile->toArray(),
1117 'readableFields' => Tinebase_UserProfile::getInstance()->getReadableFields(),
1118 'updateableFields' => Tinebase_UserProfile::getInstance()->getUpdateableFields(),
1123 * update user profile
1125 * @param array $profileData
1128 public function updateUserProfile($profileData)
1130 $contact = new Addressbook_Model_Contact(array(), TRUE);
1131 $contact->setFromJsonInUsersTimezone($profileData);
1133 // NOTE: $userProfile is a contact where non readable fields are clearad out!
1134 $userProfile = Tinebase_UserProfile::getInstance()->update($contact);
1136 // NOTE: This hurts! We don't have methods to call in our frontends yet which convert
1137 // a record to the json representaion :( Thus image link will be broken!
1138 $userProfile->setTimezone(Tinebase_Core::getUserTimezone());
1139 return $userProfile->toArray();
1143 * dummy function to measure speed of framework initialization
1145 public function void()
1151 * gets the userProfile config
1155 public function getUserProfileConfig()
1158 'possibleFields' => array_values(Tinebase_UserProfile::getInstance()->getPossibleFields()),
1159 'readableFields' => array_values(Tinebase_UserProfile::getInstance()->getReadableFields()),
1160 'updateableFields' => array_values(Tinebase_UserProfile::getInstance()->getUpdateableFields()),
1165 * saves userProfile config
1167 * @param array $configData
1169 public function setUserProfileConfig($configData)
1171 Tinebase_UserProfile::getInstance()->setReadableFields($configData['readableFields']);
1172 Tinebase_UserProfile::getInstance()->setUpdateableFields($configData['updateableFields']);
1176 * switch to another user's account
1178 * @param string $loginName
1181 public function changeUserAccount($loginName)
1183 $result = Tinebase_Controller::getInstance()->changeUserAccount($loginName);
1185 'success' => $result
1189 /************************ department functions **************************/
1192 * search / get departments
1194 * @param array $filter filter array
1195 * @param array $paging pagination info
1198 public function searchDepartments($filter, $paging)
1200 $result = $this->_search($filter, $paging, Tinebase_Department::getInstance(), 'Tinebase_Model_DepartmentFilter');
1204 /************************* relation functions ***************************/
1207 * get all relations of a given record
1209 * @param string $model own model to get relations for
1210 * @param string $id own id to get relations for
1211 * @param string $degree only return relations of given degree
1212 * @param array $type only return relations of given type
1213 * @param string $relatedModel only return relations having this related model
1216 public function getRelations($model, $id, $degree = NULL, $type = array(), $relatedModel = NULL)
1218 if (! is_array($type)) {
1221 $relations = Tinebase_Relations::getInstance()->getRelations($model, 'Sql', $id, $degree, $type, false, $relatedModel);
1223 // @TODO we still have no converter for relations :-(
1224 // -> related records returned here are different to the records returned by the apps itself!
1225 // -> this problem also applies to to generic json converter!
1226 if (count($relations) > 0) {
1227 $relations->setTimezone(Tinebase_Core::getUserTimezone());
1228 $relations->bypassFilters = true;
1229 $result = $relations->toArray();
1234 'results' => array_values($result),
1235 'totalcount' => count($result),
1239 /************************ config functions ******************************/
1242 * get config settings for application
1244 * @param string $id application name
1247 public function getConfig($id)
1249 $controllerName = $id . '_Controller';
1250 $appController = Tinebase_Controller_Abstract::getController($controllerName);
1254 'settings' => $appController->getConfigSettings(TRUE),
1259 * save application config
1261 * @param array $recordData
1264 public function saveConfig($recordData)
1266 //if (Tinebase_Core::isLogLevel(Zend_Log::DEBUG)) Tinebase_Core::getLogger()->debug(__METHOD__ . '::' . __LINE__ . ' ' . print_r($recordData, TRUE));
1268 $controllerName = $recordData['id'] . '_Controller';
1269 $appController = Tinebase_Controller_Abstract::getController($controllerName);
1270 $appController->saveConfigSettings($recordData['settings']);
1272 return $this->getConfig($recordData['id']);
1275 /************************ tempFile functions ******************************/
1278 * joins all given tempfiles in given order to a single new tempFile
1280 * @param array $tempFilesData of tempfiles arrays $tempFiles
1281 * @return array new tempFile
1283 public function joinTempFiles($tempFilesData)
1285 $tempFileRecords = new Tinebase_Record_RecordSet('Tinebase_Model_TempFile');
1286 foreach($tempFilesData as $tempFileData) {
1287 $record = new Tinebase_Model_TempFile(array(), TRUE);
1288 $record->setFromJsonInUsersTimezone($tempFileData);
1289 $tempFileRecords->addRecord($record);
1292 $joinedTempFile = Tinebase_TempFile::getInstance()->joinTempFiles($tempFileRecords);
1294 return $joinedTempFile->toArray();
1297 /************************ protected functions ***************************/
1300 * returns multiple records prepared for json transport
1302 * @param Tinebase_Record_RecordSet $_records Tinebase_Record_Abstract
1303 * @param Tinebase_Model_Filter_FilterGroup $_filter
1304 * @param Tinebase_Model_Pagination $_pagination
1305 * @return array data
1307 protected function _multipleRecordsToJson(Tinebase_Record_RecordSet $_records, $_filter = NULL, $_pagination = NULL)
1309 if (count($_records) == 0) {
1313 switch ($_records->getRecordClassName()) {
1314 case 'Tinebase_Model_Preference':
1315 $accountFilterArray = $_filter->getFilter('account')->toArray();
1316 $adminMode = ($accountFilterArray['value']['accountId'] == 0 && $accountFilterArray['value']['accountType'] == Tinebase_Acl_Rights::ACCOUNT_TYPE_ANYONE);
1317 foreach ($_records as $record) {
1318 if (! isset($app) || $record->application_id != $app->getId()) {
1319 $app = Tinebase_Application::getInstance()->getApplicationById($record->application_id);
1321 $preference = Tinebase_Core::getPreference($app->name, TRUE);
1322 $preference->resolveOptions($record);
1323 if ($record->type == Tinebase_Model_Preference::TYPE_DEFAULT || ! $adminMode && $record->type == Tinebase_Model_Preference::TYPE_ADMIN) {
1324 $record->value = Tinebase_Model_Preference::DEFAULT_VALUE;
1330 $result = parent::_multipleRecordsToJson($_records, $_filter, $_pagination);
1335 * return autocomplete suggestions for a given recordclass, the property and value
1337 * @param string $appName
1338 * @param string $modelName
1339 * @param string $property
1340 * @param string $startswith
1344 public function autoComplete($appName, $modelName, $property, $startswith)
1346 $recordClassName = $appName . '_Model_' . $modelName;
1347 $controller = Tinebase_Core::getApplicationInstance($appName, $modelName);
1348 $filterClassName = $recordClassName . 'Filter';
1350 if (! class_exists($recordClassName)) {
1351 throw new Tinebase_Exception_InvalidArgument('A record class for the given appName and modelName does not exist!');
1354 if (! $controller) {
1355 throw new Tinebase_Exception_InvalidArgument('A controller for the given appName and modelName does not exist!');
1358 if (! class_exists($filterClassName)) {
1359 throw new Tinebase_Exception_InvalidArgument('A filter for the given appName and modelName does not exist!');
1362 if (! in_array($property, $recordClassName::getAutocompleteFields())) {
1363 throw new Tinebase_Exception_UnexpectedValue('bad property name');
1366 $filter = new $filterClassName(array(
1367 array('field' => $property, 'operator' => 'startswith', 'value' => $startswith),
1370 $paging = new Tinebase_Model_Pagination(array('sort' => $property));
1372 $values = array_unique($controller->search($filter, $paging)->{$property});
1375 'results' => array(),
1376 'totalcount' => count($values)
1379 foreach($values as $value) {
1380 $result['results'][] = array($property => $value);
1387 * Toogles advanced search preference
1392 public function toogleAdvancedSearch($state)
1394 Tinebase_Core::getPreference()->setValue(Tinebase_Preference::ADVANCED_SEARCH, (int)$state);
1395 return $state == Tinebase_Core::getPreference()->getValue(Tinebase_Preference::ADVANCED_SEARCH, 0);