View Issue Details

IDProjectCategoryView StatusLast Update
0003444mantisbtfeaturepublic2020-06-24 11:37
ReporterTomWalter Assigned To 
PrioritynormalSeverityfeatureReproducibilityN/A
Status confirmedResolutionopen 
Summary0003444: Add user groups to streamline user management
Description

It would be nice to have user groups, to which Access levels and Projects could be assigned, rather than assigning those things individually. For example in the case where you are tracking several projects from different clients, and each client has multiple users, and you want to be able to easily assign all the users from that client to the one project.

Tagsusergroups
Attached Files
diff_from_RELEASE_0_18_3_20040512.diff (62,093 bytes)   
Index: bug_view_advanced_page.php
===================================================================
RCS file: /cvsroot/mantisbt/mantisbt/bug_view_advanced_page.php,v
retrieving revision 1.50
diff -u -r1.50 bug_view_advanced_page.php
--- bug_view_advanced_page.php	5 Feb 2004 12:45:19 -0000	1.50
+++ bug_view_advanced_page.php	26 May 2004 18:12:52 -0000
@@ -17,6 +17,7 @@
 	require_once( $t_core_path.'bug_api.php' );
 	require_once( $t_core_path.'custom_field_api.php' );
 	require_once( $t_core_path.'file_api.php' );
+	require_once( $t_core_path.'group_api.php');
 	require_once( $t_core_path.'compress_api.php' );
 	require_once( $t_core_path.'date_api.php' );
 	require_once( $t_core_path.'relationship_api.php' );
@@ -502,6 +503,98 @@
 
 	# User list monitoring the bug
 	include( $t_mantis_dir . 'bug_monitor_list_view_inc.php' );
+	
+		
+?>
+
+<?php
+if  ( access_has_global_level( DEVELOPER ) ) {
+?>	
+
+<!-- USER GROUP MANAGEMENT (ADD) ( this really should be in a separate inc file ) -->
+<br />
+<div align="center">
+	<form method="post" action="bug_group_add.php">
+		<input type="hidden" name="bug_id" value="<?php echo $f_bug_id ?>" />
+		<table class="width100" cellspacing="1">
+			<tr>
+				<td class="form-title" colspan="5">
+					<?php echo lang_get( 'bug_add_group_title' ) ?>
+				</td>
+			</tr>
+			<tr class="row-1" valign="top">
+				<td class="category">
+					<?php echo lang_get( 'groupname' ) ?>
+				</td>
+				<td>
+					<select name="group_id[]" multiple size="3">
+						<?php print_bug_group_list_option_list( $f_bug_id ) ?>
+					</select>
+				</td>
+				<td>
+					<input type="submit" value="<?php echo lang_get( 'add_group_button' ) ?>" />
+				</td>
+			</tr>
+		</table>
+	</form>
+</div>
+
+
+<br />
+<div align="center">
+	<table class="width100" cellspacing="1">
+		<tr>
+			<td class="form-title" colspan="4">
+				<?php echo lang_get( 'manage_view_list_title' ) ?>
+			</td>
+		</tr>
+		<tr class="row-category">
+			<td>
+				<?php echo lang_get( 'groupname' ) ?>
+			</td>
+			<td>
+				<?php echo lang_get( 'access_level' ) ?>
+			</td>
+			<td class="center">
+				<?php echo lang_get( 'actions' ) ?>
+			</td>
+		</tr>
+<?php
+	$t_groups = bug_get_all_group_rows( $f_bug_id );
+	
+	# reset the class counter
+	helper_alternate_class( 0 );
+
+	foreach ( $t_groups as $t_group ) {
+?>
+		<tr <?php echo helper_alternate_class() ?> >
+			<td>
+				<?php echo $t_group['groupname'] ?>
+			</td>
+			<td>
+				<?php echo get_enum_element( 'access_levels', $t_group['access_level'] ) ?>
+			</td>
+			<td class="center">
+			<?php
+				if ( access_has_global_level( DEVELOPER ) ) {
+					if ( bug_includes_group( $f_bug_id, $t_group['id'] )  ) {
+						print_bracket_link( 'bug_group_remove.php?bug_id=' . $f_bug_id . '&amp;group_id=' . $t_group['id'], lang_get( 'remove_link' ) );
+					}
+				}
+			?>
+			</td>
+		</tr>
+<?php
+	}  # end for
+?>
+	</table>
+</div>
+<?php
+ } # end if
+?>
+
+	
+<?php
 
 	# Bugnotes
 	include( $t_mantis_dir . 'bugnote_add_inc.php' );
Index: config_defaults_inc.php
===================================================================
RCS file: /cvsroot/mantisbt/mantisbt/config_defaults_inc.php,v
retrieving revision 1.145.2.1
diff -u -r1.145.2.1 config_defaults_inc.php
--- config_defaults_inc.php	12 May 2004 11:36:14 -0000	1.145.2.1
+++ config_defaults_inc.php	26 May 2004 18:12:53 -0000
@@ -841,6 +841,9 @@
 	$g_mantis_custom_field_table      	    = $g_db_table_prefix.'_custom_field_table';
 	$g_mantis_custom_field_string_table     = $g_db_table_prefix.'_custom_field_string_table';
 	$g_mantis_upgrade_table					= $g_db_table_prefix.'_upgrade_table';
+	$g_mantis_group_table				    = $g_db_table_prefix.'_group_table';
+	$g_mantis_group_user_list_table			= $g_db_table_prefix.'_group_user_list_table';
+	$g_mantis_bug_group_list_table			= $g_db_table_prefix.'_bug_group_list_table';
 
 	###########################
 	# Mantis Enum Strings
Index: core.php
===================================================================
RCS file: /cvsroot/mantisbt/mantisbt/core.php,v
retrieving revision 1.32
diff -u -r1.32 core.php
--- core.php	5 Feb 2004 01:17:13 -0000	1.32
+++ core.php	26 May 2004 18:12:53 -0000
@@ -102,4 +102,5 @@
 	require_once( $t_core_path.'print_api.php' );
 	require_once( $t_core_path.'helper_api.php' );
 	require_once( $t_core_path.'user_api.php' );
+	require_once( $t_core_path.'group_api.php' );
 ?>
Index: core/bug_api.php
===================================================================
RCS file: /cvsroot/mantisbt/mantisbt/core/bug_api.php,v
retrieving revision 1.50.2.1
diff -u -r1.50.2.1 bug_api.php
--- core/bug_api.php	10 May 2004 13:13:24 -0000	1.50.2.1
+++ core/bug_api.php	26 May 2004 18:12:53 -0000
@@ -698,6 +698,118 @@
 		
 		return db_result( $result );
 	}
+	
+	# --------------------
+	# check to see if the bug_group combo already exists
+	# returns true is duplicate is found, otherwise false
+	function bug_includes_group( $p_bug_id, $p_group_id ) {
+		$t_bug_group_list_table = config_get( 'mantis_bug_group_list_table' );
+
+		$c_bug_id	= db_prepare_int( $p_bug_id );
+		$c_group_id	= db_prepare_int( $p_group_id );
+
+		$query = "SELECT COUNT(*)
+				  FROM $t_bug_group_list_table
+				  WHERE bug_id='$c_bug_id' AND
+						group_id='$c_group_id'";
+		$result = db_query( $query );
+
+		if ( 0 == db_result( $result ) ) {
+			return false;
+		} else {
+			return true;
+		}
+	}
+
+	# --------------------
+	# Returns a list of all groups that have view access to this bug
+	function bug_get_group_view_list( $p_bug_id ) {
+		$c_bug_id = db_prepare_int( $p_bug_id );
+		
+		$t_group_bug_list_table = config_get( 'mantis_group_bug_list_table' );
+		
+		$query = "SELECT group_id
+				FROM $t_group_bug_list_table
+				WHERE bug_id='$c_bug_id'
+				ORDER BY group_id";
+		$result = db_query( $query );
+		
+		return db_result( $result );
+	}
+
+	# --------------------
+	# return the descriptor holding all the info from the bug_group list
+	# for the specified bug
+	function bug_get_local_group_rows( $p_bug_id ) {
+		$c_bug_id = db_prepare_int( $p_bug_id );
+
+		$t_bug_group_list_table = config_get( 'mantis_bug_group_list_table' );
+
+		$query = "SELECT *
+				FROM $t_bug_group_list_table
+				WHERE project_id='$c_bug_id'";
+
+		$result = db_query( $query );
+
+		$t_group_rows = array();
+		$t_row_count = db_num_rows( $result );
+
+		for ( $i=0 ; $i < $t_row_count ; $i++ ) {
+			array_push( $t_group_rows, db_fetch_array( $result ) );
+		}
+
+		return $t_group_rows;
+	}
+
+	# --------------------
+	# Return an array of info about groups who have access to the the given bug
+	# For each user we have 'id', 'groupname', and 'access_level' (overall access level)
+	# If the second parameter is given, return only groups with an access level
+	#  higher than the given value.
+	function bug_get_all_group_rows( $p_bug_id  ) {
+		$c_bug_id = db_prepare_int( $p_bug_id );
+
+		$t_group_table = config_get( 'mantis_group_table' );
+		$t_bug_group_list_table = config_get( 'mantis_bug_group_list_table' );
+
+		$t_on = ON;
+
+		$t_access_level = ANYBODY;
+
+		if ( VS_PRIVATE == bug_get_field( $p_bug_id, 'view_state' ) ) {
+			$t_access_level = max( $t_access_level, config_get( 'private_bug_threshold' ) );
+		}
+
+		$t_access_clause = '';
+
+		if ( $t_access_level > 0 ) {
+			$t_access_clause = ' AND access_level >= ' . $t_access_level;
+		}
+
+		$t_groups = array();
+
+		// Get the project overrides
+		$query = "SELECT g.id, g.groupname, g.access_level
+					FROM $t_bug_group_list_table l, $t_group_table g
+					WHERE l.group_id = g.id
+					  AND g.enabled = $t_on
+					  AND l.bug_id = $c_bug_id
+					ORDER BY g.groupname";
+
+		$result = db_query( $query );
+		$t_row_count = db_num_rows( $result );
+
+		for ( $i=0 ; $i < $t_row_count ; $i++ ) {
+			$row = db_fetch_array( $result );
+
+			if ( $row['access_level'] >= $t_access_level ) {
+				$t_groups[$row['id']] = $row;
+			}
+		}
+
+		return multi_sort( array_values($t_groups), 'username' );
+	}
+	
 
 	#===================================
 	# Data Modification
@@ -924,6 +1036,62 @@
 
 		return true;
 	}
