2 /*********************************************************************************
3 * SugarCRM Community Edition is a customer relationship management program developed by
4 * SugarCRM, Inc. Copyright (C) 2004-2012 SugarCRM Inc.
6 * This program is free software; you can redistribute it and/or modify it under
7 * the terms of the GNU Affero General Public License version 3 as published by the
8 * Free Software Foundation with the addition of the following permission added
9 * to Section 15 as permitted in Section 7(a): FOR ANY PART OF THE COVERED WORK
10 * IN WHICH THE COPYRIGHT IS OWNED BY SUGARCRM, SUGARCRM DISCLAIMS THE WARRANTY
11 * OF NON INFRINGEMENT OF THIRD PARTY RIGHTS.
13 * This program is distributed in the hope that it will be useful, but WITHOUT
14 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
15 * FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
18 * You should have received a copy of the GNU Affero General Public License along with
19 * this program; if not, see http://www.gnu.org/licenses or write to the Free
20 * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
23 * You can contact SugarCRM, Inc. headquarters at 10050 North Wolfe Road,
24 * SW2-130, Cupertino, CA 95014, USA. or at email address contact@sugarcrm.com.
26 * The interactive user interfaces in modified source and object code versions
27 * of this program must display Appropriate Legal Notices, as required under
28 * Section 5 of the GNU Affero General Public License version 3.
30 * In accordance with Section 7(b) of the GNU Affero General Public License version 3,
31 * these Appropriate Legal Notices must retain the display of the "Powered by
32 * SugarCRM" logo. If the display of the logo is not reasonably feasible for
33 * technical reasons, the Appropriate Legal Notices must display the words
34 * "Powered by SugarCRM".
35 ********************************************************************************/
37 require_once('service/v3_1/SugarWebServiceUtilv3_1.php');
39 class SugarWebServiceUtilv4 extends SugarWebServiceUtilv3_1
41 function get_module_view_defs($moduleName, $type, $view)
43 require_once('include/MVC/View/SugarView.php');
46 if( empty($moduleName) )
49 $view = strtolower($view);
50 switch (strtolower($type)){
53 require_once('include/SugarWireless/SugarWirelessListView.php');
54 $GLOBALS['module'] = $moduleName; //WirelessView keys off global variable not instance variable...
55 $v = new SugarWirelessListView();
56 $results = $v->getMetaDataFile();
57 $results = self::formatWirelessListViewResultsToArray($results);
60 elseif ($view == 'subpanel')
61 $results = $this->get_subpanel_defs($moduleName, $type);
63 require_once('include/SugarWireless/SugarWirelessView.php');
64 $v = new SugarWirelessView();
65 $v->module = $moduleName;
66 $fullView = ucfirst($view) . 'View';
67 $meta = $v->getMetaDataFile('Wireless' . $fullView);
68 $metadataFile = $meta['filename'];
69 require($metadataFile);
70 //Wireless detail metadata may actually be just edit metadata.
71 $results = isset($viewdefs[$meta['module_name']][$fullView] ) ? $viewdefs[$meta['module_name']][$fullView] : $viewdefs[$meta['module_name']]['EditView'];
77 if ($view == 'subpanel')
78 $results = $this->get_subpanel_defs($moduleName, $type);
81 $v = new SugarView(null,array());
82 $v->module = $moduleName;
84 $fullView = ucfirst($view) . 'View';
85 $metadataFile = $v->getMetaDataFile();
86 require_once($metadataFile);
88 $results = $listViewDefs[$moduleName];
90 $results = $viewdefs[$moduleName][$fullView];
94 //Add field level acls.
95 $results = $this->addFieldLevelACLs($moduleName,$type, $view, $results);
101 * Format the results for wirless list view metadata from an associative array to a
102 * numerically indexed array. This conversion will ensure that consumers of the metadata
103 * can eval the json response and iterative over the results with the order of the fields
106 * @param array $fields
109 function formatWirelessListViewResultsToArray($fields)
112 foreach($fields as $key => $defs)
114 $defs['name'] = $key;
122 * Equivalent of get_list function within SugarBean but allows the possibility to pass in an indicator
123 * if the list should filter for favorites. Should eventually update the SugarBean function as well.
126 function get_data_list($seed, $order_by = "", $where = "", $row_offset = 0, $limit=-1, $max=-1, $show_deleted = 0, $favorites = false)
128 $GLOBALS['log']->debug("get_list: order_by = '$order_by' and where = '$where' and limit = '$limit'");
129 if(isset($_SESSION['show_deleted']))
133 $order_by=$seed->process_order_by($order_by, null);
136 if(!empty($favorites)) {
137 $params['favorites'] = true;
140 $query = $seed->create_new_list_query($order_by, $where,array(),$params, $show_deleted);
141 return $seed->process_list_query($query, $row_offset, $limit, $max, $where);
145 * Convert modules list to Web services result
147 * @param array $list List of module candidates (only keys are used)
148 * @param array $availModules List of module availability from Session
150 public function getModulesFromList($list, $availModules)
152 global $app_list_strings;
153 $enabled_modules = array();
154 $availModulesKey = array_flip($availModules);
155 foreach ($list as $key=>$value)
157 if( isset($availModulesKey[$key]) )
159 $label = !empty( $app_list_strings['moduleList'][$key] ) ? $app_list_strings['moduleList'][$key] : '';
160 $acl = $this->checkModuleRoleAccess($key);
161 $fav = $this->is_favorites_enabled($key);
162 $enabled_modules[] = array('module_key' => $key,'module_label' => $label, 'favorite_enabled' => $fav, 'acls' => $acl);
165 return $enabled_modules;
169 * Return a boolean indicating if the bean name is favorites enabled.
171 * @param string The module name
172 * @return bool true indicating bean is favorites enabled
174 function is_favorites_enabled($module_name)
176 global $beanList, $beanFiles;
183 * Parse wireless editview metadata and add ACL values.
185 * @param String $module_name
186 * @param array $metadata
187 * @return array Metadata with acls added
189 function metdataAclParserWirelessEdit($module_name, $metadata)
191 global $beanList, $beanFiles;
192 $class_name = $beanList[$module_name];
193 require_once($beanFiles[$class_name]);
194 $seed = new $class_name();
197 $results['templateMeta'] = $metadata['templateMeta'];
199 //Wireless metadata only has a single panel definition.
200 foreach ($metadata['panels'] as $row)
203 foreach ($row as $field)
206 if( is_string($field) )
207 $aclField['name'] = $field;
211 if($seed->bean_implements('ACL'))
212 $aclField['acl'] = $this->getFieldLevelACLValue($seed->module_dir, $aclField['name']);
214 $aclField['acl'] = ACL_FIELD_DEFAULT;
216 $aclRow[] = $aclField;
218 $aclRows[] = $aclRow;
221 $results['panels'] = $aclRows;
226 * Parse wireless detailview metadata and add ACL values.
228 * @param String $module_name
229 * @param array $metadata
230 * @return array Metadata with acls added
232 function metdataAclParserWirelessDetail($module_name, $metadata)
234 return self::metdataAclParserWirelessEdit($module_name, $metadata);
238 * Parse wireless listview metadata and add ACL values.
240 * @param String $module_name
241 * @param array $metadata
242 * @return array Metadata with acls added
244 function metdataAclParserWirelessList($module_name, $metadata)
246 global $beanList, $beanFiles;
247 $class_name = $beanList[$module_name];
248 require_once($beanFiles[$class_name]);
249 $seed = new $class_name();
252 foreach ($metadata as $entry)
254 $field_name = $entry['name'];
255 if($seed->bean_implements('ACL'))
256 $entry['acl'] = $this->getFieldLevelACLValue($seed->module_dir, strtolower($field_name));
267 * Processes the filter_fields attribute to use with SugarBean::create_new_list_query()
269 * @param object $value SugarBean
270 * @param array $fields
273 protected function filter_fields_for_query(SugarBean $value, array $fields)
275 $GLOBALS['log']->info('Begin: SoapHelperWebServices->filter_fields_for_query');
276 $filterFields = array();
277 foreach($fields as $field)
279 if (isset($value->field_defs[$field]))
281 $filterFields[$field] = $value->field_defs[$field];
284 $GLOBALS['log']->info('End: SoapHelperWebServices->filter_fields_for_query');
285 return $filterFields;
288 function get_field_list($value,$fields, $translate=true) {
290 $GLOBALS['log']->info('Begin: SoapHelperWebServices->get_field_list(too large a struct, '.print_r($fields, true).", $translate");
291 $module_fields = array();
292 $link_fields = array();
293 if(!empty($value->field_defs)){
295 foreach($value->field_defs as $var){
296 if(!empty($fields) && !in_array( $var['name'], $fields))continue;
297 if(isset($var['source']) && ($var['source'] != 'db' && $var['source'] != 'non-db' &&$var['source'] != 'custom_fields') && $var['name'] != 'email1' && $var['name'] != 'email2' && (!isset($var['type'])|| $var['type'] != 'relate'))continue;
298 if ((isset($var['source']) && $var['source'] == 'non_db') && (isset($var['type']) && $var['type'] != 'link')) {
302 $options_dom = array();
303 $options_ret = array();
304 // Apparently the only purpose of this check is to make sure we only return fields
305 // when we've read a record. Otherwise this function is identical to get_module_field_list
306 if( isset($var['required']) && ($var['required'] || $var['required'] == 'true' ) ){
310 if($var['type'] == 'bool')
311 $var['options'] = 'checkbox_dom';
313 if(isset($var['options'])){
314 $options_dom = translate($var['options'], $value->module_dir);
315 if(!is_array($options_dom)) $options_dom = array();
316 foreach($options_dom as $key=>$oneOption)
317 $options_ret[$key] = $this->get_name_value($key,$oneOption);
320 if(!empty($var['dbType']) && $var['type'] == 'bool') {
321 $options_ret['type'] = $this->get_name_value('type', $var['dbType']);
325 $entry['name'] = $var['name'];
326 $entry['type'] = $var['type'];
327 $entry['group'] = isset($var['group']) ? $var['group'] : '';
328 $entry['id_name'] = isset($var['id_name']) ? $var['id_name'] : '';
330 if ($var['type'] == 'link') {
331 $entry['relationship'] = (isset($var['relationship']) ? $var['relationship'] : '');
332 $entry['module'] = (isset($var['module']) ? $var['module'] : '');
333 $entry['bean_name'] = (isset($var['bean_name']) ? $var['bean_name'] : '');
334 $link_fields[$var['name']] = $entry;
337 $entry['label'] = isset($var['vname']) ? translate($var['vname'], $value->module_dir) : $var['name'];
339 $entry['label'] = isset($var['vname']) ? $var['vname'] : $var['name'];
341 $entry['required'] = $required;
342 $entry['options'] = $options_ret;
343 $entry['related_module'] = (isset($var['id_name']) && isset($var['module'])) ? $var['module'] : '';
344 $entry['calculated'] = (isset($var['calculated']) && $var['calculated']) ? true : false;
345 $entry['len'] = isset($var['len']) ? $var['len'] : '';
347 if(isset($var['default'])) {
348 $entry['default_value'] = $var['default'];
350 if( $var['type'] == 'parent' && isset($var['type_name']) )
351 $entry['type_name'] = $var['type_name'];
353 $module_fields[$var['name']] = $entry;
358 if($value->module_dir == 'Meetings' || $value->module_dir == 'Calls')
360 if( isset($module_fields['duration_minutes']) && isset($GLOBALS['app_list_strings']['duration_intervals']))
362 $options_dom = $GLOBALS['app_list_strings']['duration_intervals'];
363 $options_ret = array();
364 foreach($options_dom as $key=>$oneOption)
365 $options_ret[$key] = $this->get_name_value($key,$oneOption);
367 $module_fields['duration_minutes']['options'] = $options_ret;
371 if($value->module_dir == 'Bugs'){
372 require_once('modules/Releases/Release.php');
373 $seedRelease = new Release();
374 $options = $seedRelease->get_releases(TRUE, "Active");
375 $options_ret = array();
376 foreach($options as $name=>$value){
377 $options_ret[] = array('name'=> $name , 'value'=>$value);
379 if(isset($module_fields['fixed_in_release'])){
380 $module_fields['fixed_in_release']['type'] = 'enum';
381 $module_fields['fixed_in_release']['options'] = $options_ret;
383 if(isset($module_fields['found_in_release'])){
384 $module_fields['found_in_release']['type'] = 'enum';
385 $module_fields['found_in_release']['options'] = $options_ret;
387 if(isset($module_fields['release'])){
388 $module_fields['release']['type'] = 'enum';
389 $module_fields['release']['options'] = $options_ret;
391 if(isset($module_fields['release_name'])){
392 $module_fields['release_name']['type'] = 'enum';
393 $module_fields['release_name']['options'] = $options_ret;
397 if(isset($value->assigned_user_name) && isset($module_fields['assigned_user_id'])) {
398 $module_fields['assigned_user_name'] = $module_fields['assigned_user_id'];
399 $module_fields['assigned_user_name']['name'] = 'assigned_user_name';
401 if(isset($value->assigned_name) && isset($module_fields['team_id'])) {
402 $module_fields['team_name'] = $module_fields['team_id'];
403 $module_fields['team_name']['name'] = 'team_name';
405 if(isset($module_fields['modified_user_id'])) {
406 $module_fields['modified_by_name'] = $module_fields['modified_user_id'];
407 $module_fields['modified_by_name']['name'] = 'modified_by_name';
409 if(isset($module_fields['created_by'])) {
410 $module_fields['created_by_name'] = $module_fields['created_by'];
411 $module_fields['created_by_name']['name'] = 'created_by_name';
414 $GLOBALS['log']->info('End: SoapHelperWebServices->get_field_list');
415 return array('module_fields' => $module_fields, 'link_fields' => $link_fields);
419 function new_handle_set_entries($module_name, $name_value_lists, $select_fields = FALSE) {
420 $GLOBALS['log']->info('Begin: SoapHelperWebServices->new_handle_set_entries');
421 global $beanList, $beanFiles, $current_user, $app_list_strings;
423 $ret_values = array();
425 $class_name = $beanList[$module_name];
426 require_once($beanFiles[$class_name]);
429 $total = sizeof($name_value_lists);
430 foreach($name_value_lists as $name_value_list){
431 $seed = new $class_name();
433 $seed->update_vcal = false;
434 foreach($name_value_list as $name => $value){
435 if(is_array($value) && $value['name'] == 'id'){
436 $seed->retrieve($value['value']);
439 else if($name === 'id' ){
440 $seed->retrieve($value);
444 foreach($name_value_list as $name => $value) {
445 //Normalize the input
446 if(!is_array($value)){
451 $field_name = $value['name'];
452 $val = $value['value'];
455 if($seed->field_name_map[$field_name]['type'] == 'enum'){
456 $vardef = $seed->field_name_map[$field_name];
457 if(isset($app_list_strings[$vardef['options']]) && !isset($app_list_strings[$vardef['options']][$val]) ) {
458 if ( in_array($val,$app_list_strings[$vardef['options']]) ){
459 $val = array_search($val,$app_list_strings[$vardef['options']]);
463 if($module_name == 'Users' && !empty($seed->id) && ($seed->id != $current_user->id) && $field_name == 'user_hash'){
467 $seed->$field_name = $val;
470 if($count == $total){
471 $seed->update_vcal = false;
475 //Add the account to a contact
476 if($module_name == 'Contacts'){
477 $GLOBALS['log']->debug('Creating Contact Account');
478 $this->add_create_account($seed);
479 $duplicate_id = $this->check_for_duplicate_contacts($seed);
480 if($duplicate_id == null){
481 if($seed->ACLAccess('Save') && ($seed->deleted != 1 || $seed->ACLAccess('Delete'))){
483 if($seed->deleted == 1){
484 $seed->mark_deleted($seed->id);
490 //since we found a duplicate we should set the sync flag
491 if( $seed->ACLAccess('Save')){
492 $seed = new $class_name();
493 $seed->id = $duplicate_id;
494 $seed->contacts_users_id = $current_user->id;
496 $ids[] = $duplicate_id;//we have a conflict
500 else if($module_name == 'Meetings' || $module_name == 'Calls'){
501 //we are going to check if we have a meeting in the system
502 //with the same outlook_id. If we do find one then we will grab that
504 if( $seed->ACLAccess('Save') && ($seed->deleted != 1 || $seed->ACLAccess('Delete'))){
505 if(empty($seed->id) && !isset($seed->id)){
506 if(!empty($seed->outlook_id) && isset($seed->outlook_id)){
507 //at this point we have an object that does not have
508 //the id set, but does have the outlook_id set
509 //so we need to query the db to find if we already
510 //have an object with this outlook_id, if we do
511 //then we can set the id, otherwise this is a new object
513 $query = $seed->table_name.".outlook_id = '".$seed->outlook_id."'";
514 $response = $seed->get_list($order_by, $query, 0,-1,-1,0);
515 $list = $response['list'];
516 if(count($list) > 0){
517 foreach($list as $value)
519 $seed->id = $value->id;
525 if (empty($seed->reminder_time)) {
526 $seed->reminder_time = -1;
528 if($seed->reminder_time == -1){
529 $defaultRemindrTime = $current_user->getPreference('reminder_time');
530 if ($defaultRemindrTime != -1){
531 $seed->reminder_checked = '1';
532 $seed->reminder_time = $defaultRemindrTime;
536 if($seed->deleted == 1){
537 $seed->mark_deleted($seed->id);
544 if( $seed->ACLAccess('Save') && ($seed->deleted != 1 || $seed->ACLAccess('Delete'))){
550 // if somebody is calling set_entries_detail() and wants fields returned...
551 if ($select_fields !== FALSE) {
552 $ret_values[$count] = array();
554 foreach ($select_fields as $select_field) {
555 if (isset($seed->$select_field)) {
556 $ret_values[$count][$select_field] = $this->get_name_value($select_field, $seed->$select_field);
562 // handle returns for set_entries_detail() and set_entries()
563 if ($select_fields !== FALSE) {
564 $GLOBALS['log']->info('End: SoapHelperWebServices->new_handle_set_entries');
566 'name_value_lists' => $ret_values,
570 $GLOBALS['log']->info('End: SoapHelperWebServices->new_handle_set_entries');
578 function checkSessionAndModuleAccess($session, $login_error_key, $module_name, $access_level, $module_access_level_error_key, $errorObject)
580 if(isset($_REQUEST['oauth_token'])) {
581 $session = $this->checkOAuthAccess($errorObject);
583 if(!$session) return false;
584 return parent::checkSessionAndModuleAccess($session, $login_error_key, $module_name, $access_level, $module_access_level_error_key, $errorObject);
587 public function checkOAuthAccess($errorObject)
589 require_once "include/SugarOAuthServer.php";
591 $oauth = new SugarOAuthServer();
592 $token = $oauth->authorizedToken();
593 if(empty($token) || empty($token->assigned_user_id)) {
596 } catch(OAuthException $e) {
597 $GLOBALS['log']->debug("OAUTH Exception: $e");
598 $errorObject->set_error('invalid_login');
599 $this->setFaultObject($errorObject);
604 $user->retrieve($token->assigned_user_id);
605 if(empty($user->id)) {
608 global $current_user;
609 $current_user = $user;
610 ini_set("session.use_cookies", 0); // disable cookies to prevent session ID from going out
612 session_regenerate_id();
613 $_SESSION['oauth'] = $oauth->authorization();
614 $_SESSION['avail_modules'] = $this->get_user_module_list($user);
617 $_SESSION['is_valid_session']= true;
618 $_SESSION['ip_address'] = query_client_ip();
619 $_SESSION['user_id'] = $current_user->id;
620 $_SESSION['type'] = 'user';
621 $_SESSION['authenticated_user_id'] = $current_user->id;
629 * @param String $module The name of the module to get the subpanel definition for
630 * @param String $type The type of subpanel definition ('wireless' or 'default')
631 * @return array Array of the subpanel definition; empty array if no matching definition found
633 function get_subpanel_defs($module, $type)
635 global $beanList, $beanFiles;
641 if (file_exists('custom/modules/'.$module.'/metadata/wireless.subpaneldefs.php'))
642 require_once('custom/modules/'.$module.'/metadata/wireless.subpaneldefs.php');
643 else if (file_exists('modules/'.$module.'/metadata/wireless.subpaneldefs.php'))
644 require_once('modules/'.$module.'/metadata/wireless.subpaneldefs.php');
646 //If an Ext/WirelessLayoutdefs/wireless.subpaneldefs.ext.php file exists, then also load it as well
647 if(file_exists('custom/modules/'.$module.'/Ext/WirelessLayoutdefs/wireless.subpaneldefs.ext.php'))
649 require_once('custom/modules/'.$module.'/Ext/WirelessLayoutdefs/wireless.subpaneldefs.ext.php');
655 if (file_exists ('modules/'.$module.'/metadata/subpaneldefs.php' ))
656 require ('modules/'.$module.'/metadata/subpaneldefs.php');
657 if ( file_exists('custom/modules/'.$module.'/Ext/Layoutdefs/layoutdefs.ext.php' ))
658 require ('custom/modules/'.$module.'/Ext/Layoutdefs/layoutdefs.ext.php');
661 //Filter results for permissions
662 foreach ($layout_defs[$module]['subpanel_setup'] as $subpanel => $subpaneldefs)
664 $moduleToCheck = $subpaneldefs['module'];
665 if(!isset($beanList[$moduleToCheck]))
667 $class_name = $beanList[$moduleToCheck];
668 $bean = new $class_name();
669 if($bean->ACLAccess('list'))
670 $results[$subpanel] = $subpaneldefs;