5 * Copyright 2004, GForge, LLC
6 * Copyright 2009, Roland Mas
8 * This file is part of FusionForge.
10 * FusionForge is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License as published
12 * by the Free Software Foundation; either version 2 of the License,
13 * or (at your option) any later version.
15 * FusionForge is distributed in the hope that it will be useful, but
16 * WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18 * General Public License for more details.
20 * You should have received a copy of the GNU General Public License
21 * along with FusionForge; if not, write to the Free Software
22 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
26 require_once $gfcommon.'include/rbac_texts.php' ;
28 class Role extends Error {
34 var $role_values=array(
35 'projectadmin'=>array('0','A'),
36 'frs'=>array('0','1'),
37 'scm'=>array('-1','0','1'),
38 'docman'=>array('0','1'),
39 'forumadmin'=>array('0','2'),
40 'forum'=>array('-1','0','1','2'),
41 'newforum'=>array('-1','0','1','2'),
42 'trackeradmin'=>array('0','2'),
43 'tracker'=>array('-1','0','1','2','3'),
44 'newtracker'=>array('-1','0','1','2','3'),
45 'pmadmin'=>array('0','2'),
46 'pm'=>array('-1','0','1','2','3'),
47 'newpm'=>array('-1','0','1','2','3'),
48 'webcal'=>array('0','1','2'));
53 * Role($group,$id) - CONSTRUCTOR.
55 * @param object The Group object.
56 * @param int The role_id.
58 function Role ($Group,$role_id=false) {
59 # Initialize the default group settings
60 if ($GLOBALS['default_roles']) {
61 $this->defaults=$GLOBALS['default_roles'];
63 $this->defaults=array(
64 'Admin'=>array( 'projectadmin'=>'A', 'frs'=>'1', 'scm'=>'1', 'docman'=>'1', 'forumadmin'=>'2', 'forum'=>'2', 'newforum'=>'2', 'trackeradmin'=>'2', 'tracker'=>'2', 'newtracker'=>'2', 'pmadmin'=>'2', 'pm'=>'2', 'newpm'=>'2', 'webcal'=>'1' ),
65 'Senior Developer'=>array( 'projectadmin'=>'0', 'frs'=>'1', 'scm'=>'1', 'docman'=>'1', 'forumadmin'=>'2', 'forum'=>'2', 'newforum'=>'2', 'trackeradmin'=>'2', 'tracker'=>'2', 'newtracker'=>'2', 'pmadmin'=>'2', 'pm'=>'2', 'newpm'=>'2', 'webcal'=>'2' ),
66 'Junior Developer'=>array( 'projectadmin'=>'0', 'frs'=>'0', 'scm'=>'1', 'docman'=>'0', 'forumadmin'=>'0', 'forum'=>'1', 'newforum'=>'1', 'trackeradmin'=>'0', 'tracker'=>'1', 'newtracker'=>'1', 'pmadmin'=>'0', 'pm'=>'1', 'newpm'=>'1', 'webcal'=>'2' ),
67 'Doc Writer'=>array( 'projectadmin'=>'0', 'frs'=>'0', 'scm'=>'0', 'docman'=>'1', 'forumadmin'=>'0', 'forum'=>'1', 'newforum'=>'1', 'trackeradmin'=>'0', 'tracker'=>'0', 'newtracker'=>'0', 'pmadmin'=>'0', 'pm'=>'0' , 'newpm'=>'0' , 'webcal'=>'2'),
68 'Support Tech'=>array( 'projectadmin'=>'0', 'frs'=>'0', 'scm'=>'0', 'docman'=>'1', 'forumadmin'=>'0', 'forum'=>'1', 'newforum'=>'1', 'trackeradmin'=>'0', 'tracker'=>'2', 'newtracker'=>'2', 'pmadmin'=>'0', 'pm'=>'0' , 'newpm'=>'0' , 'webcal'=>'2')
74 if (!$Group || !is_object($Group) || $Group->isError()) {
75 $this->setError('Role::'.$Group->getErrorMessage());
78 $this->Group =& $Group;
80 $hook_params = array ();
81 $hook_params['role'] =& $this;
82 plugin_hook ("role_get", $hook_params);
86 //setting up an empty object
87 //probably going to call create()
90 return $this->fetchData($role_id);
94 * getID - get the ID of this role.
96 * @return integer The ID Number.
99 return $this->data_array['role_id'];
103 * getName - get the name of this role.
105 * @return string The name of this role.
108 return $this->data_array['role_name'];
112 * create - create a new role in the database.
114 * @param string The name of the role.
115 * @param array A multi-dimensional array of data in this format: $data['section_name']['ref_id']=$val
116 * @return integer The id on success or false on failure.
118 function create($role_name,$data) {
119 $perm =& $this->Group->getPermission( session_get_user() );
120 if (!$perm || !is_object($perm) || $perm->isError() || !$perm->isAdmin()) {
121 $this->setPermissionDeniedError();
125 // Check if role_name is not already used.
126 $res = db_query_params('SELECT role_name FROM role WHERE group_id=$1 AND role_name=$2',
127 array ($this->Group->getID(), htmlspecialchars($role_name)));
128 if (db_numrows($res)) {
129 $this->setError('Cannot create a role with this name (already used)');
134 $res = db_query_params ('INSERT INTO role (group_id, role_name) VALUES ($1, $2)',
135 array ($this->Group->getID(),
136 htmlspecialchars($role_name))) ;
138 $this->setError('create::'.db_error());
142 $role_id=db_insertid($res,'role','role_id');
144 $this->setError('create::db_insertid::'.db_error());
149 $arr1 = array_keys($data);
150 for ($i=0; $i<count($arr1); $i++) {
151 // array_values($Report->adjust_days)
152 $arr2 = array_keys($data[$arr1[$i]]);
153 for ($j=0; $j<count($arr2); $j++) {
154 $usection_name=$arr1[$i];
156 $uvalue=$data[$arr1[$i]][$arr2[$j]];
163 $res = db_query_params ('INSERT INTO role_setting (role_id,section_name,ref_id,value) VALUES ($1,$2,$3,$4)',
169 $this->setError('create::insertsetting::'.db_error());
175 if (!$this->fetchData($role_id)) {
183 function createDefault($name) {
184 //echo '<html><body><pre>';
186 //print_r($this->defaults);
187 $arr =& $this->defaults[$name];
188 $keys = array_keys($arr);
195 for ($i=0; $i<count($keys); $i++) {
197 if ($keys[$i] == 'forum') {
198 $res = db_query_params ('SELECT group_forum_id FROM forum_group_list WHERE group_id=$1',
199 array ($this->Group->getID())) ;
201 $this->setError('Error: Forum'.db_error());
204 for ($j=0; $j<db_numrows($res); $j++) {
205 $data[$keys[$i]][db_result($res,$j,'group_forum_id')]= $arr[$keys[$i]];
207 } elseif ($keys[$i] == 'pm') {
208 $res = db_query_params ('SELECT group_project_id FROM project_group_list WHERE group_id=$1',
209 array ($this->Group->getID())) ;
211 $this->setError('Error: TaskMgr'.db_error());
214 for ($j=0; $j<db_numrows($res); $j++) {
215 $data[$keys[$i]][db_result($res,$j,'group_project_id')]= $arr[$keys[$i]];
217 } elseif ($keys[$i] == 'tracker') {
218 $res = db_query_params ('SELECT group_artifact_id FROM artifact_group_list WHERE group_id=$1',
219 array ($this->Group->getID())) ;
221 $this->setError('Error: Tracker'.db_error());
224 for ($j=0; $j<db_numrows($res); $j++) {
225 $data[$keys[$i]][db_result($res,$j,'group_artifact_id')]= $arr[$keys[$i]];
228 $data[$keys[$i]][0]= $arr[$keys[$i]];
234 return $this->create($name,$data);
238 * fetchData - May need to refresh database fields.
240 * If an update occurred and you need to access the updated info.
242 * @return boolean success;
244 function fetchData($role_id) {
245 unset($this->data_array);
246 unset($this->setting_array);
247 $res = db_query_params ('SELECT * FROM role WHERE role_id=$1',
249 if (!$res || db_numrows($res) < 1) {
250 $this->setError('Role::fetchData()::'.db_error());
253 $this->data_array =& db_fetch_array($res);
254 $res = db_query_params ('SELECT * FROM role_setting WHERE role_id=$1',
257 $this->setError('Role::fetchData()::'.db_error());
260 $this->setting_array=array();
261 while ($arr =& db_fetch_array($res)) {
262 $this->setting_array[$arr['section_name']][$arr['ref_id']] = $arr['value'];
267 function normalizeData () {
269 $this->fetchData ($this->getID()) ;
273 // Add missing settings
274 // ...project-wide settings
275 $arr = array ('projectadmin', 'frs', 'scm', 'docman', 'forumadmin', 'trackeradmin', 'newtracker', 'pmadmin', 'newpm', 'webcal') ;
276 foreach ($arr as $section) {
277 if (array_key_exists ($section, $this->setting_array)) {
278 $new_sa[$section][0] = $this->setting_array[$section][0] ;
279 } elseif (array_key_exists ($this->data_array['role_name'], $this->defaults
280 && array_key_exists ($section, $this->defaults[$this->data_array['role_name']])) {
281 $new_sa[$section][0] = $this->defaults[$this->data_array['role_name']][$section] ;
283 $new_sa[$section][0] = 0 ;
287 // ...tracker-related settings
288 $new_sa['tracker'] = array () ;
289 $res = db_query_params ('SELECT group_artifact_id FROM artifact_group_list WHERE group_id=$1',
290 array ($this->Group->getID())) ;
292 $this->setError('Error: Tracker '.db_error());
295 for ($j=0; $j<db_numrows($res); $j++) {
296 $tid = db_result ($res,$j,'group_artifact_id') ;
297 if (array_key_exists ('tracker', $this->setting_array)
298 && array_key_exists ($tid, $this->setting_array['tracker']) ) {
299 $new_sa['tracker'][$tid] = $this->setting_array['tracker'][$tid] ;
301 $new_sa['tracker'][$tid] = $new_sa['newtracker'][0] ;
305 // ...forum-related settings
306 $new_sa['forum'] = array () ;
307 $res = db_query_params ('SELECT group_forum_id FROM forum_group_list WHERE group_id=$1',
308 array ($this->Group->getID())) ;
310 $this->setError('Error: Forum '.db_error());
313 for ($j=0; $j<db_numrows($res); $j++) {
314 $tid = db_result ($res,$j,'group_forum_id') ;
315 if (array_key_exists ('forum', $this->setting_array)
316 && array_key_exists ($tid, $this->setting_array['forum']) ) {
317 $new_sa['forum'][$tid] = $this->setting_array['forum'][$tid] ;
319 $new_sa['forum'][$tid] = $new_sa['newforum'][0] ;
323 // ...subproject-related settings
324 $new_sa['pm'] = array () ;
325 $res = db_query_params ('SELECT group_project_id FROM project_group_list WHERE group_id=$1',
326 array ($this->Group->getID())) ;
328 $this->setError('Error: Subproject '.db_error());
331 for ($j=0; $j<db_numrows($res); $j++) {
332 $tid = db_result ($res,$j,'group_project_id') ;
333 if (array_key_exists ('pm', $this->setting_array)
334 && array_key_exists ($tid, $this->setting_array['pm']) ) {
335 $new_sa['pm'][$tid] = $this->setting_array['pm'][$tid] ;
337 $new_sa['pm'][$tid] = $new_sa['newpm'][0] ;
341 // Delete extra settings
342 db_query_params ('DELETE FROM role_setting WHERE role_id=$1 AND section_name <> ALL ($2)',
343 array ($this->getID(),
344 db_string_array_to_any_clause (array_keys ($this->role_values)))) ;
345 db_query_params ('DELETE FROM role_setting WHERE role_id=$1 AND section_name = $2 AND ref_id <> ALL ($3)',
346 array ($this->getID(),
348 db_int_array_to_any_clause (array_keys ($new_sa['tracker'])))) ;
349 db_query_params ('DELETE FROM role_setting WHERE role_id=$1 AND section_name = $2 AND ref_id <> ALL ($3)',
350 array ($this->getID(),
352 db_int_array_to_any_clause (array_keys ($new_sa['forum'])))) ;
353 db_query_params ('DELETE FROM role_setting WHERE role_id=$1 AND section_name = $2 AND ref_id <> ALL ($3)',
354 array ($this->getID(),
356 db_int_array_to_any_clause (array_keys ($new_sa['pm'])))) ;
361 $this->update ($this->data_array['role_name'], $new_sa) ;
367 * &getRoleVals - get all the values and language text strings for this section.
369 * @return array Assoc array of values for this section.
371 function &getRoleVals($section) {
372 global $role_vals, $rbac_permission_names;
373 setup_rbac_strings () ;
376 // Optimization - save array so it is only built once per page view
378 if (!isset($role_vals[$section])) {
380 for ($i=0; $i<count($this->role_values[$section]); $i++) {
382 // Build an associative array of these key values + localized description
384 $role_vals[$section][$this->role_values[$section][$i]]=$rbac_permission_names["$section".$this->role_values[$section][$i]];
387 return $role_vals[$section];
391 * getVal - get a value out of the array of settings for this role.
393 * @param string The name of the role.
394 * @param integer The ref_id (ex: group_artifact_id, group_forum_id) for this item.
395 * @return integer The value of this item.
397 function getVal($section,$ref_id) {
398 global $role_default_array;
402 if (array_key_exists ($section, $this->setting_array)) {
403 return $this->setting_array[$section][$ref_id];
409 function setVal($section, $ref_id, $value) {
410 $this->setting_array[$section][$ref_id] = $value;
411 return $this->update( $this->getName(), $this->setting_array);
415 * delVal - delete a value out of the array of settings for this role.
417 * @param string The name of the role.
418 * @param integer The ref_id (ex: group_artifact_id, group_forum_id) for this item.
420 function delVal($section, $ref_id) {
421 unset($this->setting_array[$section][$ref_id]);
423 $sql = 'DELETE FROM role_setting
427 $res=db_query_params($sql, array($this->getID(), $section, $ref_id));
428 if (!$res || db_affected_rows($res) < 1) {
429 $this->setError('delVal($section, $ref_id)'.db_error());
436 * update - update a new in the database.
438 * @param string The name of the role.
439 * @param array A multi-dimensional array of data in this format: $data['section_name']['ref_id']=$val
440 * @return boolean True on success or false on failure.
442 function update($role_name,$data) {
445 // Cannot update role_id=1
447 if ($this->getID() == 1) {
448 $this->setError('Cannot Update Default Role');
451 $perm =& $this->Group->getPermission( session_get_user() );
452 if (!$perm || !is_object($perm) || $perm->isError() || !$perm->isAdmin()) {
453 $this->setPermissionDeniedError();
459 if ($this->getName() != stripslashes($role_name)) {
460 // Check if role_name is not already used.
461 $res = db_query_params('SELECT role_name FROM role WHERE group_id=$1 AND role_name=$2',
462 array ($this->Group->getID(), htmlspecialchars($role_name)));
463 if (db_numrows($res)) {
464 $this->setError('Cannot create a role with this name (already used)');
469 $res = db_query_params ('UPDATE role SET role_name=$1 WHERE group_id=$2 AND role_id=$3',
470 array (htmlspecialchars($role_name),
471 $this->Group->getID(),
473 if (!$res || db_affected_rows($res) < 1) {
474 $this->setError('update::name::'.db_error());
479 ////$data['section_name']['ref_id']=$val
480 $arr1 = array_keys($data);
481 for ($i=0; $i<count($arr1); $i++) {
482 // array_values($Report->adjust_days)
483 $arr2 = array_keys($data[$arr1[$i]]);
484 for ($j=0; $j<count($arr2); $j++) {
485 $usection_name=$arr1[$i];
487 $uvalue=$data[$usection_name][$uref_id];
495 // See if this setting changed. If so, then update it
497 // if ($this->getVal($usection_name,$uref_id) != $uvalue) {
498 $res = db_query_params ('UPDATE role_setting SET value=$1 WHERE role_id=$2 AND section_name=$3 AND ref_id=$4',
503 if (!$res || db_affected_rows($res) < 1) {
504 $res = db_query_params ('INSERT INTO role_setting (role_id, section_name, ref_id, value) VALUES ($1, $2, $3, $4)',
505 array ($this->getID(),
510 $this->setError('update::rolesettinginsert::'.db_error());
515 if ($usection_name == 'frs') {
516 $update_usergroup=true;
517 } elseif ($usection_name == 'scm') {
518 //$update_usergroup=true;
520 //iterate all users with this role
521 $res = db_query_params ('SELECT user_id FROM user_group WHERE role_id=$1',
522 array ($this->getID())) ;
523 for ($z=0; $z<db_numrows($res); $z++) {
525 //TODO - Shell should be separate flag
526 // If user acquired admin access to CVS,
527 // one to be given normal shell on CVS machine,
528 // else - restricted.
530 $cvs_flags=$data['scm'][0];
531 $res2 = db_query_params ('UPDATE user_group SET cvs_flags=$1 WHERE user_id=$2',
533 db_result($res,$z,'user_id')));
535 $this->setError('update::scm::'.db_error());
539 // I have doubt the following is usefull
540 // This is probably buggy if used
542 if (!$SYS->sysUserSetAttribute(db_result($res,$z,'user_id'),"debGforgeCvsShell","/bin/bash")) {
543 $this->setError($SYS->getErrorMessage());
548 if (!$SYS->sysUserSetAttribute(db_result($res,$z,'user_id'),"debGforgeCvsShell","/bin/cvssh")) {
549 $this->setError($SYS->getErrorMessage());
556 // If user acquired at least commit access to CVS,
557 // one to be promoted to CVS group, else, demoted.
560 if (!$SYS->sysGroupAddUser($this->Group->getID(),db_result($res,$z,'user_id'),1)) {
561 $this->setError($SYS->getErrorMessage());
566 if (!$SYS->sysGroupRemoveUser($this->Group->getID(),db_result($res,$z,'user_id'),1)) {
567 $this->setError($SYS->getErrorMessage());
575 } elseif ($usection_name == 'docman') {
576 $update_usergroup=true;
577 } elseif ($usection_name == 'forumadmin') {
578 $update_usergroup=true;
579 } elseif ($usection_name == 'trackeradmin') {
580 $update_usergroup=true;
581 } elseif ($usection_name == 'projectadmin') {
582 $update_usergroup=true;
583 } elseif ($usection_name == 'pmadmin') {
584 $update_usergroup=true;
589 // if ($update_usergroup) {
590 $keys = array ('forumadmin', 'pmadmin', 'trackeradmin', 'docman', 'scm', 'frs', 'projectadmin') ;
591 foreach ($keys as $k) {
592 if (!array_key_exists ($k, $data)) {
593 $data[$k] = array(0);
596 $res = db_query_params ('UPDATE user_group
605 array ($data['projectadmin'][0],
606 $data['forumadmin'][0],
611 $data['trackeradmin'][0],
614 $this->setError('::update::usergroup::'.db_error());
621 $hook_params = array ();
622 $hook_params['role'] =& $this;
623 $hook_params['role_id'] = $this->getID();
624 $hook_params['data'] = $data;
625 plugin_hook ("role_update", $hook_params);
629 $this->fetchData($this->getID());
633 function setUser($user_id) {
635 $perm =& $this->Group->getPermission( session_get_user() );
636 if (!$perm || !is_object($perm) || $perm->isError() || !$perm->isAdmin()) {
637 $this->setPermissionDeniedError();
644 // See if role is actually changing
646 $res = db_query_params ('SELECT role_id FROM user_group WHERE user_id=$1 AND group_id=$2',
648 $this->Group->getID())) ;
649 $old_roleid=db_result($res,0,0);
650 if ($this->getID() == $old_roleid) {
655 // Get the old role so we can compare new values to old
657 $oldrole= new Role($this->Group,$old_roleid);
658 if (!$oldrole || !is_object($oldrole) || $oldrole->isError()) {
659 $this->setError($oldrole->getErrorMessage());
665 // Iterate each setting to see if it's changing
666 // If not, no sense updating it
668 $arr1 = array_keys($this->setting_array);
669 for ($i=0; $i<count($arr1); $i++) {
670 // array_values($Report->adjust_days)
671 $arr2 = array_keys($this->setting_array[$arr1[$i]]);
672 for ($j=0; $j<count($arr2); $j++) {
673 $usection_name=$arr1[$i];
675 $uvalue=$this->setting_array[$usection_name][$uref_id];
683 // See if this setting changed. If so, then update it
685 // if (($this->getVal($usection_name,$uref_id) != $oldrole->getVal($usection_name,$uref_id)) || ($old_roleid == 1)) {
686 if ($usection_name == 'frs') {
687 $update_usergroup=true;
688 } elseif ($usection_name == 'scm') {
689 //TODO - Shell should be separate flag
690 // If user acquired admin access to CVS,
691 // one to be given normal shell on CVS machine,
692 // else - restricted.
694 $cvs_flags=$this->getVal('scm',0);
695 $res2 = db_query_params ('UPDATE user_group SET cvs_flags=$1 WHERE user_id=$2 AND group_id=$3',
698 $this->Group->getID())) ;
700 $this->setError('update::scm::'.db_error());
704 // I have doubt the following is usefull
705 // This is probably buggy if used
707 if (!$SYS->sysUserSetAttribute($user_id,"debGforgeCvsShell","/bin/bash")) {
708 $this->setError($SYS->getErrorMessage());
713 if (!$SYS->sysUserSetAttribute($user_id,"debGforgeCvsShell","/bin/cvssh")) {
714 $this->setError($SYS->getErrorMessage());
721 // If user acquired at least commit access to CVS,
722 // one to be promoted to CVS group, else, demoted.
723 // When we add the user we also check he has a shell as a group member
724 // When we remove we only check for SCM (cvs_only=1)
727 //echo "<h3>Role::setUser SYS->sysGroupAddUser(".$this->Group->getID().",$user_id,1)</h3>";
728 if (!$SYS->sysGroupAddUser($this->Group->getID(),$user_id,0)) {
729 $this->setError($SYS->getErrorMessage());
734 //echo "<h3>Role::setUser SYS->sysGroupRemoveUser(".$this->Group->getID().",$user_id,1)</h3>";
735 if (!$SYS->sysGroupRemoveUser($this->Group->getID(),$user_id,1)) {
736 $this->setError($SYS->getErrorMessage());
742 } elseif ($usection_name == 'docman') {
743 $update_usergroup=true;
744 } elseif ($usection_name == 'forumadmin') {
745 $update_usergroup=true;
746 } elseif ($usection_name == 'trackeradmin') {
747 $update_usergroup=true;
748 } elseif ($usection_name == 'projectadmin') {
749 $update_usergroup=true;
750 } elseif ($usection_name == 'pmadmin') {
751 $update_usergroup=true;
756 // if ($update_usergroup) {
757 $res = db_query_params ('UPDATE user_group
766 WHERE user_id=$9 AND group_id=$10',
767 array ($this->getVal('projectadmin',0),
768 $this->getVal('forumadmin',0),
769 $this->getVal('pmadmin',0),
770 $this->getVal('docman',0),
771 $this->getVal('scm',0),
772 $this->getVal('frs',0),
773 $this->getVal('trackeradmin',0),
776 $this->Group->getID()));
778 $this->setError('::update::usergroup::'.db_error());
785 $hook_params = array ();
786 $hook_params['role'] =& $this;
787 $hook_params['role_id'] = $this->getID();
788 $hook_params['user_id'] = $user_id;
789 plugin_hook ("role_setuser", $hook_params);
801 // c-file-style: "bsd"