+	
+	# --------------------
+	# add group to a bug view list
+	function bug_add_group( $p_bug_id, $p_group_id ) {
+		$t_bug_group_list_table = config_get( 'mantis_bug_group_list_table' );
+
+		$c_bug_id	= db_prepare_int( $p_bug_id );
+		$c_group_id	= db_prepare_int( $p_group_id );
+
+		$query = "INSERT
+				  INTO $t_bug_group_list_table
+				    ( bug_id, group_id )
+				  VALUES
+				    ( '$c_bug_id', '$c_group_id' )";
+		
+		db_query( $query );
+
+		# db_query errors on failure so:
+		return true;
+	}
+	
+	# --------------------
+	# remove group from bug view list
+	function bug_remove_group( $p_bug_id, $p_group_id ) {
+		$t_bug_group_list_table = config_get( 'mantis_bug_group_list_table' );
+
+		$c_bug_id	= db_prepare_int( $p_bug_id );
+		$c_group_id	= db_prepare_int( $p_group_id );
+
+		$query = "DELETE FROM $t_bug_group_list_table
+				  WHERE bug_id='$c_bug_id' AND
+						group_id='$c_group_id'";
+
+		db_query( $query );
+
+		# db_query errors on failure so:
+		return true;
+	}
+
+	# --------------------
+	# delete all groups from the bug view list for a given bug
+	# this is useful when deleting a bug
+	function bug_remove_all_groups( $p_bug_id ) {
+		$t_bug_group_list_table = config_get( 'mantis_bug_group_list_table' );
+
+		$c_bug_id	= db_prepare_int( $p_bug_id );
+
+		$query = "DELETE FROM $t_bug_group_list_table
+				WHERE bug_id='$c_bug_id'";
+
+		db_query( $query );
+
+		# db_query errors on failure so:
+		return true;
+	}
+	
 
 	#===================================
 	# Other
Index: core/constant_inc.php
===================================================================
RCS file: /cvsroot/mantisbt/mantisbt/core/constant_inc.php,v
retrieving revision 1.10
diff -u -r1.10 constant_inc.php
--- core/constant_inc.php	11 Feb 2004 22:16:29 -0000	1.10
+++ core/constant_inc.php	26 May 2004 18:12:54 -0000
@@ -116,6 +116,9 @@
 
 	# no user
 	define( 'NO_USER',		0 );
+	
+	# no group
+	define( 'NO_GROUP', 		0 );
 
 	# history constants
 	define( 'NORMAL_TYPE',					0 );
@@ -194,6 +197,11 @@
 	define( 'ERROR_USER_NAME_INVALID',				805 );
 	define( 'ERROR_USER_DOES_NOT_HAVE_REQ_ACCESS',		806 );
 
+	# ERROR_GROUP_*
+	define( 'ERROR_GROUP_NAME_NOT_UNIQUE',			1700 );
+	define( 'ERROR_GROUP_NOT_FOUND',			1701 );
+	define( 'ERROR_GROUP_NAME_INVALID',			1705 );
+
 	# ERROR_AUTH_*
 	define( 'ERROR_AUTH_INVALID_COOKIE',			900 );
 
Index: core/html_api.php
===================================================================
RCS file: /cvsroot/mantisbt/mantisbt/core/html_api.php,v
retrieving revision 1.88
diff -u -r1.88 html_api.php
--- core/html_api.php	29 Feb 2004 09:07:45 -0000	1.88
+++ core/html_api.php	26 May 2004 18:12:54 -0000
@@ -464,12 +464,14 @@
 		}
 
 		$t_manage_user_page 		= 'manage_user_page.php';
+		$t_manage_group_page		= 'manage_group_page.php';
 		$t_manage_project_menu_page = 'manage_proj_page.php';
 		$t_manage_custom_field_page = 'manage_custom_field_page.php';
 		$t_documentation_page 		= 'documentation_page.php';
 
 		switch ( $p_page ) {
 			case $t_manage_user_page				: $t_manage_user_page 				= ''; break;
+			case $t_manage_group_page:	  $t_manage_group_page		= ''; break;
 			case $t_manage_project_menu_page: $t_manage_project_menu_page 	= ''; break;
 			case $t_manage_custom_field_page: $t_manage_custom_field_page 	= ''; break;
 			case $t_documentation_page		: $t_documentation_page 		= ''; break;
@@ -477,6 +479,7 @@
 
 		echo '<br /><div align="center">';
 			print_bracket_link( $t_manage_user_page, lang_get( 'manage_users_link' ) );
+			print_bracket_link( $t_manage_group_page, lang_get( 'manage_groups_link' ) );
 			print_bracket_link( $t_manage_project_menu_page, lang_get( 'manage_projects_link' ) );
 			print_bracket_link( $t_manage_custom_field_page, lang_get( 'manage_custom_field_link' ) );
 			print_bracket_link( $t_documentation_page, lang_get( 'documentation_link' ) );
Index: core/print_api.php
===================================================================
RCS file: /cvsroot/mantisbt/mantisbt/core/print_api.php,v
retrieving revision 1.72
diff -u -r1.72 print_api.php
--- core/print_api.php	5 Feb 2004 01:17:13 -0000	1.72
+++ core/print_api.php	26 May 2004 18:12:54 -0000
@@ -697,6 +697,117 @@
 			PRINT $t_project_name.' ['.$t_access_level.'] ('.$t_view_state.') [<a class="small" href="manage_user_proj_delete.php?project_id='.$t_project_id.'&amp;user_id='.$p_user_id.'">'. lang_get( 'remove_link' ).'</a>]<br />';
 		}
 	}
+	
+	
+	# --------------------
+	# list of users that are NOT in the specified group and that are enabled
+	function print_group_user_list_option_list( $p_group_id=null ) {
+		global	$g_mantis_group_user_list_table, $g_mantis_user_table;
+
+		if ( null == $p_group_id ) {
+			return;
+		}
+		$c_group_id = (integer)$p_group_id;
+
+		$t_adm = ADMINISTRATOR;
+		$query = "SELECT DISTINCT u.id, u.username
+				FROM $g_mantis_user_table u
+				LEFT JOIN $g_mantis_group_user_list_table g
+				ON g.user_id=u.id AND g.group_id='$c_group_id'
+				WHERE u.access_level<$t_adm AND
+					u.enabled = 1 AND
+					g.user_id IS NULL AND
+					u.access_level<'$t_adm'
+				ORDER BY u.username";
+		$result = db_query( $query );
+		$category_count = db_num_rows( $result );
+		for ($i=0;$i<$category_count;$i++) {
+			$row = db_fetch_array( $result );
+			$t_username = $row['username'];
+			$t_user_id = $row['id'];
+			PRINT "<option value=\"$t_user_id\">$t_username</option>";
+		}
+	}
+	
+	# --------------------
+	# list of groups that a user is NOT in
+	function print_group_user_list_option_list2( $p_user_id ) {
+		global	$g_mantis_group_user_list_table, $g_mantis_group_table;
+
+		$c_user_id = db_prepare_int( $p_user_id );
+
+		$query = "SELECT DISTINCT g.id, g.groupname
+				FROM $g_mantis_group_table g
+				LEFT JOIN $g_mantis_group_user_list_table u
+				ON g.id=u.group_id AND u.user_id='$c_user_id'
+				WHERE g.enabled=1 AND
+					u.user_id IS NULL
+				ORDER BY g.groupname";
+		$result = db_query( $query );
+		$category_count = db_num_rows( $result );
+		for ($i=0;$i<$category_count;$i++) {
+			$row = db_fetch_array( $result );
+			$t_group_name	= $row['groupname'];
+			$t_user_id			= $row['id'];
+			PRINT "<option value=\"$t_user_id\">$t_group_name</option>";
+		}
+	}
+	# --------------------
+	# list of groups that a user is NOT in
+	function print_group_user_list( $p_user_id ) {
+		global	$g_mantis_group_user_list_table, $g_mantis_group_table;
+
+		$c_user_id = db_prepare_int( $p_user_id );
+
+		$query = "SELECT DISTINCT g.id, g.groupname
+				FROM $g_mantis_group_table g
+				LEFT JOIN $g_mantis_group_user_list_table u
+				ON g.id=u.group_id
+				WHERE g.enabled=1 AND
+					u.user_id='$c_user_id'
+				ORDER BY g.groupname";
+		$result = db_query( $query );
+		$category_count = db_num_rows( $result );
+		for ($i=0;$i<$category_count;$i++) {
+			$row = db_fetch_array( $result );
+			$t_group_id	= $row['id'];
+			$t_group_name	= $row['groupname'];
+			PRINT $t_group_name.' ['.$t_access_level.'] ('.$t_view_state.') [<a class="small" href="manage_user_proj_delete.php?project_id='.$t_project_id.'&amp;user_id='.$p_user_id.'">'. lang_get( 'remove_link' ).'</a>]<br />';
+		}
+	}
+
+	
+	# --------------------
+	# list of users that are NOT in the specified group and that are enabled
+	function print_bug_group_list_option_list( $p_bug_id=null ) {
+		global	$g_mantis_bug_group_list_table, $g_mantis_group_table;
+
+		if ( null == $p_bug_id ) {
+			return;
+		}
+		$c_bug_id = (integer)$p_bug_id;
+
+		$t_adm = ADMINISTRATOR;
+		$query = "SELECT DISTINCT u.id, u.groupname
+				FROM $g_mantis_group_table u
+				LEFT JOIN $g_mantis_bug_group_list_table g
+				ON g.group_id=u.id AND g.bug_id='$c_bug_id'
+				WHERE u.access_level<$t_adm AND
+					u.enabled = 1 AND
+					g.group_id IS NULL AND
+					u.access_level<'$t_adm'
+				ORDER BY u.groupname";
+		$result = db_query( $query );
+		$category_count = db_num_rows( $result );
+		for ($i=0;$i<$category_count;$i++) {
+			$row = db_fetch_array( $result );
+			$t_groupname = $row['groupname'];
+			$t_group_id = $row['id'];
+			PRINT "<option value=\"$t_group_id\">$t_groupname</option>";
+		}
+	}
+	
+	
 
 	# --------------------
 	###########################################################################
Index: lang/strings_english.txt
===================================================================
RCS file: /cvsroot/mantisbt/mantisbt/lang/strings_english.txt,v
retrieving revision 1.154
diff -u -r1.154 strings_english.txt
--- lang/strings_english.txt	22 Feb 2004 04:26:48 -0000	1.154
+++ lang/strings_english.txt	26 May 2004 18:12:55 -0000
@@ -203,6 +203,9 @@
 $MANTIS_ERROR[ERROR_VERSION_NOT_FOUND] = 'Version not found.';
 $MANTIS_ERROR[ERROR_USER_NAME_INVALID] = 'The username is invalid. Usernames may only contain letters, numbers, spaces, hyphens, and underscores.';
 $MANTIS_ERROR[ERROR_USER_DOES_NOT_HAVE_REQ_ACCESS] = 'User does not have required access level';
