/** * Fetches data from the $args array and updates the bean with that data * @param $api ServiceBase The API class of the request, used in cases where the API changes how security is applied * @param $args array The arguments array passed in from the API * @param $primaryBean SugarBean The near side of the link * @param $securityTypeLocal string What ACL to check on the near side of the link * @param $securityTypeRemote string What ACL to check on the far side of the link * @return array Two elements: The link name, and the SugarBean of the far end * @throws SugarApiExceptionNotAuthorized * @throws SugarApiExceptionNotFound */ protected function checkRelatedSecurity(ServiceBase $api, $args, SugarBean $primaryBean, $securityTypeLocal = 'view', $securityTypeRemote = 'view') { $this->requireArgs($args, array('link_name')); if (!$primaryBean->ACLAccess($securityTypeLocal)) { throw new SugarApiExceptionNotAuthorized('No access to ' . $securityTypeLocal . ' records for module: ' . $args['module']); } // Load up the relationship $linkName = $args['link_name']; if (!$primaryBean->load_relationship($linkName)) { // The relationship did not load, I'm guessing it doesn't exist throw new SugarApiExceptionNotFound('Could not find a relationship named: ' . $args['link_name']); } // Figure out what is on the other side of this relationship, check permissions $linkModuleName = $primaryBean->{$linkName}->getRelatedModuleName(); $linkSeed = BeanFactory::getBean($linkModuleName); // FIXME: No create ACL yet if ($securityTypeRemote == 'create') { $securityTypeRemote = 'edit'; } // only check here for edit...view and list are checked on formatBean if ($securityTypeRemote == 'edit' && !$linkSeed->ACLAccess($securityTypeRemote)) { throw new SugarApiExceptionNotAuthorized('No access to ' . $securityTypeRemote . ' records for module: ' . $linkModuleName); } return array($linkName, $linkSeed); }
function additional_details($fields, SugarBean $bean, $params) { global $current_language, $timedate, $app_list_strings; $mod_strings = return_module_language($current_language, $bean->module_name); // Create DB Date versions of each date field foreach ($fields as $i => $f) { if (empty($f)) { continue; } if (!isset($bean->field_name_map[strtolower($i)])) { continue; } if ($bean->field_name_map[strtolower($i)]['type'] == 'datetime' or $bean->field_name_map[strtolower($i)]['type'] == 'datetimecombo') { $db_date = $timedate->fromUser($f); $db_date_format = $db_date->format('Y-m-d H:i:s'); $fields['DB_' . $i] = $db_date_format; } } // Load smarty templates $templateCaption = new Sugar_Smarty(); $templateCaption->assign('APP', $app_list_strings); $templateCaption->assign('MOD', $mod_strings); $templateCaption->assign('FIELD', $fields); $templateCaption->assign('ACL_EDIT_VIEW', $bean->ACLAccess('EditView')); $templateCaption->assign('ACL_DETAIL_VIEW', $bean->ACLAccess('DetailView')); $templateCaption->assign('PARAM', $params); $templateCaption->assign('MODULE_NAME', $bean->module_name); $templateCaption->assign('OBJECT_NAME', $bean->object_name); $caption = $templateCaption->fetch('modules/' . $bean->module_name . '/tpls/additionalDetails.caption.tpl'); $templateBody = new Sugar_Smarty(); $templateBody->assign('APP', $app_list_strings); $templateBody->assign('MOD', $mod_strings); $templateBody->assign('FIELD', $fields); $templateBody->assign('ACL_EDIT_VIEW', $bean->ACLAccess('EditView')); $templateBody->assign('ACL_DETAIL_VIEW', $bean->ACLAccess('DetailView')); $templateBody->assign('PARAM', $params); $templateBody->assign('MODULE_NAME', $bean->module_name); $templateBody->assign('OBJECT_NAME', $bean->object_name); $body = $templateBody->fetch('modules/' . $bean->module_name . '/tpls/additionalDetails.body.tpl'); $editLink = "index.php?action=EditView&module='. {$bean->module_name} .'&record={$fields['ID']}"; $viewLink = "index.php?action=DetailView&module='. {$bean->module_name} .'&record={$fields['ID']}"; return array('fieldToAddTo' => 'NAME', 'string' => $body, 'editLink' => $editLink, 'viewLink' => $viewLink, 'caption' => $caption, 'body' => $body, 'version' => '7.7.6'); }
/** * Check if we have access to upload this file * @param SugarBean $bean * @param string $field * @param array $args * @throws SugarApiExceptionNotAuthorized */ protected function checkFileAccess($bean, $field, $args) { if (!$bean->ACLAccess('view')) { throw new SugarApiExceptionNotAuthorized('No access to view records for module: ' . $args['module']); } // Handle ACL - if there is no current field data, it is a CREATE // This addresses an issue where the portal user has create but not edit // rights for particular modules. The perspective here is that even if // a record exists, if there is no attachment, you are CREATING the // attachment instead of EDITING the parent record. -rgonzalez $accessType = empty($bean->{$field}) ? 'create' : 'edit'; $this->verifyFieldAccess($bean, $field, $accessType); }
/** * Retrieves current activity bean and checks access to action * * @param string $actionToCheck * @return bool Result of check */ protected function retrieveCurrentBean($actionToCheck = false) { $module = $_REQUEST['current_module']; $record = null; if (!empty($_REQUEST['record'])) { $record = $_REQUEST['record']; } require_once "data/BeanFactory.php"; $this->currentBean = BeanFactory::getBean($module, $record); if (!empty($actionToCheck)) { if (!$this->currentBean->ACLAccess($actionToCheck)) { $this->view = 'json'; $jsonData = array('access' => 'no'); $this->view_object_map['jsonData'] = $jsonData; return false; } } return true; }
/** * Disable edit if call is recurring and source is not Sugar. It should be edited only from Outlook. * @param $view string * @param $is_owner bool */ function ACLAccess($view,$is_owner = 'not_set'){ // don't check if call is being synced from Outlook if($this->syncing == false){ $view = strtolower($view); switch($view){ case 'edit': case 'save': case 'editview': case 'delete': if(!empty($this->recurring_source) && $this->recurring_source != "Sugar"){ return false; } } } return parent::ACLAccess($view,$is_owner); }
/** * Perform the actual massupdate. */ protected function action_massupdate() { if (!empty($_REQUEST['massupdate']) && $_REQUEST['massupdate'] == 'true' && (!empty($_REQUEST['uid']) || !empty($_REQUEST['entire']))) { if (!empty($_REQUEST['Delete']) && $_REQUEST['Delete'] == 'true' && !$this->bean->ACLAccess('delete') || (empty($_REQUEST['Delete']) || $_REQUEST['Delete'] != 'true') && !$this->bean->ACLAccess('save')) { ACLController::displayNoAccess(true); sugar_cleanup(true); } set_time_limit(0); //I'm wondering if we will set it never goes timeout here. // until we have more efficient way of handling MU, we have to disable the limit $GLOBALS['db']->setQueryLimit(0); require_once "include/MassUpdate.php"; require_once 'modules/MySettings/StoreQuery.php'; $seed = loadBean($_REQUEST['module']); $mass = new MassUpdate(); $mass->setSugarBean($seed); if (isset($_REQUEST['entire']) && empty($_POST['mass'])) { $mass->generateSearchWhere($_REQUEST['module'], $_REQUEST['current_query_by_page']); } $mass->handleMassUpdate(); $storeQuery = new StoreQuery(); //restore the current search. to solve bug 24722 for multi tabs massupdate. $temp_req = ['current_query_by_page' => $_REQUEST['current_query_by_page'], 'return_module' => $_REQUEST['return_module'], 'return_action' => $_REQUEST['return_action']]; if ($_REQUEST['return_module'] == 'Emails') { if (!empty($_REQUEST['type']) && !empty($_REQUEST['ie_assigned_user_id'])) { $this->req_for_email = ['type' => $_REQUEST['type'], 'ie_assigned_user_id' => $_REQUEST['ie_assigned_user_id']]; // Specifically for My Achieves } } $_REQUEST = []; $_REQUEST = unserialize(base64_decode($temp_req['current_query_by_page'])); unset($_REQUEST[$seed->module_dir . '2_' . strtoupper($seed->object_name) . '_offset']); //after massupdate, the page should redirect to no offset page $storeQuery->saveFromRequest($_REQUEST['module']); $_REQUEST = ['return_module' => $temp_req['return_module'], 'return_action' => $temp_req['return_action']]; //for post_massupdate, to go back to original page. } else { sugar_die("You must massupdate at least one record"); } }
/** * Formats the bean so it is ready to be handed back to the API's client. Certian fields will get extra processing * to make them easier to work with from the client end. * * @param $bean SugarBean The bean you want formatted * @param $fieldList array Which fields do you want formatted and returned (leave blank for all fields) * @param $options array Currently no options are supported * @return array The bean in array format, ready for passing out the API to clients. */ public function formatForApi(SugarBean $bean, array $fieldList = array(), array $options = array()) { $sfh = new SugarFieldHandler(); // if you are listing something the action is list // if any other format is called its a view $action = !empty($options['action']) && $options['action'] == 'list' ? 'list' : 'view'; $data = array(); $hasAccess = empty($bean->deleted) && $bean->ACLAccess($action); if ($hasAccess) { foreach ($bean->field_defs as $fieldName => $properties) { // Prune fields before ACL check because it can be expensive (Bug58133) if (!empty($fieldList) && !in_array($fieldName, $fieldList)) { // They want to skip this field continue; } if (!$bean->ACLFieldAccess($fieldName, 'read')) { // No read access to the field, eh? Unset the field from the array of data returned unset($data[$fieldName]); continue; } $type = !empty($properties['custom_type']) ? $properties['custom_type'] : $properties['type']; $field = $sfh->getSugarField($type); if (empty($field)) { continue; } if (isset($bean->{$fieldName}) || $type == 'relate') { $field->apiFormatField($data, $bean, $options, $fieldName, $properties, $fieldList, $this->api); } } // mark if its a favorite if (in_array('my_favorite', $fieldList) || empty($fieldList)) { if (isset($bean->my_favorite)) { $data['my_favorite'] = (bool) $bean->my_favorite; } else { // If the module doesn't support favorites, set it to false $data['my_favorite'] = false; } } } else { if (isset($bean->id)) { $data['id'] = $bean->id; } if (isset($bean->deleted) && $bean->deleted == true) { $data['deleted'] = (bool) $bean->deleted; } else { if (isset($bean->date_modified) && !empty($bean->field_defs['date_modified'])) { $field = $sfh->getSugarField($bean->field_defs['date_modified']['type']); $field->apiFormatField($data, $bean, array(), 'date_modified', $bean->field_defs['date_modified'], $fieldList, $this->api); } } if ($this->api->user->isAdmin()) { // BR-759 requests that assigned_user_id is returned on deleted records // to better sync some external systems if (isset($bean->assigned_user_id) && in_array('assigned_user_id', $fieldList)) { $data['assigned_user_id'] = $bean->assigned_user_id; } } } // in some cases the ACL data should be displayed, even when the used doesn't have access to the bean // (e.g. after bean is assigned to a different user and thus is no more accessible) if ($hasAccess || !empty($options['display_acl'])) { // if not an admin and the hashes differ, send back bean specific acl's $data['_acl'] = $this->getBeanAcl($bean, $fieldList); } return $data; }