[ Index ]
 

Code source de eGroupWare 1.2.106-2

Accédez au Source d'autres logiciels libresSoutenez Angelica Josefina !

title

Body

[fermer]

/workflow/inc/engine/src/common/ -> WfSecurity.php (source)

   1  <?php
   2  require_once(GALAXIA_LIBRARY.SEP.'src'.SEP.'common'.SEP.'Base.php');
   3  
   4  //!! WfSecurity
   5  //! A class to handle most security checks in the engine
   6  /*!
   7    This class is used to ...
   8  */
   9  class WfSecurity extends Base {
  10    
  11    // processes config values cached for this object life duration
  12    // init is done at first use for each process
  13    var $processesConfig= Array();
  14        
  15    /*!
  16    * Constructor takes a PEAR::Db object
  17    */
  18    function WfSecurity(&$db) 
  19    {
  20      $this->child_name = 'WfSecurity';
  21      parent::Base($db);
  22      require_once(GALAXIA_LIBRARY.SEP.'src'.SEP.'API'.SEP.'Instance.php');
  23      require_once(GALAXIA_LIBRARY.SEP.'src'.SEP.'API'.SEP.'Process.php');
  24      require_once(GALAXIA_LIBRARY.SEP.'src'.SEP.'API'.SEP.'BaseActivity.php');
  25    }
  26  
  27    //! load the config values for a given process
  28    /*!
  29    * config values for a given process are cached while this WfSecurity object stay alive
  30    * @param $pId is the process id
  31    * @private
  32    */
  33    function loadConfigValues($pId)
  34    {
  35      //check if we already have the config values for this processId
  36      if (!(isset($this->processesConfig[$pId])))
  37      {
  38        //define conf values we need
  39        $arrayConf=array(
  40          'ownership_give_abort_right'        =>1,
  41          'ownership_give_exception_right'    =>1,
  42          'ownership_give_release_right'        =>1,
  43          'role_give_abort_right'               =>0,
  44          'role_give_release_right'        =>0,
  45          'role_give_exception_right'        =>0,
  46        );
  47        //check theses values for this process and store the result for this object life duration
  48        $myProcess =& new Process($this->db);
  49        $myProcess->getProcess($pId);
  50        $this->processesConfig[$pId] = $myProcess->getConfigValues($arrayConf);
  51        unset($myProcess);
  52      }
  53    }
  54  
  55    //! Checks if a user has a access to an activity, use it at runtime
  56    /*!
  57    * To do so it checks if the user is in the users having the roles associated with the activity
  58    * or if he is in the groups having roles associated with the activity
  59    * @public
  60    * @param $user is the user id
  61    * @param $activityId is the activity id
  62    * @param $readonly is a boolean, false by default. If true we only check read-only access level
  63    *     for the user on this activity
  64    * @return true if access is granted false in other case. Errors are stored in the object.
  65    */
  66    function checkUserAccess($user, $activity_id, $readonly=false) 
  67    {
  68      //group mapping, warning groups and user can have the same id
  69      $groups = galaxia_retrieve_user_groups($user);
  70          
  71      $query = 'select count(*) from '.GALAXIA_TABLE_PREFIX.'activity_roles gar 
  72          INNER JOIN '.GALAXIA_TABLE_PREFIX.'roles gr ON gar.wf_role_id=gr.wf_role_id
  73          INNER JOIN '.GALAXIA_TABLE_PREFIX.'user_roles gur ON gur.wf_role_id=gr.wf_role_id 
  74          where gar.wf_activity_id=? 
  75          and ( (gur.wf_user=? and gur.wf_account_type=?)';
  76      if (is_array($groups))
  77      {
  78        $query .= ' or (gur.wf_user in ('.implode(',',$groups).") and gur.wf_account_type='g')";
  79      }
  80      $query .= ')';
  81  
  82      if (!($readonly))
  83      {
  84        $query.= 'and NOT(gar.wf_readonly=1)';
  85      }
  86      $result= $this->getOne($query ,array($activity_id, $user, 'u'));
  87      if ($result)
  88      {
  89        //echo "<br>Access granted for ".$user;
  90        return true;
  91      }
  92      else
  93      {
  94        $this->error[]= tra('Access denied for user %1 on activity %2, no role', $user, $activity_id);
  95        return false;
  96      }
  97    }
  98  
  99    //! Return true if actual running user is authorized for a given action on a given activity/instance. Use it at runtime.
 100    /*!
 101    * @public
 102    * This function will check the given action for the current running user, lock the table rows if necessary to ensure
 103    * nothing will move from another process between the check and the later action. 
 104    * loacked tables can be instances and instance-activities.
 105    * NOTA BENE: there is no lock on activity/processes table, we assume the admin is not changing the activity data
 106    * on a running/production process, this is why there is versioning and activation on processes
 107    * Encapsulate this function call in a transaction, locks will be removed at the end of the transaction, whent COMMIT 
 108    * or ROLLBACK will be launched.
 109    * @param $activityId is the activity id, can be 0
 110    * @param $instanceId is the instanceId, can be 0
 111    * @param $action is a string containing ONE action asked, it must be one of :
 112    *    * 'grab'
 113    *    * 'release'
 114    *    * 'exception'
 115    *    * 'resume'
 116    *    * 'abort'
 117    *    * 'run'
 118    *    * 'send'
 119    *    * 'view'
 120    *    * 'viewrun'
 121    *    * 'complete' (internal action before completing)
 122    *    * 'restart' admin function, restarting a failed automatic activity
 123    * be carefull, View can be done in 2 ways
 124    *     * viewrun : by the view activity if the process has a view activity, and only by this way in such case
 125    *     * view: by a general view form with access to everybody if the process has no view activity
 126    * @return true if action access is granted false in other case. Errors are stored in the object.
 127    */
 128    function checkUserAction($activityId, $instanceId,$action)
 129    {
 130      //Warning: 
 131      //start and standalone activities have no instances associated
 132      //aborted and completed instances have no activities associated
 133  
 134      //$this->error[] = 'DEBUG: action:'.$action;
 135      if ($action!='run' && $action!='send' && $action!='view' && $action!='viewrun' && $action!='complete' && $action!='grab' && $action!='release' && $action!='exception' && $action!='resume' && $action!='abort' && $action!='restart')
 136      {
 137        $this->error[] = tra('Security check: Cannot understand asked action');
 138        return false;
 139      }
 140      
 141      $user = galaxia_retrieve_running_user();
 142      //$this->error[] = 'DEBUG: running user:'.$user;
 143      if ( (!(isset($user))) || (empty($user)) )
 144      {
 145        $this->error[] = tra('Cannot retrieve the user running the security check');
 146        return false;
 147      }
 148  
 149      //0 - prepare RowLocks ----------------------------------------------------------
 150      $lock_instance_activities = false;
 151      $lock_instances = false;
 152      switch($action)
 153      {
 154        case 'view':
 155        case 'viewrun':
 156          //no impact on write mode, no lock
 157          break;
 158        case 'grab':
 159          //impacted tables is instance_activities
 160          $lock_instance_activities = true;
 161          break;
 162        case 'release' :
 163          //impacted tables is instance_activities
 164          $lock_instance_activities = true;
 165          break;
 166        case 'exception':
 167          //impacted tables is instances
 168          $lock_instances = true;
 169          break;
 170        case 'resume':
 171          //impacted tables is instances
 172          $lock_instances = true;
 173          break;
 174        case 'abort':
 175          //impacted tables are instances and instance_activities (deleting rows)
 176          $lock_instance_activities = true;
 177          $lock_instances = true;
 178          break;
 179        case 'run':
 180          //impacted tables is instance_activities (new running user)
 181          $lock_instance_activities = true;
 182          break;
 183        case 'send':
 184          //impacted tables is instance_activities (deleting/adding row)
 185          $lock_instance_activities = true;
 186          break;
 187        case 'complete':
 188          //impacted tables are instances and instance_activities
 189          $lock_instance_activities = true;
 190          $lock_instances = true;
 191          break;
 192        case 'restart':
 193          //nothing to do, it will be done by the run part.
 194          break;
 195      }
 196      // no lock on instance_activities without a lock on instances
 197      // to avoid changing status of an instance or deletion of an instance while impacting instance_activities
 198      if ($lock_instance_activities) $lock_instances = true;
 199      
 200      //1 - load data -----------------------------------------------------------------
 201      $_no_activity=false;
 202      $_no_instance=false;
 203      
 204      //retrieve some activity datas and process data
 205      if ($activityId==0)
 206      {
 207        $_no_activity = true;
 208      }
 209      else
 210      {
 211        $query = 'select ga.wf_activity_id, ga.wf_type, ga.wf_is_interactive, ga.wf_is_autorouted, 
 212                gp.wf_name as wf_procname, gp.wf_is_active, gp.wf_version, gp.wf_p_id
 213                from '.GALAXIA_TABLE_PREFIX.'activities ga 
 214                  INNER JOIN '.GALAXIA_TABLE_PREFIX.'processes gp ON gp.wf_p_id=ga.wf_p_id
 215                  where ga.wf_activity_id = ?';
 216        $result = $this->query($query, array($activityId));
 217        $resactivity = Array();
 218        if (!!$result)
 219        {
 220          $resactivity = $result->fetchRow();
 221          $pId = $resactivity['wf_p_id'];
 222          //DEBUG
 223          //$debugactivity = implode(",",$resactivity);
 224          //$this->error[] = 'DEBUG: '. date("[d/m/Y h:i:s]").'activity:'.$debugactivity;
 225        }
 226        if (count($resactivity)==0)
 227        {
 228          $_no_activity = true;
 229        }
 230      }
 231  
 232      //retrieve some instance and process data (need process data here as well if there is no activity)
 233      if ($instanceId==0)
 234      {
 235        $_no_instance = true;
 236      }
 237      else
 238      {
 239        if ($lock_instances)
 240        {
 241          //we need to make a row lock now, before any read action
 242          $where = 'wf_instance_id='.(int)$instanceId;
 243          //$this->error[]= '<br> Debug:locking instances '.$where;
 244          if (!($this->db->RowLock(GALAXIA_TABLE_PREFIX.'instances', $where)))
 245          {
 246            $this->error[] = tra('failed to obtain lock on %1 table', 'instances');
 247            return false;
 248          }
 249        }
 250        $query = 'select gi.wf_instance_id, gi.wf_owner, gi.wf_status, 
 251                gp.wf_name as wf_procname, gp.wf_is_active, gp.wf_version, gp.wf_p_id
 252                from '.GALAXIA_TABLE_PREFIX.'instances gi
 253                INNER JOIN '.GALAXIA_TABLE_PREFIX.'processes gp ON gp.wf_p_id=gi.wf_p_id
 254                where gi.wf_instance_id=?';
 255        $result = $this->query($query,array($instanceId));
 256        if (!!$result)
 257        {
 258  
 259          $resinstance = $result->fetchRow();
 260          $pId = $resinstance['wf_p_id'];
 261          //DEBUG
 262          //$debuginstance = implode(",",$resinstance);
 263          //$this->error[] = 'DEBUG: '. date("[d/m/Y h:i:s]").'instance:'.$debuginstance;
 264        }
 265        if (count($resinstance)==0)
 266        {
 267          $_no_instance = true;
 268        }
 269      }
 270  
 271      if ($_no_activity && $_no_instance)
 272      {
 273        $this->error[] = tra('Action %1 is impossible if we have no activity and no instance designated for it!',$action);
 274        return false;
 275      }
 276      
 277      //retrieve some instance/activity data
 278      //if no_activity or no_instance we are with out-flow/without instances activities or with instances terminated 
 279      //we would not obtain anything there
 280      if (!($_no_activity || $_no_instance))
 281      {
 282        if ($lock_instance_activities)
 283        {
 284          //we need to lock this row now, before any read action
 285          $where = 'wf_instance_id='.(int)$instanceId.' and wf_activity_id='.(int)$activityId;
 286          //$this->error[] = '<br> Debug:locking instance_activities '.$where;
 287          if (!($this->db->RowLock(GALAXIA_TABLE_PREFIX.'instance_activities', $where)))
 288          {
 289            $this->error[] = tra('failed to obtain lock on %1 table','instances_activities');
 290            return false;
 291          }
 292        }
 293        $query = 'select gia.wf_instance_id, gia.wf_user, gia.wf_status
 294                from '.GALAXIA_TABLE_PREFIX.'instance_activities gia
 295                  where gia.wf_activity_id = ? and gia.wf_instance_id = ?';
 296        $result = $this->query($query, array($activityId, $instanceId));
 297        $res_inst_act = Array();
 298        if (!!$result)
 299        {
 300          $res_inst_act = $result->fetchRow();
 301          //DEBUG
 302          //$debuginstact = implode(",",$res_inst_act);
 303          //$this->error[] = 'DEBUG: '. date("[d/m/Y h:i:s]").'instance/activity:'.$debuginstact;
 304  
 305        }
 306      }
 307  
 308      //Now that we have the process we can load config values
 309      //$this->error[] = 'DEBUG: load config values for process:'.$pId;
 310      $this->loadConfigValues($pId);
 311      //$debuconfig = '';foreach ($this->processesConfig[$pId] as $label => $value){$debugconfig .= ':'.$label.'=>'.$value;} $this->error[] = 'DEBUG: config:'.$debugconfig;
 312  
 313  
 314      
 315      //2 - decide which tests must be done ------------------------------------------------
 316      //init tests
 317      $_check_active_process = false; // is the process is valid?
 318      $_check_instance = false; //have we got an instance?
 319      $_check_instance_status = array(); //use to test some status between 'active','exception','aborted','completed'
 320      $_fail_on_exception = false; //no comment
 321      $_check_activity = false; //have we got an activity?
 322      //is there a relationship between instance and activity? this one can be decided already
 323      $_check_instance_activity =  !(($_no_instance) || ($_no_activity));
 324      $_bypass_user_role_if_owner = false; //if our user is the owner we ignore user tests
 325      $_bypass_user_on_non_interactive = false; //if activty is not interactive we do not perform user tests
 326      $_bypass_user_if_admin = false; //is our user a special rights user?
 327      $_bypass_instance_on_pseudo = false; //should we jump the instance check when in 'start' activity?
 328      $_check_is_user = false; //is the actual_user our user?
 329      $_check_is_not_star = false; //is the actual <>*?
 330      $_check_is_star = false; // is the actual user *?
 331      $_check_is_in_role = false; //is our user in associated roles with readonly=false?
 332      $_check_is_in_role_in_readonly = false; //is our user in associated roles?
 333      $_check_no_view_activity = false; //is the process having no view activities?
 334      $_check_is_admin_only = false; //is the action vaible only for admins?
 335      
 336      //first have a look at the action asked
 337      switch($action)
 338      {
 339        case 'restart':
 340          // we need an activity 'in_flow' ie: not start or standalone that means we need an instance
 341          // we need an instance not completed or aborted that means we need an activity
 342          // but if we have an instance it musn't be in 'exception' as well
 343          // authorization is given to admin only
 344          $_check_active_process          = true;
 345          $_check_activity                = true;
 346          $_check_instance        = true;
 347          $_fail_on_exception             = true;
 348          $_check_is_admin_only        = true;
 349          break;
 350        case 'view':
 351          //process can be inactive
 352          //we need an existing instance
 353          //no activity needed
 354          $_check_instance = true;
 355          $_bypass_user_if_admin    = true;
 356          //but be carefull the view function is forbidden on process having the viewrun action with activities
 357          $_check_no_view_activity = true;
 358          break;
 359        case 'viewrun':
 360          //process can be inactive
 361          //we need an existing instance
 362          //we need an activity
 363          //need a read-only role at least on this activity
 364          $_check_instance = true;
 365          $_bypass_user_if_admin    = true;
 366          $_check_activity = true; 
 367          $_check_is_in_role_in_readonly = true;
 368          //The view type is a special activity related to all instances
 369          $_check_instance_activity = false;
 370          break;
 371        case 'complete':
 372          // we need an activity 'in_flow' ie: not start or standalone that means we need an instance
 373          // (the 'view' activity is not 'in_flow' and has instance, but no relashionship, no need to 
 374          // test it here or later for grab or others actions). 
 375          // warning we can complete a start activity, in this case it is the contrary, we musn't have an instance
 376          // we need an instance not completed or aborted that means we need an activity
 377          // but if we have an instance it musn't be in 'exception' as well
 378          // authorization is given to currentuser only,
 379          // for interactive activities (except start), instance user need to be the actual user
 380          // 'view' cannot be completed
 381          $_check_active_process        = true;
 382          $_check_instance            = true;
 383          $_bypass_instance_on_pseudo    = true;
 384          $_fail_on_exception        = true;
 385          $_check_activity            = true;
 386          $_bypass_user_on_non_interactive = true;
 387          $_check_is_user            = true;
 388          $_check_is_not_star        = true;
 389          break;
 390        case 'grab': 
 391          // we need an activity 'in_flow' ie: not start or standalone that means we need an instance
 392          // we need an instance not completed or aborted that means we need an activity
 393          // authorization are given to currentuser, role, never owner actually
 394          // TODO: add conf setting to give grab access to owner (that mean run access as well maybe)
 395          // current user MUST be '*' or user (no matter to grab something we already have)
 396          // check is star is done after check_is_user which can be false
 397          $_check_active_process    = true;
 398          $_check_activity    = true;
 399          $_check_instance    = true;
 400          $_check_is_user        = true;
 401          $_check_is_star        = true;
 402          $_bypass_user_if_admin    = true;
 403          $_check_is_in_role    = true;
 404          break;
 405        case 'release' :
 406          // we need an activity 'in_flow' ie: not start or standalone that means we need an instance
 407          // we need an instance not completed or aborted that means we need an activity
 408          // authorization are given to currentuser, maybe role, maybe owner,
 409          // current must not be '*'
 410          $_check_active_process    = true;
 411          $_check_activity        = true;
 412          $_check_instance        = true;
 413          $_check_is_user        = true;
 414          $_check_is_not_star     = true;
 415          $_bypass_user_if_admin    = true;
 416          if ($this->processesConfig[$pId]['role_give_release_right']) $_check_is_in_role         = true;
 417          if ($this->processesConfig[$pId]['ownership_give_release_right']) $_bypass_user_role_if_owner     = true;
 418          break;
 419        case 'exception':
 420          // we need an activity 'in_flow' ie: not start or standalone that means we need an instance
 421          // we need an instance not completed or aborted that means we need an activity
 422          // authorization are given to currentuser, maybe role, maybe owner,
 423          $_check_active_process    = true;
 424          $_check_activity        = true;
 425          $_check_instance        = true;
 426          $_check_instance_status = array('active');
 427          $_bypass_user_if_admin    = true;
 428          $_check_is_user        = true;
 429          if ($this->processesConfig[$pId]['role_give_exception_right']) $_check_is_in_role                 = true;
 430          if ($this->processesConfig[$pId]['ownership_give_exception_right']) $_bypass_user_role_if_owner   = true;
 431          break;
 432        case 'resume':
 433          // like exception but inversed activity status
 434          $_check_active_process    = true;
 435          $_check_activity        = true;
 436          $_check_instance        = true;
 437          $_check_instance_status = array('exception');
 438          $_bypass_user_if_admin    = true;
 439          $_check_is_user        = true;
 440          if ($this->processesConfig[$pId]['role_give_exception_right']) $_check_is_in_role                 = true;
 441          if ($this->processesConfig[$pId]['ownership_give_exception_right']) $_bypass_user_role_if_owner   = true;
 442          break;
 443        case 'abort':
 444          // process can be inactive
 445          // we do not need an activity
 446          // we need an instance
 447          // authorization are given to currentuser, maybe role, maybe owner,
 448          // TODO: add conf setting to refuse abort by user
 449          $_check_instance        = true;
 450          $_check_instance_status = array('active','exception','completed');
 451          $_bypass_user_if_admin    = true;
 452          $_check_is_user        = true;
 453          if ($this->processesConfig[$pId]['role_give_abort_right']) $_check_is_in_role                 = true;
 454          if ($this->processesConfig[$pId]['ownership_give_abort_right']) $_bypass_user_role_if_owner   = true;
 455          break;
 456        case 'run':
 457          // the hell door:
 458          // all activities can be runned, even without instance, even if non interactive
 459          // if we have one we need an instance not completed or aborted that means we need an activity
 460          // but if we have an instance it musn't be in 'exception' as well
 461          // for interactive activities (except start and standalone), instance user need to be the actual user
 462          // run is ok if user is in role and actual user is '*', no rights for owner actually
 463          // no user bypassing on admin user, admin must grab (release if needed) the instance before
 464          $_check_active_process        = true;
 465          $_check_activity            = true;
 466          $_fail_on_exception        = true;
 467          $_bypass_user_on_non_interactive = true;
 468          $_check_is_user            = true;
 469          $_check_is_star            = true;
 470          $_check_is_in_role        = true;
 471          break;
 472        case 'send':
 473          // we need an instance not completed or aborted that means we need an activity
 474          // but if we have an instance it musn't be in 'exception' as well
 475          // authorization are given to currentuser, maybe role, no rights for owner actually
 476          // run is ok if user is in role and actual user is '*'
 477          // no user bypassing on admin user, admin must grab (release if needed) the instance before
 478          $_check_active_process          = true;
 479          $_check_activity                = true;
 480          $_fail_on_exception             = true;
 481          $_bypass_user_if_admin        = true;
 482          $_check_is_user                 = true;
 483          $_check_is_star            = true;
 484          $_check_is_in_role        = true;
 485          break;
 486      }
 487      
 488      //3- now perform asked tests ---------------------------------------------------------------------
 489      if ($_check_active_process) // require an active process?
 490      {
 491        //$this->error[] = 'DEBUG: check active process';
 492        if ($_no_instance) //we need an instance or an activity to perfom the check
 493        {
 494          //we cannot be there without instance and without activity, we now we have one activity at least
 495          if (!($resactivity['wf_is_active']=='y'))
 496          {
 497            $this->error[] = tra('Process %1 %2 is not active, action %3 is impossible', $resactivity['wf_procname'], $resactivity['wf_version'], $action);
 498            return false;
 499          }
 500        }
 501        else
 502        {
 503          if (!($resinstance['wf_is_active']=='y'))
 504          {
 505            $this->error[] = tra('Process %1 %2 is not active, action %3 is impossible', $resinstance['wf_procname'], $resactivity['wf_version'], $action);
 506            return false;
 507          }
 508        }
 509      }
 510      
 511      if ($_check_instance)
 512      {
 513        //$this->error[] = 'DEBUG: check instance';
 514        if ( (!($_bypass_instance_on_pseudo)) && ($_no_instance))
 515        {
 516          $this->error[] = tra('Action %1 needs an instance and instance %2 does not exists', $action, $instanceId);
 517          return false;
 518        }
 519      }
 520      
 521      if ($_check_activity)
 522      {
 523        //$this->error[] = 'DEBUG: check activity';
 524        if ($_no_activity)
 525        {
 526          $this->error[] = tra('Action %1 needs an activity and activity %2 does not exists', $action, $activityId);
 527          return false;
 528        }
 529      }
 530      
 531      if ($_check_instance_activity) //is there a realtionship between instance and activity
 532      {
 533        //$this->error[] = 'DEBUG: check activity-instance relationship'.count($res_inst_act);
 534        if ( (!isset($res_inst_act)) || empty($res_inst_act) || (count($res_inst_act)==0) )
 535        {
 536          $this->error[] = tra('Instance %1 is not associated with activity %2, action %3 is impossible.', $instanceId, $activityId, $action);
 537          return false;
 538        }
 539      }
 540      
 541      if (!(count($_check_instance_status) == 0)) //use to test some status between 'active','exception','aborted','completed'
 542      {
 543        //DEBUG
 544        //$debug_status = implode(",",$_check_instance_status);
 545        //$this->error[] = 'DEBUG: check instance status, actually :'.$resinstance['wf_status'].' need:'.$debug_status;
 546        if (!(in_array($resinstance['wf_status'],$_check_instance_status)))
 547        {
 548          $this->error[] = tra('Instance %1 is in %2 state, action %3 is impossible.', $instanceId, $resinstance['wf_status'], $action);
 549          return false;
 550        }
 551      }
 552      if (($_fail_on_exception) && ($resinstance['wf_status']=='exception'))
 553      {
 554          $this->error[] = tra('Instance %1 is in exception, action %2 is not possible.', $instanceId, $action);
 555          return false;
 556      }
 557      
 558      // Test on the process to see if he has a view activity
 559      if ($_check_no_view_activity)
 560      {
 561        if (!(isset($this->pm)))
 562        {
 563          require_once(GALAXIA_LIBRARY.SEP.'src'.SEP.'ProcessManager'.SEP.'ProcessManager.php');
 564          $this->pm =& new ProcessManager($this->db);
 565        }
 566        //$this->error[] = 'DEBUG: checking to see if there is no view activities on process :'.$pId.':'.$this->pm->get_process_view_activity($pId);
 567        if ($this->pm->get_process_view_activity($pId))
 568        {
 569          $this->error[] = tra('This process has a view activity. Access in view mode is granted only for this view activty.');
 570          return false;
 571        }
 572      }
 573      
 574      // user tests ---------------
 575      $checks = true;
 576      //is our actual workflow user a special rights user?
 577      // TODO test actual workflow user diff of $user
 578      //$this->error[] = 'DEBUG: user can admin instance :'.galaxia_user_can_admin_instance().' bypass?:'.$_bypass_user_if_admin;
 579      $is_admin = galaxia_user_can_admin_instance();
 580      if (! ( (($_bypass_user_if_admin) && ($is_admin)) || (($_check_is_admin_only) && ($is_admin))) )
 581      {
 582        //if our user is the owner we ignore user tests
 583        //$this->error[] = 'DEBUG: user is owner :'.$resinstance['wf_owner'].' bypass?:'.$_bypass_user_role_if_owner;
 584        if (!( ($_bypass_user_role_if_owner) && ((int)$resinstance['wf_owner']==(int)$user) ))
 585        {
 586          //$this->error[] = 'DEBUG: no_activity:'.$_no_activity.' interactive? :'.$resactivity['wf_is_interactive'].' bypass?:'.$_bypass_user_on_non_interactive;
 587          //if activity is not interactive we do not perform user tests
 588          if (!( (!($_no_activity)) && ($_bypass_user_on_non_interactive) && ($resactivity['wf_is_interactive']=='n') ))
 589          {
 590            //$this->error[] = 'DEBUG: no bypassing done:';
 591            //is the actual_user our user?
 592            if ( (!($_no_instance)) && $_check_is_user) 
 593            {
 594              //$this->error[] = 'DEBUG: check user is actual instance user:'.$user.':'.$res_inst_act['wf_user'];
 595              if (!((int)$res_inst_act['wf_user']==(int)$user))
 596              {
 597                //user test was false, but maybe we'll have better chance later
 598                $checks = false;
 599              }
 600            }
 601            // special '*' user
 602            if ($res_inst_act['wf_user']=='*')
 603            {
 604              //$this->error[] = 'DEBUG: we have the special * user:';
 605              //is the actual *?
 606              if ($_check_is_star)
 607              {
 608                // redemption here
 609                //$this->error[] = 'DEBUG Ok, we have a star';
 610                $checks = true;
 611              }
 612              
 613              //is the actual <>*?
 614              if ($_check_is_not_star)
 615              {
 616                //no redemption here
 617                $this->error[] = tra('Action %1 is impossible, there are no user assigned to this activity for this instance', $action);
 618                return false;
 619              }
 620              //perform the role test if actual user is '*'
 621              //$this->error[] = 'DEBUG: role checking?:'.$_check_is_in_role;
 622              if ($_check_is_in_role)
 623              {
 624                //$this->error[] = 'DEBUG: we have *, checking role of user:'.$user;
 625                $checks=$this->checkUserAccess($user, $activityId);
 626              }
 627              //$this->error[] = 'DEBUG: role checking in read-only at least?:'.$_check_is_in_role_in_readonly;
 628              if ($_check_is_in_role_in_readonly)
 629              {
 630                //$this->error[] = 'DEBUG: we have *, checking readonly role of user:'.$user;
 631                $checks=$this->checkUserAccess($user, $activityId, true);
 632              }        
 633            }
 634            else
 635            {
 636              //we have not *, do we need * as the actual? (done only if check_is_user is false)
 637              //notice that if check_user was false and we have not the '*' user and if you do not want
 638              //the check_is_star it means the user can bypass the actual user if you have a check_is_in_role ok!
 639              if ( (!($checks)) && ($_check_is_star))
 640              {
 641                // that was necessary
 642                $this->error[] = tra('Action %1 is impossible, another user is already in place', $action);
 643                return false;
 644              }
 645              //is our user in associated roles (done even if check_is_user was true)
 646              //$this->error[] = 'DEBUG: role checking?:'.$_check_is_in_role;
 647              if ($_check_is_in_role)
 648              {
 649                //$this->error[] = 'DEBUG: we have not *, checking role for user:'.$user;
 650                $checks=$this->checkUserAccess($user, $activityId);
 651              }
 652              //$this->error[] = 'DEBUG: role checking in read-only at least?:'.$_check_is_in_role_in_readonly;
 653              if ($_check_is_in_role_in_readonly)
 654              {
 655                //$this->error[] = 'DEBUG: we have not *, checking role in read-only for user:'.$user;
 656                $checks=$this->checkUserAccess($user, $activityId, true);
 657              }
 658  
 659            }
 660          }
 661        }
 662      }
 663      //$this->error[] = 'DEBUG: final check:'.$checks;
 664      return $checks;
 665    }
 666  
 667    //! Return avaible actions for a given user on a given activity and a given instance assuming he already have access to it.
 668    /*!
 669    * To be able to decide this function needs all the parameters, use the GUI object equivalent function if you want less parameters.
 670    * @public
 671    * @param $user is the user id
 672    * @param $instanceId is the instance id
 673    * @param $activityId is the activity id
 674    * @param $readonly has to be true if the user has only read-only level access with his role mappings
 675    * @param $pId is the process id
 676    * @param $actType is the activity type
 677    * @param $actInteractive is 'y' or 'n' and is the activity interactivity
 678    * @param $actAutorouted is 'y' or 'n' and is the activity routage 
 679    * @param $actStatus is the activity status ('running' or 'completed')
 680    * @param $instanceOwner is the instance owner id
 681    * @param $instanceStatus is the instance status ('running', 'completed', 'aborted' or 'exception')
 682    * @param $currentUser is the actual instance/activity user id or '*'.
 683    * @param $viewactivity is false if the process has no view activity, else it's the id of the view activity
 684    * @return an array of this form:
 685    *     array('action name' => 'action description')
 686    * 'actions names' are: 'grab', 'release', 'run', 'send', 'view', 'viewrun', 'exception', 'resume', 'monitor'
 687    * note that for the 'viewrun' key value is an array with a 'lang' key for the translation and a 'link' key for the view activity id
 688    * Some config values can change theses rules but basically here they are:
 689    *    * 'grab'    : be the user of this activity. User has access to it and instance status is ok.
 690    *    * 'release'    : let * be the user of this activity. Must be the actual user or the owner of the instance.
 691    *    * 'run'    : run an associated form. This activity is interactive, user has access, instance status is ok.
 692    *    * 'send'    : send this instance, activity was non-autorouted and he has access and status is ok.
 693    *    * 'view'    : view the instance, activity ok, always avaible if no view activity on the process except for start or standalone act.
 694    *    * 'viewrun'    : view the instance in a view activity, need role on view activity, always avaible except for start or standalone act.
 695    *    * 'abort'    : abort an instance, ok when we are the user
 696    *    * 'exception' : set the instance status to exception, need to be the user 
 697    *    * 'resume'    : back to running when instance status was exception, need to be the user
 698    *    * 'monitor' : admin the instance, for special rights users
 699    * 'actions description' are translated explanations like 'release access to this activity'
 700    * This function will as well load process configuration which could have some impact on the rights. 
 701    * Theses config data will be cached during the existence of this WfSecurity object.
 702    * WARNING: this is a snapshot, the engine give you a snaphsot of the rights a user have on an instance-activity
 703    * at a given time, this is not meaning theses rights will still be there when the user launch the action.
 704    * You should absolutely use the GUI Object or runtime to execute theses actions (except monitor) and they could be rejected.
 705    * WARNING: we do not check the user access rights. If you launch this function for a list of instances obtained via a 
 706    * GUI object theses access rights are allready checked (for example we do not check your readonly parameter is true).
 707    * In fact this function is GUI oriented, it is not granting rights
 708    */
 709    function getUserActions($user, $instanceId, $activityId, $readonly, $pId, $actType, $actInteractive, $actAutorouted, $actStatus, $instanceOwner, $instanceStatus, $currentUser, $view_activity)
 710    {
 711      $result= array();//returned array
 712      $stopflow=false;//true when the instance is in a state where the flow musn't advance
 713                      //ie: we can't send or run it
 714      $deathflow=false;//true when the instance is in a state where the flow will never advance anymore
 715                      //ie: we can't send, run, grab, release, exception or resume it
 716      $associated_instance=true;//false when no instance is associated with the activity
 717                      // ie: we cannot send, grab, release, exception, resume or view the instance but we can run
 718                      // it covers standalone activities and start activities not completed
 719      $_run  = false;
 720      $_send = false;
 721      $_grab = false;
 722      $_release = false;
 723      $_abort = false;
 724      $_view = false;
 725      $_viewrun = false;
 726      $_resume = false;
 727      $_exception = false;
 728      // this can be decided right now, it depends only on user rights
 729      $_monitor = galaxia_user_can_admin_instance($user);
 730  
 731      $this->loadConfigValues($pId);
 732  
 733      // check the instance status
 734      // 'completed' => no action except 'view'/'viewrun' or 'abort' or 'monitor'
 735      // 'aborted' =>  no action except 'view'/'viewrun' or 'monitor'
 736      // 'active' => ok first add 'exception'
 737      // 'exception' => first add 'resume', no 'run' or 'send' after
 738      if (!($view_activity))
 739      {
 740        $_view = true;
 741      }
 742      else
 743      {
 744        //we should have a 'viewrun' instead of a 'view' action, but maybe we do not have access on this view activity
 745        //this access right will be checked by gui_get_process_view_activity
 746        $_viewrun = true;
 747      }
 748      
 749      //on readonly mode things are simplier, no more rights
 750      if (!($readonly))
 751      {
 752        if ($instanceStatus == 'aborted')
 753        {
 754          $deathflow=true;
 755        }
 756        else
 757        {
 758          // first check ABORT
 759          if ( ($user==$currentUser) ||
 760               (($user==$instanceOwner)&&($this->processesConfig[$pId]['ownership_give_abort_right'])) ||
 761               ($this->processesConfig[$pId]['role_give_abort_right']))
 762          {// we are the assigned user 
 763           //OR we are the owner and it gives rights
 764           //OR we have the role and it gives rights
 765           $_abort =true;
 766          }
 767          // now handle resume and exception but before detect completed instances
 768          if ($instanceStatus == 'completed')
 769          {
 770            $deathflow=true;
 771          }
 772          else
 773          {
 774            if ($instanceStatus == 'exception')
 775            {
 776              $stopflow = true;
 777              if ( ($user==$currentUser) ||
 778                   (($user==$instanceOwner)&&($this->processesConfig[$pId]['ownership_give_exception_right'])) ||
 779                   ($this->processesConfig[$pId]['role_give_exception_right']))
 780              {// we are the assigned user OR we are the owner and it gives rights
 781                $_resume = true;
 782              }
 783            }
 784            elseif ($instanceStatus == 'active')
 785            {
 786              //handle rules about ownership
 787              if ( ($user==$currentUser) ||
 788                  (($user==$instanceOwner)&&($this->processesConfig[$pId]['ownership_give_exception_right'])) ||
 789                  ($this->processesConfig[$pId]['role_give_exception_right']))
 790              {// we are the assigned user OR we are the owner and it gives rights
 791                $_exception = true;
 792              }
 793            }
 794          }
 795        }
 796    
 797        //now we check the activity
 798        // start (only uncompleted) and standalone activities have no instance associated.
 799        // If we are not in a 'stop' or 'death' flow we can check interactivity
 800        // interactive -> run
 801        // not interactive -> send (except for 'standalone')
 802        // if we are not in a 'death flow' we can add grab and release actions
 803        if ( ($actType=='standalone') || (($actType=='start') && (!($actStatus=='completed'))) )
 804        {
 805          $associated_instance=false;
 806          // there's no instance to view in fact
 807          $_view = false;
 808          $_viewrun = false;
 809        }
 810        if (($actInteractive=='y') && (!($deathflow)))
 811        {
 812          if ($associated_instance)
 813          {
 814              if ($currentUser=='*')
 815              {
 816                $_grab = true;
 817              }
 818              else
 819              {
 820                if ( ($user==$currentUser) ||
 821                   (($user==$instanceOwner)&&($this->processesConfig[$pId]['ownership_give_release_right'])) ||
 822                   ($this->processesConfig[$pId]['role_give_release_right']))
 823                {// we are the assigned user 
 824                 //OR we are the owner and it gives rights
 825                 //OR we have the role and it gives rights
 826                  $_release = true;
 827                }
 828              }
 829          }
 830          if (($actStatus=='running') && !($stopflow) && !($deathflow))
 831          {
 832            if (($currentUser=='*') || ($currentUser==$user))
 833            {
 834              $_run = true;
 835            }
 836          }
 837        }
 838        //for non autorouted activities we'll have to send, useless on standalone but usefull for start
 839        //activities which can be sended if completed and of course for all other activities
 840        if ($actAutorouted=='n')
 841        {
 842          if ($associated_instance)
 843          {
 844            if (($actStatus=='completed') && !($stopflow) && !($deathflow))
 845            {
 846              $_send = true;
 847            }
 848          }
 849        }
 850      }//end if !$readonly
 851  
 852      //build final array
 853      if ($_run) $result['run']=tra('Execute this activity');
 854      if ($_send) $result['send']=tra('Send this instance to the next activity');
 855      if ($_grab) $result['grab']=tra('Assign me this activity');
 856      if ($_release) $result['release']=tra('Release access to this activity');
 857      if ($_abort) $result['abort']=tra('Abort this instance');
 858      if ($_view) $result['view']=tra('View this instance');
 859      if ($_viewrun) $result['viewrun']= array('lang' => tra('View this instance'), 'link' => $view_activity);
 860      if ($_resume) $result['resume']=tra('Resume this exception instance');
 861      if ($_exception) $result['exception']=tra('Exception this instance');
 862      if ($_monitor) $result['monitor']=tra('Monitor this instance');
 863      return $result;
 864    }
 865  
 866    
 867  }
 868  
 869  
 870  ?>


Généré le : Sun Feb 25 17:20:01 2007 par Balluche grâce à PHPXref 0.7