+$MANTIS_ERROR[ERROR_GROUP_NAME_INVALID] = 'ERROR: The groupname is invalid.';
+$MANTIS_ERROR[ERROR_GROUP_NOT_FOUND]  	= 'ERROR: The group was not found.';
+$MANTIS_ERROR[ERROR_GROUP_NAME_NOT_UNIQUE]  = 'ERROR: The groupname is not unique.';
 
 $s_login_error = 'ERROR: your account may be disabled or the username/password you entered is incorrect.';
 $s_login_cookies_disabled = 'ERROR: Your browser either doesn\'t know how to handle cookies, or refuses to handle them.';
@@ -532,6 +535,24 @@
 $s_last_visit = 'Last Visit';
 $s_edit_user_link = 'Edit User';
 
+# manage_group_page.php 
+$s_manage_groups_link = 'Manage Groups';
+$s_manage_groups_title = 'Manage Groups';
+$s_new_groups_title = 'New Groups';
+$s_create_new_group_link = 'Create New Group';
+$s_groupname = 'Groupname';
+$s_update_group_button = 'Update Group';
+$s_group_level = 'Group Level';
+
+# manage_group_create_page.php
+$s_create_new_group_title = 'Create New Group';
+$s_create_group_button = 'Create Group';
+$s_group_add_user_title = 'Add User to Group';
+
+# manage_create_new_group.php
+$s_created_group_part1 = 'Created group';
+$s_created_group_part2 = 'with an access level of';
+
 # manage_proj_add.php
 $s_project_added_msg = 'Project has been successfully added...';
 
@@ -634,6 +655,14 @@
 $s_manage_user_protected_msg = 'Account protected. Access level and enabled protected. Otherwise, account has been updated...';
 $s_manage_user_updated_msg = 'Account successfully updated...';
 
+# manage_group_page.php
+$s_edit_group_title = 'Edit Group';
+$s_delete_group_button = 'Delete Group';
+
+# manage_group_update.php
+$s_manage_group_protected_msg = 'Group protected. Access level and enabled protected. Otherwise, account has been updated...';
+$s_manage_group_updated_msg = 'Group successfully updated...';
+
 # menu_inc.php
 $s_main_link = 'Main';
 $s_view_bugs_link = 'View Bugs';
@@ -724,6 +753,12 @@
 # proj_user_update.php
 $s_updated_user_msg = 'Successfully updated user';
 
+# bug_group_add
+$s_bug_add_group_title = 'Add Group to View List';
+$s_bug_group_list_title = 'Group View List';
+$s_add_group_button = 'Add Group';
+$s_manage_view_list_title = 'Manage View List';
+
 # report_add.php
 $s_must_enter_category = 'You must select a category';
 $s_must_enter_severity = 'You must select a severity';
