3 * FusionForge role-based access control
5 * Copyright 2004, GForge, LLC
6 * Copyright 2009-2010, Roland Mas
7 * http://fusionforge.org
9 * This file is part of FusionForge. FusionForge is free software;
10 * you can redistribute it and/or modify it under the terms of the
11 * GNU General Public License as published by the Free Software
12 * Foundation; either version 2 of the Licence, or (at your option)
15 * FusionForge is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU General Public License for more details.
20 * You should have received a copy of the GNU General Public License along
21 * with FusionForge; if not, write to the Free Software Foundation, Inc.,
22 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
25 require "PFO-RBAC.interface.php";
27 define ('USE_PFO_RBAC', true);
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, 3, 5, 7),
72 'pm' => array(0, 1, 3, 5, 7),
73 'forum' => array(0, 1, 2, 3, 4),
75 'new_tracker' => array(0, 1, 3, 5, 7),
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),
83 'webcal' => array(0, 1, 2),
87 $this->global_settings = array(
88 'forge_admin', // “God mode”: all actions allowed
89 'approve_projects', // Ability to approve pending projects
90 'approve_news', // Ability to approve news bits to the forge front page
94 // TODO: document these (Project-related permissions ?)
95 $this->defaults = array(
96 'Admin' => array( 'project_admin'=> 1,
103 'tracker_admin' => 1,
109 'Senior Developer' => array( 'project_read' => 1,
115 'tracker_admin' => 1,
121 'Junior Developer' => array( 'project_read' => 1,
130 'Doc Writer' => array( 'project_read' => 1,
138 'Support Tech' => array( 'project_read' => 1,
142 'tracker_admin' => 1,
151 public function getUsers() {
154 public function hasUser($user) {
155 throw new Exception ("Not implemented") ;
157 function hasGlobalPermission($section, $action = NULL) {
158 return $this->hasPermission ($section, -1, $action) ;
160 public function getSettings() {
161 throw new Exception ("Not implemented") ;
163 public function setSettings($data) {
164 throw new Exception ("Not implemented") ;
166 public function delete () {
167 throw new Exception ("Not implemented") ;
171 * getLinkedProjects - List of projects referencing that role
173 * Includes the home project (for roles that have one)
175 * @return array Array of Group objects
177 public function getLinkedProjects() {
180 $hp = $this->getHomeProject();
182 $ids[] = $hp->getID();
185 $res = db_query_params('SELECT group_id FROM role_project_refs WHERE role_id=$1',
186 array($this->getID()));
188 while ($arr = db_fetch_array ($res)) {
189 $ids[] = $arr['group_id'];
193 return group_get_objects(array_unique($ids));
196 function linkProject ($project) { // From the PFO spec
197 $hp = $this->getHomeProject();
198 if ($hp != NULL && $hp->getID() == $project->getID()) {
199 $this->setError(_("Can't link to home project"));
203 $res = db_query_params('SELECT group_id FROM role_project_refs WHERE role_id=$1 AND group_id=$2',
204 array($this->getID(),
207 if (db_numrows($res)) {
210 $res = db_query_params('INSERT INTO role_project_refs (role_id, group_id) VALUES ($1, $2)',
211 array($this->getID(),
213 if (!$res || db_affected_rows($res) < 1) {
214 $this->setError('linkProject('.$project->getID().') '.db_error());
221 function unlinkProject($project) { // From the PFO spec
222 $hp = $this->getHomeProject();
223 if ($hp != NULL && $hp->getID() == $project->getID()) {
224 $this->setError (_("Can't unlink from home project"));
228 $res = db_query_params('DELETE FROM role_project_refs WHERE role_id=$1 AND group_id=$2',
229 array($this->getID(),
232 $this->setError('unlinkProject('.$project->getID().') '.db_error());
236 $this->removeObsoleteSettings ();
242 * fetchData - May need to refresh database fields.
244 * If an update occurred and you need to access the updated info.
246 * @return boolean success;
248 function fetchData($role_id) {
249 unset($this->data_array);
250 unset($this->setting_array);
251 unset($this->perms_array);
253 $res = db_query_params('SELECT * FROM pfo_role WHERE role_id=$1',
255 if (!$res || db_numrows($res) < 1) {
256 $this->setError('BaseRole::fetchData()::'.db_error());
259 $this->data_array = db_fetch_array($res);
260 if ($this->data_array['is_public'] == 't') {
261 $this->data_array['is_public'] = true;
263 $this->data_array['is_public'] = false;
265 $res = db_query_params('SELECT section_name, ref_id, perm_val FROM pfo_role_setting WHERE role_id=$1',
268 $this->setError('BaseRole::fetchData()::'.db_error());
271 // TODO: document perms_array
272 $this->perms_array=array();
273 while ($arr = db_fetch_array($res)) {
274 $this->perms_array[$arr['section_name']][$arr['ref_id']] = $arr['perm_val'];
280 function setSetting ($section, $reference, $value) {
281 $cur = $this->getSettingRaw($section, $reference);
282 if (($value == $cur) && ($cur != NULL)) {
286 $role_id = $this->getID () ;
288 $res = db_query_params ('DELETE FROM pfo_role_setting WHERE role_id=$1 AND section_name=$2 AND ref_id=$3',
293 $res = db_query_params ('INSERT INTO pfo_role_setting (role_id, section_name, ref_id, perm_val) VALUES ($1, $2, $3, $4)',
300 function getSettingsForProject ($project) {
302 $group_id = $project->getID() ;
304 $sections = array ('project_read', 'project_admin', 'frs', 'scm', 'docman', 'tracker_admin', 'new_tracker', 'forum_admin', 'new_forum', 'pm_admin', 'new_pm') ;
305 foreach ($sections as $section) {
306 $result[$section][$group_id] = $this->getVal ($section, $group_id) ;
309 $atf = new ArtifactTypeFactory ($project) ;
310 $tids = $atf->getAllArtifactTypeIds () ;
311 foreach ($tids as $tid) {
312 $result['tracker'][$tid] = $this->getVal ('tracker', $tid) ;
314 $sections[] = 'tracker' ;
316 $ff = new ForumFactory ($project) ;
317 $fids = $ff->getAllForumIds () ;
318 foreach ($fids as $fid) {
319 $result['forum'][$fid] = $this->getVal ('forum', $fid) ;
321 $sections[] = 'forum' ;
323 $pgf = new ProjectGroupFactory ($project) ;
324 $pgids = $pgf->getAllProjectGroupIds () ;
325 foreach ($pgids as $pgid) {
326 $result['pm'][$pgid] = $this->getVal ('pm', $pgid) ;
331 // Add settings not yet listed so far (probably plugins)
332 // Currently handled:
333 // - global settings (ignored here)
334 // - project-wide settings (core and plugins)
335 // - settings for multiple-instance tools coming from the core (trackers/pm/forums)
337 // - settings for multiple-instance tools from plugins
338 foreach (array_keys ($this->perms_array) as $section) {
339 if (!in_array ($section, $sections)) {
340 if (!in_array ($section, $this->global_settings)) {
341 $result[$section][$group_id] = $this->getVal ($section, $group_id) ;
350 * TODO: Enter description here ...
353 function getGlobalSettings () {
356 $sections = array ('forge_admin', 'forge_stats', 'approve_projects', 'approve_news') ;
357 foreach ($sections as $section) {
358 $result[$section][-1] = $this->getVal($section, -1) ;
360 // Add settings not yet listed so far (probably plugins)
361 foreach (array_keys ($this->perms_array) as $section) {
362 if (!in_array ($section, $sections)) {
363 if (in_array ($section, $this->global_settings)) {
364 $result[$section][-1] = $this->getVal ($section, -1) ;
373 * TODO: Enter description here ...
374 * @param unknown_type $section
375 * @param unknown_type $reference
376 * @return number|boolean
378 function getSetting($section, $reference) {
379 $r = $this->getSettingRaw($section, $reference);
386 function getSettingRaw($section, $reference) {
387 if (isset ($this->perms_array[$section][$reference])) {
388 $value = $this->perms_array[$section][$reference] ;
401 case 'approve_projects':
403 if ($this->hasGlobalPermission('forge_admin')) {
410 if ($this->hasGlobalPermission('forge_admin')) {
416 case 'project_admin':
417 if ($this->hasGlobalPermission('forge_admin')) {
424 case 'tracker_admin':
427 if ($this->hasPermission('project_admin', $reference)) {
434 if ($this->hasPermission('project_admin', $reference)) {
441 if ($this->hasPermission('project_admin', $reference)) {
448 if ($this->hasPermission('project_admin', $reference)) {
455 if ($this->hasPermission('forum_admin', forum_get_groupid($reference))) {
461 if ($this->hasPermission('forum_admin', $reference)) {
468 if ($this->hasPermission('tracker_admin', artifacttype_get_groupid($reference))) {
474 if ($this->hasPermission('tracker_admin', $reference)) {
481 if ($this->hasPermission('pm_admin', projectgroup_get_groupid($reference))) {
487 if ($this->hasPermission('pm_admin', $reference)) {
493 $hook_params = array ();
494 $hook_params['role'] = $this ;
495 $hook_params['section'] = $section ;
496 $hook_params['reference'] = $reference ;
497 $hook_params['value'] = $value ;
498 $hook_params['result'] = NULL ;
499 plugin_hook_by_reference ("role_get_setting", $hook_params);
500 return $hook_params['result'] ;
506 * getVal - get a value out of the array of settings for this role.
508 * @param string The name of the role.
509 * @param integer The ref_id (ex: group_artifact_id, group_forum_id) for this item.
510 * @return integer The value of this item.
512 function getVal($section, $ref_id) {
513 global $role_default_array;
517 return $this->getSetting($section, $ref_id) ;
521 * &getRoleVals - get all the values and language text strings for this section.
523 * @return array Assoc array of values for this section.
525 function &getRoleVals($section) {
526 global $role_vals, $rbac_permission_names;
527 setup_rbac_strings () ;
530 // Optimization - save array so it is only built once per page view
532 if (!isset($role_vals[$section])) {
534 for ($i=0; $i<count($this->role_values[$section]); $i++) {
536 // Build an associative array of these key values + localized description
538 $role_vals[$section][$this->role_values[$section][$i]]=$rbac_permission_names["$section".$this->role_values[$section][$i]];
541 return $role_vals[$section];
544 function hasPermission($section, $reference, $action = NULL) {
547 $value = $this->getSetting ($section, $reference) ;
554 case 'approve_projects':
556 case 'project_admin':
558 case 'tracker_admin':
561 return ($value >= 1) ;
567 return ($value >= 1) ;
570 return ($value >= 2) ;
578 return ($value >= 1) ;
581 return ($value >= 2) ;
589 return ($value >= 1) ;
592 return ($value >= 2) ;
595 return ($value >= 3) ;
598 return ($value >= 4) ;
606 return ($value >= 1) ;
609 return ($value >= 2) ;
612 return ($value >= 3) ;
621 return ($value >= 1) ;
624 return ($value >= 2) ;
626 case 'unmoderated_post':
627 return ($value >= 3) ;
630 return ($value >= 4) ;
639 return (($value & 1) != 0) ;
642 return (($value & 2) != 0) ;
645 return (($value & 4) != 0) ;
654 return (($value & 1) != 0) ;
657 return (($value & 2) != 0) ;
660 return (($value & 4) != 0) ;
665 $hook_params = array ();
666 $hook_params['section'] = $section ;
667 $hook_params['reference'] = $reference ;
668 $hook_params['action'] = $action ;
669 $hook_params['value'] = $value ;
670 $hook_params['result'] = false ;
671 plugin_hook_by_reference ("role_has_permission", $hook_params);
672 return $hook_params['result'] ;
678 * update - update a role in the database.
680 * @param string The name of the role.
681 * @param array A multi-dimensional array of data in this format: $data['section_name']['ref_id']=$val
682 * @param boolean Perform permission checking
683 * @return boolean True on success or false on failure.
685 function update($role_name,$data,$check_perms=true) {
688 if ($this->getHomeProject() == NULL) {
689 if (!forge_check_global_perm ('forge_admin')) {
690 $this->setPermissionDeniedError();
693 } elseif (!forge_check_perm ('project_admin', $this->getHomeProject()->getID())) {
694 $this->setPermissionDeniedError();
702 if ($role_name != $this->getName()) {
703 $this->setName($role_name) ;
706 foreach ($data as $sect => $refs) {
707 foreach ($refs as $refid => $value) {
708 $this->setSetting ($sect, $refid, $value) ;
709 if ($sect == 'scm') {
710 foreach ($this->getUsers() as $u) {
711 if (!$SYS->sysGroupCheckUser($refid,$u->getID())) {
712 $this->setError($SYS->getErrorMessage());
721 $hook_params = array ();
722 $hook_params['role'] =& $this;
723 $hook_params['role_id'] = $this->getID();
724 $hook_params['data'] = $data;
725 plugin_hook ("role_update", $hook_params);
729 $this->fetchData($this->getID());
733 function getDisplayableName($group = NULL) {
734 if ($this->getHomeProject() == NULL) {
735 return sprintf (_('%s (global role)'),
737 } elseif ($group == NULL
738 || $this->getHomeProject()->getID() != $group->getID()) {
739 return sprintf (_('%s (in project %s)'),
741 $this->getHomeProject()->getPublicName()) ;
743 return $this->getName () ;
747 function removeObsoleteSettings () {
750 // Remove obsolete project-wide settings
751 $sections = array ('project_read', 'project_admin', 'frs', 'scm', 'docman', 'tracker_admin', 'new_tracker', 'forum_admin', 'new_forum', 'pm_admin', 'new_pm', 'webcal') ;
752 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)',
753 array ($this->getID(),
754 db_string_array_to_any_clause($sections))) ;
757 // Remove obsolete settings for multiple-instance tools
758 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))',
759 array ($this->getID(),
761 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))',
762 array ($this->getID(),
764 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))',
765 array ($this->getID(),
772 function normalizeDataForSection (&$new_sa, $section) {
773 if (array_key_exists ($section, $this->setting_array)) {
774 $new_sa[$section][0] = $this->setting_array[$section][0] ;
775 } elseif (array_key_exists ($this->data_array['role_name'], $this->defaults)
776 && array_key_exists ($section, $this->defaults[$this->data_array['role_name']])) {
777 $new_sa[$section][0] = $this->defaults[$this->data_array['role_name']][$section] ;
779 $new_sa[$section][0] = 0 ;
784 function normalizePermsForSection (&$new_pa, $section, $refid) {
785 if (array_key_exists ($section, $this->perms_array)
786 && array_key_exists ($refid, $this->perms_array[$section])) {
787 $new_pa[$section][$refid] = $this->perms_array[$section][$refid] ;
788 } elseif (array_key_exists ($this->data_array['role_name'], $this->defaults)
789 && array_key_exists ($section, $this->defaults[$this->data_array['role_name']])) {
790 $new_pa[$section][$refid] = $this->defaults[$this->data_array['role_name']][$section] ;
792 $new_pa[$section][$refid] = 0 ;
797 function normalizeData () { // From the PFO spec
798 $this->removeObsoleteSettings () ;
800 $this->fetchData ($this->getID()) ;
802 $projects = $this->getLinkedProjects() ;
806 // Add missing settings
807 // ...project-wide settings
808 $arr = array ('project_read', 'project_admin', 'frs', 'scm', 'docman', 'tracker_admin', 'new_tracker', 'forum_admin', 'new_forum', 'pm_admin', 'new_pm', 'webcal') ;
809 foreach ($projects as $p) {
810 foreach ($arr as $section) {
811 $this->normalizePermsForSection ($new_pa, $section, $p->getID()) ;
814 $this->normalizePermsForSection ($new_pa, 'forge_admin', -1) ;
815 $this->normalizePermsForSection ($new_pa, 'approve_projects', -1) ;
816 $this->normalizePermsForSection ($new_pa, 'approve_news', -1) ;
817 $this->normalizePermsForSection ($new_pa, 'forge_stats', -1) ;
819 $hook_params = array ();
820 $hook_params['role'] =& $this;
821 $hook_params['new_sa'] =& $new_sa ;
822 $hook_params['new_pa'] =& $new_pa ;
823 plugin_hook ("role_normalize", $hook_params);
825 // ...tracker-related settings
826 $new_sa['tracker'] = array () ;
827 $new_pa['tracker'] = array () ;
828 foreach ($projects as $p) {
829 $atf = new ArtifactTypeFactory ($p) ;
830 $trackerids = $atf->getAllArtifactTypeIds () ;
831 foreach ($trackerids as $tid) {
832 if (array_key_exists ('tracker', $this->perms_array)
833 && array_key_exists ($tid, $this->perms_array['tracker']) ) {
834 $new_pa['tracker'][$tid] = $this->perms_array['tracker'][$tid] ;
835 } elseif (array_key_exists ('new_tracker', $this->perms_array)
836 && array_key_exists ($p->getID(), $this->perms_array['new_tracker']) ) {
837 $new_pa['tracker'][$tid] = $new_pa['new_tracker'][$p->getID()] ;
842 // ...forum-related settings
843 $new_sa['forum'] = array () ;
844 $new_pa['forum'] = array () ;
845 foreach ($projects as $p) {
846 $ff = new ForumFactory ($p) ;
847 $fids = $ff->getAllForumIds () ;
848 foreach ($fids as $fid) {
849 if (array_key_exists ('forum', $this->perms_array)
850 && array_key_exists ($fid, $this->perms_array['forum']) ) {
851 $new_pa['forum'][$fid] = $this->perms_array['forum'][$fid] ;
852 } elseif (array_key_exists ('new_forum', $this->perms_array)
853 && array_key_exists ($p->getID(), $this->perms_array['new_forum']) ) {
854 $new_pa['forum'][$fid] = $new_pa['new_forum'][$p->getID()] ;
859 // ...pm-related settings
860 $new_sa['pm'] = array () ;
861 $new_pa['pm'] = array () ;
862 foreach ($projects as $p) {
863 $pgf = new ProjectGroupFactory ($p) ;
864 $pgids = $pgf->getAllProjectGroupIds () ;
865 foreach ($pgids as $gid) {
866 if (array_key_exists ('pm', $this->perms_array)
867 && array_key_exists ($gid, $this->perms_array['pm']) ) {
868 $new_pa['pm'][$gid] = $this->perms_array['pm'][$gid] ;
869 } elseif (array_key_exists ('new_pm', $this->perms_array)
870 && array_key_exists ($p->getID(), $this->perms_array['new_pm']) ) {
871 $new_pa['pm'][$gid] = $new_pa['new_pm'][$p->getID()] ;
877 $this->update ($this->getName(), $new_pa, false) ;
885 * TODO: RBAC::RoleExplicit Enter description here ...
888 abstract class RoleExplicit extends BaseRole implements PFO_RoleExplicit {
889 public function addUsers($users) {
893 foreach ($users as $user) {
894 $ids[] = $user->getID();
897 $already_there = array();
898 $res = db_query_params('SELECT user_id FROM pfo_user_role WHERE user_id=ANY($1) AND role_id=$2',
899 array(db_int_array_to_any_clause($ids), $this->getID()));
903 while ($arr = db_fetch_array($res)) {
904 $already_there[] = $arr['user_id'] ;
907 foreach ($ids as $id) {
908 if (!in_array ($id, $already_there)) {
909 $res = db_query_params ('INSERT INTO pfo_user_role (user_id, role_id) VALUES ($1, $2)',
918 foreach ($this->getLinkedProjects() as $p) {
919 foreach ($ids as $uid) {
920 if (!$SYS->sysGroupCheckUser($p->getID(),$uid)) {
929 public function addUser ($user) {
930 if (!$this->addUsers (array ($user))) {
933 $hook_params['user'] = $user;
934 $hook_params['role'] = $this;
935 plugin_hook ("role_adduser", $hook_params);
940 public function removeUsers($users) {
944 foreach ($users as $user) {
945 $ids[] = $user->getID() ;
948 $already_there = array () ;
949 $res = db_query_params ('DELETE FROM pfo_user_role WHERE user_id=ANY($1) AND role_id=$2',
950 array (db_int_array_to_any_clause($ids), $this->getID())) ;
952 foreach ($this->getLinkedProjects() as $p) {
953 foreach ($ids as $uid) {
954 $SYS->sysGroupCheckUser($p->getID(),$uid) ;
961 public function removeUser ($user) {
962 if(!$this->removeUsers (array ($user))){
965 $hook_params['user'] = $user;
966 $hook_params['role'] = $this;
967 plugin_hook ("role_removeuser", $hook_params);
972 public function getUsers() {
974 $res = db_query_params ('SELECT user_id FROM pfo_user_role WHERE role_id=$1',
975 array ($this->getID())) ;
976 while ($arr = db_fetch_array($res)) {
977 $result[] = user_get_object ($arr['user_id']) ;
983 public function hasUser($user) {
984 $res = db_query_params ('SELECT user_id FROM pfo_user_role WHERE user_id=$1 AND role_id=$2',
985 array ($user->getID(), $this->getID())) ;
986 if ($res && db_numrows($res)) {
993 function getID() { // From the PFO spec
994 return $this->data_array['role_id'];
997 function getName() { // From the PFO spec
998 return $this->data_array['role_name'];
1002 class RoleAnonymous extends BaseRole implements PFO_RoleAnonymous {
1003 // This role is implemented as a singleton
1004 private static $_instance ;
1006 public static function getInstance() {
1007 if (isset(self::$_instance)) {
1008 return self::$_instance ;
1012 self::$_instance = new $c ;
1014 $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',
1015 array ('PFO_RoleAnonymous')) ;
1016 if (!$res || !db_numrows($res)) {
1017 throw new Exception ("No PFO_RoleAnonymous role in the database") ;
1019 self::$_instance->_role_id = db_result ($res, 0, 'role_id') ;
1021 $hook_params = array ();
1022 $hook_params['role'] =& self::$_instance;
1023 plugin_hook ("role_get", $hook_params);
1025 self::$_instance->fetchData (self::$_instance->_role_id) ;
1027 return self::$_instance ;
1030 public function getID () {
1031 return $this->_role_id ;
1033 public function isPublic () {
1036 public function setPublic ($flag) {
1037 throw new Exception ("Can't setPublic() on RoleAnonymous") ;
1039 public function getHomeProject () {
1042 public function getName () {
1043 return _('Anonymous/not logged in') ;
1045 public function setName ($name) {
1046 throw new Exception ("Can't setName() on RoleAnonymous") ;
1050 class RoleLoggedIn extends BaseRole implements PFO_RoleLoggedIn {
1051 // This role is implemented as a singleton
1052 private static $_instance ;
1054 public static function getInstance() {
1055 if (isset(self::$_instance)) {
1056 return self::$_instance ;
1060 self::$_instance = new $c ;
1062 $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',
1063 array ('PFO_RoleLoggedIn')) ;
1064 if (!$res || !db_numrows($res)) {
1065 throw new Exception ("No PFO_RoleLoggedIn role in the database") ;
1067 self::$_instance->_role_id = db_result ($res, 0, 'role_id') ;
1069 $hook_params = array ();
1070 $hook_params['role'] =& self::$_instance;
1071 plugin_hook ("role_get", $hook_params);
1073 self::$_instance->fetchData (self::$_instance->_role_id) ;
1075 return self::$_instance ;
1078 public function getID () {
1079 return $this->_role_id ;
1081 public function isPublic () {
1084 public function setPublic ($flag) {
1085 throw new Exception ("Can't setPublic() on RoleLoggedIn") ;
1087 public function getHomeProject () {
1090 public function getName () {
1091 return _('Any user logged in') ;
1093 public function setName ($name) {
1094 throw new Exception ("Can't setName() on RoleLoggedIn") ;
1098 abstract class RoleUnion extends BaseRole implements PFO_RoleUnion {
1099 public function addRole ($role) {
1100 throw new Exception ("Not implemented") ;
1102 public function removeRole ($role) {
1103 throw new Exception ("Not implemented") ;
1108 * TODO: Enter description here ...
1111 class RoleComparator {
1112 var $criterion = 'composite' ;
1113 var $reference_project = NULL ;
1115 function Compare ($a, $b) {
1116 switch ($this->criterion) {
1118 return strcoll ($a->getName(), $b->getName()) ;
1121 $aid = $a->getID() ;
1122 $bid = $b->getID() ;
1126 return ($a < $b) ? -1 : 1;
1130 if ($this->reference_project == NULL) {
1131 return $this->CompareNoRef ($a, $b) ;
1133 $rpid = $this->reference_project->getID () ;
1134 $ap = $a->getHomeProject() ;
1135 $bp = $b->getHomeProject() ;
1136 $a_is_local = ($ap != NULL && $ap->getID() == $rpid) ; // Local
1137 $b_is_local = ($bp != NULL && $bp->getID() == $rpid) ;
1139 if ($a_is_local && !$b_is_local) {
1141 } elseif (!$a_is_local && $b_is_local) {
1144 return $this->CompareNoRef ($a, $b) ;
1149 * TODO: Enter description here ...
1154 function CompareNoRef ($a, $b) {
1155 $ap = $a->getHomeProject() ;
1156 $bp = $b->getHomeProject() ;
1157 if ($ap == NULL && $bp != NULL) {
1159 } elseif ($ap != NULL && $bp == NULL) {
1161 } elseif ($ap == NULL && $bp == NULL) {
1162 $tmp = strcoll ($a->getName(), $b->getName()) ;
1165 $projcmp = new ProjectComparator () ;
1166 $projcmp->criterion = 'name' ;
1167 $tmp = $projcmp->Compare ($ap, $bp) ;
1168 if ($tmp) { /* Different projects, sort accordingly */
1171 return strcoll ($a->getName(), $b->getName()) ;
1176 function sortRoleList (&$list, $relative_to = NULL, $criterion='composite') {
1177 $cmp = new RoleComparator () ;
1178 $cmp->criterion = $criterion ;
1179 $cmp->reference_project = $relative_to ;
1181 return usort ($list, array ($cmp, 'Compare')) ;
1186 // c-file-style: "bsd"