Skip to content

Commit

Permalink
Improve project users manage page
Browse files Browse the repository at this point in the history
Improve Project edit page, user management.
Add js functionality based in list.js with pagination, sorting and
search/filtering.
Allow the staging of changes for modifications in access level and user
removal, within the user list.
Changes are applied as a whole and can be reviewed and validated after
form submission.

Fixes: #5151
  • Loading branch information
cproensa authored and dregad committed Mar 3, 2019
1 parent 32d60e5 commit e504944
Show file tree
Hide file tree
Showing 8 changed files with 813 additions and 150 deletions.
14 changes: 10 additions & 4 deletions core/prepare_api.php
Expand Up @@ -61,11 +61,13 @@ function prepare_email_link( $p_email, $p_text ) {
}

/**
* prepares the name of the user given the id. also makes it an email link.
* @param integer $p_user_id A valid user identifier.
* Prepares the name of the user given the id.
* Also can make it a link to user info page.
* @param integer $p_user_id A valid user identifier.
* @param boolean $p_link Whether to include an html link
* @return string
*/
function prepare_user_name( $p_user_id ) {
function prepare_user_name( $p_user_id, $p_link = true ) {
# Catch a user_id of NO_USER (like when a handler hasn't been assigned)
if( NO_USER == $p_user_id ) {
return '';
Expand All @@ -82,7 +84,11 @@ function prepare_user_name( $p_user_id ) {
$t_name = string_display_line( $t_name );

if( user_exists( $p_user_id ) && user_get_field( $p_user_id, 'enabled' ) ) {
return '<a ' . $t_tooltip . ' href="' . string_sanitize_url( 'view_user_page.php?id=' . $p_user_id, true ) . '">' . $t_name . '</a>';
if( $p_link ) {
return '<a ' . $t_tooltip . ' href="' . string_sanitize_url( 'view_user_page.php?id=' . $p_user_id, true ) . '">' . $t_name . '</a>';
} else {
return '<span ' . $t_tooltip . '>' . $t_name . '</span>';
}
}

return '<del ' . $t_tooltip . '>' . $t_name . '</del>';
Expand Down
115 changes: 81 additions & 34 deletions core/project_api.php
Expand Up @@ -745,74 +745,121 @@ function project_get_upload_path( $p_project_id ) {
}

/**
* add user with the specified access level to a project
* Add user with the specified access level to a project.
* @param integer $p_project_id A project identifier.
* @param integer $p_user_id A valid user id identifier.
* @param integer $p_access_level The access level to add the user with.
* @return void
*/
function project_add_user( $p_project_id, $p_user_id, $p_access_level ) {
$t_access_level = (int)$p_access_level;
if( DEFAULT_ACCESS_LEVEL == $t_access_level ) {
# Default access level for this user
$t_access_level = user_get_access_level( $p_user_id );
}

db_param_push();
$t_query = 'INSERT INTO {project_user_list}
( project_id, user_id, access_level )
VALUES
( ' . db_param() . ', ' . db_param() . ', ' . db_param() . ')';

db_query( $t_query, array( (int)$p_project_id, (int)$p_user_id, $t_access_level ) );
project_add_users( $p_project_id, array( $p_user_id => $p_access_level ) );
}

/**
* update entry
* must make sure entry exists beforehand
* Update user with the specified access level to a project.
* @param integer $p_project_id A project identifier.
* @param integer $p_user_id A user identifier.
* @param integer $p_access_level Access level to set.
* @return void
*/
function project_update_user_access( $p_project_id, $p_user_id, $p_access_level ) {
db_param_push();
$t_query = 'UPDATE {project_user_list}
SET access_level=' . db_param() . '
WHERE project_id=' . db_param() . ' AND
user_id=' . db_param();

db_query( $t_query, array( (int)$p_access_level, (int)$p_project_id, (int)$p_user_id ) );
project_add_users( $p_project_id, array( $p_user_id => $p_access_level ) );
}

/**
* update or add the entry as appropriate
* This function involves one more database query than project_update_user_acces() or project_add_user()
* Update or add user with the specified access level to a project.
* This function involves one more database query than project_update_user_acces() or project_add_user().
* @param integer $p_project_id A project identifier.
* @param integer $p_user_id A user identifier.
* @param integer $p_access_level Project Access level to grant the user.
* @return boolean
*/
function project_set_user_access( $p_project_id, $p_user_id, $p_access_level ) {
if( project_includes_user( $p_project_id, $p_user_id ) ) {
return project_update_user_access( $p_project_id, $p_user_id, $p_access_level );
} else {
return project_add_user( $p_project_id, $p_user_id, $p_access_level );
project_add_users( $p_project_id, array( $p_user_id => $p_access_level ) );
}

/**
* Add or modify multiple users associated to a project with a specific access level.
* $p_changes is an array of access levels indexed by user_id, such as:
* array ( user1 => access_level, user2 => access_level, ... )
* This function will manage inserts and updates as needed.
*
* @param integer $p_project_id A project identifier.
* @param array $p_changes An array of modifications.
* @return void
*/
function project_add_users( $p_project_id, array $p_changes ) {
# normalize input
$t_changes = array();
foreach( $p_changes as $t_id => $t_value ) {
if( DEFAULT_ACCESS_LEVEL == $t_value ) {
$t_changes[(int)$t_id] = user_get_access_level( $t_id );
} else {
$t_changes[(int)$t_id] = (int)$t_value;
}
}

$t_user_ids = array_keys( $t_changes );
if( empty( $t_user_ids ) ) {
return;
}

$t_project_id = (int)$p_project_id;
$t_query = new DbQuery();
$t_sql = 'SELECT user_id FROM {project_user_list} WHERE project_id = ' . $t_query->param( $t_project_id )
. ' AND ' . $t_query->sql_in( 'user_id', $t_user_ids );
$t_query->sql( $t_sql );
$t_updating = array_column( $t_query->fetch_all(), 'user_id' );

if( !empty( $t_updating ) ) {
$t_update = new DbQuery( 'UPDATE {project_user_list} SET access_level = :new_value WHERE user_id = :user_id' );
foreach( $t_updating as $t_id ) {
$t_params = array( 'user_id' => (int)$t_id, 'new_value' => $t_changes[$t_id] );
$t_update->execute( $t_params );
unset( $t_changes[$t_id] );
}
}
# remaining items are for insert
if( !empty( $t_changes ) ) {
$t_insert = new DbQuery( 'INSERT INTO {project_user_list} ( project_id, user_id, access_level ) VALUES :params' );
foreach( $t_changes as $t_id => $t_value ) {
$t_insert->bind( 'params', array( $t_project_id, $t_id, $t_value ) );
$t_insert->execute();
}
}
}

/**
* remove user from project
* Remove user from project.
* @param integer $p_project_id A project identifier.
* @param integer $p_user_id A user identifier.
* @return void
*/
function project_remove_user( $p_project_id, $p_user_id ) {
db_param_push();
$t_query = 'DELETE FROM {project_user_list}
WHERE project_id=' . db_param() . ' AND user_id=' . db_param();
project_remove_users( $p_project_id, array( $p_user_id ) );
}

/**
* Remove multiple users from project.
* @param integer $p_project_id A project identifier.
* @param array $p_user_ids Array of user identifiers.
* @return type
*/
function project_remove_users( $p_project_id, array $p_user_ids ) {
# normalize input
$t_user_ids = array();
foreach( $p_user_ids as $t_id ) {
$t_user_ids[] = (int)$t_id;
}
if( empty( $t_user_ids ) ) {
return;
}

db_query( $t_query, array( (int)$p_project_id, (int)$p_user_id ) );
$t_query = new DbQuery();
$t_sql = 'DELETE FROM {project_user_list} WHERE project_id = ' . $t_query->param( (int)$p_project_id )
. ' AND ' . $t_query->sql_in( 'user_id', $t_user_ids );
$t_query->sql( $t_sql );
$t_query->execute();
}

/**
Expand Down
4 changes: 2 additions & 2 deletions css/ace-mantis.css
Expand Up @@ -274,14 +274,14 @@ pre {

.input-sm {
width: 90px !important;
display: inline-block !important;
/*display: inline-block !important;*/ /* removed because it messes with js hide/show capabilities */
vertical-align: middle !important;
padding: 4px 6px !important;
}

.input-xs {
width: auto !important;
display: inline-block !important;
/*display: inline-block !important;*/ /* removed because it messes with js hide/show capabilities */
vertical-align: middle !important;
padding: 1px 2px !important;
}
Expand Down
41 changes: 41 additions & 0 deletions css/default.css
Expand Up @@ -117,3 +117,44 @@ td.print-overdue { font-weight: bold; }
table.filters td.category {
color: #337ab7;
}

.listjs-table .sort:after {
display: inline-block;
width: 0;
height: 0;
border-left: 5px solid transparent;
border-right: 5px solid transparent;
border-bottom: 5px solid transparent;
content: "";
position: relative;
top: -10px;
right: -5px;
}

.listjs-table .sort.desc:after {
width: 0;
height: 0;
border-left: 5px solid transparent;
border-right: 5px solid transparent;
border-top: 5px solid #707070;
content: "";
position: relative;
top: 4px;
right: -5px;
}

.listjs-table .sort.asc:after {
width: 0;
height: 0;
border-left: 5px solid transparent;
border-right: 5px solid transparent;
border-bottom: 5px solid #707070;
content: "";
position: relative;
top: -4px;
right: -5px;
}

.listjs-table .sort:hover {
text-decoration: underline;
}

0 comments on commit e504944

Please sign in to comment.