2 if(!defined('sugarEntry') || !sugarEntry) die('Not A Valid Entry Point');
3 /*********************************************************************************
4 * SugarCRM Community Edition is a customer relationship management program developed by
5 * SugarCRM, Inc. Copyright (C) 2004-2012 SugarCRM Inc.
7 * This program is free software; you can redistribute it and/or modify it under
8 * the terms of the GNU Affero General Public License version 3 as published by the
9 * Free Software Foundation with the addition of the following permission added
10 * to Section 15 as permitted in Section 7(a): FOR ANY PART OF THE COVERED WORK
11 * IN WHICH THE COPYRIGHT IS OWNED BY SUGARCRM, SUGARCRM DISCLAIMS THE WARRANTY
12 * OF NON INFRINGEMENT OF THIRD PARTY RIGHTS.
14 * This program is distributed in the hope that it will be useful, but WITHOUT
15 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
16 * FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
19 * You should have received a copy of the GNU Affero General Public License along with
20 * this program; if not, see http://www.gnu.org/licenses or write to the Free
21 * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
24 * You can contact SugarCRM, Inc. headquarters at 10050 North Wolfe Road,
25 * SW2-130, Cupertino, CA 95014, USA. or at email address contact@sugarcrm.com.
27 * The interactive user interfaces in modified source and object code versions
28 * of this program must display Appropriate Legal Notices, as required under
29 * Section 5 of the GNU Affero General Public License version 3.
31 * In accordance with Section 7(b) of the GNU Affero General Public License version 3,
32 * these Appropriate Legal Notices must retain the display of the "Powered by
33 * SugarCRM" logo. If the display of the logo is not reasonably feasible for
34 * technical reasons, the Appropriate Legal Notices must display the words
35 * "Powered by SugarCRM".
36 ********************************************************************************/
38 require_once('modules/ACLActions/actiondefs.php');
39 class ACLAction extends SugarBean{
40 var $module_dir = 'ACLActions';
41 var $object_name = 'ACLAction';
42 var $table_name = 'acl_actions';
43 var $new_schema = true;
44 var $disable_custom_fields = true;
50 * static addActions($category, $type='module')
51 * Adds all default actions for a category/type
53 * @param STRING $category - the category (e.g module name - Accounts, Contacts)
54 * @param STRING $type - the type (e.g. 'module', 'field')
56 static function addActions($category, $type='module'){
58 $db = DBManagerFactory::getInstance();
59 if(isset($ACLActions[$type])){
60 foreach($ACLActions[$type]['actions'] as $action_name =>$action_def){
62 $action = new ACLAction();
63 $query = "SELECT * FROM " . $action->table_name . " WHERE name='$action_name' AND category = '$category' AND acltype='$type' AND deleted=0 ";
64 $result = $db->query($query);
65 //only add if an action with that name and category don't exist
66 $row=$db->fetchByAssoc($result);
68 $action->name = $action_name;
69 $action->category = $category;
70 $action->aclaccess = $action_def['default'];
71 $action->acltype = $type;
72 $action->modified_user_id = 1;
73 $action->created_by = 1;
80 sugar_die("FAILED TO ADD: $category - TYPE $type NOT DEFINED IN modules/ACLActions/actiondefs.php");
86 * static removeActions($category, $type='module')
87 * Removes all default actions for a category/type
89 * @param STRING $category - the category (e.g module name - Accounts, Contacts)
90 * @param STRING $type - the type (e.g. 'module', 'field')
92 public static function removeActions($category, $type='module'){
94 $db = DBManagerFactory::getInstance();
95 if(isset($ACLActions[$type])){
96 foreach($ACLActions[$type]['actions'] as $action_name =>$action_def){
98 $action = new ACLAction();
99 $query = "SELECT * FROM " . $action->table_name . " WHERE name='$action_name' AND category = '$category' AND acltype='$type' and deleted=0";
100 $result = $db->query($query);
101 //only add if an action with that name and category don't exist
102 $row=$db->fetchByAssoc($result);
104 $action->mark_deleted($row['id']);
108 sugar_die("FAILED TO REMOVE: $category : $name - TYPE $type NOT DEFINED IN modules/ACLActions/actiondefs.php");
113 * static AccessColor($access)
115 * returns the color associated with an access level
116 * these colors exist in the definitions in modules/ACLActions/actiondefs.php
117 * @param INT $access - the access level you want the color for
118 * @return the color either name or hex representation or false if the level does not exist
120 protected static function AccessColor($access){
121 global $ACLActionAccessLevels;
122 if(isset($ACLActionAccessLevels[$access])){
124 return $ACLActionAccessLevels[$access]['color'];
131 * static AccessName($access)
133 * returns the translated name associated with an access level
134 * these label definitions exist in the definitions in modules/ACLActions/actiondefs.php
135 * @param INT $access - the access level you want the color for
136 * @return the translated access level name or false if the level does not exist
138 static function AccessName($access){
139 global $ACLActionAccessLevels;
140 if(isset($ACLActionAccessLevels[$access])){
141 return translate($ACLActionAccessLevels[$access]['label'], 'ACLActions');
148 * static AccessLabel($access)
150 * returns the label associated with an access level
151 * these label definitions exist in the definitions in modules/ACLActions/actiondefs.php
152 * @param INT $access - the access level you want the color for
153 * @return the access level label or false if the level does not exist
155 protected static function AccessLabel($access){
156 global $ACLActionAccessLevels;
157 if(isset($ACLActionAccessLevels[$access])){
158 $label=preg_replace('/(LBL_ACCESS_)(.*)/', '$2', $ACLActionAccessLevels[$access]['label']);
159 return strtolower($label);
167 * static getAccessOptions()
168 * this is used for building select boxes
169 * @return array containg access levels (ints) as keys and access names as values
171 protected static function getAccessOptions( $action, $type='module'){
175 if(empty($ACLActions[$type]['actions'][$action]['aclaccess']))return $options;
176 foreach($ACLActions[$type]['actions'][$action]['aclaccess'] as $action){
177 $options[$action] = ACLAction::AccessName($action);
184 * function static getDefaultActions()
185 * This function will return a list of acl actions with their default access levels
189 public static function getDefaultActions($type='module', $action=''){
190 $query = "SELECT * FROM acl_actions WHERE deleted=0 ";
192 $query .= " AND acltype='$type'";
195 $query .= "AND name='$action'";
197 $query .= " ORDER BY category";
199 $db = DBManagerFactory::getInstance();
200 $result = $db->query($query);
201 $default_actions = array();
202 while($row = $db->fetchByAssoc($result) ){
203 $acl = new ACLAction();
204 $acl->populateFromRow($row);
205 $default_actions[] = $acl;
207 return $default_actions;
212 * static getUserActions($user_id,$refresh=false, $category='', $action='')
213 * returns a list of user actions
214 * @param GUID $user_id
215 * @param BOOLEAN $refresh
216 * @param STRING $category
217 * @param STRING $action
218 * @return ARRAY of ACLActionsArray
221 static function getUserActions($user_id,$refresh=false, $category='',$type='', $action=''){
222 //check in the session if we already have it loaded
223 if(!$refresh && !empty($_SESSION['ACL'][$user_id])){
224 if(empty($category) && empty($action)){
225 return $_SESSION['ACL'][$user_id];
227 if(!empty($category) && isset($_SESSION['ACL'][$user_id][$category])){
230 return $_SESSION['ACL'][$user_id][$category];
232 return $_SESSION['ACL'][$user_id][$category][$type];
233 }else if(!empty($type) && isset($_SESSION['ACL'][$user_id][$category][$type][$action])){
234 return $_SESSION['ACL'][$user_id][$category][$type][$action];
239 //if we don't have it loaded then lets check against the db
240 $additional_where = '';
241 $db = DBManagerFactory::getInstance();
242 if(!empty($category)){
243 $additional_where .= " AND acl_actions.category = '$category' ";
246 $additional_where .= " AND acl_actions.name = '$action' ";
249 $additional_where .= " AND acl_actions.acltype = '$type' ";
251 $query = "SELECT acl_actions .*, acl_roles_actions.access_override
253 LEFT JOIN acl_roles_users ON acl_roles_users.user_id = '$user_id' AND acl_roles_users.deleted = 0
254 LEFT JOIN acl_roles_actions ON acl_roles_actions.role_id = acl_roles_users.role_id AND acl_roles_actions.action_id = acl_actions.id AND acl_roles_actions.deleted=0
255 WHERE acl_actions.deleted=0 $additional_where ORDER BY category,name";
256 $result = $db->query($query);
257 $selected_actions = array();
258 while($row = $db->fetchByAssoc($result, FALSE) ){
259 $acl = new ACLAction();
261 $acl->populateFromRow($row);
262 if(!empty($row['access_override'])){
263 $acl->aclaccess = $row['access_override'];
266 if(!isset($selected_actions[$acl->category])){
267 $selected_actions[$acl->category] = array();
270 if(!isset($selected_actions[$acl->category][$acl->acltype][$acl->name])
271 || ($selected_actions[$acl->category][$acl->acltype][$acl->name]['aclaccess'] > $acl->aclaccess
275 (!empty($selected_actions[$acl->category][$acl->acltype][$acl->name]['isDefault'])
282 $selected_actions[$acl->category][$acl->acltype][$acl->name] = $acl->toArray();
283 $selected_actions[$acl->category][$acl->acltype][$acl->name]['isDefault'] = !$isOverride;
288 //only set the session variable if it was a full list;
289 if(empty($category) && empty($action)){
290 if(!isset($_SESSION['ACL'])){
291 $_SESSION['ACL'] = array();
293 $_SESSION['ACL'][$user_id] = $selected_actions;
295 if(empty($action) && !empty($category)){
297 $_SESSION['ACL'][$user_id][$category][$type] = $selected_actions[$category][$type];}
298 $_SESSION['ACL'][$user_id][$category] = $selected_actions[$category];
300 if(!empty($action) && !empty($category) && !empty($type)){
301 $_SESSION['ACL'][$user_id][$category][$type][$action] = $selected_actions[$category][$action];
306 return $selected_actions;
309 * (static/ non-static)function hasAccess($is_owner= false , $access = 0)
310 * checks if a user has access to this acl if the user is an owner it will check if owners have access
312 * This function may either be used statically or not. If used staticlly a user must pass in an access level not equal to zero
313 * @param boolean $is_owner
315 * @return true or false
317 static function hasAccess($is_owner=false, $access = 0){
319 if($access != 0 && $access == ACL_ALLOW_ALL || ($is_owner && $access == ACL_ALLOW_OWNER))return true;
320 //if this exists, then this function is not static, so check the aclaccess parameter
321 if(isset($this) && isset($this->aclaccess)){
322 if($this->aclaccess == ACL_ALLOW_ALL || ($is_owner && $this->aclaccess == ACL_ALLOW_OWNER))
337 * static function userHasAccess($user_id, $category, $action, $is_owner = false)
339 * @param GUID $user_id the user id who you want to check access for
340 * @param STRING $category the category you would like to check access for
341 * @param STRING $action the action of that category you would like to check access for
342 * @param BOOLEAN OPTIONAL $is_owner if the object is owned by the user you are checking access for
344 public static function userHasAccess($user_id, $category, $action,$type='module', $is_owner = false){
345 global $current_user;
346 if($current_user->isAdminForModule($category)&& !isset($_SESSION['ACL'][$user_id][$category][$type][$action]['aclaccess'])){
349 //check if we don't have it set in the cache if not lets reload the cache
350 if(ACLAction::getUserAccessLevel($user_id, $category, 'access', $type) < ACL_ALLOW_ENABLED) return false;
351 if(empty($_SESSION['ACL'][$user_id][$category][$type][$action])){
352 ACLAction::getUserActions($user_id, false);
356 if(!empty($_SESSION['ACL'][$user_id][$category][$type][$action])){
357 return ACLAction::hasAccess($is_owner, $_SESSION['ACL'][$user_id][$category][$type][$action]['aclaccess']);
363 * function getUserAccessLevel($user_id, $category, $action,$type='module')
364 * returns the access level for a given category and action
366 * @param GUID $user_id
367 * @param STRING $category
368 * @param STRING $action
369 * @param STRING $type
370 * @return INT (ACCESS LEVEL)
373 public static function getUserAccessLevel($user_id, $category, $action,$type='module'){
374 if(empty($_SESSION['ACL'][$user_id][$category][$type][$action])){
375 ACLAction::getUserActions($user_id, false);
378 if(!empty($_SESSION['ACL'][$user_id][$category][$type][$action])){
379 if (!empty($_SESSION['ACL'][$user_id][$category][$type]['admin']) && $_SESSION['ACL'][$user_id][$category][$type]['admin']['aclaccess'] >= ACL_ALLOW_ADMIN)
381 // If you have admin access for a module, all ACL's are allowed
382 return $_SESSION['ACL'][$user_id][$category][$type]['admin']['aclaccess'];
384 return $_SESSION['ACL'][$user_id][$category][$type][$action]['aclaccess'];
389 * STATIC function userNeedsOwnership($user_id, $category, $action,$type='module')
390 * checks if a user should have ownership to do an action
392 * @param GUID $user_id
393 * @param STRING $category
394 * @param STRING $action
395 * @param STRING $type
398 public static function userNeedsOwnership($user_id, $category, $action,$type='module'){
399 //check if we don't have it set in the cache if not lets reload the cache
401 if(empty($_SESSION['ACL'][$user_id][$category][$type][$action])){
402 ACLAction::getUserActions($user_id, false);
407 if(!empty($_SESSION['ACL'][$user_id][$category][$type][$action])){
408 return $_SESSION['ACL'][$user_id][$category][$type][$action]['aclaccess'] == ACL_ALLOW_OWNER;
415 * static pass by ref setupCategoriesMatrix(&$categories)
416 * takes in an array of categories and modifes them adding display information
418 * @param unknown_type $categories
420 public static function setupCategoriesMatrix(&$categories){
421 global $ACLActions, $current_user;
424 foreach($categories as $cat_name=>$category){
425 foreach($category as $type_name=>$type){
426 foreach($type as $act_name=>$action){
427 $names[$act_name] = translate($ACLActions[$type_name]['actions'][$act_name]['label'], 'ACLActions');
428 $categories[$cat_name][$type_name][$act_name]['accessColor'] = ACLAction::AccessColor($action['aclaccess']);
429 if($type_name== 'module'){
431 if($act_name != 'aclaccess' && $categories[$cat_name]['module']['access']['aclaccess'] == ACL_ALLOW_DISABLED){
432 $categories[$cat_name][$type_name][$act_name]['accessColor'] = 'darkgray';
433 $disabled[] = $cat_name;
437 $categories[$cat_name][$type_name][$act_name]['accessName'] = ACLAction::AccessName($action['aclaccess']);
438 $categories[$cat_name][$type_name][$act_name]['accessLabel'] = ACLAction::AccessLabel($action['aclaccess']);
440 if($cat_name=='Users'&& $act_name=='admin'){
441 $categories[$cat_name][$type_name][$act_name]['accessOptions'][ACL_ALLOW_DEFAULT]=ACLAction::AccessName(ACL_ALLOW_DEFAULT);;
442 $categories[$cat_name][$type_name][$act_name]['accessOptions'][ACL_ALLOW_DEV]=ACLAction::AccessName(ACL_ALLOW_DEV);;
445 $categories[$cat_name][$type_name][$act_name]['accessOptions'] = ACLAction::getAccessOptions($act_name, $type_name);
451 if(!is_admin($current_user)){
452 foreach($disabled as $cat_name){
453 unset($categories[$cat_name]);
463 * returns this acl as an array
465 * @return array of fields with id, name, access and category
468 $array_fields = array('id', 'aclaccess');
470 foreach($array_fields as $field){
471 $arr[$field] = $this->$field;
477 * function fromArray($arr)
478 * converts an array into an acl mapping name value pairs into files
482 function fromArray($arr){
483 foreach($arr as $name=>$value){
484 $this->$name = $value;
489 * function clearSessionCache()
490 * clears the session variable storing the cache information for acls
493 function clearSessionCache(){
494 unset($_SESSION['ACL']);