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 define ('USE_PFO_RBAC', true);
31 // Code shared between classes
34 * TODO: RBAC::BaseRole Enter description here ...
37 abstract class BaseRole extends Error {
39 * TODO: Enter description here ...
44 * TODO: Enter description here ...
49 * TODO: Enter description here ...
55 // var $setting_array;
57 public function BaseRole() {
58 // TODO: document these tables
59 // $gfcommon.'include/rbac_texts.php' may provide some hints...
60 $this->role_values = array(
61 'forge_admin' => array(0, 1),
62 'approve_projects' => array(0, 1),
63 'approve_news' => array(0, 1),
64 'forge_stats' => array(0, 1, 2),
66 'project_read' => array(0, 1),
67 'project_admin' => array(0, 1),
69 'tracker_admin' => array(0, 1),
70 'pm_admin' => array(0, 1),
71 'forum_admin' => array(0, 1),
73 'tracker' => array(0, 1, 9, 11, 13, 15),
74 'pm' => array(0, 1, 3, 5, 7),
75 'forum' => array(0, 1, 2, 3, 4),
77 'new_tracker' => array(0, 1, 9, 11, 13, 15),
78 'new_pm' => array(0, 1, 3, 5, 7),
79 'new_forum' => array(0, 1, 2, 3, 4),
81 'scm' => array (0, 1, 2),
82 'docman' => array (0, 1, 2, 3, 4),
83 'frs' => array (0, 1, 2, 3),
88 $this->global_settings = array(
89 'forge_admin', // “God mode”: all actions allowed
90 'approve_projects', // Ability to approve pending projects
91 'approve_news', // Ability to approve news bits to the forge front page
95 // TODO: document these (Project-related permissions ?)
96 $this->defaults = array(
97 'Admin' => array( 'project_admin'=> 1,
104 'tracker_admin' => 1,
109 'Senior Developer' => array( 'project_read' => 1,
115 'tracker_admin' => 1,
120 'Junior Developer' => array( 'project_read' => 1,
128 'Doc Writer' => array( 'project_read' => 1,
135 'Support Tech' => array( 'project_read' => 1,
139 'tracker_admin' => 1,
147 public function getUsers() {
150 public function hasUser($user) {
151 throw new Exception ("Not implemented") ;
153 function hasGlobalPermission($section, $action = NULL) {
154 return $this->hasPermission ($section, -1, $action) ;
156 public function getSettings() {
157 throw new Exception ("Not implemented") ;
159 public function setSettings($data) {
160 throw new Exception ("Not implemented") ;
162 public function delete () {
163 throw new Exception ("Not implemented") ;
167 * getLinkedProjects - List of projects referencing that role
169 * Includes the home project (for roles that have one)
171 * @return array Array of Group objects
173 public function getLinkedProjects() {
176 $hp = $this->getHomeProject();
178 $ids[] = $hp->getID();
181 $res = db_query_params('SELECT group_id FROM role_project_refs WHERE role_id=$1',
182 array($this->getID()));
184 while ($arr = db_fetch_array ($res)) {
185 $ids[] = $arr['group_id'];
189 return group_get_objects(array_unique($ids));
192 function linkProject ($project) { // From the PFO spec
194 $hp = $this->getHomeProject();
195 if ($hp != NULL && $hp->getID() == $project->getID()) {
196 $this->setError(_("Can't link to home project"));
200 $res = db_query_params('SELECT group_id FROM role_project_refs WHERE role_id=$1 AND group_id=$2',
201 array($this->getID(),
204 if (db_numrows($res)) {
207 $res = db_query_params('INSERT INTO role_project_refs (role_id, group_id) VALUES ($1, $2)',
208 array($this->getID(),
210 if (!$res || db_affected_rows($res) < 1) {
211 $this->setError('linkProject('.$project->getID().') '.db_error());
215 $this->normalizeData();
217 foreach ($this->getUsers() as $u) {
218 if (!$SYS->sysCheckCreateUser($u->getID())) {
219 $this->setError($SYS->getErrorMessage());
227 function unlinkProject($project) { // From the PFO spec
229 $hp = $this->getHomeProject();
230 if ($hp != NULL && $hp->getID() == $project->getID()) {
231 $this->setError (_("Can't unlink from home project"));
235 $res = db_query_params('DELETE FROM role_project_refs WHERE role_id=$1 AND group_id=$2',
236 array($this->getID(),
239 $this->setError('unlinkProject('.$project->getID().') '.db_error());
243 $this->removeObsoleteSettings ();
245 foreach ($this->getUsers() as $u) {
246 if (!$SYS->sysCheckCreateUser($u->getID())) {
247 $this->setError($SYS->getErrorMessage());
256 * fetchData - May need to refresh database fields.
258 * If an update occurred and you need to access the updated info.
260 * @return boolean success;
262 function fetchData($role_id) {
263 unset($this->data_array);
264 unset($this->setting_array);
265 unset($this->perms_array);
267 $res = db_query_params('SELECT * FROM pfo_role WHERE role_id=$1',
269 if (!$res || db_numrows($res) < 1) {
270 $this->setError('BaseRole::fetchData()::'.db_error());
273 $this->data_array = db_fetch_array($res);
274 if ($this->data_array['is_public'] == 't') {
275 $this->data_array['is_public'] = true;
277 $this->data_array['is_public'] = false;
279 $res = db_query_params('SELECT section_name, ref_id, perm_val FROM pfo_role_setting WHERE role_id=$1',
282 $this->setError('BaseRole::fetchData()::'.db_error());
285 // TODO: document perms_array
286 $this->perms_array=array();
287 while ($arr = db_fetch_array($res)) {
288 $this->perms_array[$arr['section_name']][$arr['ref_id']] = $arr['perm_val'];
294 function setSetting ($section, $reference, $value) {
295 $cur = $this->getSettingRaw($section, $reference);
296 if (($value == $cur) && ($cur != NULL)) {
300 $role_id = $this->getID () ;
302 $res = db_query_params ('DELETE FROM pfo_role_setting WHERE role_id=$1 AND section_name=$2 AND ref_id=$3',
307 $res = db_query_params ('INSERT INTO pfo_role_setting (role_id, section_name, ref_id, perm_val) VALUES ($1, $2, $3, $4)',
312 $this->perms_array[$section][$reference] = $value;
315 function getSettingsForProject ($project) {
317 $group_id = $project->getID() ;
319 $sections = array ('project_read', 'project_admin', 'frs', 'scm', 'docman', 'tracker_admin', 'new_tracker') ;
320 foreach ($sections as $section) {
321 $result[$section][$group_id] = $this->getVal ($section, $group_id) ;
324 $atf = new ArtifactTypeFactory ($project) ;
325 if (!$atf->isError()) {
326 $tids = $atf->getAllArtifactTypeIds () ;
327 foreach ($tids as $tid) {
328 $result['tracker'][$tid] = $this->getVal ('tracker', $tid) ;
331 array_push ($sections,'tracker');
333 $sections_forum = array('forum_admin', 'new_forum');
334 foreach ($sections_forum as $section_forum) {
335 $result[$section_forum][$group_id] = $this->getVal ($section_forum, $group_id) ;
337 $sections = array_merge($sections, $sections_forum);
339 $ff = new ForumFactory ($project) ;
340 if (!$ff->isError()) {
341 $fids = $ff->getAllForumIdsWithNews () ;
342 foreach ($fids as $fid) {
343 $result['forum'][$fid] = $this->getVal ('forum', $fid) ;
346 array_push ($sections,'forum');
348 $sections_pm = array('pm_admin', 'new_pm');
349 foreach ($sections_pm as $section_pm) {
350 $result[$section_pm][$group_id] = $this->getVal ($section_pm, $group_id) ;
352 $sections = array_merge($sections, $sections_pm);
354 $pgf = new ProjectGroupFactory ($project) ;
355 if (!$pgf->isError()) {
356 $pgids = $pgf->getAllProjectGroupIds () ;
357 foreach ($pgids as $pgid) {
358 $result['pm'][$pgid] = $this->getVal ('pm', $pgid) ;
361 array_push ($sections,'pm') ;
364 // Add settings not yet listed so far (probably plugins)
365 // Currently handled:
366 // - global settings (ignored here)
367 // - project-wide settings (core and plugins)
368 // - settings for multiple-instance tools coming from the core (trackers/pm/forums)
370 // - settings for multiple-instance tools from plugins
371 foreach (array_keys ($this->perms_array) as $section) {
372 if (!in_array ($section, $sections)) {
373 if (!in_array ($section, $this->global_settings)) {
374 $result[$section][$group_id] = $this->getVal ($section, $group_id) ;
383 * TODO: Enter description here ...
386 function getGlobalSettings () {
389 $sections = array ('forge_admin', 'forge_stats', 'approve_projects', 'approve_news') ;
390 foreach ($sections as $section) {
391 $result[$section][-1] = $this->getVal($section, -1) ;
393 // Add settings not yet listed so far (probably plugins)
394 foreach (array_keys ($this->perms_array) as $section) {
395 if (!in_array ($section, $sections)) {
396 if (in_array ($section, $this->global_settings)) {
397 $result[$section][-1] = $this->getVal ($section, -1) ;
406 * TODO: Enter description here ...
407 * @param unknown_type $section
408 * @param unknown_type $reference
409 * @return number|boolean
411 function getSetting($section, $reference) {
412 $value = $this->getSettingRaw($section, $reference);
413 if ($value == NULL) {
426 case 'approve_projects':
428 if ($this->hasGlobalPermission('forge_admin')) {
435 if ($this->hasGlobalPermission('forge_admin')) {
441 case 'project_admin':
442 if ($this->hasGlobalPermission('forge_admin')) {
449 case 'tracker_admin':
452 if ($this->hasPermission('project_admin', $reference)) {
459 if ($this->hasPermission('project_admin', $reference)) {
466 if ($this->hasPermission('project_admin', $reference)) {
473 if ($this->hasPermission('project_admin', $reference)) {
480 if ($this->hasPermission('forum_admin', forum_get_groupid($reference))) {
486 if ($this->hasPermission('forum_admin', $reference)) {
493 if ($this->hasPermission('tracker_admin', artifacttype_get_groupid($reference))) {
499 if ($this->hasPermission('tracker_admin', $reference)) {
506 if ($this->hasPermission('pm_admin', projectgroup_get_groupid($reference))) {
512 if ($this->hasPermission('pm_admin', $reference)) {
518 $hook_params = array ();
519 $hook_params['role'] = $this ;
520 $hook_params['section'] = $section ;
521 $hook_params['reference'] = $reference ;
522 $hook_params['value'] = $value ;
523 $hook_params['result'] = NULL ;
524 plugin_hook_by_reference ("role_get_setting", $hook_params);
525 return $hook_params['result'] ;
530 function getSettingRaw($section, $reference) {
531 if (isset ($this->perms_array[$section][$reference])) {
532 return $this->perms_array[$section][$reference] ;
537 * getVal - get a value out of the array of settings for this role.
539 * @param string The name of the role.
540 * @param integer The ref_id (ex: group_artifact_id, group_forum_id) for this item.
541 * @return integer The value of this item.
543 function getVal($section, $ref_id) {
544 global $role_default_array;
548 return $this->getSetting($section, $ref_id) ;
552 * &getRoleVals - get all the values and language text strings for this section.
554 * @return array Assoc array of values for this section.
556 function &getRoleVals($section) {
557 global $role_vals, $rbac_permission_names;
558 setup_rbac_strings () ;
561 // Optimization - save array so it is only built once per page view
563 if (!isset($role_vals[$section])) {
565 for ($i=0; $i<count($this->role_values[$section]); $i++) {
567 // Build an associative array of these key values + localized description
569 $role_vals[$section][$this->role_values[$section][$i]] =
570 util_ifsetor($rbac_permission_names["$section".$this->role_values[$section][$i]],
571 _('UNKNOWN (internal error, report bug to FusionForge)'));
574 return $role_vals[$section];
577 function hasPermission($section, $reference, $action = NULL) {
580 $value = $this->getSetting ($section, $reference) ;
587 case 'approve_projects':
589 case 'project_admin':
591 case 'tracker_admin':
594 return ($value >= 1) ;
600 return ($value >= 1) ;
603 return ($value >= 2) ;
611 return ($value >= 1) ;
614 return ($value >= 2) ;
622 return ($value >= 1) ;
625 return ($value >= 2) ;
628 return ($value >= 3) ;
631 return ($value >= 4) ;
639 return ($value >= 1) ;
642 return ($value >= 2) ;
645 return ($value >= 3) ;
654 return ($value >= 1) ;
657 return ($value >= 2) ;
659 case 'unmoderated_post':
660 return ($value >= 3) ;
663 return ($value >= 4) ;
672 return (($value & 1) != 0) ;
675 return (($value & 2) != 0) ;
678 return (($value & 4) != 0) ;
681 return (($value & 8) != 0) ;
684 * bit4 (value & 16) is reserved
685 * for tracker item vote from Evolvis
694 return (($value & 1) != 0) ;
697 return (($value & 2) != 0) ;
700 return (($value & 4) != 0) ;
705 $hook_params = array ();
706 $hook_params['section'] = $section ;
707 $hook_params['reference'] = $reference ;
708 $hook_params['action'] = $action ;
709 $hook_params['value'] = $value ;
710 $hook_params['result'] = false ;
711 plugin_hook_by_reference ("role_has_permission", $hook_params);
712 return $hook_params['result'] ;
718 * update - update a role in the database.
720 * @param string The name of the role.
721 * @param array A multi-dimensional array of data in this format: $data['section_name']['ref_id']=$val
722 * @param boolean Perform permission checking
723 * @return boolean True on success or false on failure.
725 function update($role_name,$data,$check_perms=true) {
728 if ($this->getHomeProject() == NULL) {
729 if (!forge_check_global_perm ('forge_admin')) {
730 $this->setPermissionDeniedError();
733 } elseif (!forge_check_perm ('project_admin', $this->getHomeProject()->getID())) {
734 $this->setPermissionDeniedError();
742 if ($role_name != $this->getName()) {
743 $this->setName($role_name) ;
746 foreach ($data as $sect => $refs) {
747 foreach ($refs as $refid => $value) {
748 $this->setSetting ($sect, $refid, $value) ;
752 $hook_params = array ();
753 $hook_params['role'] =& $this;
754 $hook_params['role_id'] = $this->getID();
755 $hook_params['data'] = $data;
756 plugin_hook ("role_update", $hook_params);
760 $this->fetchData($this->getID());
762 foreach ($this->getUsers() as $u) {
763 if (!$SYS->sysCheckCreateUser($u->getID())) {
764 $this->setError($SYS->getErrorMessage());
772 function getDisplayableName($group = NULL) {
773 if ($this->getHomeProject() == NULL) {
774 return sprintf (_('%s (global role)'),
776 } elseif ($group == NULL
777 || $this->getHomeProject()->getID() != $group->getID()) {
778 return sprintf (_('%s (in project %s)'),
780 $this->getHomeProject()->getPublicName()) ;
782 return $this->getName () ;
786 function removeObsoleteSettings () {
789 // Remove obsolete project-wide settings
790 $sections = array ('project_read', 'project_admin', 'frs', 'scm', 'docman', 'tracker_admin', 'new_tracker', 'forum_admin', 'new_forum', 'pm_admin', 'new_pm') ;
791 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)',
792 array ($this->getID(),
793 db_string_array_to_any_clause($sections))) ;
796 // Remove obsolete settings for multiple-instance tools
797 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))',
798 array ($this->getID(),
800 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))',
801 array ($this->getID(),
803 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))',
804 array ($this->getID(),
808 $this->fetchData($this->getID());
812 function normalizeDataForSection (&$new_sa, $section) {
813 if (array_key_exists ($section, $this->setting_array)) {
814 $new_sa[$section][0] = $this->setting_array[$section][0] ;
815 } elseif (array_key_exists ($this->data_array['role_name'], $this->defaults)
816 && array_key_exists ($section, $this->defaults[$this->data_array['role_name']])) {
817 $new_sa[$section][0] = $this->defaults[$this->data_array['role_name']][$section] ;
819 $new_sa[$section][0] = 0 ;
824 function normalizePermsForSection (&$new_pa, $section, $refid) {
825 if (array_key_exists ($section, $this->perms_array)
826 && array_key_exists ($refid, $this->perms_array[$section])) {
827 $new_pa[$section][$refid] = $this->perms_array[$section][$refid] ;
828 } elseif (array_key_exists ($this->data_array['role_name'], $this->defaults)
829 && array_key_exists ($section, $this->defaults[$this->data_array['role_name']])) {
830 $new_pa[$section][$refid] = $this->defaults[$this->data_array['role_name']][$section] ;
832 $new_pa[$section][$refid] = 0 ;
837 function normalizeData () { // From the PFO spec
838 $this->removeObsoleteSettings () ;
840 $this->fetchData ($this->getID()) ;
842 $projects = $this->getLinkedProjects() ;
846 // Add missing settings
847 // ...project-wide settings
848 $arr = array ('project_read', 'project_admin', 'frs', 'scm', 'docman', 'tracker_admin', 'new_tracker', 'forum_admin', 'new_forum', 'pm_admin', 'new_pm') ;
849 foreach ($projects as $p) {
850 foreach ($arr as $section) {
851 $this->normalizePermsForSection ($new_pa, $section, $p->getID()) ;
854 $this->normalizePermsForSection ($new_pa, 'forge_admin', -1) ;
855 $this->normalizePermsForSection ($new_pa, 'approve_projects', -1) ;
856 $this->normalizePermsForSection ($new_pa, 'approve_news', -1) ;
857 $this->normalizePermsForSection ($new_pa, 'forge_stats', -1) ;
859 $hook_params = array ();
860 $hook_params['role'] =& $this;
861 $hook_params['new_sa'] =& $new_sa ;
862 $hook_params['new_pa'] =& $new_pa ;
863 plugin_hook ("role_normalize", $hook_params);
865 // ...tracker-related settings
866 $new_sa['tracker'] = array () ;
867 $new_pa['tracker'] = array () ;
868 foreach ($projects as $p) {
869 if (!$p->usesTracker()) {
872 $atf = new ArtifactTypeFactory ($p) ;
873 if (!$atf->isError()) {
874 $trackerids = $atf->getAllArtifactTypeIds () ;
875 foreach ($trackerids as $tid) {
876 if (array_key_exists ('tracker', $this->perms_array)
877 && array_key_exists ($tid, $this->perms_array['tracker']) ) {
878 $new_pa['tracker'][$tid] = $this->perms_array['tracker'][$tid] ;
879 } elseif (array_key_exists ('new_tracker', $this->perms_array)
880 && array_key_exists ($p->getID(), $this->perms_array['new_tracker']) ) {
881 $new_pa['tracker'][$tid] = $new_pa['new_tracker'][$p->getID()] ;
887 // ...forum-related settings
888 $new_sa['forum'] = array () ;
889 $new_pa['forum'] = array () ;
890 foreach ($projects as $p) {
891 if (!$p->usesForum()) {
894 $ff = new ForumFactory ($p) ;
895 if (!$ff->isError()) {
896 $fids = $ff->getAllForumIdsWithNews () ;
897 foreach ($fids as $fid) {
898 if (array_key_exists ('forum', $this->perms_array)
899 && array_key_exists ($fid, $this->perms_array['forum']) ) {
900 $new_pa['forum'][$fid] = $this->perms_array['forum'][$fid] ;
901 } elseif (array_key_exists ('new_forum', $this->perms_array)
902 && array_key_exists ($p->getID(), $this->perms_array['new_forum']) ) {
903 $new_pa['forum'][$fid] = $new_pa['new_forum'][$p->getID()] ;
909 // ...pm-related settings
910 $new_sa['pm'] = array () ;
911 $new_pa['pm'] = array () ;
912 foreach ($projects as $p) {
916 $pgf = new ProjectGroupFactory ($p) ;
917 if (!$pgf->isError()) {
918 $pgids = $pgf->getAllProjectGroupIds () ;
919 foreach ($pgids as $gid) {
920 if (array_key_exists ('pm', $this->perms_array)
921 && array_key_exists ($gid, $this->perms_array['pm']) ) {
922 $new_pa['pm'][$gid] = $this->perms_array['pm'][$gid] ;
923 } elseif (array_key_exists ('new_pm', $this->perms_array)
924 && array_key_exists ($p->getID(), $this->perms_array['new_pm']) ) {
925 $new_pa['pm'][$gid] = $new_pa['new_pm'][$p->getID()] ;
932 $this->update ($this->getName(), $new_pa, false) ;
940 * TODO: RBAC::RoleExplicit Enter description here ...
943 abstract class RoleExplicit extends BaseRole implements PFO_RoleExplicit {
944 public function addUsers($users) {
948 foreach ($users as $user) {
949 $ids[] = $user->getID();
952 $already_there = array();
953 $res = db_query_params('SELECT user_id FROM pfo_user_role WHERE user_id=ANY($1) AND role_id=$2',
954 array(db_int_array_to_any_clause($ids), $this->getID()));
958 while ($arr = db_fetch_array($res)) {
959 $already_there[] = $arr['user_id'] ;
962 foreach ($ids as $id) {
963 if (!in_array ($id, $already_there)) {
964 $res = db_query_params ('INSERT INTO pfo_user_role (user_id, role_id) VALUES ($1, $2)',
973 foreach ($this->getLinkedProjects() as $p) {
974 foreach ($ids as $uid) {
975 if (!$SYS->sysGroupCheckUser($p->getID(),$uid)) {
984 public function addUser ($user) {
985 if (!$this->addUsers (array ($user))) {
988 $hook_params['user'] = $user;
989 $hook_params['role'] = $this;
990 plugin_hook ("role_adduser", $hook_params);
995 public function removeUsers($users) {
999 foreach ($users as $user) {
1000 $ids[] = $user->getID() ;
1003 $already_there = array () ;
1004 $res = db_query_params ('DELETE FROM pfo_user_role WHERE user_id=ANY($1) AND role_id=$2',
1005 array (db_int_array_to_any_clause($ids), $this->getID())) ;
1007 foreach ($this->getLinkedProjects() as $p) {
1008 foreach ($ids as $uid) {
1009 $SYS->sysGroupCheckUser($p->getID(),$uid) ;
1016 public function removeUser ($user) {
1017 if(!$this->removeUsers (array ($user))){
1020 $hook_params['user'] = $user;
1021 $hook_params['role'] = $this;
1022 plugin_hook ("role_removeuser", $hook_params);
1027 public function getUsers() {
1028 $result = array () ;
1029 $res = db_query_params ('SELECT user_id FROM pfo_user_role WHERE role_id=$1',
1030 array ($this->getID())) ;
1031 while ($arr = db_fetch_array($res)) {
1032 $result[] = user_get_object ($arr['user_id']) ;
1038 public function hasUser($user) {
1039 $res = db_query_params ('SELECT user_id FROM pfo_user_role WHERE user_id=$1 AND role_id=$2',
1040 array ($user->getID(), $this->getID())) ;
1041 if ($res && db_numrows($res)) {
1048 function getID() { // From the PFO spec
1049 return $this->data_array['role_id'];
1052 function getName() { // From the PFO spec
1053 return $this->data_array['role_name'];
1057 class RoleAnonymous extends BaseRole implements PFO_RoleAnonymous {
1058 // This role is implemented as a singleton
1059 private static $_instance ;
1061 public static function getInstance() {
1062 if (isset(self::$_instance)) {
1063 return self::$_instance ;
1067 self::$_instance = new $c ;
1069 $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',
1070 array ('PFO_RoleAnonymous')) ;
1071 if (!$res || !db_numrows($res)) {
1072 throw new Exception ("No PFO_RoleAnonymous role in the database") ;
1074 self::$_instance->_role_id = db_result ($res, 0, 'role_id') ;
1076 $hook_params = array ();
1077 $hook_params['role'] =& self::$_instance;
1078 plugin_hook ("role_get", $hook_params);
1080 self::$_instance->fetchData (self::$_instance->_role_id) ;
1082 return self::$_instance ;
1085 public function getID () {
1086 return $this->_role_id ;
1088 public function isPublic () {
1091 public function setPublic ($flag) {
1092 throw new Exception ("Can't setPublic() on RoleAnonymous") ;
1094 public function getHomeProject () {
1097 public function getName () {
1098 return _('Anonymous/not logged in') ;
1100 public function setName ($name) {
1101 throw new Exception ("Can't setName() on RoleAnonymous") ;
1105 class RoleLoggedIn extends BaseRole implements PFO_RoleLoggedIn {
1106 // This role is implemented as a singleton
1107 private static $_instance ;
1109 public static function getInstance() {
1110 if (isset(self::$_instance)) {
1111 return self::$_instance ;
1115 self::$_instance = new $c ;
1117 $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',
1118 array ('PFO_RoleLoggedIn')) ;
1119 if (!$res || !db_numrows($res)) {
1120 throw new Exception ("No PFO_RoleLoggedIn role in the database") ;
1122 self::$_instance->_role_id = db_result ($res, 0, 'role_id') ;
1124 $hook_params = array ();
1125 $hook_params['role'] =& self::$_instance;
1126 plugin_hook ("role_get", $hook_params);
1128 self::$_instance->fetchData (self::$_instance->_role_id) ;
1130 return self::$_instance ;
1133 public function getID () {
1134 return $this->_role_id ;
1136 public function isPublic () {
1139 public function setPublic ($flag) {
1140 throw new Exception ("Can't setPublic() on RoleLoggedIn") ;
1142 public function getHomeProject () {
1145 public function getName () {
1146 return _('Any user logged in') ;
1148 public function setName ($name) {
1149 throw new Exception ("Can't setName() on RoleLoggedIn") ;
1153 abstract class RoleUnion extends BaseRole implements PFO_RoleUnion {
1154 public function addRole ($role) {
1155 throw new Exception ("Not implemented") ;
1157 public function removeRole ($role) {
1158 throw new Exception ("Not implemented") ;
1163 * TODO: Enter description here ...
1166 class RoleComparator {
1167 var $criterion = 'composite' ;
1168 var $reference_project = NULL ;
1170 function Compare ($a, $b) {
1171 switch ($this->criterion) {
1173 return strcoll ($a->getName(), $b->getName()) ;
1176 $aid = $a->getID() ;
1177 $bid = $b->getID() ;
1181 return ($a < $b) ? -1 : 1;
1185 if ($this->reference_project == NULL) {
1186 return $this->CompareNoRef ($a, $b) ;
1188 $rpid = $this->reference_project->getID () ;
1189 $ap = $a->getHomeProject() ;
1190 $bp = $b->getHomeProject() ;
1191 $a_is_local = ($ap != NULL && $ap->getID() == $rpid) ; // Local
1192 $b_is_local = ($bp != NULL && $bp->getID() == $rpid) ;
1194 if ($a_is_local && !$b_is_local) {
1196 } elseif (!$a_is_local && $b_is_local) {
1199 return $this->CompareNoRef ($a, $b) ;
1204 * TODO: Enter description here ...
1209 function CompareNoRef ($a, $b) {
1210 $ap = $a->getHomeProject() ;
1211 $bp = $b->getHomeProject() ;
1212 if ($ap == NULL && $bp != NULL) {
1214 } elseif ($ap != NULL && $bp == NULL) {
1216 } elseif ($ap == NULL && $bp == NULL) {
1217 $tmp = strcoll ($a->getName(), $b->getName()) ;
1220 $projcmp = new ProjectComparator () ;
1221 $projcmp->criterion = 'name' ;
1222 $tmp = $projcmp->Compare ($ap, $bp) ;
1223 if ($tmp) { /* Different projects, sort accordingly */
1226 return strcoll ($a->getName(), $b->getName()) ;
1231 function sortRoleList (&$list, $relative_to = NULL, $criterion='composite') {
1232 $cmp = new RoleComparator () ;
1233 $cmp->criterion = $criterion ;
1234 $cmp->reference_project = $relative_to ;
1236 return usort ($list, array ($cmp, 'Compare')) ;
1241 // c-file-style: "bsd"