Index: bug_group_add.php
===================================================================
RCS file: bug_group_add.php
diff -N bug_group_add.php
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ bug_group_add.php	1 Jan 1970 00:00:00 -0000
@@ -0,0 +1,25 @@
+<?php
+	# Mantis - a php based bugtracking system
+	# Copyright (C) 2000 - 2002  Kenzaburo Ito - kenito@300baud.org
+	# Copyright (C) 2002 - 2003  Mantis Team   - mantisbt-dev@lists.sourceforge.net
+	# This program is distributed under the terms and conditions of the GPL
+	# See the README and LICENSE files for details
+
+	# --------------------------------------------------------
+	# $Id: bug_group_add.php,v 1.1 2003/08/08 20:14:07 dwoods Exp $
+	# --------------------------------------------------------
+?>
+<?php require_once( 'core.php' ) ?>
+<?php
+	$f_bug_id	= gpc_get_int( 'bug_id' );
+	$f_group_id	= gpc_get_int_array( 'group_id', array() );
+
+	access_ensure_global_level( DEVELOPER );
+
+	# Add user(s) to the current group
+	foreach( $f_group_id as $t_group_id ) {
+		bug_add_group( $f_bug_id, $t_group_id );
+	}
+
+	print_header_redirect( 'bug_view_advanced_page.php?bug_id=' . $f_bug_id );
+?>
Index: bug_group_remove.php
===================================================================
RCS file: bug_group_remove.php
diff -N bug_group_remove.php
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ bug_group_remove.php	1 Jan 1970 00:00:00 -0000
@@ -0,0 +1,22 @@
+<?php
+	# Mantis - a php based bugtracking system
+	# Copyright (C) 2000 - 2002  Kenzaburo Ito - kenito@300baud.org
+	# Copyright (C) 2002 - 2003  Mantis Team   - mantisbt-dev@lists.sourceforge.net
+	# This program is distributed under the terms and conditions of the GPL
+	# See the README and LICENSE files for details
+
+	# --------------------------------------------------------
+	# $Id: bug_group_remove.php,v 1.1 2003/08/08 20:14:22 dwoods Exp $
+	# --------------------------------------------------------
+?>
+<?php require_once( 'core.php' ) ?>
+<?php
+	$f_bug_id	= gpc_get_int( 'bug_id' );
+	$f_group_id	= gpc_get_int( 'group_id' );
+
+	access_ensure_project_level( DEVELOPER );
+
+	bug_remove_group( $f_bug_id, $f_group_id );
+
+	print_header_redirect( 'bug_view_advanced_page.php?bug_id=' . $f_bug_id );
+?>
Index: manage_group_create.php
===================================================================
RCS file: manage_group_create.php
diff -N manage_group_create.php
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ manage_group_create.php	1 Jan 1970 00:00:00 -0000
@@ -0,0 +1,60 @@
+<?php
+	# Mantis - a php based bugtracking system
+	# Copyright (C) 2000 - 2002  Kenzaburo Ito - kenito@300baud.org
+	# Copyright (C) 2002 - 2003  Mantis Team   - mantisbt-dev@lists.sourceforge.net
+	# This program is distributed under the terms and conditions of the GPL
+	# See the README and LICENSE files for details
+
+	# --------------------------------------------------------
+	# $Id: manage_group_create.php,v 1.1 2003/08/06 19:50:23 dwoods Exp $
+	# --------------------------------------------------------
+?>
+<?php
+	require_once( 'core.php' );
+	
+	$t_core_path = config_get( 'core_path' );
+	
+	require_once( $t_core_path.'email_api.php' );
+	require_once( $t_core_path.'group_api.php' );
+?>
+<?php
+	access_ensure_global_level( config_get( 'manage_user_threshold' ) );
+
+	$f_groupname	= gpc_get_string( 'groupname' );
+	$f_access_level	= gpc_get_string( 'access_level' );
+	$f_protected	= gpc_get_bool( 'protected' );
+	$f_enabled	= gpc_get_bool( 'enabled' );
+
+	# check for empty username
+	$f_groupname = trim( $f_groupname );
+	if ( is_blank( $f_groupname ) ) {
+		trigger_error( ERROR_EMPTY_FIELD, ERROR );
+	}
+
+	# Check the name for validity here so we do it before promting to use a
+	#  blank password (don't want to prompt the user if the process will fail
+	#  anyway)
+	group_ensure_name_valid( $f_groupname );
+
+	group_create( $f_groupname, $f_access_level, $f_protected, $f_enabled );
+
+	$t_redirect_url = 'manage_group_page.php';
+
+	html_page_top1();
+
+	html_meta_redirect( $t_redirect_url );
+
+	html_page_top2();
+?>
+
+<br />
+<div align="center">
+<?php
+	$t_access_level = get_enum_element( 'access_levels', $f_access_level );
+	echo lang_get( 'created_group_part1' ) . ' <span class="bold">' . $f_groupname . '</span> ' . lang_get( 'created_group_part2' ) . ' <span class="bold">' . $t_access_level . '</span><br />';
+
+	print_bracket_link( $t_redirect_url, lang_get( 'proceed' ) );
+?>
+</div>
+
+<?php html_page_bottom1( __FILE__ ) ?>
Index: manage_group_create_page.php
===================================================================
RCS file: manage_group_create_page.php
diff -N manage_group_create_page.php
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ manage_group_create_page.php	1 Jan 1970 00:00:00 -0000
@@ -0,0 +1,73 @@
+<?php
+	# Mantis - a php based bugtracking system
+	# Copyright (C) 2000 - 2002  Kenzaburo Ito - kenito@300baud.org
+	# Copyright (C) 2002 - 2003  Mantis Team   - mantisbt-dev@lists.sourceforge.net
+	# This program is distributed under the terms and conditions of the GPL
+	# See the README and LICENSE files for details
+
+	# --------------------------------------------------------
+	# $Id: manage_group_create_page.php,v 1.1 2003/08/06 19:50:55 dwoods Exp $
+	# --------------------------------------------------------
+?>
+<?php require_once( 'core.php' ) ?>
+<?php
+	access_ensure_global_level( config_get( 'manage_user_threshold' ) );
+
+	html_page_top1();
+	html_page_top2();
+
+	print_manage_menu( 'manage_group_create_page.php' );
+?>
+<br />
+<div align="center">
+<form method="post" action="manage_group_create.php">
+<table class="width50" cellspacing="1">
+<tr>
+	<td class="form-title" colspan="2">
+		<?php echo lang_get( 'create_new_group_title' ) ?>
+	</td>
+</tr>
+<tr <?php echo helper_alternate_class() ?>>
+	<td class="category" width="25%">
+		<?php echo lang_get( 'groupname' ) ?>
+	</td>
+	<td width="75%">
+		<input type="text" name="groupname" size="32" maxlength="32" />
+	</td>
+</tr>
+<tr <?php echo helper_alternate_class() ?>>
+	<td class="category">
+		<?php echo lang_get( 'access_level' ) ?>
+	</td>
+	<td>
+		<select name="access_level">
+			<?php print_enum_string_option_list( 'access_levels', config_get( 'default_new_group_access_level' ) ) ?>
+		</select>
+	</td>
+</tr>
+<tr <?php echo helper_alternate_class() ?>>
+	<td class="category">
+		<?php echo lang_get( 'enabled' ) ?>
+	</td>
+	<td>
+		<input type="checkbox" name="enabled" checked="checked" />
+	</td>
+</tr>
+<tr <?php echo helper_alternate_class() ?>>
+	<td class="category">
+		<?php echo lang_get( 'protected' ) ?>
+	</td>
+	<td colspan="2">
+		<input type="checkbox" name="protected" />
+	</td>
+</tr>
+<tr>
+	<td class="center" colspan="2">
+		<input type="submit" value="<?php echo lang_get( 'create_group_button' ) ?>" />
+	</td>
+</tr>
+</table>
+</form>
+</div>
+
+<?php html_page_bottom1( __FILE__ ) ?>
Index: manage_group_edit_page.php
===================================================================
RCS file: manage_group_edit_page.php
diff -N manage_group_edit_page.php
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ manage_group_edit_page.php	1 Jan 1970 00:00:00 -0000
@@ -0,0 +1,187 @@
+<?php
+	# Mantis - a php based bugtracking system
+	# Copyright (C) 2000 - 2002  Kenzaburo Ito - kenito@300baud.org
+	# Copyright (C) 2002 - 2003  Mantis Team   - mantisbt-dev@lists.sourceforge.net
+	# This program is distributed under the terms and conditions of the GPL
+	# See the README and LICENSE files for details
+
+	# --------------------------------------------------------
+	# $Id: manage_group_edit_page.php,v 1.1 2003/08/06 19:50:55 dwoods Exp $
+	# --------------------------------------------------------
+?>
+<?php 	require_once( 'core.php' ); ?>
+
+<?php
+	access_ensure_global_level( config_get( 'manage_user_threshold' ) );
+
+	$f_group_id = gpc_get_int( 'group_id' );
+
+	$t_group = group_get_row( $f_group_id );
+
+	html_page_top1();
+	html_page_top2();
+
+	print_manage_menu();
+?>
+
+<br />
+
+
+<!-- USER INFO -->
+<div align="center">
+<form method="post" action="manage_group_update.php">
+<table class="width75" cellspacing="1">
+<!-- Title -->
+<tr>
+	<td class="form-title" colspan="2">
+		<input type="hidden" name="group_id" value="<?php echo $t_group['id'] ?>" />
+		<?php echo lang_get( 'edit_group_title' ) ?>
+	</td>
+</tr>
+
+<!-- Groupname -->
+<tr <?php echo helper_alternate_class( 1 ) ?>>
+	<td class="category" width="30%">
+		<?php echo lang_get( 'groupname' ) ?>:
+	</td>
+	<td width="70%">
+		<input type="text" size="16" maxlength="32" name="groupname" value="<?php echo $t_group['groupname'] ?>" />
+	</td>
+</tr>
+
+<!-- Group Level -->
+<tr <?php echo helper_alternate_class() ?>>
+	<td class="category">
+		<?php echo lang_get( 'group_level' ) ?>:
+	</td>
+	<td>
+		<select name="access_level">
+			<?php print_enum_string_option_list( 'access_levels', $t_group['access_level'] ) ?>
+		</select>
+	</td>
+</tr>
+
+<!-- Enabled Checkbox -->
+<tr <?php echo helper_alternate_class() ?>>
+	<td class="category">
+		<?php echo lang_get( 'enabled' ) ?>:
+	</td>
+	<td>
+		<input type="checkbox" name="enabled" <?php check_checked( $t_group['enabled'], ON ); ?> />
+	</td>
+</tr>
+
+<!-- Protected Checkbox -->
+<tr <?php echo helper_alternate_class() ?>>
+	<td class="category">
+		<?php echo lang_get( 'protected' ) ?>:
+	</td>
+	<td>
+		<input type="checkbox" name="protected" <?php check_checked( $t_group['protected'], ON ); ?> />
+	</td>
+</tr>
+
+<!-- Submit Button -->
+<tr>
+	<td colspan="2" class="center">
+		<input type="submit" value="<?php echo lang_get( 'update_group_button' ) ?>" />
+	</td>
+</tr>
+</table>
+</form>
+</div>
+
+<br />
+
+
+<!-- USER MANAGEMENT (ADD) -->
+
+<br />
+<div align="center">
+	<form method="post" action="manage_group_user_add.php">
+		<input type="hidden" name="group_id" value="<?php echo $f_group_id ?>" />
+		<table class="width75" cellspacing="1">
+			<tr>
+				<td class="form-title" colspan="5">
+					<?php echo lang_get( 'group_add_user_title' ) ?>
+				</td>
+			</tr>
+			<tr class="row-1" valign="top">
+				<td class="category">
+					<?php echo lang_get( 'username' ) ?>
+				</td>
+				<td>
+					<select name="user_id[]" multiple size="10">
+						<?php print_group_user_list_option_list( $f_group_id ) ?>
+					</select>
+				</td>
+				<td>
+					<input type="submit" value="<?php echo lang_get( 'add_user_button' ) ?>" />
+				</td>
+			</tr>
+		</table>
+	</form>
+</div>
+
+
+<!-- LIST OF USERS -->
+<br />
+<div align="center">
+	<table class="width75" cellspacing="1">
+		<tr>
+			<td class="form-title" colspan="4">
+				<?php echo lang_get( 'manage_groups_title' ) ?>
+			</td>
+		</tr>
+		<tr class="row-category">
+			<td>
+				<?php echo lang_get( 'username' ) ?>
+			</td>
+			<td>
+				<?php echo lang_get( 'email' ) ?>
+			</td>
+			<td>
+				<?php echo lang_get( 'access_level' ) ?>
+			</td>
+			<td class="center">
+				<?php echo lang_get( 'actions' ) ?>
+			</td>
+		</tr>
+<?php
+	$t_users = group_get_all_user_rows( $f_group_id );
+
+	# reset the class counter
+	helper_alternate_class( 0 );
+
+	foreach ( $t_users as $t_user ) {
+?>
+		<tr <?php echo helper_alternate_class() ?>>
+			<td>
+				<?php echo $t_user['username'] ?>
+			</td>
+			<td>
+			<?php 
+				$t_email = user_get_email( $t_user['id'] );
+				print_email_link( $t_email, $t_email );
+			?>
+			</td>
+			<td>
+				<?php echo get_enum_element( 'access_levels', $t_user['access_level'] ) ?>
+			</td>
+			<td class="center">
+			<?php
+				if ( access_has_global_level( config_get( 'manage_user_threshold' ) ) ) {
+					if ( group_includes_user( $f_group_id, $t_user['id'] )  ) {
+						print_bracket_link( 'manage_group_user_remove.php?group_id=' . $f_group_id . '&amp;user_id=' . $t_user['id'], lang_get( 'remove_link' ) );
+					}
+				}
+			?>
+			</td>
+		</tr>
+<?php
+	}  # end for
+?>
+	</table>
+</div>
+
+<?php html_page_bottom1( __FILE__ ) ?>
Index: manage_group_page.php
===================================================================
RCS file: manage_group_page.php
diff -N manage_group_page.php
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ manage_group_page.php	1 Jan 1970 00:00:00 -0000
@@ -0,0 +1,173 @@
+<?php
+	# Mantis - a php based bugtracking system
+	# Copyright (C) 2000 - 2002  Kenzaburo Ito - kenito@300baud.org
+	# Copyright (C) 2002 - 2003  Mantis Team   - mantisbt-dev@lists.sourceforge.net
+	# This program is distributed under the terms and conditions of the GPL
+	# See the README and LICENSE files for details
+?>
+<?php
+	require_once( 'core.php' );
+	
+	$t_core_path = config_get( 'core_path' );
+
+	require_once( $t_core_path . 'icon_api.php' );
+?>
+<?php
+	access_ensure_global_level( config_get( 'manage_user_threshold' ) );
+
+	$f_sort	= gpc_get_string( 'sort', 'username' );
+	$f_dir	= gpc_get_string( 'dir', 'ASC' );
+	$f_hide = gpc_get_bool( 'hide' );
+	$f_save = gpc_get_bool( 'save' );
+
+	$t_cookie_name = config_get( 'manage_cookie' );
+
+	# set cookie values for hide, sort by, and dir
+	if ( $f_save ) {
+		$t_manage_string = $f_hide.':'.$f_sort.':'.$f_dir;
+		gpc_set_cookie( $t_cookie_name, $t_manage_string, true );
+	} else if ( !is_blank( gpc_get_cookie( $t_cookie_name, '' ) ) ) {
+		$t_manage_arr = explode( ':', gpc_get_cookie( $t_cookie_name ) );
+		$f_hide = $t_manage_arr[0];
+
+		if ( isset( $t_manage_arr[1] ) ) {
+			$f_sort = $t_manage_arr[1];
+		} else {
+			$f_sort = 'username';
+		}
+
+		if ( isset( $t_manage_arr[2] ) ) {
+			$f_dir  = $t_manage_arr[2];
+		} else {
+			$f_dir = 'DESC';
+		}
+	}
+
+	# Clean up the form variables
+	$c_sort = addslashes($f_sort);
+
+	if ($f_dir == 'ASC') {
+		$c_dir = 'ASC';
+	} else {
+		$c_dir = 'DESC';
+	}
+
+	if ($f_hide == 0) { # a 0 will turn it off
+		$c_hide = 0;
+	} else {            # anything else (including 'on') will turn it on
+		$c_hide = 1;
+	}
+?>
+<?php html_page_top1() ?>
+<?php html_page_top2() ?>
+
+<?php print_manage_menu( 'manage_group_page.php' ) ?>
+
+<?php # New Groups Form BEGIN ?>
+<?php
+	$t_group_table = config_get( 'mantis_group_table' );
+
+	$days_old = 7;
+	$query = "SELECT *
+		FROM $t_group_table
+		WHERE TO_DAYS(NOW()) - TO_DAYS(date_created) <= '$days_old'
+		ORDER BY date_created DESC";
+	$result = db_query( $query );
+	$new_group_count = db_num_rows( $result );
+?>
+<br />
+<table class="width100" cellspacing="1">
+<tr>
+	<td class="form-title">
+		<?php echo lang_get( 'new_groups_title' ) ?> (<?php echo lang_get( '1_week_title' ) ?>) [<?php echo $new_group_count ?>]
+	</td>
+</tr>
+<tr <?php echo helper_alternate_class() ?>>
+	<td>
+<?php
+for ($i=0;$i<$new_group_count;$i++) {
+	$row = db_fetch_array( $result );
+	$t_groupname = $row['groupname'];
+
+	echo $t_groupname.' : ';
+}
+?>
+	</td>
+</tr>
+</table>
+<?php # New Accounts Form END ?>
+
+
+<?php # Manage Form BEGIN ?>
+<?php
+	# Get the group data in $c_sort order
+	$query = "SELECT *,  UNIX_TIMESTAMP(date_created) as date_created
+			FROM $t_group_table
+			ORDER BY '$c_sort' $c_dir";
+
+	$result = db_query($query);
+	$group_count = db_num_rows( $result );
+?>
+<br />
+<table class="width100" cellspacing="1">
+<tr>
+	<td class="form-title" colspan="5">
+		<?php echo lang_get( 'manage_groups_title' ) ?> [<?php echo $group_count ?>]
+		<?php print_bracket_link( 'manage_group_create_page.php', lang_get( 'create_new_group_link' ) ) ?>
+	</td>
+	<td class="center" colspan="2">
+		<form method="post" action="manage_group_page.php">
+		<input type="hidden" name="sort" value="<?php echo $c_sort ?>" />
+		<input type="hidden" name="dir" value="<?php echo $c_dir ?>" />
+		<input type="hidden" name="save" value="1" />
+		<input type="checkbox" name="hide" value="1" <?php check_checked( $c_hide, 1 ); ?> /> <?php echo lang_get( 'hide_inactive' ) ?>
+		<input type="submit" value="<?php echo lang_get( 'filter_button' ) ?>" />
+		</form>
+	</td>
+</tr>
+<tr class="row-category">
+	<td>
+		<?php print_manage_user_sort_link(  'manage_group_page.php', lang_get( 'groupname' ), 'groupname', $c_dir, $c_sort, $c_hide ) ?>
+		<?php print_sort_icon( $c_dir, $c_sort, 'groupname' ) ?>
+	</td>
+	<td>
+		<?php print_manage_user_sort_link(  'manage_group_page.php', lang_get( 'group_level' ), 'access_level', $c_dir, $c_sort, $c_hide ) ?>
+		<?php print_sort_icon( $c_dir, $c_sort, 'access_level' ) ?>
+	</td>
+	<td>
+		<?php print_manage_user_sort_link(  'manage_group_page.php', lang_get( 'enabled' ), 'enabled', $c_dir, $c_sort, $c_hide ) ?>
+		<?php print_sort_icon( $c_dir, $c_sort, 'enabled' ) ?>
+	</td>
+	<td>
+		<?php print_manage_user_sort_link(  'manage_group_page.php', lang_get( 'protected' ), 'protected', $c_dir, $c_sort, $c_hide ) ?>
+		<?php print_sort_icon( $c_dir, $c_sort, 'protected' ) ?>
+	</td>
+	<td>
+		<?php print_manage_user_sort_link(  'manage_group_page.php', lang_get( 'date_created' ), 'date_created', $c_dir, $c_sort, $c_hide ) ?>
+		<?php print_sort_icon( $c_dir, $c_sort, 'date_created' ) ?>
+	</td>
+</tr>
+<?php
+	for ($i=0;$i<$group_count;$i++) {
+		# prefix group data with g_
+		$row = db_fetch_array($result);
+		extract( $row, EXTR_PREFIX_ALL, 'g' );
+
+		$g_date_created  = date( config_get( 'normal_date_format' ), $g_date_created );
+?>
+<tr <?php echo helper_alternate_class( $i ) ?>>
+	<td>
+		<a href="manage_group_edit_page.php?group_id=<?php echo $g_id ?>"><?php echo $g_groupname ?></a>
+	</td>
+	<td><?php echo get_enum_element( 'access_levels', $g_access_level ) ?></td>
+	<td><?php echo trans_bool( $g_enabled ) ?></td>
+	<td><?php echo trans_bool( $g_protected ) ?></td>
+	<td><?php echo $g_date_created ?></td>
+</tr>
+<?php
+	}  # end for
+?>
+</table>
+<?php # Manage Form END ?>
+
+<?php html_page_bottom1( __FILE__ ) ?>
Index: manage_group_update.php
===================================================================
RCS file: manage_group_update.php
diff -N manage_group_update.php
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ manage_group_update.php	1 Jan 1970 00:00:00 -0000
@@ -0,0 +1,81 @@
+<?php
+	# Mantis - a php based bugtracking system
+	# Copyright (C) 2000 - 2002  Kenzaburo Ito - kenito@300baud.org
+	# Copyright (C) 2002 - 2003  Mantis Team   - mantisbt-dev@lists.sourceforge.net
+	# This program is distributed under the terms and conditions of the GPL
+	# See the README and LICENSE files for details
+?>
+<?php
+	require_once( 'core.php' );
+?>
+<?php
+	access_ensure_global_level( config_get( 'manage_user_threshold' ) );
+
+	$f_protected	= gpc_get_bool( 'protected' );
+	$f_enabled	= gpc_get_bool( 'enabled' );
+	$f_groupname	= gpc_get_string( 'groupname', '' );
+	$f_access_level	= gpc_get_int( 'access_level' );
+	$f_group_id	= gpc_get_int( 'group_id' );
+	
+	$f_username	= trim( $f_groupname );
+
+	$t_old_groupname = group_get_field( $f_group_id, 'groupname' );
+
+	# check that the username is unique
+	if ( $t_old_groupname != $f_groupname &&
+		 false == group_is_name_unique( $f_groupname ) ) {
+		trigger_error( ERROR_GROUP_NAME_NOT_UNIQUE, ERROR );
+	}
+
+	$c_groupname	= db_prepare_string( $f_groupname );
+	$c_protected	= db_prepare_bool( $f_protected );
+	$c_enabled	= db_prepare_bool( $f_enabled );
+	$c_group_id	= db_prepare_int( $f_group_id );
+	$c_access_level	= db_prepare_int( $f_access_level );
+
+	$t_group_table = config_get( 'mantis_group_table' );
+
+	$t_old_protected = group_get_field( $f_group_id, 'protected' );
+
+	# if the group is already protected and the admin is not removing the
+	#  protected flag then don't update the access level and enabled flag.
+	#  If the group was unprotected or the protected flag is being turned off
+	#  then proceed with a full update.
+	if ( $f_protected && $t_old_protected ) {
+	    $query = "UPDATE $t_group_table
+	    		SET groupname='$c_groupname', protected='$c_protected'
+	    		WHERE id='$c_group_id'";
+	} else {
+	    $query = "UPDATE $t_group_table
+	    		SET groupname='$c_groupname', access_level='$c_access_level', 
+				enabled='$c_enabled', protected='$c_protected'
+	    		WHERE id='$c_group_id'";
+	}
+
+    $result = db_query( $query );
+    $t_redirect_url = 'manage_group_page.php';
+?>
+<?php html_page_top1() ?>
+<?php
+	if ( $result ) {
+		html_meta_redirect( $t_redirect_url );
+	}
+?>
+<?php html_page_top2() ?>
+
+<br />
+<div align="center">
+<?php
+	if ( $f_protected && $t_old_protected ) {				# PROTECTED
+		echo lang_get( 'manage_group_protected_msg' ) . '<br />';
+	} else if ( $result ) {					# SUCCESS
+		echo lang_get( 'operation_successful' ) . '<br />';
+	} else {								# FAILURE
+		print_sql_error( $query );
+	}
+
+	print_bracket_link( $t_redirect_url, lang_get( 'proceed' ) );
+?>
+</div>
+
+<?php html_page_bottom1( __FILE__ ) ?>
Index: manage_group_user_add.php
===================================================================
RCS file: manage_group_user_add.php
diff -N manage_group_user_add.php
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ manage_group_user_add.php	1 Jan 1970 00:00:00 -0000
@@ -0,0 +1,25 @@
+<?php
+	# Mantis - a php based bugtracking system
+	# Copyright (C) 2000 - 2002  Kenzaburo Ito - kenito@300baud.org
+	# Copyright (C) 2002 - 2003  Mantis Team   - mantisbt-dev@lists.sourceforge.net
+	# This program is distributed under the terms and conditions of the GPL
+	# See the README and LICENSE files for details
+
+	# --------------------------------------------------------
+	# $Id: manage_group_user_add.php,v 1.2 2003/08/08 20:13:01 dwoods Exp $
+	# --------------------------------------------------------
+?>
+<?php require_once( 'core.php' ) ?>
+<?php
+	$f_group_id	= gpc_get_int( 'group_id' );
+	$f_user_id	= gpc_get_int_array( 'user_id', array() );
+
+	access_ensure_global_level( config_get( 'manage_user_threshold' ) );
+
+	# Add user(s) to the current group
+	foreach( $f_user_id as $t_user_id ) {
+		group_add_user( $f_group_id, $t_user_id );
+	}
+
+	print_header_redirect( 'manage_group_edit_page.php?group_id=' . $f_group_id );
+?>
Index: manage_group_user_remove.php
===================================================================
RCS file: manage_group_user_remove.php
diff -N manage_group_user_remove.php
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ manage_group_user_remove.php	1 Jan 1970 00:00:00 -0000
@@ -0,0 +1,27 @@
+<?php
+	# Mantis - a php based bugtracking system
+	# Copyright (C) 2000 - 2002  Kenzaburo Ito - kenito@300baud.org
+	# Copyright (C) 2002 - 2003  Mantis Team   - mantisbt-dev@lists.sourceforge.net
+	# This program is distributed under the terms and conditions of the GPL
+	# See the README and LICENSE files for details
+
+	# --------------------------------------------------------
+	# $Id: manage_group_user_remove.php,v 1.1 2003/08/06 19:50:55 dwoods Exp $
+	# --------------------------------------------------------
+?>
+<?php require_once( 'core.php' ) ?>
+<?php
+	$f_group_id	= gpc_get_int( 'group_id' );
+	$f_user_id	= gpc_get_int( 'user_id' );
+
+	# We should check both since we are in the group section and an
+	#  admin might raise the first threshold and not realize they need
+	#  to raise the second 
+	# Eventually there will be separate access levels for managing groups
+	access_ensure_project_level( config_get( 'manage_user_threshold' ) ); # group threshold
+	access_ensure_project_level( config_get( 'manage_user_threshold' ) ); # user threshold
+
+	group_remove_user( $f_group_id, $f_user_id );
+
+	print_header_redirect( 'manage_group_edit_page.php?group_id=' . $f_group_id );
+?>
Index: core/group_api.php
===================================================================
RCS file: core/group_api.php
diff -N core/group_api.php
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ core/group_api.php	1 Jan 1970 00:00:00 -0000
@@ -0,0 +1,606 @@
+<?php
+	# Mantis - a php based bugtracking system
+	# Copyright (C) 2000 - 2002  Kenzaburo Ito - kenito@300baud.org
+	# Copyright (C) 2002 - 2003  Mantis Team   - mantisbt-dev@lists.sourceforge.net
+	# This program is distributed under the terms and conditions of the GPL
+	# See the README and LICENSE files for details
+
+	# --------------------------------------------------------
+	# $Id: group_api.php,v 1.2 2003/08/08 20:16:05 dwoods Exp $
+	# --------------------------------------------------------
+
+	$t_core_dir = dirname( __FILE__ ).DIRECTORY_SEPARATOR;
+	
+	require_once( $t_core_dir . 'email_api.php' );
+	require_once( $t_core_dir . 'ldap_api.php' );
+
+	###########################################################################
+	# Group API
+	###########################################################################
+
+	#===================================
+	# Caching
+	#===================================
+
+	#########################################
+	# SECURITY NOTE: cache globals are initialized here to prevent them
+	#   being spoofed if register_globals is turned on
+	#
+	$g_cache_group = array();
+
+	# --------------------
+	# Cache a group row if necessary and return the cached copy
+	#  If the second parameter is true (default), trigger an error
+	#  if the group can't be found.  If the second parameter is
+	#  false, return false if the group can't be found.
+	function group_cache_row( $p_group_id, $p_trigger_errors=true) {
+		global $g_cache_group;
+
+		$c_group_id = db_prepare_int( $p_group_id );
+
+		$t_group_table = config_get( 'mantis_group_table' );
+
+		if ( isset ( $g_cache_group[$c_group_id] ) ) {
+			return $g_cache_group[$c_group_id];
+		}
+
+		$query = "SELECT *
+				  FROM $t_group_table
+				  WHERE id='$c_group_id'";
+		$result = db_query( $query );
+
+		if ( 0 == db_num_rows( $result ) ) {
+			if ( $p_trigger_errors ) {
+				trigger_error( ERROR_GROUP_NOT_FOUND, ERROR );
+			} else {
+				return false;
+			}
+		}
+
+		$row = db_fetch_array( $result );
+
+		$g_cache_group[$c_group_id] = $row;
+
+		return $row;
+	}
+
+	# --------------------
+	# Clear the group cache (or just the given id if specified)
+	function group_clear_cache( $p_group_id = null ) {
+		global $g_cache_group;
+
+		if ( null === $p_group_id ) {
+			$g_cache_group = array();
+		} else {
+			$c_group_id = db_prepare_int( $p_group_id );
+			unset( $g_cache_group[$c_group_id] );
+		}
+
+		return true;
+	}
+
+	#===================================
+	# Boolean queries and ensures
+	#===================================
+
+	# --------------------
+	# check to see if group exists by id
+	# return true if it does, false otherwise
+	#
+	# Use group_cache_row() to benefit from caching if called multiple times
+	#  and because if the user does exist the data may well be wanted
+	function group_exists( $p_group_id ) {
+		$row = group_cache_row( $p_group_id, false );
+
+		if ( false === $row ) {
+			return false;
+		} else {
+			return true;
+		}
+	}
+
+	# --------------------
+	# check to see if group exists by id
+	# if it doesn't exist then error
+	#  otherwise let execution continue undisturbed
+	function group_ensure_exists( $p_group_id ) {
+		if ( ! group_exists( $p_group_id ) ) {
+			trigger_error( ERROR_USER_NOT_FOUND, ERROR );
+		}
+	}
+
+	# --------------------
+	# return true if the groupname is unique, false if there is already a group
+	#  with that groupname
+	function group_is_name_unique( $p_groupname ) {
+		$c_groupname = db_prepare_string( $p_groupname );
+
+		$t_group_table = config_get( 'mantis_group_table' );
+
+		$query = "SELECT COUNT(*)
+				  FROM $t_group_table
+				  WHERE groupname='$c_groupname'";
+
+	    $result = db_query( $query );
+
+	    if ( db_result( $result ) > 0 ) {
+			return false;
+		} else {
+			return true;
+		}
+	}
+
+	# --------------------
+	# Check if the groupname is unique and trigger an ERROR if it isn't
+	function group_ensure_name_unique( $p_groupname ) {
+		if ( ! group_is_name_unique( $p_groupname ) ) {
+			trigger_error( ERROR_USER_NAME_NOT_UNIQUE, ERROR );
+		}
+	}
+
+	# --------------------
+	# Check if the groupname is a valid username (does not account for uniqueness)
+	# Return true if it is, false otherwise
+	function group_is_name_valid( $p_groupname ) {
+		# The DB field is only 32 characters
+		if ( strlen( $p_groupname ) > 32 ) {
+			return false;	
+		}
+
+		# Only allow a basic set of characters
+		if ( 0 == preg_match( '/^\w+$/', $p_groupname ) ) {
+			return false;
+		}
+
+		# We have a valid groupname
+		return true;
+	}
+
+	# --------------------
+	# Check if the groupname is a valid groupname (does not account for uniqueness)
+	# Trigger an error if the username is not valid
+	function group_ensure_name_valid( $p_groupname ) {
+		if ( ! group_is_name_valid( $p_groupname ) ) {
+			trigger_error( ERROR_USER_NAME_INVALID, ERROR );
+		}
+	}
+
+	# --------------------
+	# return whether user is monitoring bug for the user id and bug id
+	# -- NOT IMPLEMENTED YET --- dwoods
+	/*
+	function group_is_monitoring_bug( $p_group_id, $p_bug_id ) {
+		$c_group_id	= db_prepare_int( $p_group_id );
+		$c_bug_id	= db_prepare_int( $p_bug_id );
+
+		$t_bug_monitor_table = config_get( 'mantis_bug_monitor_table' );
+
+		$query = "SELECT COUNT(*)
+				  FROM $t_bug_monitor_table
+				  WHERE user_id='$c_group_id' AND bug_id='$c_bug_id'";
+
+		$result = db_query( $query );
+
+		if ( 0 == db_result( $result ) ) {
+			return false;
+		} else {
+			return true;
+		}
+	}
+	*/
+
+	# --------------------
+	# return true if the user has access of ADMINISTRATOR or higher, false otherwise
+	# --- NOT IMPLEMENTED YET --- dwoods
+	/*
+	function group_is_development( $p_group_id ) {
+		$t_access_level = user_get_field( $p_group_id, 'access_level' );
+
+		if ( $t_access_level >= DEVELOPER ) {
+			return true;
+		} else {
+			return false;
+		}
+	}
+	*/
+
+	# --------------------
+	# return true is the group account is protected, false otherwise
+	function group_is_protected( $p_group_id ) {
+		return ( ON == group_get_field( $p_group_id, 'protected' ) );
+	}
+
+	# --------------------
+	# Trigger an ERROR if the group is protected
+	function group_ensure_unprotected( $p_group_id ) {
+		if ( group_is_protected( $p_group_id ) ) {
+			trigger_error( ERROR_PROTECTED_ACCOUNT, ERROR );
+		}
+	}
+
+	# --------------------
+	# return true is the group is enabled, false otherwise
+	function group_is_enabled( $p_group_id ) {
+		return ( ON == group_get_field( $p_group_id, 'enabled' ) );
+	}
+
+	#===================================
+	# Creation / Deletion / Updating
+	#===================================
+
+	# --------------------
+	# Create a user.
+	# returns false if error, the generated cookie string if ok
+	function group_create( $p_groupname, $p_access_level=null, $p_protected=false, $p_enabled=true ) {
+		if ( null === $p_access_level ) {
+			$p_access_level = config_get( 'default_new_group_access_level');
+		}
+
+		$c_groupname	= db_prepare_string( $p_groupname );
+		$c_access_level	= db_prepare_int( $p_access_level );
+		$c_protected	= db_prepare_bool( $p_protected );
+		$c_enabled	= db_prepare_bool( $p_enabled );
+
+		group_ensure_name_valid( $p_groupname );
+		group_ensure_name_unique( $p_groupname );
+
+		$t_seed = $p_username;
+		$t_cookie_string	= auth_generate_unique_cookie_string( $t_seed );
+
+		$t_group_table 		= config_get( 'mantis_group_table' );
+
+		$query = "INSERT INTO $t_group_table
+				    ( id, groupname, date_created, enabled, protected, 
+				      access_level, cookie_string )
+				  VALUES
+				    ( null, '$c_groupname', NOW(), $c_enabled, $c_protected, 
+				      $c_access_level, '$t_cookie_string')";
+		db_query( $query );
+
+		return $t_cookie_string;
+	}
+
+	# --------------------
+	# delete agroup
+	# returns true when the account was successfully deleted
+	function group_delete( $p_group_id ) {
+		$c_group_id = db_prepare_int($p_group_id);
+
+		group_ensure_unprotected( $p_group_id );
+
+		$t_group_table 			= config_get('mantis_group_table');
+		$t_group_user_list_table 	= config_get('mantis_group_user_list_table');
+
+		# Remove account
+		$query = "DELETE
+				  FROM $t_group_table
+				  WHERE id='$c_group_id'";
+		db_query( $query );
+
+		$query = "DELETE
+				  FROM $t_group_user_list_table
+				  WHERE group_id='$c_group_id'";
+		db_query( $query );
+
+		group_clear_cache( $p_group_id );
+
+		return true;
+    }
+
+	#===================================
+	# Data Access
+	#===================================
+
+	# --------------------
+	# get a group id from a groupname
+	#  return false if the groupname does not exist
+	function group_get_id_by_name( $p_groupname ) {
+		$c_groupname = db_prepare_string( $p_groupname );
+
+		$t_group_table = config_get( 'mantis_group_table' );
+
+		$query = "SELECT id
+				  FROM $t_group_table
+				  WHERE groupname='$c_groupname'";
+		$result = db_query( $query );
+
+		if ( 0 == db_num_rows( $result ) ) {
+			return false;
+		} else {
+			return db_result( $result );
+		}
+	}
+
+	# --------------------
+	# return all data associated with a particular group name
+	#  return false if the groupname does not exist
+	function group_get_row_by_name( $p_groupname ) {
+		$t_group_id = group_get_id_by_name( $p_groupname );
+
+		if ( false === $t_group_id ) {
+			return false;
+		}
+
+		$row = group_get_row( $t_group_id );
+
+		return $row;
+	}
+
+	# --------------------
+	# return a group row
+	function group_get_row( $p_group_id ) {
+		return group_cache_row( $p_group_id );
+	}
+
+	# --------------------
+	# return the specified group field for the group id
+	function group_get_field( $p_group_id, $p_field_name ) {
+		if ( NO_GROUP == $p_group_id ) {
+			trigger_error( 'group_get_field() for NO_GROUP', WARNING );
+			return "@null@";
+		}
+
+		$row = group_get_row( $p_group_id );
+
+		if ( isset( $row[$p_field_name] ) ) {
+			return $row[$p_field_name];
+		} else {
+			trigger_error( ERROR_DB_FIELD_NOT_FOUND, WARNING );
+			return '';
+		}
+	}
+
+	# --------------------
+	# return the groupname or a string saying "group no longer exists"
+	#  if the group does not exist
+	function group_get_name( $p_group_id ) {
+		$row = group_cache_row( $p_group_id, false );
+
+		if ( false == $row ) {
+			return lang_get( 'prefix_for_deleted_groups' ) . (integer)$p_group_id;
+		} else {
+			return $row['groupname'];
+		}
+	}
+
+	# --------------------
+	# return the groups's access level
+	function group_get_access_level( $p_group_id ) {
+		$t_access_level  = group_get_field( $p_group_id, 'access_level' );
+
+		return $t_access_level;
+	}
+	
+	# --------------------
+	# check to see if the user/group combo already exists
+	# returns true is duplicate is found, otherwise false
+	function group_includes_user( $p_group_id, $p_user_id ) {
+		$t_group_user_list_table = config_get( 'mantis_group_user_list_table' );
+
+		$c_group_id	= db_prepare_int( $p_group_id );
+		$c_user_id	= db_prepare_int( $p_user_id );
+
+		$query = "SELECT COUNT(*)
+				  FROM $t_group_user_list_table
+				  WHERE group_id='$c_group_id' AND
+						user_id='$c_user_id'";
+		$result = db_query( $query );
+
+		if ( 0 == db_result( $result ) ) {
+			return false;
+		} else {
+			return true;
+		}
+	}
+	
+	# --------------------
+	# Return an array of info about users who are part of the given group
+	# For each user we have 'id', 'username', and 'access_level' (overall access level)
+	# If the second parameter is given, return only users with an access level
+	#  higher than the given value.
+	function group_get_all_user_rows( $p_group_id, $p_access_level=ANYBODY ) {
+		$c_group_id	= db_prepare_int( $p_group_id );
+
+		# Optimization when access_level is NOBODY
+		if ( NOBODY == $p_access_level ) {
+			return array();
+		}
+
+		$t_user_table = config_get( 'mantis_user_table' );
+		$t_group_user_list_table = config_get( 'mantis_group_user_list_table' );
+
+		$t_on = ON;
+
+		$t_access_level = $p_access_level;
+
+		$t_access_clause = '';
+
+		if ( $t_access_level > 0 ) {
+			$t_access_clause = ' AND access_level >= ' . $t_access_level;
+		}
+
+		$t_users = array();
+
+		$query = "SELECT id, username, access_level
+					FROM $t_user_table
+					WHERE enabled = $t_on
+					  $t_access_clause
+					ORDER BY username";
+
+		$result = db_query( $query );
+		$t_row_count = db_num_rows( $result );
+		for ( $i=0 ; $i < $t_row_count ; $i++ ) {
+			$row = db_fetch_array( $result );
+			$t_users[$row['id']] = $row;
+		}
+
+		$query = "SELECT u.id, u.username
+					FROM $t_group_user_list_table l, $t_user_table u
+					WHERE l.user_id = u.id
+					  AND u.enabled = $t_on
+					  AND l.group_id = $c_group_id
+					ORDER BY u.username";
+
+		$result = db_query( $query );
+		$t_row_count = db_num_rows( $result );
+		for ( $i=0 ; $i < $t_row_count ; $i++ ) {
+			$row = db_fetch_array( $result );
+			$f_access_level = $t_users[$row['id']]['access_level'];
+			if ( $f_access_level >= $p_access_level ) {
+				$t_users[$row['id']] = $row;
+				$t_users[$row['id']]['access_level'] = $f_access_level;
+			} else {
+				# If user's overridden level is lower than required, so remove
+				#  them from the list if they were previously there
+				unset( $t_users[$row['id']] );
+			}
+		}
+
+		return multi_sort( array_values($t_users), 'username' );
+	}
+	
+	# --------------------
+	# Return an array of user_id's that belong to the given group, if their access
+	# level is above the access given.
+	function group_get_users( $p_group_id, $p_access_level=ANYBODY ) {
+		$c_group_id	= db_prepare_int( $p_group_id );
+
+		# Optimization when access_level is NOBODY
+		if ( NOBODY == $p_access_level ) {
+			return array();
+		}
+
+		$t_user_table = config_get( 'mantis_user_table' );
+		$t_group_user_list_table = config_get( 'mantis_group_user_list_table' );
+
+		$t_on = ON;
+
+		$t_access_level = $p_access_level;
+
+		$t_access_clause = '';
+
+		if ( $t_access_level > 0 ) {
+			$t_access_clause = ' AND access_level >= ' . $t_access_level;
+		}
+
+		$t_users = array();
+
+		// Get the project overrides
+		$query = "SELECT u.id, u.username
+				FROM $t_group_user_list_table l, $t_user_table u
+				WHERE l.user_id = u.id
+				  AND u.enabled = $t_on
+				  AND l.group_id = $c_group_id
+				ORDER BY u.username";
+
+		$result = db_query( $query );
+		$t_row_count = db_num_rows( $result );
+		for ( $i=0 ; $i < $t_row_count ; $i++ ) {
+			$row = db_fetch_array( $result );
+			
+			if ( $f_access_level >= $p_access_level ) {
+				$t_users[$row['id']] = $row;
+				array_push( $t_users, $row['id'] );
+			}
+		}
+
+		return $t_users;
+	}
+	
+
+	#===================================
+	# Data Modification
+	#===================================
+	
+	# --------------------
+	# add user to a group
+	function group_add_user( $p_group_id, $p_user_id ) {
+		$t_group_user_list_table = config_get( 'mantis_group_user_list_table' );
+
+		$c_group_id	= db_prepare_int( $p_group_id );
+		$c_user_id	= db_prepare_int( $p_user_id );
+
+		$query = "INSERT
+				  INTO $t_group_user_list_table
+				    ( group_id, user_id )
+				  VALUES
+				    ( '$c_group_id', '$c_user_id' )";
+		
+		db_query( $query );
+
+		# db_query errors on failure so:
+		return true;
+	}
+	
+	# --------------------
+	# remove user from group
+	function group_remove_user( $p_group_id, $p_user_id ) {
+		$t_group_user_list_table = config_get( 'mantis_group_user_list_table' );
+
+		$c_group_id	= db_prepare_int( $p_group_id );
+		$c_user_id	= db_prepare_int( $p_user_id );
+
+		$query = "DELETE FROM $t_group_user_list_table
+				  WHERE group_id='$c_group_id' AND
+						user_id='$c_user_id'";
+
+		db_query( $query );
+
+		# db_query errors on failure so:
+		return true;
+	}
+
+	# --------------------
+	# delete all users from the group user list for a given group
+	# this is useful when deleting a group
+	function group_remove_all_users( $p_group_id ) {
+		$t_group_user_list_table = config_get( 'mantis_group_user_list_table' );
+
+		$c_group_id	= db_prepare_int( $p_group_id );
+
+		$query = "DELETE FROM $t_group_user_list_table
+				WHERE group_id='$c_group_id'";
+
+		db_query( $query );
+
+		# db_query errors on failure so:
+		return true;
+	}
+
+	# --------------------
+	# Set a group field
+	function group_set_field( $p_group_id, $p_field_name, $p_field_value ) {
+		$c_group_id	= db_prepare_int( $p_group_id );
+		$c_field_name	= db_prepare_string( $p_field_name );
+		$c_field_value	= db_prepare_string( $p_field_value );
+
+		group_ensure_unprotected( $p_group_id );
+
+		$t_group_table = config_get( 'mantis_group_table' );
+
+		$query = "UPDATE $t_group_table
+				  SET $c_field_name='$c_field_value'
+				  WHERE id='$c_group_id'";
+
+		db_query( $query );
+
+		group_clear_cache( $p_group_id );
+
+		#db_query() errors on failure so:
+		return true;
+	}
+	
+	# --------------------
+	# 
+	
+	# --------------------
+	# Set the user's groupname to the given string after checking that it is valid
+	function group_set_name( $p_group_id, $p_groupname ) {
+		group_ensure_name_valid( $p_groupname );
+		group_ensure_name_unique( $p_groupname );
+
+		return group_set_field( $p_group_id, 'groupname', $p_groupname );
+	}
+	
+			
+?>
group_new_files.zip (13,881 bytes)
group_tables.sql (1,080 bytes)   
#
# Table structure for table 'mantis_group_table'
#

