3 * FusionForge role-based access control
5 * Copyright 2004, GForge, LLC
6 * Copyright 2009-2010, Roland Mas
7 * Copyright 2012-2013, Franck Villaume - TrivialDev
8 * Copyright 2013, French Ministry of National Education
9 * http://fusionforge.org
11 * This file is part of FusionForge. FusionForge is free software;
12 * you can redistribute it and/or modify it under the terms of the
13 * GNU General Public License as published by the Free Software
14 * Foundation; either version 2 of the Licence, or (at your option)
17 * FusionForge is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 * GNU General Public License for more details.
22 * You should have received a copy of the GNU General Public License along
23 * with FusionForge; if not, write to the Free Software Foundation, Inc.,
24 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
27 require 'PFO-RBAC.interface.php';
29 // Code shared between classes
32 * TODO: RBAC::BaseRole Enter description here ...
35 abstract class BaseRole extends Error {
37 * TODO: Enter description here ...
42 * TODO: Enter description here ...
47 * TODO: Enter description here ...
53 // var $setting_array;
55 public function BaseRole() {
56 // TODO: document these tables
57 // $gfcommon.'include/rbac_texts.php' may provide some hints...
58 $this->role_values = array(
59 'forge_admin' => array(0, 1),
60 'approve_projects' => array(0, 1),
61 'approve_news' => array(0, 1),
62 'forge_stats' => array(0, 1, 2),
64 'project_read' => array(0, 1),
65 'project_admin' => array(0, 1),
67 'tracker_admin' => array(0, 1),
68 'pm_admin' => array(0, 1),
69 'forum_admin' => array(0, 1),
71 'tracker' => array(0, 1, 9, 11, 13, 15),
72 'pm' => array(0, 1, 3, 5, 7),
73 'forum' => array(0, 1, 2, 3, 4),
75 'new_tracker' => array(0, 1, 9, 11, 13, 15),
76 'new_pm' => array(0, 1, 3, 5, 7),
77 'new_forum' => array(0, 1, 2, 3, 4),
79 'scm' => array (0, 1, 2),
80 'docman' => array (0, 1, 2, 3, 4),
81 'frs' => array (0, 1, 2, 3),
86 $this->global_settings = array(
87 'forge_admin', // “God mode”: all actions allowed
88 'approve_projects', // Ability to approve pending projects
89 'approve_news', // Ability to approve news bits to the forge front page
93 // TODO: document these (Project-related permissions ?)
94 $this->defaults = array(
95 'Admin' => array( 'project_admin'=> 1,
102 'tracker_admin' => 1,
107 'Senior Developer' => array( 'project_read' => 1,
113 'tracker_admin' => 1,
118 'Junior Developer' => array( 'project_read' => 1,
126 'Doc Writer' => array( 'project_read' => 1,
133 'Support Tech' => array( 'project_read' => 1,
137 'tracker_admin' => 1,
145 public function getUsers() {
148 public function hasUser($user) {
149 throw new Exception ("Not implemented") ;
151 function hasGlobalPermission($section, $action = NULL) {
152 return $this->hasPermission ($section, -1, $action) ;
154 public function getSettings() {
155 throw new Exception ("Not implemented") ;
157 public function setSettings($data) {
158 throw new Exception ("Not implemented") ;
160 public function delete () {
161 throw new Exception ("Not implemented") ;
165 * getLinkedProjects - List of projects referencing that role
167 * Includes the home project (for roles that have one)
169 * @return array Array of Group objects
171 public function getLinkedProjects() {
174 $hp = $this->getHomeProject();
176 $ids[] = $hp->getID();
179 $res = db_query_params('SELECT group_id FROM role_project_refs WHERE role_id=$1',
180 array($this->getID()));
182 while ($arr = db_fetch_array ($res)) {
183 $ids[] = $arr['group_id'];
187 return group_get_objects(array_unique($ids));
190 function linkProject ($project) { // From the PFO spec
192 $hp = $this->getHomeProject();
193 if ($hp != NULL && $hp->getID() == $project->getID()) {
194 $this->setError(_("Cannot link to home project"));
198 $res = db_query_params('SELECT group_id FROM role_project_refs WHERE role_id=$1 AND group_id=$2',
199 array($this->getID(),
202 if (db_numrows($res)) {
205 $res = db_query_params('INSERT INTO role_project_refs (role_id, group_id) VALUES ($1, $2)',
206 array($this->getID(),
208 if (!$res || db_affected_rows($res) < 1) {
209 $this->setError('linkProject('.$project->getID().') '.db_error());
213 $this->normalizeData();
215 foreach ($this->getUsers() as $u) {
216 if (!$SYS->sysCheckCreateUser($u->getID())) {
217 $this->setError($SYS->getErrorMessage());
225 function unlinkProject($project) { // From the PFO spec
227 $hp = $this->getHomeProject();
228 if ($hp != NULL && $hp->getID() == $project->getID()) {
229 $this->setError (_("Cannot unlink from home project"));
233 $res = db_query_params('DELETE FROM role_project_refs WHERE role_id=$1 AND group_id=$2',
234 array($this->getID(),
237 $this->setError('unlinkProject('.$project->getID().') '.db_error());
241 $this->removeObsoleteSettings ();
243 foreach ($this->getUsers() as $u) {
244 if (!$SYS->sysCheckCreateUser($u->getID())) {
245 $this->setError($SYS->getErrorMessage());
254 * fetchData - May need to refresh database fields.
256 * If an update occurred and you need to access the updated info.
258 * @param int $role_id
259 * @return bool success
261 function fetchData($role_id) {
262 unset($this->data_array);
263 unset($this->setting_array);
264 unset($this->perms_array);
266 $res = db_query_params('SELECT * FROM pfo_role WHERE role_id=$1',
268 if (!$res || db_numrows($res) < 1) {
269 $this->setError('BaseRole::fetchData()::'.db_error());
272 $this->data_array = db_fetch_array($res);
273 if ($this->data_array['is_public'] == 't') {
274 $this->data_array['is_public'] = true;
276 $this->data_array['is_public'] = false;
278 $res = db_query_params('SELECT section_name, ref_id, perm_val FROM pfo_role_setting WHERE role_id=$1',
281 $this->setError('BaseRole::fetchData()::'.db_error());
284 // TODO: document perms_array
285 $this->perms_array=array();
286 while ($arr = db_fetch_array($res)) {
287 $this->perms_array[$arr['section_name']][$arr['ref_id']] = $arr['perm_val'];
293 function setSetting ($section, $reference, $value) {
294 $cur = $this->getSettingRaw($section, $reference);
295 if (($value == $cur) && ($cur != NULL)) {
299 $role_id = $this->getID () ;
301 db_query_params ('DELETE FROM pfo_role_setting WHERE role_id=$1 AND section_name=$2 AND ref_id=$3',
306 db_query_params ('INSERT INTO pfo_role_setting (role_id, section_name, ref_id, perm_val) VALUES ($1, $2, $3, $4)',
311 $this->perms_array[$section][$reference] = $value;
314 function getSettingsForProject ($project) {
316 $group_id = $project->getID();
318 $sections = array ('project_read', 'project_admin', 'frs', 'scm', 'docman', 'tracker_admin', 'new_tracker') ;
319 foreach ($sections as $section) {
320 $result[$section][$group_id] = $this->getVal ($section, $group_id) ;
323 $atf = new ArtifactTypeFactory ($project) ;
324 if (!$atf->isError()) {
325 $tids = $atf->getAllArtifactTypeIds () ;
326 foreach ($tids as $tid) {
327 $result['tracker'][$tid] = $this->getVal ('tracker', $tid) ;
330 array_push ($sections,'tracker');
332 $sections_forum = array('forum_admin', 'new_forum');
333 foreach ($sections_forum as $section_forum) {
334 $result[$section_forum][$group_id] = $this->getVal ($section_forum, $group_id) ;
336 $sections = array_merge($sections, $sections_forum);
338 $ff = new ForumFactory ($project) ;
339 if (!$ff->isError()) {
340 $fids = $ff->getAllForumIdsWithNews () ;
341 foreach ($fids as $fid) {
342 $result['forum'][$fid] = $this->getVal ('forum', $fid) ;
345 array_push ($sections,'forum');
347 $sections_pm = array('pm_admin', 'new_pm');
348 foreach ($sections_pm as $section_pm) {
349 $result[$section_pm][$group_id] = $this->getVal ($section_pm, $group_id) ;
351 $sections = array_merge($sections, $sections_pm);
353 $pgf = new ProjectGroupFactory ($project) ;
354 if (!$pgf->isError()) {
355 $pgids = $pgf->getAllProjectGroupIds () ;
356 foreach ($pgids as $pgid) {
357 $result['pm'][$pgid] = $this->getVal ('pm', $pgid) ;
360 array_push ($sections,'pm') ;
362 // Add settings not yet listed so far (probably plugins)
363 // Currently handled:
364 // - global settings (ignored here)
365 // - project-wide settings (core and plugins)
366 // - settings for multiple-instance tools coming from the core (trackers/pm/forums)
368 // - settings for multiple-instance tools from plugins
369 foreach (array_keys ($this->perms_array) as $section) {
370 if (!in_array ($section, $sections)) {
371 if (!in_array ($section, $this->global_settings)) {
372 $result[$section][$group_id] = $this->getVal ($section, $group_id) ;
381 * TODO: Enter description here ...
384 function getGlobalSettings () {
387 $sections = array ('forge_admin', 'forge_stats', 'approve_projects', 'approve_news') ;
388 foreach ($sections as $section) {
389 $result[$section][-1] = $this->getVal($section, -1) ;
391 // Add settings not yet listed so far (probably plugins)
392 foreach (array_keys ($this->perms_array) as $section) {
393 if (!in_array ($section, $sections)) {
394 if (in_array ($section, $this->global_settings)) {
395 $result[$section][-1] = $this->getVal ($section, -1) ;
404 * TODO: Enter description here ...
405 * @param unknown_type $section
406 * @param unknown_type $reference
407 * @return number|boolean
409 function getSetting($section, $reference) {
410 $value = $this->getSettingRaw($section, $reference);
411 if ($value == NULL) {
424 case 'approve_projects':
426 if ($this->hasGlobalPermission('forge_admin')) {
433 if ($this->hasGlobalPermission('forge_admin')) {
439 case 'project_admin':
440 if ($this->hasGlobalPermission('forge_admin')) {
447 if ($this->hasPermission('project_admin', $reference)) {
452 case 'tracker_admin':
455 if ($this->hasPermission('project_admin', $reference)) {
457 } elseif (!$this->hasPermission('project_read', $reference)) {
464 if ($this->hasPermission('project_admin', $reference)) {
466 } elseif (!$this->hasPermission('project_read', $reference)) {
473 if ($this->hasPermission('project_admin', $reference)) {
475 } elseif (!$this->hasPermission('project_read', $reference)) {
482 if ($this->hasPermission('project_admin', $reference)) {
484 } elseif (!$this->hasPermission('project_read', $reference)) {
491 if ($this->hasPermission('forum_admin', forum_get_groupid($reference))) {
493 } elseif (!$this->hasPermission('project_read', forum_get_groupid($reference))) {
499 if ($this->hasPermission('forum_admin', $reference)) {
501 } elseif (!$this->hasPermission('project_read', $reference)) {
508 if ($this->hasPermission('tracker_admin', artifacttype_get_groupid($reference))) {
510 } elseif (!$this->hasPermission('project_read', artifacttype_get_groupid($reference))) {
516 if ($this->hasPermission('tracker_admin', $reference)) {
518 } elseif (!$this->hasPermission('project_read', $reference)) {
525 if ($this->hasPermission('pm_admin', projectgroup_get_groupid($reference))) {
527 } elseif (!$this->hasPermission('project_read', projectgroup_get_groupid($reference))) {
533 if ($this->hasPermission('pm_admin', $reference)) {
535 } elseif (!$this->hasPermission('project_read', $reference)) {
541 $hook_params = array ();
542 $hook_params['role'] = $this ;
543 $hook_params['section'] = $section ;
544 $hook_params['reference'] = $reference ;
545 $hook_params['value'] = $value ;
546 $hook_params['result'] = NULL ;
547 plugin_hook_by_reference ("role_get_setting", $hook_params);
548 return $hook_params['result'] ;
553 function getSettingRaw($section, $reference) {
554 if (isset ($this->perms_array[$section][$reference])) {
555 return $this->perms_array[$section][$reference] ;
560 * getVal - get a value out of the array of settings for this role.
562 * @param string $section The name of the role.
563 * @param integer $ref_id The ref_id (ex: group_artifact_id, group_forum_id) for this item.
564 * @return integer The value of this item.
566 function getVal($section, $ref_id) {
570 return $this->getSetting($section, $ref_id) ;
574 * &getRoleVals - get all the values and language text strings for this section.
576 * @param string $section
577 * @return array Assoc array of values for this section.
579 function &getRoleVals($section) {
580 global $role_vals, $rbac_permission_names;
581 setup_rbac_strings();
584 // Optimization - save array so it is only built once per page view
586 if (!isset($role_vals[$section])) {
588 for ($i=0; $i<count($this->role_values[$section]); $i++) {
590 // Build an associative array of these key values + localized description
592 $role_vals[$section][$this->role_values[$section][$i]] =
593 util_ifsetor($rbac_permission_names["$section".$this->role_values[$section][$i]],
594 _('UNKNOWN (internal error, report bug to FusionForge)'));
597 return $role_vals[$section];
600 function hasPermission($section, $reference, $action = NULL) {
603 $value = $this->getSetting ($section, $reference) ;
610 case 'approve_projects':
612 case 'project_admin':
614 case 'tracker_admin':
617 return ($value >= 1) ;
623 return ($value >= 1) ;
626 return ($value >= 2) ;
634 return ($value >= 1) ;
637 return ($value >= 2) ;
645 return ($value >= 1) ;
648 return ($value >= 2) ;
651 return ($value >= 3) ;
654 return ($value >= 4) ;
662 return ($value >= 1) ;
665 return ($value >= 2) ;
668 return ($value >= 3) ;
677 return ($value >= 1) ;
680 return ($value >= 2) ;
682 case 'unmoderated_post':
683 return ($value >= 3) ;
686 return ($value >= 4) ;
695 return (($value & 1) != 0) ;
698 return (($value & 2) != 0) ;
701 return (($value & 4) != 0) ;
704 return (($value & 8) != 0) ;
707 * bit4 (value & 16) is reserved
708 * for tracker item vote from Evolvis
717 return (($value & 1) != 0) ;
720 return (($value & 2) != 0) ;
723 return (($value & 4) != 0) ;
728 $hook_params = array ();
729 $hook_params['section'] = $section ;
730 $hook_params['reference'] = $reference ;
731 $hook_params['action'] = $action ;
732 $hook_params['value'] = $value ;
733 $hook_params['result'] = false ;
734 plugin_hook_by_reference ("role_has_permission", $hook_params);
735 return $hook_params['result'] ;
741 * update - update a role in the database.
743 * @param string $role_name The name of the role.
744 * @param array $data A multi-dimensional array of data in this format: $data['section_name']['ref_id']=$val
745 * @param boolean $check_perms Perform permission checking
746 * @return boolean True on success or false on failure.
748 function update($role_name,$data,$check_perms=true) {
751 if ($this->getHomeProject() == NULL) {
752 if (!forge_check_global_perm ('forge_admin')) {
753 $this->setPermissionDeniedError();
756 } elseif (!forge_check_perm ('project_admin', $this->getHomeProject()->getID())) {
757 $this->setPermissionDeniedError();
764 $role_id = $this->getID () ;
766 if ($role_name != $this->getName()) {
767 $this->setName($role_name) ;
770 $res = db_query_params ('DELETE FROM pfo_role_setting WHERE role_id=$1',
773 $res = db_prepare ('INSERT INTO pfo_role_setting (role_id, section_name, ref_id, perm_val) VALUES ($1, $2, $3, $4)',
774 'insert_into_pfo_role_setting');
776 foreach ($data as $sect => $refs) {
777 foreach ($refs as $refid => $value) {
778 $res = db_execute ('insert_into_pfo_role_setting',
786 $res = db_unprepare ('insert_into_pfo_role_setting');
788 $hook_params = array ();
789 $hook_params['role'] =& $this;
790 $hook_params['role_id'] = $this->getID();
791 $hook_params['data'] = $data;
792 plugin_hook ("role_update", $hook_params);
795 $this->fetchData($this->getID());
797 foreach ($this->getUsers() as $u) {
798 if (!$SYS->sysCheckCreateUser($u->getID())) {
799 $this->setError($SYS->getErrorMessage());
807 function getDisplayableName($group = NULL) {
808 if ($this->getHomeProject() == NULL) {
809 return sprintf (_('%s (global role)'),
811 } elseif ($group == NULL
812 || $this->getHomeProject()->getID() != $group->getID()) {
813 return sprintf (_('%s (in project %s)'),
815 $this->getHomeProject()->getPublicName()) ;
817 return $this->getName () ;
821 function removeObsoleteSettings () {
824 // Remove obsolete project-wide settings
825 $sections = array ('project_read', 'project_admin', 'frs', 'scm', 'docman', 'tracker_admin', 'new_tracker', 'forum_admin', 'new_forum', 'pm_admin', 'new_pm') ;
826 db_query_params ('DELETE FROM pfo_role_setting where role_id=$1 AND section_name=ANY($2) and ref_id NOT IN (SELECT home_group_id FROM pfo_role WHERE role_id=$1 AND home_group_id IS NOT NULL UNION SELECT group_id from role_project_refs WHERE role_id=$1)',
827 array ($this->getID(),
828 db_string_array_to_any_clause($sections))) ;
830 // Remove obsolete settings for multiple-instance tools
831 db_query_params ('DELETE FROM pfo_role_setting where role_id=$1 AND section_name=$2 and ref_id NOT IN (SELECT group_artifact_id FROM artifact_group_list WHERE group_id IN (SELECT home_group_id FROM pfo_role WHERE role_id=$1 AND home_group_id IS NOT NULL UNION SELECT group_id from role_project_refs WHERE role_id=$1))',
832 array ($this->getID(),
834 db_query_params ('DELETE FROM pfo_role_setting where role_id=$1 AND section_name=$2 and ref_id NOT IN (SELECT group_project_id FROM project_group_list WHERE group_id IN (SELECT home_group_id FROM pfo_role WHERE role_id=$1 AND home_group_id IS NOT NULL UNION SELECT group_id from role_project_refs WHERE role_id=$1))',
835 array ($this->getID(),
837 db_query_params ('DELETE FROM pfo_role_setting where role_id=$1 AND section_name=$2 and ref_id NOT IN (SELECT group_forum_id FROM forum_group_list WHERE group_id IN (SELECT home_group_id FROM pfo_role WHERE role_id=$1 AND home_group_id IS NOT NULL UNION SELECT group_id from role_project_refs WHERE role_id=$1))',
838 array ($this->getID(),
842 $this->fetchData($this->getID());
846 function normalizePermsForSection (&$new_pa, $section, $refid) {
847 if (array_key_exists ($section, $this->perms_array)
848 && array_key_exists ($refid, $this->perms_array[$section])) {
849 $new_pa[$section][$refid] = $this->perms_array[$section][$refid] ;
850 } elseif (array_key_exists ($this->data_array['role_name'], $this->defaults)
851 && array_key_exists ($section, $this->defaults[$this->data_array['role_name']])) {
852 $new_pa[$section][$refid] = $this->defaults[$this->data_array['role_name']][$section] ;
854 $new_pa[$section][$refid] = 0 ;
859 function normalizeData () { // From the PFO spec
860 $this->removeObsoleteSettings () ;
862 $this->fetchData ($this->getID()) ;
864 $projects = $this->getLinkedProjects() ;
867 // Add missing settings
868 // ...project-wide settings
869 $arr = array ('project_read', 'project_admin', 'frs', 'scm', 'docman', 'tracker_admin', 'new_tracker', 'forum_admin', 'new_forum', 'pm_admin', 'new_pm') ;
870 foreach ($projects as $p) {
871 foreach ($arr as $section) {
872 $this->normalizePermsForSection ($new_pa, $section, $p->getID()) ;
875 $this->normalizePermsForSection ($new_pa, 'forge_admin', -1) ;
876 $this->normalizePermsForSection ($new_pa, 'approve_projects', -1) ;
877 $this->normalizePermsForSection ($new_pa, 'approve_news', -1) ;
878 $this->normalizePermsForSection ($new_pa, 'forge_stats', -1) ;
880 $hook_params = array ();
881 $hook_params['role'] =& $this;
882 $hook_params['new_pa'] =& $new_pa ;
883 plugin_hook ("role_normalize", $hook_params);
885 // ...tracker-related settings
886 $new_pa['tracker'] = array () ;
887 foreach ($projects as $p) {
888 if (!$p->usesTracker()) {
891 $atf = new ArtifactTypeFactory ($p) ;
892 if (!$atf->isError()) {
893 $trackerids = $atf->getAllArtifactTypeIds () ;
894 foreach ($trackerids as $tid) {
895 if (array_key_exists ('tracker', $this->perms_array)
896 && array_key_exists ($tid, $this->perms_array['tracker']) ) {
897 $new_pa['tracker'][$tid] = $this->perms_array['tracker'][$tid] ;
898 } elseif (array_key_exists ('new_tracker', $this->perms_array)
899 && array_key_exists ($p->getID(), $this->perms_array['new_tracker']) ) {
900 $new_pa['tracker'][$tid] = $new_pa['new_tracker'][$p->getID()] ;
906 // ...forum-related settings
907 $new_pa['forum'] = array () ;
908 foreach ($projects as $p) {
909 if (!$p->usesForum()) {
912 $ff = new ForumFactory ($p) ;
913 if (!$ff->isError()) {
914 $fids = $ff->getAllForumIdsWithNews () ;
915 foreach ($fids as $fid) {
916 if (array_key_exists ('forum', $this->perms_array)
917 && array_key_exists ($fid, $this->perms_array['forum']) ) {
918 $new_pa['forum'][$fid] = $this->perms_array['forum'][$fid] ;
919 } elseif (array_key_exists ('new_forum', $this->perms_array)
920 && array_key_exists ($p->getID(), $this->perms_array['new_forum']) ) {
921 $new_pa['forum'][$fid] = $new_pa['new_forum'][$p->getID()] ;
927 // ...pm-related settings
928 $new_pa['pm'] = array () ;
929 foreach ($projects as $p) {
933 $pgf = new ProjectGroupFactory ($p) ;
934 if (!$pgf->isError()) {
935 $pgids = $pgf->getAllProjectGroupIds () ;
936 foreach ($pgids as $gid) {
937 if (array_key_exists ('pm', $this->perms_array)
938 && array_key_exists ($gid, $this->perms_array['pm']) ) {
939 $new_pa['pm'][$gid] = $this->perms_array['pm'][$gid] ;
940 } elseif (array_key_exists ('new_pm', $this->perms_array)
941 && array_key_exists ($p->getID(), $this->perms_array['new_pm']) ) {
942 $new_pa['pm'][$gid] = $new_pa['new_pm'][$p->getID()] ;
949 $this->update ($this->getName(), $new_pa, false) ;
957 * TODO: RBAC::RoleExplicit Enter description here ...
960 abstract class RoleExplicit extends BaseRole implements PFO_RoleExplicit {
961 public function addUsers($users) {
965 foreach ($users as $user) {
966 $ids[] = $user->getID();
969 $already_there = array();
970 $res = db_query_params('SELECT user_id FROM pfo_user_role WHERE user_id=ANY($1) AND role_id=$2',
971 array(db_int_array_to_any_clause($ids), $this->getID()));
975 while ($arr = db_fetch_array($res)) {
976 $already_there[] = $arr['user_id'] ;
979 foreach ($ids as $id) {
980 if (!in_array ($id, $already_there)) {
981 $res = db_query_params ('INSERT INTO pfo_user_role (user_id, role_id) VALUES ($1, $2)',
990 foreach ($this->getLinkedProjects() as $p) {
991 foreach ($ids as $uid) {
992 if (!$SYS->sysGroupCheckUser($p->getID(),$uid)) {
1001 public function addUser ($user) {
1002 if (!$this->addUsers (array ($user))) {
1005 $hook_params['user'] = $user;
1006 $hook_params['role'] = $this;
1007 plugin_hook ("role_adduser", $hook_params);
1012 public function removeUsers($users) {
1016 foreach ($users as $user) {
1017 $ids[] = $user->getID() ;
1020 $already_there = array () ;
1021 $res = db_query_params ('DELETE FROM pfo_user_role WHERE user_id=ANY($1) AND role_id=$2',
1022 array (db_int_array_to_any_clause($ids), $this->getID())) ;
1024 foreach ($this->getLinkedProjects() as $p) {
1025 foreach ($ids as $uid) {
1026 $SYS->sysGroupCheckUser($p->getID(),$uid) ;
1033 public function removeUser ($user) {
1034 if(!$this->removeUsers (array ($user))){
1037 $hook_params['user'] = $user;
1038 $hook_params['role'] = $this;
1039 plugin_hook ("role_removeuser", $hook_params);
1044 public function getUsers() {
1045 $result = array () ;
1046 $res = db_query_params ('SELECT user_id FROM pfo_user_role WHERE role_id=$1',
1047 array ($this->getID())) ;
1048 while ($arr = db_fetch_array($res)) {
1049 $result[] = user_get_object ($arr['user_id']) ;
1055 public function hasUser($user) {
1056 $res = db_query_params ('SELECT user_id FROM pfo_user_role WHERE user_id=$1 AND role_id=$2',
1057 array ($user->getID(), $this->getID())) ;
1058 if ($res && db_numrows($res)) {
1065 function getID() { // From the PFO spec
1066 return $this->data_array['role_id'];
1069 function getName() { // From the PFO spec
1070 return $this->data_array['role_name'];
1074 class RoleAnonymous extends BaseRole implements PFO_RoleAnonymous {
1075 // This role is implemented as a singleton
1076 private static $_instance ;
1078 public static function getInstance() {
1079 if (isset(self::$_instance)) {
1080 return self::$_instance ;
1084 self::$_instance = new $c ;
1086 $res = db_query_params ('SELECT r.role_id FROM pfo_role r, pfo_role_class c WHERE r.role_class = c.class_id AND c.class_name = $1',
1087 array ('PFO_RoleAnonymous')) ;
1088 if (!$res || !db_numrows($res)) {
1089 throw new Exception ("No PFO_RoleAnonymous role in the database") ;
1091 self::$_instance->_role_id = db_result ($res, 0, 'role_id') ;
1093 $hook_params = array ();
1094 $hook_params['role'] =& self::$_instance;
1095 plugin_hook ("role_get", $hook_params);
1097 self::$_instance->fetchData (self::$_instance->_role_id) ;
1099 return self::$_instance ;
1102 public function getID () {
1103 return $this->_role_id ;
1105 public function isPublic () {
1108 public function setPublic ($flag) {
1109 throw new Exception ("Can't setPublic() on RoleAnonymous") ;
1111 public function getHomeProject () {
1114 public function getName () {
1115 return _('Anonymous/not logged in') ;
1117 public function setName ($name) {
1118 throw new Exception ("Can't setName() on RoleAnonymous") ;
1122 class RoleLoggedIn extends BaseRole implements PFO_RoleLoggedIn {
1123 // This role is implemented as a singleton
1124 private static $_instance ;
1126 public static function getInstance() {
1127 if (isset(self::$_instance)) {
1128 return self::$_instance ;
1132 self::$_instance = new $c ;
1134 $res = db_query_params ('SELECT r.role_id FROM pfo_role r, pfo_role_class c WHERE r.role_class = c.class_id AND c.class_name = $1',
1135 array ('PFO_RoleLoggedIn')) ;
1136 if (!$res || !db_numrows($res)) {
1137 throw new Exception ("No PFO_RoleLoggedIn role in the database") ;
1139 self::$_instance->_role_id = db_result ($res, 0, 'role_id') ;
1141 $hook_params = array ();
1142 $hook_params['role'] =& self::$_instance;
1143 plugin_hook ("role_get", $hook_params);
1145 self::$_instance->fetchData (self::$_instance->_role_id) ;
1147 return self::$_instance ;
1150 public function getID () {
1151 return $this->_role_id ;
1153 public function isPublic () {
1156 public function setPublic ($flag) {
1157 throw new Exception ("Can't setPublic() on RoleLoggedIn") ;
1159 public function getHomeProject () {
1162 public function getName () {
1163 return _('Any user logged in') ;
1165 public function setName ($name) {
1166 throw new Exception ("Can't setName() on RoleLoggedIn") ;
1170 abstract class RoleUnion extends BaseRole implements PFO_RoleUnion {
1171 public function addRole ($role) {
1172 throw new Exception ("Not implemented") ;
1174 public function removeRole ($role) {
1175 throw new Exception ("Not implemented") ;
1180 * TODO: Enter description here ...
1183 class RoleComparator {
1184 var $criterion = 'composite' ;
1185 var $reference_project = NULL ;
1187 function Compare ($a, $b) {
1188 switch ($this->criterion) {
1190 return strcoll ($a->getName(), $b->getName()) ;
1193 $aid = $a->getID() ;
1194 $bid = $b->getID() ;
1198 return ($a < $b) ? -1 : 1;
1202 if ($this->reference_project == NULL) {
1203 return $this->CompareNoRef ($a, $b) ;
1205 $rpid = $this->reference_project->getID () ;
1206 $ap = $a->getHomeProject() ;
1207 $bp = $b->getHomeProject() ;
1208 $a_is_local = ($ap != NULL && $ap->getID() == $rpid) ; // Local
1209 $b_is_local = ($bp != NULL && $bp->getID() == $rpid) ;
1211 if ($a_is_local && !$b_is_local) {
1213 } elseif (!$a_is_local && $b_is_local) {
1216 return $this->CompareNoRef ($a, $b) ;
1221 * TODO: Enter description here ...
1226 function CompareNoRef ($a, $b) {
1227 $ap = $a->getHomeProject() ;
1228 $bp = $b->getHomeProject() ;
1229 if ($ap == NULL && $bp != NULL) {
1231 } elseif ($ap != NULL && $bp == NULL) {
1233 } elseif ($ap == NULL && $bp == NULL) {
1234 $tmp = strcoll ($a->getName(), $b->getName()) ;
1237 $projcmp = new ProjectComparator () ;
1238 $projcmp->criterion = 'name' ;
1239 $tmp = $projcmp->Compare ($ap, $bp) ;
1240 if ($tmp) { /* Different projects, sort accordingly */
1243 return strcoll ($a->getName(), $b->getName()) ;
1248 function sortRoleList (&$list, $relative_to = NULL, $criterion='composite') {
1249 $cmp = new RoleComparator () ;
1250 $cmp->criterion = $criterion ;
1251 $cmp->reference_project = $relative_to ;
1253 return usort ($list, array ($cmp, 'Compare')) ;
1258 // c-file-style: "bsd"