3 * FusionForge role-based access control
5 * Copyright 2004, GForge, LLC
6 * Copyright 2009-2010, Roland Mas
7 * Copyright 2012, Franck Villaume - TrivialDev
8 * http://fusionforge.org
10 * This file is part of FusionForge. FusionForge is free software;
11 * you can redistribute it and/or modify it under the terms of the
12 * GNU General Public License as published by the Free Software
13 * Foundation; either version 2 of the Licence, or (at your option)
16 * FusionForge is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU General Public License for more details.
21 * You should have received a copy of the GNU General Public License along
22 * with FusionForge; if not, write to the Free Software Foundation, Inc.,
23 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
26 require "PFO-RBAC.interface.php";
28 define ('USE_PFO_RBAC', true);
30 // Code shared between classes
33 * TODO: RBAC::BaseRole Enter description here ...
36 abstract class BaseRole extends Error {
38 * TODO: Enter description here ...
43 * TODO: Enter description here ...
48 * TODO: Enter description here ...
54 // var $setting_array;
56 public function BaseRole() {
57 // TODO: document these tables
58 // $gfcommon.'include/rbac_texts.php' may provide some hints...
59 $this->role_values = array(
60 'forge_admin' => array(0, 1),
61 'approve_projects' => array(0, 1),
62 'approve_news' => array(0, 1),
63 'forge_stats' => array(0, 1, 2),
65 'project_read' => array(0, 1),
66 'project_admin' => array(0, 1),
68 'tracker_admin' => array(0, 1),
69 'pm_admin' => array(0, 1),
70 'forum_admin' => array(0, 1),
72 'tracker' => array(0, 1, 3, 5, 7),
73 'pm' => array(0, 1, 3, 5, 7),
74 'forum' => array(0, 1, 2, 3, 4),
76 'new_tracker' => array(0, 1, 3, 5, 7),
77 'new_pm' => array(0, 1, 3, 5, 7),
78 'new_forum' => array(0, 1, 2, 3, 4),
80 'scm' => array (0, 1, 2),
81 'docman' => array (0, 1, 2, 3, 4),
82 'frs' => array (0, 1, 2, 3),
84 // 'webcal' => array(0, 1, 2),
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,
110 'Senior Developer' => array( 'project_read' => 1,
116 'tracker_admin' => 1,
122 'Junior Developer' => array( 'project_read' => 1,
131 'Doc Writer' => array( 'project_read' => 1,
139 'Support Tech' => array( 'project_read' => 1,
143 'tracker_admin' => 1,
152 public function getUsers() {
155 public function hasUser($user) {
156 throw new Exception ("Not implemented") ;
158 function hasGlobalPermission($section, $action = NULL) {
159 return $this->hasPermission ($section, -1, $action) ;
161 public function getSettings() {
162 throw new Exception ("Not implemented") ;
164 public function setSettings($data) {
165 throw new Exception ("Not implemented") ;
167 public function delete () {
168 throw new Exception ("Not implemented") ;
172 * getLinkedProjects - List of projects referencing that role
174 * Includes the home project (for roles that have one)
176 * @return array Array of Group objects
178 public function getLinkedProjects() {
181 $hp = $this->getHomeProject();
183 $ids[] = $hp->getID();
186 $res = db_query_params('SELECT group_id FROM role_project_refs WHERE role_id=$1',
187 array($this->getID()));
189 while ($arr = db_fetch_array ($res)) {
190 $ids[] = $arr['group_id'];
194 return group_get_objects(array_unique($ids));
197 function linkProject ($project) { // From the PFO spec
199 $hp = $this->getHomeProject();
200 if ($hp != NULL && $hp->getID() == $project->getID()) {
201 $this->setError(_("Can't link to home project"));
205 $res = db_query_params('SELECT group_id FROM role_project_refs WHERE role_id=$1 AND group_id=$2',
206 array($this->getID(),
209 if (db_numrows($res)) {
212 $res = db_query_params('INSERT INTO role_project_refs (role_id, group_id) VALUES ($1, $2)',
213 array($this->getID(),
215 if (!$res || db_affected_rows($res) < 1) {
216 $this->setError('linkProject('.$project->getID().') '.db_error());
220 $this->normalizeData();
222 foreach ($this->getUsers() as $u) {
223 if (!$SYS->sysCheckCreateUser($u->getID())) {
224 $this->setError($SYS->getErrorMessage());
232 function unlinkProject($project) { // From the PFO spec
234 $hp = $this->getHomeProject();
235 if ($hp != NULL && $hp->getID() == $project->getID()) {
236 $this->setError (_("Can't unlink from home project"));
240 $res = db_query_params('DELETE FROM role_project_refs WHERE role_id=$1 AND group_id=$2',
241 array($this->getID(),
244 $this->setError('unlinkProject('.$project->getID().') '.db_error());
248 $this->removeObsoleteSettings ();
250 foreach ($this->getUsers() as $u) {
251 if (!$SYS->sysCheckCreateUser($u->getID())) {
252 $this->setError($SYS->getErrorMessage());
261 * fetchData - May need to refresh database fields.
263 * If an update occurred and you need to access the updated info.
265 * @return boolean success;
267 function fetchData($role_id) {
268 unset($this->data_array);
269 unset($this->setting_array);
270 unset($this->perms_array);
272 $res = db_query_params('SELECT * FROM pfo_role WHERE role_id=$1',
274 if (!$res || db_numrows($res) < 1) {
275 $this->setError('BaseRole::fetchData()::'.db_error());
278 $this->data_array = db_fetch_array($res);
279 if ($this->data_array['is_public'] == 't') {
280 $this->data_array['is_public'] = true;
282 $this->data_array['is_public'] = false;
284 $res = db_query_params('SELECT section_name, ref_id, perm_val FROM pfo_role_setting WHERE role_id=$1',
287 $this->setError('BaseRole::fetchData()::'.db_error());
290 // TODO: document perms_array
291 $this->perms_array=array();
292 while ($arr = db_fetch_array($res)) {
293 $this->perms_array[$arr['section_name']][$arr['ref_id']] = $arr['perm_val'];
299 function setSetting ($section, $reference, $value) {
300 $cur = $this->getSettingRaw($section, $reference);
301 if (($value == $cur) && ($cur != NULL)) {
305 $role_id = $this->getID () ;
307 $res = db_query_params ('DELETE FROM pfo_role_setting WHERE role_id=$1 AND section_name=$2 AND ref_id=$3',
312 $res = db_query_params ('INSERT INTO pfo_role_setting (role_id, section_name, ref_id, perm_val) VALUES ($1, $2, $3, $4)',
317 $this->perms_array[$section][$reference] = $value;
320 function getSettingsForProject ($project) {
322 $group_id = $project->getID() ;
324 $sections = array ('project_read', 'project_admin', 'frs', 'scm', 'docman', 'tracker_admin', 'new_tracker') ;
325 foreach ($sections as $section) {
326 $result[$section][$group_id] = $this->getVal ($section, $group_id) ;
329 $atf = new ArtifactTypeFactory ($project) ;
330 if (!$atf->isError()) {
331 $tids = $atf->getAllArtifactTypeIds () ;
332 foreach ($tids as $tid) {
333 $result['tracker'][$tid] = $this->getVal ('tracker', $tid) ;
336 array_push ($sections,'tracker');
338 $sections_forum = array('forum_admin', 'new_forum');
339 foreach ($sections_forum as $section_forum) {
340 $result[$section_forum][$group_id] = $this->getVal ($section_forum, $group_id) ;
342 $sections = array_merge($sections, $sections_forum);
344 $ff = new ForumFactory ($project) ;
345 if (!$ff->isError()) {
346 $fids = $ff->getAllForumIdsWithNews () ;
347 foreach ($fids as $fid) {
348 $result['forum'][$fid] = $this->getVal ('forum', $fid) ;
351 array_push ($sections,'forum');
353 $sections_pm = array('pm_admin', 'new_pm');
354 foreach ($sections_pm as $section_pm) {
355 $result[$section_pm][$group_id] = $this->getVal ($section_pm, $group_id) ;
357 $sections = array_merge($sections, $sections_pm);
359 $pgf = new ProjectGroupFactory ($project) ;
360 if (!$pgf->isError()) {
361 $pgids = $pgf->getAllProjectGroupIds () ;
362 foreach ($pgids as $pgid) {
363 $result['pm'][$pgid] = $this->getVal ('pm', $pgid) ;
366 array_push ($sections,'pm') ;
369 // Add settings not yet listed so far (probably plugins)
370 // Currently handled:
371 // - global settings (ignored here)
372 // - project-wide settings (core and plugins)
373 // - settings for multiple-instance tools coming from the core (trackers/pm/forums)
375 // - settings for multiple-instance tools from plugins
376 foreach (array_keys ($this->perms_array) as $section) {
377 if (!in_array ($section, $sections)) {
378 if (!in_array ($section, $this->global_settings)) {
379 $result[$section][$group_id] = $this->getVal ($section, $group_id) ;
388 * TODO: Enter description here ...
391 function getGlobalSettings () {
394 $sections = array ('forge_admin', 'forge_stats', 'approve_projects', 'approve_news') ;
395 foreach ($sections as $section) {
396 $result[$section][-1] = $this->getVal($section, -1) ;
398 // Add settings not yet listed so far (probably plugins)
399 foreach (array_keys ($this->perms_array) as $section) {
400 if (!in_array ($section, $sections)) {
401 if (in_array ($section, $this->global_settings)) {
402 $result[$section][-1] = $this->getVal ($section, -1) ;
411 * TODO: Enter description here ...
412 * @param unknown_type $section
413 * @param unknown_type $reference
414 * @return number|boolean
416 function getSetting($section, $reference) {
417 $value = $this->getSettingRaw($section, $reference);
418 if ($value == NULL) {
431 case 'approve_projects':
433 if ($this->hasGlobalPermission('forge_admin')) {
440 if ($this->hasGlobalPermission('forge_admin')) {
446 case 'project_admin':
447 if ($this->hasGlobalPermission('forge_admin')) {
454 case 'tracker_admin':
457 if ($this->hasPermission('project_admin', $reference)) {
464 if ($this->hasPermission('project_admin', $reference)) {
471 if ($this->hasPermission('project_admin', $reference)) {
478 if ($this->hasPermission('project_admin', $reference)) {
485 if ($this->hasPermission('forum_admin', forum_get_groupid($reference))) {
491 if ($this->hasPermission('forum_admin', $reference)) {
498 if ($this->hasPermission('tracker_admin', artifacttype_get_groupid($reference))) {
504 if ($this->hasPermission('tracker_admin', $reference)) {
511 if ($this->hasPermission('pm_admin', projectgroup_get_groupid($reference))) {
517 if ($this->hasPermission('pm_admin', $reference)) {
523 $hook_params = array ();
524 $hook_params['role'] = $this ;
525 $hook_params['section'] = $section ;
526 $hook_params['reference'] = $reference ;
527 $hook_params['value'] = $value ;
528 $hook_params['result'] = NULL ;
529 plugin_hook_by_reference ("role_get_setting", $hook_params);
530 return $hook_params['result'] ;
535 function getSettingRaw($section, $reference) {
536 if (isset ($this->perms_array[$section][$reference])) {
537 return $this->perms_array[$section][$reference] ;
542 * getVal - get a value out of the array of settings for this role.
544 * @param string The name of the role.
545 * @param integer The ref_id (ex: group_artifact_id, group_forum_id) for this item.
546 * @return integer The value of this item.
548 function getVal($section, $ref_id) {
549 global $role_default_array;
553 return $this->getSetting($section, $ref_id) ;
557 * &getRoleVals - get all the values and language text strings for this section.
559 * @return array Assoc array of values for this section.
561 function &getRoleVals($section) {
562 global $role_vals, $rbac_permission_names;
563 setup_rbac_strings () ;
566 // Optimization - save array so it is only built once per page view
568 if (!isset($role_vals[$section])) {
570 for ($i=0; $i<count($this->role_values[$section]); $i++) {
572 // Build an associative array of these key values + localized description
574 $role_vals[$section][$this->role_values[$section][$i]] =
575 util_ifsetor($rbac_permission_names["$section".$this->role_values[$section][$i]],
576 _('UNKNOWN (internal error, report bug to FusionForge)'));
579 return $role_vals[$section];
582 function hasPermission($section, $reference, $action = NULL) {
585 $value = $this->getSetting ($section, $reference) ;
592 case 'approve_projects':
594 case 'project_admin':
596 case 'tracker_admin':
599 return ($value >= 1) ;
605 return ($value >= 1) ;
608 return ($value >= 2) ;
616 return ($value >= 1) ;
619 return ($value >= 2) ;
627 return ($value >= 1) ;
630 return ($value >= 2) ;
633 return ($value >= 3) ;
636 return ($value >= 4) ;
644 return ($value >= 1) ;
647 return ($value >= 2) ;
650 return ($value >= 3) ;
659 return ($value >= 1) ;
662 return ($value >= 2) ;
664 case 'unmoderated_post':
665 return ($value >= 3) ;
668 return ($value >= 4) ;
677 return (($value & 1) != 0) ;
680 return (($value & 2) != 0) ;
683 return (($value & 4) != 0) ;
692 return (($value & 1) != 0) ;
695 return (($value & 2) != 0) ;
698 return (($value & 4) != 0) ;
703 $hook_params = array ();
704 $hook_params['section'] = $section ;
705 $hook_params['reference'] = $reference ;
706 $hook_params['action'] = $action ;
707 $hook_params['value'] = $value ;
708 $hook_params['result'] = false ;
709 plugin_hook_by_reference ("role_has_permission", $hook_params);
710 return $hook_params['result'] ;
716 * update - update a role in the database.
718 * @param string The name of the role.
719 * @param array A multi-dimensional array of data in this format: $data['section_name']['ref_id']=$val
720 * @param boolean Perform permission checking
721 * @return boolean True on success or false on failure.
723 function update($role_name,$data,$check_perms=true) {
726 if ($this->getHomeProject() == NULL) {
727 if (!forge_check_global_perm ('forge_admin')) {
728 $this->setPermissionDeniedError();
731 } elseif (!forge_check_perm ('project_admin', $this->getHomeProject()->getID())) {
732 $this->setPermissionDeniedError();
740 if ($role_name != $this->getName()) {
741 $this->setName($role_name) ;
744 foreach ($data as $sect => $refs) {
745 foreach ($refs as $refid => $value) {
746 $this->setSetting ($sect, $refid, $value) ;
750 $hook_params = array ();
751 $hook_params['role'] =& $this;
752 $hook_params['role_id'] = $this->getID();
753 $hook_params['data'] = $data;
754 plugin_hook ("role_update", $hook_params);
758 $this->fetchData($this->getID());
760 foreach ($this->getUsers() as $u) {
761 if (!$SYS->sysCheckCreateUser($u->getID())) {
762 $this->setError($SYS->getErrorMessage());
770 function getDisplayableName($group = NULL) {
771 if ($this->getHomeProject() == NULL) {
772 return sprintf (_('%s (global role)'),
774 } elseif ($group == NULL
775 || $this->getHomeProject()->getID() != $group->getID()) {
776 return sprintf (_('%s (in project %s)'),
778 $this->getHomeProject()->getPublicName()) ;
780 return $this->getName () ;
784 function removeObsoleteSettings () {
787 // Remove obsolete project-wide settings
788 $sections = array ('project_read', 'project_admin', 'frs', 'scm', 'docman', 'tracker_admin', 'new_tracker', 'forum_admin', 'new_forum', 'pm_admin', 'new_pm', 'webcal') ;
789 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)',
790 array ($this->getID(),
791 db_string_array_to_any_clause($sections))) ;
794 // Remove obsolete settings for multiple-instance tools
795 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))',
796 array ($this->getID(),
798 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))',
799 array ($this->getID(),
801 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))',
802 array ($this->getID(),
806 $this->fetchData($this->getID());
810 function normalizeDataForSection (&$new_sa, $section) {
811 if (array_key_exists ($section, $this->setting_array)) {
812 $new_sa[$section][0] = $this->setting_array[$section][0] ;
813 } elseif (array_key_exists ($this->data_array['role_name'], $this->defaults)
814 && array_key_exists ($section, $this->defaults[$this->data_array['role_name']])) {
815 $new_sa[$section][0] = $this->defaults[$this->data_array['role_name']][$section] ;
817 $new_sa[$section][0] = 0 ;
822 function normalizePermsForSection (&$new_pa, $section, $refid) {
823 if (array_key_exists ($section, $this->perms_array)
824 && array_key_exists ($refid, $this->perms_array[$section])) {
825 $new_pa[$section][$refid] = $this->perms_array[$section][$refid] ;
826 } elseif (array_key_exists ($this->data_array['role_name'], $this->defaults)
827 && array_key_exists ($section, $this->defaults[$this->data_array['role_name']])) {
828 $new_pa[$section][$refid] = $this->defaults[$this->data_array['role_name']][$section] ;
830 $new_pa[$section][$refid] = 0 ;
835 function normalizeData () { // From the PFO spec
836 $this->removeObsoleteSettings () ;
838 $this->fetchData ($this->getID()) ;
840 $projects = $this->getLinkedProjects() ;
844 // Add missing settings
845 // ...project-wide settings
846 $arr = array ('project_read', 'project_admin', 'frs', 'scm', 'docman', 'tracker_admin', 'new_tracker', 'forum_admin', 'new_forum', 'pm_admin', 'new_pm', 'webcal') ;
847 foreach ($projects as $p) {
848 foreach ($arr as $section) {
849 $this->normalizePermsForSection ($new_pa, $section, $p->getID()) ;
852 $this->normalizePermsForSection ($new_pa, 'forge_admin', -1) ;
853 $this->normalizePermsForSection ($new_pa, 'approve_projects', -1) ;
854 $this->normalizePermsForSection ($new_pa, 'approve_news', -1) ;
855 $this->normalizePermsForSection ($new_pa, 'forge_stats', -1) ;
857 $hook_params = array ();
858 $hook_params['role'] =& $this;
859 $hook_params['new_sa'] =& $new_sa ;
860 $hook_params['new_pa'] =& $new_pa ;
861 plugin_hook ("role_normalize", $hook_params);
863 // ...tracker-related settings
864 $new_sa['tracker'] = array () ;
865 $new_pa['tracker'] = array () ;
866 foreach ($projects as $p) {
867 $atf = new ArtifactTypeFactory ($p) ;
868 if (!$atf->isError()) {
869 $trackerids = $atf->getAllArtifactTypeIds () ;
870 foreach ($trackerids as $tid) {
871 if (array_key_exists ('tracker', $this->perms_array)
872 && array_key_exists ($tid, $this->perms_array['tracker']) ) {
873 $new_pa['tracker'][$tid] = $this->perms_array['tracker'][$tid] ;
874 } elseif (array_key_exists ('new_tracker', $this->perms_array)
875 && array_key_exists ($p->getID(), $this->perms_array['new_tracker']) ) {
876 $new_pa['tracker'][$tid] = $new_pa['new_tracker'][$p->getID()] ;
882 // ...forum-related settings
883 $new_sa['forum'] = array () ;
884 $new_pa['forum'] = array () ;
885 foreach ($projects as $p) {
886 if (!$p->usesForum()) {
889 $ff = new ForumFactory ($p) ;
890 $fids = $ff->getAllForumIdsWithNews () ;
891 foreach ($fids as $fid) {
892 if (array_key_exists ('forum', $this->perms_array)
893 && array_key_exists ($fid, $this->perms_array['forum']) ) {
894 $new_pa['forum'][$fid] = $this->perms_array['forum'][$fid] ;
895 } elseif (array_key_exists ('new_forum', $this->perms_array)
896 && array_key_exists ($p->getID(), $this->perms_array['new_forum']) ) {
897 $new_pa['forum'][$fid] = $new_pa['new_forum'][$p->getID()] ;
902 // ...pm-related settings
903 $new_sa['pm'] = array () ;
904 $new_pa['pm'] = array () ;
905 foreach ($projects as $p) {
906 $pgf = new ProjectGroupFactory ($p) ;
907 $pgids = $pgf->getAllProjectGroupIds () ;
908 foreach ($pgids as $gid) {
909 if (array_key_exists ('pm', $this->perms_array)
910 && array_key_exists ($gid, $this->perms_array['pm']) ) {
911 $new_pa['pm'][$gid] = $this->perms_array['pm'][$gid] ;
912 } elseif (array_key_exists ('new_pm', $this->perms_array)
913 && array_key_exists ($p->getID(), $this->perms_array['new_pm']) ) {
914 $new_pa['pm'][$gid] = $new_pa['new_pm'][$p->getID()] ;
920 $this->update ($this->getName(), $new_pa, false) ;
928 * TODO: RBAC::RoleExplicit Enter description here ...
931 abstract class RoleExplicit extends BaseRole implements PFO_RoleExplicit {
932 public function addUsers($users) {
936 foreach ($users as $user) {
937 $ids[] = $user->getID();
940 $already_there = array();
941 $res = db_query_params('SELECT user_id FROM pfo_user_role WHERE user_id=ANY($1) AND role_id=$2',
942 array(db_int_array_to_any_clause($ids), $this->getID()));
946 while ($arr = db_fetch_array($res)) {
947 $already_there[] = $arr['user_id'] ;
950 foreach ($ids as $id) {
951 if (!in_array ($id, $already_there)) {
952 $res = db_query_params ('INSERT INTO pfo_user_role (user_id, role_id) VALUES ($1, $2)',
961 foreach ($this->getLinkedProjects() as $p) {
962 foreach ($ids as $uid) {
963 if (!$SYS->sysGroupCheckUser($p->getID(),$uid)) {
972 public function addUser ($user) {
973 return $this->addUsers (array ($user)) ;
976 public function removeUsers($users) {
980 foreach ($users as $user) {
981 $ids[] = $user->getID() ;
984 $already_there = array () ;
985 $res = db_query_params ('DELETE FROM pfo_user_role WHERE user_id=ANY($1) AND role_id=$2',
986 array (db_int_array_to_any_clause($ids), $this->getID())) ;
988 foreach ($this->getLinkedProjects() as $p) {
989 foreach ($ids as $uid) {
990 $SYS->sysGroupCheckUser($p->getID(),$uid) ;
997 public function removeUser ($user) {
998 return $this->removeUsers (array ($user)) ;
1001 public function getUsers() {
1002 $result = array () ;
1003 $res = db_query_params ('SELECT user_id FROM pfo_user_role WHERE role_id=$1',
1004 array ($this->getID())) ;
1005 while ($arr = db_fetch_array($res)) {
1006 $result[] = user_get_object ($arr['user_id']) ;
1012 public function hasUser($user) {
1013 $res = db_query_params ('SELECT user_id FROM pfo_user_role WHERE user_id=$1 AND role_id=$2',
1014 array ($user->getID(), $this->getID())) ;
1015 if ($res && db_numrows($res)) {
1022 function getID() { // From the PFO spec
1023 return $this->data_array['role_id'];
1026 function getName() { // From the PFO spec
1027 return $this->data_array['role_name'];
1031 class RoleAnonymous extends BaseRole implements PFO_RoleAnonymous {
1032 // This role is implemented as a singleton
1033 private static $_instance ;
1035 public static function getInstance() {
1036 if (isset(self::$_instance)) {
1037 return self::$_instance ;
1041 self::$_instance = new $c ;
1043 $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',
1044 array ('PFO_RoleAnonymous')) ;
1045 if (!$res || !db_numrows($res)) {
1046 throw new Exception ("No PFO_RoleAnonymous role in the database") ;
1048 self::$_instance->_role_id = db_result ($res, 0, 'role_id') ;
1050 $hook_params = array ();
1051 $hook_params['role'] =& self::$_instance;
1052 plugin_hook ("role_get", $hook_params);
1054 self::$_instance->fetchData (self::$_instance->_role_id) ;
1056 return self::$_instance ;
1059 public function getID () {
1060 return $this->_role_id ;
1062 public function isPublic () {
1065 public function setPublic ($flag) {
1066 throw new Exception ("Can't setPublic() on RoleAnonymous") ;
1068 public function getHomeProject () {
1071 public function getName () {
1072 return _('Anonymous/not logged in') ;
1074 public function setName ($name) {
1075 throw new Exception ("Can't setName() on RoleAnonymous") ;
1079 class RoleLoggedIn extends BaseRole implements PFO_RoleLoggedIn {
1080 // This role is implemented as a singleton
1081 private static $_instance ;
1083 public static function getInstance() {
1084 if (isset(self::$_instance)) {
1085 return self::$_instance ;
1089 self::$_instance = new $c ;
1091 $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',
1092 array ('PFO_RoleLoggedIn')) ;
1093 if (!$res || !db_numrows($res)) {
1094 throw new Exception ("No PFO_RoleLoggedIn role in the database") ;
1096 self::$_instance->_role_id = db_result ($res, 0, 'role_id') ;
1098 $hook_params = array ();
1099 $hook_params['role'] =& self::$_instance;
1100 plugin_hook ("role_get", $hook_params);
1102 self::$_instance->fetchData (self::$_instance->_role_id) ;
1104 return self::$_instance ;
1107 public function getID () {
1108 return $this->_role_id ;
1110 public function isPublic () {
1113 public function setPublic ($flag) {
1114 throw new Exception ("Can't setPublic() on RoleLoggedIn") ;
1116 public function getHomeProject () {
1119 public function getName () {
1120 return _('Any user logged in') ;
1122 public function setName ($name) {
1123 throw new Exception ("Can't setName() on RoleLoggedIn") ;
1127 abstract class RoleUnion extends BaseRole implements PFO_RoleUnion {
1128 public function addRole ($role) {
1129 throw new Exception ("Not implemented") ;
1131 public function removeRole ($role) {
1132 throw new Exception ("Not implemented") ;
1137 * TODO: Enter description here ...
1140 class RoleComparator {
1141 var $criterion = 'composite' ;
1142 var $reference_project = NULL ;
1144 function Compare ($a, $b) {
1145 switch ($this->criterion) {
1147 return strcoll ($a->getName(), $b->getName()) ;
1150 $aid = $a->getID() ;
1151 $bid = $b->getID() ;
1155 return ($a < $b) ? -1 : 1;
1159 if ($this->reference_project == NULL) {
1160 return $this->CompareNoRef ($a, $b) ;
1162 $rpid = $this->reference_project->getID () ;
1163 $ap = $a->getHomeProject() ;
1164 $bp = $b->getHomeProject() ;
1165 $a_is_local = ($ap != NULL && $ap->getID() == $rpid) ; // Local
1166 $b_is_local = ($bp != NULL && $bp->getID() == $rpid) ;
1168 if ($a_is_local && !$b_is_local) {
1170 } elseif (!$a_is_local && $b_is_local) {
1173 return $this->CompareNoRef ($a, $b) ;
1178 * TODO: Enter description here ...
1183 function CompareNoRef ($a, $b) {
1184 $ap = $a->getHomeProject() ;
1185 $bp = $b->getHomeProject() ;
1186 if ($ap == NULL && $bp != NULL) {
1188 } elseif ($ap != NULL && $bp == NULL) {
1190 } elseif ($ap == NULL && $bp == NULL) {
1191 $tmp = strcoll ($a->getName(), $b->getName()) ;
1194 $projcmp = new ProjectComparator () ;
1195 $projcmp->criterion = 'name' ;
1196 $tmp = $projcmp->Compare ($ap, $bp) ;
1197 if ($tmp) { /* Different projects, sort accordingly */
1200 return strcoll ($a->getName(), $b->getName()) ;
1205 function sortRoleList (&$list, $relative_to = NULL, $criterion='composite') {
1206 $cmp = new RoleComparator () ;
1207 $cmp->criterion = $criterion ;
1208 $cmp->reference_project = $relative_to ;
1210 return usort ($list, array ($cmp, 'Compare')) ;
1215 // c-file-style: "bsd"