CREATE TABLE mantis_group_table (
  id int(7) unsigned NOT NULL auto_increment,
  groupname varchar(32) NOT NULL default '',
  date_created datetime NOT NULL default '1970-01-01 00:00:01',
  enabled int(1) NOT NULL default '1',
  protected int(1) NOT NULL default '0',
  access_level int(2) NOT NULL default '10',
  cookie_string varchar(64) NOT NULL default '',
  PRIMARY KEY  (id),
  UNIQUE KEY groupname (groupname),
  UNIQUE KEY cookie_string (cookie_string)
) TYPE=MyISAM;


#
# Table structure for table 'mantis_group_user_list_table'
#

CREATE TABLE mantis_group_user_list_table (
  group_id int(7) unsigned NOT NULL default '0',
  user_id int(7) unsigned NOT NULL default '0',
  PRIMARY KEY  (group_id,user_id)
) TYPE=MyISAM;


#
# Table structure for table 'mantis_bug_group_list_table'
#

CREATE TABLE mantis_bug_group_list_table (
  bug_id int(7) unsigned NOT NULL default '0',
  group_id int(7) unsigned NOT NULL default '0',
  PRIMARY KEY  (bug_id,group_id)
) TYPE=MyISAM;

group_tables.sql (1,080 bytes)   
Snap3.jpg (68,874 bytes)   
Snap3.jpg (68,874 bytes)   

