source: sandbox/workflow/branches/609/inc/engine/src/common/WfSecurity.php @ 2323

Revision 2323, 39.5 KB checked in by pedroerp, 14 years ago (diff)

Ticket #609 - Removendo 'require_once's desnecessários.

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