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

Revision 2311, 39.8 KB checked in by pedroerp, 14 years ago (diff)

Ticket #609 - Migrando instanciação das classes da engine para a factory.

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