Relationships

has duplicate 0007752 closedgiallu User groups 
has duplicate 0011003 closeddhx User groups for easy managing 
has duplicate 0011867 closedatrol User Groups / Custom User Fields 
has duplicate 0007614 closeddregad Better user accounts administration should be implemented (to support the administration of large group of users). 
has duplicate 0019601 closedatrol How classify my account 
has duplicate 0023695 closedatrol How to create user group in mantis 2.9.0 
related to 0002342 closedgrangeway Create groups and locations for users to belong to 
related to 0012390 new Feature request: User inheritance, similar to current category inheritance 
related to 0022745 new Grant Access in VIEW mode (Read Only) 'skipping' user threshold 
related to 0023317 new Support mentions for groups of users or user levels 
child of 0005381 new more flexible group/role/profile/permission management 

Activities

lauploix

lauploix

2004-05-18 06:57

reporter   ~0005532

I agree. We have 15+ projects, and mainly 5+ user groups (sales, programmers, consulting, ...).

It would be so nice to be able to manage the rights at group level... and just add a user to a group when a new user arrives.

dwoods

dwoods

2004-05-24 13:08

reporter   ~0005574

I have implented something similar in some customizations a while ago. We have a number of distibutors of our product, and it's not always desirable for them to see ongoing issues with other distibutors (at least in management's eyes).

Basically, each bug has "group view list" associated with it. Only users in those groups can see the bug (it gets filtered out of the view_all pages as well). There is a new [Manage Groups] link to a new page in the Manage screen.

I made these changes based on 0.18.0a4, and am just in the process of porting my changes to 0.18.3. I could post it here when I'm finished if anyone's interested.

lauploix

lauploix

2004-05-25 01:59

reporter   ~0005580

Hi dwoods, I think this is also interesting to have a 'per bug' right management sometimes. In fact, I sometimes want to enable a specific user to view/update/... a bug that he has no right on.

Pb is I usually have sg like 150+ open issues, in 15+ different projects, with 100+ users in 5+ user groups. Mantis is really great for that. But that means that I cannot manage all rights on a per bug basic.

What would be so great would be : once I have a new user, I just put him in several "groups" and he gets all the update/view/manage/... rights that the groups have.

But this is no contradiction with a more specific 'per user' or 'per bug' user rights management for specific purposes.

nuclearspike

nuclearspike

2004-05-25 10:23

reporter   ~0005583

in a somewhat related note, also have the auto-assignment of new issues be able to go to a user group/role. A customer enters a new problem, it first should get assigned to the triage group who verifies the bug before it gets assigned to the developer who works on that category. If it first goes to one person, that person is sometimes gone for weeks on the road and other people need to handle the triage. Our current solution is sort of hackish. We create a "Triage" user, have things assigned to them, then the triage group just checks for things assigned to that user, rather than to themselves. this, however, means that all new bugs go there and we cannot use the category auto-assignments for the actual developer. Auto-assignments may be best on a per-status level. New -> Triage, Confirmed -> Manager of the project or may go directly to the developer of that category. That's getting more into workflows... which is a separate request entirely. :D

dwoods

dwoods

2004-05-26 14:31

reporter   ~0005594

Last edited: 2004-05-26 14:32

I've attached a diff from 0.18.3, as well as all new files in a .zip (diff includes new files) and an sql file to create new tables.

As it is right now, it doesn't actually filter out the issues in the view_all_page according to the group 'view list'. I wanted to change how i was doing this before I add it in.
Basically it went something like:

for each bug passed though all other filters
get the group_view_list for that bug
for each group
if current_user is in group
show bug
if current_user is reporter
show bug

Also, the only way to add/remove groups to an issue is in the bug_view_advanced_page, which is clearly the wrong place. It should be in the bug_advanced_update_page.
Also I would like to add the ability to add a group to multiple bugs at the same time (via the checkboxes).

Also each user should have a 'default' group, that get added to the view list automatically when they submit new issue.

Still working on it.. :)

edited on: 05-26-04 14:32

nuclearspike

nuclearspike

2004-09-01 13:34

reporter   ~0007363

this is nice, but it adds groups to be able to see individual bugs, is there a way an entire group can be associated with a project?

dwoods

dwoods

2004-09-05 18:03

reporter   ~0007448

I have updated the patch since my posting, but forgot to update the post.
It's now diff'd from the latest from HEAD as of about a 2 months ago.

My company also wanted me to make additional modifications to allow 'projects' in addition to 'issues' (where are project is actually just another issue, only originating from within the company for one of our developers to handle). And the projects as they are now I have changed to 'products'.

Anyway, the patch I'm including has these changes in there as well. I apologize for this, but hope this at least some of the code I have written may be of some use. The user group stuff is fairly self-contained.

The user groups are only used right now for implementing an 'access-list' on a per-issue basis, as mentioned in a previous note, but it would also be nice if an issue could be assigned to a group of users. I think the basic framework is there...

I also attempted to add to the upgrade scripts to create the new tables. They seemed to work for me okay.

djcarr

djcarr

2009-05-24 23:31

reporter   ~0021906

Last edited: 2009-05-24 23:35

With 100+ projects and 100+ users this is an area where the administration workload starts to become difficult. Being able to assign roles (or "user groups") to projects and then giving users one or several roles, would really bring Mantis into the realm of corporate applications.

Could others desiring this feature please also put a little encouragement in.. thank you :)

tk

tk

2009-05-27 01:35

reporter   ~0021931

Just for comment:

As a partial workaround, I implemented "assignment groups" by creating fake users which have a mailing list as email destination. The mailing list contains all people in that group.
In that way I can assign issues to groups of people. Now since the group members are all of level developer (otherwise assignment of an issue to them would make no sense) the actual user-in-charge can assign the issue to himself as soon as he starts working on it.

djcarr

djcarr

2009-06-01 19:08

reporter   ~0022027

Last edited: 2009-06-01 19:15

Thanks for the input 'tk' - perhaps the scenario you are talking about is covered by 0000955 or 0006644? While I can see how that may be useful it is still somewhat different to this issue which is for a users-roles-privileges engine.

sveyret

sveyret

2009-10-09 04:57

reporter   ~0023105

Hi, I have made specifications about what I think could solve all the problems (see attached PDF file). Can you tell me your opinion about it? I hope I will find time to work on that issue soon.

Thank you.

sveyret

sveyret

2009-10-15 04:59

reporter   ~0023199

Specifications are now added to the Wiki page so everyone can work on it…

andy778

andy778

2010-10-22 02:31

reporter   ~0027115

Any idea when this will be developed and how much sponsoring would this require to get this done?

tiliarou

tiliarou

2011-01-20 08:18

reporter   ~0028016

I'm very interested by this feature ! Adding group management to Mantis would make it so much better !
Is someone still working on this issue ? Does he need more sponsoring ?

djcarr

djcarr

2011-01-20 17:53

reporter   ~0028022

Last edited: 2011-01-20 17:58

The specs in the wiki are very detailed but represent a very large amount of work. I am not sure why the login authentication code needs to be modified.

A simpler approach to address the original request:

  • New table 'mantis_role_table' with fields: role_id, name, access_level
  • New table 'mantis_project_role_table' with fields: project_id, role_id, access_level
  • New table 'mantis_user_role_table' with fields: user_id, role_id
  • Change all access level lookups in code to include these tables as well
  • Use the highest access level found for that user and project

This is a relatively straightforward change that will provide big benefits to administrators and doesn't require migration of existing data to a new structure.

sveyret

sveyret

2011-01-27 03:28

reporter   ~0028101

I stopped working on this feature after a very big code loss at a time I was still trying to make git working… :-(
I will have no time to restart this job for the moment.
There are Mantis developpers currently working to re-write Mantis using the Zend framework. As Zend framework has got an easy way to manage access controls, this will probably be a good occasion to include group management.

andy778

andy778

2011-08-11 11:51

reporter   ~0029464

What is the current plan with this?

cas

cas

2011-08-12 03:00

reporter   ~0029467

Perhaps it will show up in a later version but so far there is little feedback on this. There are a few smaller patches around to group users and/or assiging sub tasks within one issue. if thos are usable for you, very much depends on your requirements

andy778

andy778

2011-08-12 11:26

reporter   ~0029470

We have over 300 mantis users and over 100 projects and the projects are private so what we would like is to add users to groups alias and groups should then be added under each project. Also ldap/AD authentication is needed. Sponsoring is also possible to arrange if needed.

cas

cas

2012-09-14 02:02

reporter   ~0032842

Now creating a plugin that will allow users to be connected to multiple groups (which can be defined seperately).
My tasks plugin will allow to assign tasks to one of those groups. Each task can then be handled by anyone from that group. System will register which user in the end will complete the task.
Although not full group management, it will be enough for our purposes.

cas

cas

2012-09-19 01:45

reporter   ~0032872

For those interested, the plugin is available and released together with an updated version of the Tasks plugin.
See:
http://www.mantisbt.org/bugs/view.php?id=14716

HeikoSL

HeikoSL

2014-04-01 04:37

reporter   ~0039801

I have created another plugin for usergroups:
This plugin can be used to create groups of users in your mantis bugtracker. You may use nested groups and you can decide if groups can handle a bug. Notifications will be send to all group members.

The plugin creates one table that holds the groups with their members. But: To use this plugin you must edit some core functions!

See: https://github.com/langerheiko/ManageUsergroups

hincelin

hincelin

2014-04-17 08:42

reporter   ~0040114

@ HeikoSL,
Thanks for this new plungin.
Can it be used with 1.2.17 ?
Sincerely

HeikoSL

HeikoSL

2014-04-22 07:57

reporter   ~0040132

I am running it on 1.2.14, but I tested it with 1.2.17. It's working.

zhanghongquan

zhanghongquan

2015-04-09 02:55

reporter   ~0049366

Thank you
There is no Groups management,Please see the Screenshot

zhanghongquan

zhanghongquan

2015-04-09 02:56

reporter   ~0049367

sorry,my version is 1.2.18

titovetch

titovetch

2018-06-19 07:00

reporter   ~0060112

it will be a huge great feature if this implementing

polzin

polzin

2020-05-14 16:36

reporter   ~0063984

With a large number of users and projects, this would definitely be a big improvement.
Any chance this gets implemented?
The attached plugin does not work any longer... :-/

cas

cas

2020-05-15 04:06

reporter   ~0063985

@polzin, which plugin is not working?

polzin

polzin

2020-05-15 05:05

reporter   ~0063986

@cas, thanks for asking,

The one from @HeikoSL looked promissing, but is not compatible with Core 2.0.

I tried your plugins, but a) I did not find the documentation on your homepage, I did not understand if the usergroups for accessrights work without the tasks extension. b) when testing out I received 404 error when editing a group and did not find a way to add users to a group.

cas

cas

2020-05-15 05:55

reporter   ~0063988

@polzin, my plugin works differently although can be used without the tasks module.
I do like the one from Heiko so have tried to reach him to see if he still supports this plugin.
If not, I will have a look to see if it can be easily transferred to 2.X
As for mine, there should be a readme available ( but I do not think it suits your purpose).

polzin

polzin

2020-05-15 09:33

reporter   ~0063989

@cas, can you post the link to your readme?
My purpose (as the one of this issue) is: Large number of users and projects, assign users to groups and assign access rights to groups. Can your plugin do this?

cas

cas

2020-05-15 09:57

reporter   ~0063990

@polzin, my plugin does not allow to grant access rights to groups, is still userbased. Did get a reply from Heiko and he has no problem that I review his plugin for version2.x.

polzin

polzin

2020-05-16 06:13

reporter   ~0063991

Last edited: 2020-05-16 06:13

@cas, that would be great, thanks!

If there is anything I could help, please drop me a note.