diff options
Diffstat (limited to 'editusers.cgi')
-rwxr-xr-x | editusers.cgi | 1333 |
1 files changed, 686 insertions, 647 deletions
diff --git a/editusers.cgi b/editusers.cgi index beb9b3a4c..fce3748ec 100755 --- a/editusers.cgi +++ b/editusers.cgi @@ -32,16 +32,18 @@ my $dbh = Bugzilla->dbh; my $userid = $user->id; my $editusers = $user->in_group('editusers'); my $disableusers = $user->in_group('disableusers'); -local our $vars = {}; +local our $vars = {}; # Reject access if there is no sense in continuing. -$editusers - || $disableusers - || $user->can_bless() - || ThrowUserError("auth_failure", {group => "editusers", - reason => "cant_bless", - action => "edit", - object => "users"}); +$editusers || $disableusers || $user->can_bless() || ThrowUserError( + "auth_failure", + { + group => "editusers", + reason => "cant_bless", + action => "edit", + object => "users" + } +); print $cgi->header(); @@ -52,290 +54,309 @@ my $otherUserLogin = $cgi->param('user'); my $token = $cgi->param('token'); # Prefill template vars with data used in all or nearly all templates -$vars->{'editusers'} = $editusers; +$vars->{'editusers'} = $editusers; $vars->{'disableusers'} = $disableusers; mirrorListSelectionValues(); Bugzilla::Hook::process('admin_editusers_action', - { vars => $vars, user => $user, action => $action }); + {vars => $vars, user => $user, action => $action}); ########################################################################### if ($action eq 'search') { - # Allow to restrict the search to any group the user is allowed to bless. - $vars->{'restrictablegroups'} = $user->bless_groups(); - $template->process('admin/users/search.html.tmpl', $vars) - || ThrowTemplateError($template->error()); -########################################################################### -} elsif ($action eq 'list') { - my $matchvalue = $cgi->param('matchvalue') || ''; - my $matchstr = trim($cgi->param('matchstr')); - my $matchtype = $cgi->param('matchtype'); - my $grouprestrict = $cgi->param('grouprestrict') || '0'; - my $query = 'SELECT DISTINCT userid, login_name, realname, is_enabled, ' . - $dbh->sql_date_format('last_seen_date', '%Y-%m-%d') . ' AS last_seen_date ' . - 'FROM profiles'; - my @bindValues; - my $nextCondition; - my $visibleGroups; - - # If a group ID is given, make sure it is a valid one. - my $group; - if ($grouprestrict) { - $group = new Bugzilla::Group(scalar $cgi->param('groupid')); - $group || ThrowUserError('invalid_group_ID'); - } + # Allow to restrict the search to any group the user is allowed to bless. + $vars->{'restrictablegroups'} = $user->bless_groups(); + $template->process('admin/users/search.html.tmpl', $vars) + || ThrowTemplateError($template->error()); - if (!$editusers && Bugzilla->params->{'usevisibilitygroups'}) { - # Show only users in visible groups. - $visibleGroups = $user->visible_groups_as_string(); - - if ($visibleGroups) { - $query .= qq{, user_group_map AS ugm +########################################################################### +} +elsif ($action eq 'list') { + my $matchvalue = $cgi->param('matchvalue') || ''; + my $matchstr = trim($cgi->param('matchstr')); + my $matchtype = $cgi->param('matchtype'); + my $grouprestrict = $cgi->param('grouprestrict') || '0'; + my $query + = 'SELECT DISTINCT userid, login_name, realname, is_enabled, ' + . $dbh->sql_date_format('last_seen_date', '%Y-%m-%d') + . ' AS last_seen_date ' + . 'FROM profiles'; + my @bindValues; + my $nextCondition; + my $visibleGroups; + + # If a group ID is given, make sure it is a valid one. + my $group; + if ($grouprestrict) { + $group = new Bugzilla::Group(scalar $cgi->param('groupid')); + $group || ThrowUserError('invalid_group_ID'); + } + + if (!$editusers && Bugzilla->params->{'usevisibilitygroups'}) { + + # Show only users in visible groups. + $visibleGroups = $user->visible_groups_as_string(); + + if ($visibleGroups) { + $query .= qq{, user_group_map AS ugm WHERE ugm.user_id = profiles.userid AND ugm.isbless = 0 AND ugm.group_id IN ($visibleGroups) }; - $nextCondition = 'AND'; - } - } else { - $visibleGroups = 1; - if ($grouprestrict eq '1') { - $query .= qq{, user_group_map AS ugm + $nextCondition = 'AND'; + } + } + else { + $visibleGroups = 1; + if ($grouprestrict eq '1') { + $query .= qq{, user_group_map AS ugm WHERE ugm.user_id = profiles.userid AND ugm.isbless = 0 }; - $nextCondition = 'AND'; - } - else { - $nextCondition = 'WHERE'; - } - } - - if (!$visibleGroups) { - $vars->{'users'} = {}; + $nextCondition = 'AND'; } else { - # Handle selection by login name, real name, or userid. - if (defined($matchtype)) { - $query .= " $nextCondition "; - my $expr = ""; - if ($matchvalue eq 'userid') { - if ($matchstr) { - my $stored_matchstr = $matchstr; - detaint_natural($matchstr) - || ThrowUserError('illegal_user_id', {userid => $stored_matchstr}); - } - $expr = "profiles.userid"; - } elsif ($matchvalue eq 'realname') { - $expr = "profiles.realname"; - } else { - $expr = "profiles.login_name"; - } - - if ($matchtype =~ /^(regexp|notregexp|exact)$/) { - $matchstr ||= '.'; - } - else { - $matchstr = '' unless defined $matchstr; - } - # We can trick_taint because we use the value in a SELECT only, - # using a placeholder. - trick_taint($matchstr); - - if ($matchtype eq 'regexp') { - $query .= $dbh->sql_regexp($expr, '?', 0, $dbh->quote($matchstr)); - } elsif ($matchtype eq 'notregexp') { - $query .= $dbh->sql_not_regexp($expr, '?', 0, $dbh->quote($matchstr)); - } elsif ($matchtype eq 'exact') { - $query .= $expr . ' = ?'; - } else { # substr or unknown - $query .= $dbh->sql_istrcmp($expr, '?', 'LIKE'); - $matchstr = "%$matchstr%"; - } - $nextCondition = 'AND'; - push(@bindValues, $matchstr); + $nextCondition = 'WHERE'; + } + } + + if (!$visibleGroups) { + $vars->{'users'} = {}; + } + else { + # Handle selection by login name, real name, or userid. + if (defined($matchtype)) { + $query .= " $nextCondition "; + my $expr = ""; + if ($matchvalue eq 'userid') { + if ($matchstr) { + my $stored_matchstr = $matchstr; + detaint_natural($matchstr) + || ThrowUserError('illegal_user_id', {userid => $stored_matchstr}); } + $expr = "profiles.userid"; + } + elsif ($matchvalue eq 'realname') { + $expr = "profiles.realname"; + } + else { + $expr = "profiles.login_name"; + } + + if ($matchtype =~ /^(regexp|notregexp|exact)$/) { + $matchstr ||= '.'; + } + else { + $matchstr = '' unless defined $matchstr; + } + + # We can trick_taint because we use the value in a SELECT only, + # using a placeholder. + trick_taint($matchstr); + + if ($matchtype eq 'regexp') { + $query .= $dbh->sql_regexp($expr, '?', 0, $dbh->quote($matchstr)); + } + elsif ($matchtype eq 'notregexp') { + $query .= $dbh->sql_not_regexp($expr, '?', 0, $dbh->quote($matchstr)); + } + elsif ($matchtype eq 'exact') { + $query .= $expr . ' = ?'; + } + else { # substr or unknown + $query .= $dbh->sql_istrcmp($expr, '?', 'LIKE'); + $matchstr = "%$matchstr%"; + } + $nextCondition = 'AND'; + push(@bindValues, $matchstr); + } - # Handle selection by group. - if ($grouprestrict eq '1') { - my $grouplist = join(',', - @{Bugzilla::Group->flatten_group_membership($group->id)}); - $query .= " $nextCondition ugm.group_id IN($grouplist) "; - } - $query .= ' ORDER BY profiles.login_name'; + # Handle selection by group. + if ($grouprestrict eq '1') { + my $grouplist + = join(',', @{Bugzilla::Group->flatten_group_membership($group->id)}); + $query .= " $nextCondition ugm.group_id IN($grouplist) "; + } + $query .= ' ORDER BY profiles.login_name'; - $vars->{'users'} = $dbh->selectall_arrayref($query, - {'Slice' => {}}, - @bindValues); + $vars->{'users'} + = $dbh->selectall_arrayref($query, {'Slice' => {}}, @bindValues); - } + } - if ($matchtype && $matchtype eq 'exact' && scalar(@{$vars->{'users'}}) == 1) { - my $match_user_id = $vars->{'users'}[0]->{'userid'}; - my $match_user = check_user($match_user_id); - edit_processing($match_user); - } else { - $template->process('admin/users/list.html.tmpl', $vars) - || ThrowTemplateError($template->error()); - } + if ($matchtype && $matchtype eq 'exact' && scalar(@{$vars->{'users'}}) == 1) { + my $match_user_id = $vars->{'users'}[0]->{'userid'}; + my $match_user = check_user($match_user_id); + edit_processing($match_user); + } + else { + $template->process('admin/users/list.html.tmpl', $vars) + || ThrowTemplateError($template->error()); + } ########################################################################### -} elsif ($action eq 'add') { - $editusers || ThrowUserError("auth_failure", {group => "editusers", - action => "add", - object => "users"}); +} +elsif ($action eq 'add') { + $editusers + || ThrowUserError("auth_failure", + {group => "editusers", action => "add", object => "users"}); - $vars->{'token'} = issue_session_token('add_user'); + $vars->{'token'} = issue_session_token('add_user'); - $template->process('admin/users/create.html.tmpl', $vars) - || ThrowTemplateError($template->error()); + $template->process('admin/users/create.html.tmpl', $vars) + || ThrowTemplateError($template->error()); ########################################################################### -} elsif ($action eq 'new') { - $editusers || ThrowUserError("auth_failure", {group => "editusers", - action => "add", - object => "users"}); +} +elsif ($action eq 'new') { + $editusers + || ThrowUserError("auth_failure", + {group => "editusers", action => "add", object => "users"}); - check_token_data($token, 'add_user'); + check_token_data($token, 'add_user'); - # When e.g. the 'Env' auth method is used, the password field - # is not displayed. In that case, set the password to *. - my $password = $cgi->param('password'); - $password = '*' if !defined $password; + # When e.g. the 'Env' auth method is used, the password field + # is not displayed. In that case, set the password to *. + my $password = $cgi->param('password'); + $password = '*' if !defined $password; - my $new_user = Bugzilla::User->create({ - login_name => scalar $cgi->param('login'), - cryptpassword => $password, - realname => scalar $cgi->param('name'), - disabledtext => scalar $cgi->param('disabledtext'), - disable_mail => scalar $cgi->param('disable_mail'), - extern_id => scalar $cgi->param('extern_id'), - }); + my $new_user = Bugzilla::User->create({ + login_name => scalar $cgi->param('login'), + cryptpassword => $password, + realname => scalar $cgi->param('name'), + disabledtext => scalar $cgi->param('disabledtext'), + disable_mail => scalar $cgi->param('disable_mail'), + extern_id => scalar $cgi->param('extern_id'), + }); - userDataToVars($new_user->id); + userDataToVars($new_user->id); - delete_token($token); + delete_token($token); - # We already display the updated page. We have to recreate a token now. - $vars->{'token'} = issue_session_token('edit_user'); - $vars->{'message'} = 'account_created'; - $template->process('admin/users/edit.html.tmpl', $vars) - || ThrowTemplateError($template->error()); + # We already display the updated page. We have to recreate a token now. + $vars->{'token'} = issue_session_token('edit_user'); + $vars->{'message'} = 'account_created'; + $template->process('admin/users/edit.html.tmpl', $vars) + || ThrowTemplateError($template->error()); ########################################################################### -} elsif ($action eq 'edit') { - my $otherUser = check_user($otherUserID, $otherUserLogin); - edit_processing($otherUser); +} +elsif ($action eq 'edit') { + my $otherUser = check_user($otherUserID, $otherUserLogin); + edit_processing($otherUser); ########################################################################### -} elsif ($action eq 'update') { - check_token_data($token, 'edit_user'); - my $otherUser = check_user($otherUserID, $otherUserLogin); - $otherUserID = $otherUser->id; - - # Lock tables during the check+update session. - $dbh->bz_start_transaction(); - - $editusers || $disableusers || $user->can_see_user($otherUser) - || ThrowUserError('auth_failure', {reason => "not_visible", - action => "modify", - object => "user"}); +} +elsif ($action eq 'update') { + check_token_data($token, 'edit_user'); + my $otherUser = check_user($otherUserID, $otherUserLogin); + $otherUserID = $otherUser->id; - $vars->{'loginold'} = $otherUser->login; + # Lock tables during the check+update session. + $dbh->bz_start_transaction(); - # Update profiles table entry; silently skip doing this if the user - # is not authorized. - my $changes = {}; - if ($editusers) { - $otherUser->set_login($cgi->param('login')); - $otherUser->set_password($cgi->param('password')) - if $cgi->param('password'); - $otherUser->set_extern_id($cgi->param('extern_id')) - if defined($cgi->param('extern_id')); - $otherUser->set_password_change_required($cgi->param('password_change_required')); - $otherUser->set_password_change_reason( - $otherUser->password_change_required - ? $cgi->param('password_change_reason') - : '' - ); - if ($user->in_group('bz_can_disable_mfa') && $otherUser->mfa && $cgi->param('mfa') eq '') { - $otherUser->set_mfa(''); - } + $editusers + || $disableusers + || $user->can_see_user($otherUser) + || ThrowUserError('auth_failure', + {reason => "not_visible", action => "modify", object => "user"}); + + $vars->{'loginold'} = $otherUser->login; + + # Update profiles table entry; silently skip doing this if the user + # is not authorized. + my $changes = {}; + if ($editusers) { + $otherUser->set_login($cgi->param('login')); + $otherUser->set_password($cgi->param('password')) if $cgi->param('password'); + $otherUser->set_extern_id($cgi->param('extern_id')) + if defined($cgi->param('extern_id')); + $otherUser->set_password_change_required( + $cgi->param('password_change_required')); + $otherUser->set_password_change_reason($otherUser->password_change_required + ? $cgi->param('password_change_reason') + : ''); + if ( $user->in_group('bz_can_disable_mfa') + && $otherUser->mfa + && $cgi->param('mfa') eq '') + { + $otherUser->set_mfa(''); } + } - if ($editusers || $disableusers) { - $otherUser->set_name($cgi->param('name')); - $otherUser->set_disabledtext($cgi->param('disabledtext')); - $otherUser->set_disable_mail($cgi->param('disable_mail')); - } + if ($editusers || $disableusers) { + $otherUser->set_name($cgi->param('name')); + $otherUser->set_disabledtext($cgi->param('disabledtext')); + $otherUser->set_disable_mail($cgi->param('disable_mail')); + } - $changes = $otherUser->update(); + $changes = $otherUser->update(); - # Update group settings. - my $sth_add_mapping = $dbh->prepare( - qq{INSERT INTO user_group_map ( + # Update group settings. + my $sth_add_mapping = $dbh->prepare( + qq{INSERT INTO user_group_map ( user_id, group_id, isbless, grant_type ) VALUES ( ?, ?, ?, ? ) - }); - my $sth_remove_mapping = $dbh->prepare( - qq{DELETE FROM user_group_map + } + ); + my $sth_remove_mapping = $dbh->prepare( + qq{DELETE FROM user_group_map WHERE user_id = ? AND group_id = ? AND isbless = ? AND grant_type = ? - }); - - my @groupsAddedTo; - my @groupsRemovedFrom; - my @groupsGrantedRightsToBless; - my @groupsDeniedRightsToBless; - - # Regard only groups the user is allowed to bless and skip all others - # silently. - # XXX: checking for existence of each user_group_map entry - # would allow to display a friendlier error message on page reloads. - userDataToVars($otherUserID); - my $permissions = $vars->{'permissions'}; - foreach my $blessable (@{$user->bless_groups()}) { - my $id = $blessable->id; - my $name = $blessable->name; - - # Change memberships. - my $groupid = $cgi->param("group_$id") || 0; - if ($groupid != $permissions->{$id}->{'directmember'}) { - if (!$groupid) { - $sth_remove_mapping->execute( - $otherUserID, $id, 0, GRANT_DIRECT); - push(@groupsRemovedFrom, $name); - } else { - $sth_add_mapping->execute( - $otherUserID, $id, 0, GRANT_DIRECT); - push(@groupsAddedTo, $name); - } - } + } + ); + + my @groupsAddedTo; + my @groupsRemovedFrom; + my @groupsGrantedRightsToBless; + my @groupsDeniedRightsToBless; + + # Regard only groups the user is allowed to bless and skip all others + # silently. + # XXX: checking for existence of each user_group_map entry + # would allow to display a friendlier error message on page reloads. + userDataToVars($otherUserID); + my $permissions = $vars->{'permissions'}; + foreach my $blessable (@{$user->bless_groups()}) { + my $id = $blessable->id; + my $name = $blessable->name; + + # Change memberships. + my $groupid = $cgi->param("group_$id") || 0; + if ($groupid != $permissions->{$id}->{'directmember'}) { + if (!$groupid) { + $sth_remove_mapping->execute($otherUserID, $id, 0, GRANT_DIRECT); + push(@groupsRemovedFrom, $name); + } + else { + $sth_add_mapping->execute($otherUserID, $id, 0, GRANT_DIRECT); + push(@groupsAddedTo, $name); + } + } - # Only members of the editusers group may change bless grants. - # Skip silently if this is not the case. - if ($editusers) { - my $groupid = $cgi->param("bless_$id") || 0; - if ($groupid != $permissions->{$id}->{'directbless'}) { - if (!$groupid) { - $sth_remove_mapping->execute( - $otherUserID, $id, 1, GRANT_DIRECT); - push(@groupsDeniedRightsToBless, $name); - } else { - $sth_add_mapping->execute( - $otherUserID, $id, 1, GRANT_DIRECT); - push(@groupsGrantedRightsToBless, $name); - } - } + # Only members of the editusers group may change bless grants. + # Skip silently if this is not the case. + if ($editusers) { + my $groupid = $cgi->param("bless_$id") || 0; + if ($groupid != $permissions->{$id}->{'directbless'}) { + if (!$groupid) { + $sth_remove_mapping->execute($otherUserID, $id, 1, GRANT_DIRECT); + push(@groupsDeniedRightsToBless, $name); } + else { + $sth_add_mapping->execute($otherUserID, $id, 1, GRANT_DIRECT); + push(@groupsGrantedRightsToBless, $name); + } + } } - if (@groupsAddedTo || @groupsRemovedFrom) { - $dbh->do(qq{INSERT INTO profiles_activity ( + } + if (@groupsAddedTo || @groupsRemovedFrom) { + $dbh->do( + qq{INSERT INTO profiles_activity ( userid, who, profiles_when, fieldid, oldvalue, newvalue @@ -343,344 +364,362 @@ if ($action eq 'search') { ?, ?, now(), ?, ?, ? ) }, - undef, - ($otherUserID, $userid, - get_field_id('bug_group'), - join(', ', @groupsRemovedFrom), join(', ', @groupsAddedTo))); - Bugzilla->memcached->clear_config({ key => "user_groups.$otherUserID" }) - } - # XXX: should create profiles_activity entries for blesser changes. + undef, + ( + $otherUserID, $userid, + get_field_id('bug_group'), join(', ', @groupsRemovedFrom), + join(', ', @groupsAddedTo) + ) + ); + Bugzilla->memcached->clear_config({key => "user_groups.$otherUserID"}); + } - $dbh->bz_commit_transaction(); + # XXX: should create profiles_activity entries for blesser changes. - # XXX: userDataToVars may be off when editing ourselves. - userDataToVars($otherUserID); - delete_token($token); + $dbh->bz_commit_transaction(); - $vars->{'message'} = 'account_updated'; - $vars->{'changed_fields'} = [keys %$changes]; - $vars->{'groups_added_to'} = \@groupsAddedTo; - $vars->{'groups_removed_from'} = \@groupsRemovedFrom; - $vars->{'groups_granted_rights_to_bless'} = \@groupsGrantedRightsToBless; - $vars->{'groups_denied_rights_to_bless'} = \@groupsDeniedRightsToBless; - # We already display the updated page. We have to recreate a token now. - $vars->{'token'} = issue_session_token('edit_user'); + # XXX: userDataToVars may be off when editing ourselves. + userDataToVars($otherUserID); + delete_token($token); - $template->process('admin/users/edit.html.tmpl', $vars) - || ThrowTemplateError($template->error()); + $vars->{'message'} = 'account_updated'; + $vars->{'changed_fields'} = [keys %$changes]; + $vars->{'groups_added_to'} = \@groupsAddedTo; + $vars->{'groups_removed_from'} = \@groupsRemovedFrom; + $vars->{'groups_granted_rights_to_bless'} = \@groupsGrantedRightsToBless; + $vars->{'groups_denied_rights_to_bless'} = \@groupsDeniedRightsToBless; + + # We already display the updated page. We have to recreate a token now. + $vars->{'token'} = issue_session_token('edit_user'); + + $template->process('admin/users/edit.html.tmpl', $vars) + || ThrowTemplateError($template->error()); ########################################################################### -} elsif ($action eq 'del') { - my $otherUser = check_user($otherUserID, $otherUserLogin); - $otherUserID = $otherUser->id; - - Bugzilla->params->{'allowuserdeletion'} - || ThrowUserError('users_deletion_disabled'); - $editusers || ThrowUserError('auth_failure', {group => "editusers", - action => "delete", - object => "users"}); - $vars->{'otheruser'} = $otherUser; - - # Find other cross references. - $vars->{'attachments'} = $dbh->selectrow_array( - 'SELECT COUNT(*) FROM attachments WHERE submitter_id = ?', - undef, $otherUserID); - $vars->{'assignee_or_qa'} = $dbh->selectrow_array( - qq{SELECT COUNT(*) +} +elsif ($action eq 'del') { + my $otherUser = check_user($otherUserID, $otherUserLogin); + $otherUserID = $otherUser->id; + + Bugzilla->params->{'allowuserdeletion'} + || ThrowUserError('users_deletion_disabled'); + $editusers + || ThrowUserError('auth_failure', + {group => "editusers", action => "delete", object => "users"}); + $vars->{'otheruser'} = $otherUser; + + # Find other cross references. + $vars->{'attachments'} + = $dbh->selectrow_array( + 'SELECT COUNT(*) FROM attachments WHERE submitter_id = ?', + undef, $otherUserID); + $vars->{'assignee_or_qa'} = $dbh->selectrow_array( + qq{SELECT COUNT(*) FROM bugs - WHERE assigned_to = ? OR qa_contact = ?}, - undef, ($otherUserID, $otherUserID)); - $vars->{'reporter'} = $dbh->selectrow_array( - 'SELECT COUNT(*) FROM bugs WHERE reporter = ?', - undef, $otherUserID); - $vars->{'cc'} = $dbh->selectrow_array( - 'SELECT COUNT(*) FROM cc WHERE who = ?', - undef, $otherUserID); - $vars->{'bugs_activity'} = $dbh->selectrow_array( - 'SELECT COUNT(*) FROM bugs_activity WHERE who = ?', - undef, $otherUserID); - $vars->{'component_cc'} = $dbh->selectrow_array( - 'SELECT COUNT(*) FROM component_cc WHERE user_id = ?', - undef, $otherUserID); - $vars->{'email_setting'} = $dbh->selectrow_array( - 'SELECT COUNT(*) FROM email_setting WHERE user_id = ?', - undef, $otherUserID); - $vars->{'flags'}{'requestee'} = $dbh->selectrow_array( - 'SELECT COUNT(*) FROM flags WHERE requestee_id = ?', - undef, $otherUserID); - $vars->{'flags'}{'setter'} = $dbh->selectrow_array( - 'SELECT COUNT(*) FROM flags WHERE setter_id = ?', - undef, $otherUserID); - $vars->{'longdescs'} = $dbh->selectrow_array( - 'SELECT COUNT(*) FROM longdescs WHERE who = ?', - undef, $otherUserID); - my $namedquery_ids = $dbh->selectcol_arrayref( - 'SELECT id FROM namedqueries WHERE userid = ?', - undef, $otherUserID); - $vars->{'namedqueries'} = scalar(@$namedquery_ids); - if (scalar(@$namedquery_ids)) { - $vars->{'namedquery_group_map'} = $dbh->selectrow_array( - 'SELECT COUNT(*) FROM namedquery_group_map WHERE namedquery_id IN' . - ' (' . join(', ', @$namedquery_ids) . ')'); - } - else { - $vars->{'namedquery_group_map'} = 0; - } - $vars->{'profile_setting'} = $dbh->selectrow_array( - 'SELECT COUNT(*) FROM profile_setting WHERE user_id = ?', - undef, $otherUserID); - $vars->{'profiles_activity'} = $dbh->selectrow_array( - 'SELECT COUNT(*) FROM profiles_activity WHERE who = ? AND userid != ?', - undef, ($otherUserID, $otherUserID)); - $vars->{'quips'} = $dbh->selectrow_array( - 'SELECT COUNT(*) FROM quips WHERE userid = ?', - undef, $otherUserID); - $vars->{'series'} = $dbh->selectrow_array( - 'SELECT COUNT(*) FROM series WHERE creator = ?', - undef, $otherUserID); - $vars->{'watch'}{'watched'} = $dbh->selectrow_array( - 'SELECT COUNT(*) FROM watch WHERE watched = ?', - undef, $otherUserID); - $vars->{'watch'}{'watcher'} = $dbh->selectrow_array( - 'SELECT COUNT(*) FROM watch WHERE watcher = ?', - undef, $otherUserID); - $vars->{'whine_events'} = $dbh->selectrow_array( - 'SELECT COUNT(*) FROM whine_events WHERE owner_userid = ?', - undef, $otherUserID); - $vars->{'whine_schedules'} = $dbh->selectrow_array( - qq{SELECT COUNT(distinct eventid) + WHERE assigned_to = ? OR qa_contact = ?}, undef, + ($otherUserID, $otherUserID) + ); + $vars->{'reporter'} + = $dbh->selectrow_array('SELECT COUNT(*) FROM bugs WHERE reporter = ?', + undef, $otherUserID); + $vars->{'cc'} = $dbh->selectrow_array('SELECT COUNT(*) FROM cc WHERE who = ?', + undef, $otherUserID); + $vars->{'bugs_activity'} + = $dbh->selectrow_array('SELECT COUNT(*) FROM bugs_activity WHERE who = ?', + undef, $otherUserID); + $vars->{'component_cc'} + = $dbh->selectrow_array('SELECT COUNT(*) FROM component_cc WHERE user_id = ?', + undef, $otherUserID); + $vars->{'email_setting'} + = $dbh->selectrow_array( + 'SELECT COUNT(*) FROM email_setting WHERE user_id = ?', + undef, $otherUserID); + $vars->{'flags'}{'requestee'} + = $dbh->selectrow_array('SELECT COUNT(*) FROM flags WHERE requestee_id = ?', + undef, $otherUserID); + $vars->{'flags'}{'setter'} + = $dbh->selectrow_array('SELECT COUNT(*) FROM flags WHERE setter_id = ?', + undef, $otherUserID); + $vars->{'longdescs'} + = $dbh->selectrow_array('SELECT COUNT(*) FROM longdescs WHERE who = ?', + undef, $otherUserID); + my $namedquery_ids + = $dbh->selectcol_arrayref('SELECT id FROM namedqueries WHERE userid = ?', + undef, $otherUserID); + $vars->{'namedqueries'} = scalar(@$namedquery_ids); + + if (scalar(@$namedquery_ids)) { + $vars->{'namedquery_group_map'} + = $dbh->selectrow_array( + 'SELECT COUNT(*) FROM namedquery_group_map WHERE namedquery_id IN' . ' (' + . join(', ', @$namedquery_ids) + . ')'); + } + else { + $vars->{'namedquery_group_map'} = 0; + } + $vars->{'profile_setting'} + = $dbh->selectrow_array( + 'SELECT COUNT(*) FROM profile_setting WHERE user_id = ?', + undef, $otherUserID); + $vars->{'profiles_activity'} + = $dbh->selectrow_array( + 'SELECT COUNT(*) FROM profiles_activity WHERE who = ? AND userid != ?', + undef, ($otherUserID, $otherUserID)); + $vars->{'quips'} + = $dbh->selectrow_array('SELECT COUNT(*) FROM quips WHERE userid = ?', + undef, $otherUserID); + $vars->{'series'} + = $dbh->selectrow_array('SELECT COUNT(*) FROM series WHERE creator = ?', + undef, $otherUserID); + $vars->{'watch'}{'watched'} + = $dbh->selectrow_array('SELECT COUNT(*) FROM watch WHERE watched = ?', + undef, $otherUserID); + $vars->{'watch'}{'watcher'} + = $dbh->selectrow_array('SELECT COUNT(*) FROM watch WHERE watcher = ?', + undef, $otherUserID); + $vars->{'whine_events'} + = $dbh->selectrow_array( + 'SELECT COUNT(*) FROM whine_events WHERE owner_userid = ?', + undef, $otherUserID); + $vars->{'whine_schedules'} = $dbh->selectrow_array( + qq{SELECT COUNT(distinct eventid) FROM whine_schedules WHERE mailto = ? AND mailto_type = ? - }, - undef, ($otherUserID, MAILTO_USER)); - $vars->{'token'} = issue_session_token('delete_user'); + }, undef, ($otherUserID, MAILTO_USER) + ); + $vars->{'token'} = issue_session_token('delete_user'); - $template->process('admin/users/confirm-delete.html.tmpl', $vars) - || ThrowTemplateError($template->error()); + $template->process('admin/users/confirm-delete.html.tmpl', $vars) + || ThrowTemplateError($template->error()); ########################################################################### -} elsif ($action eq 'delete') { - check_token_data($token, 'delete_user'); - my $otherUser = check_user($otherUserID, $otherUserLogin); - $otherUserID = $otherUser->id; - - # Cache for user accounts. - my %usercache = (0 => new Bugzilla::User()); - my %updatedbugs; - - # Lock tables during the check+removal session. - # XXX: if there was some change on these tables after the deletion - # confirmation checks, we may do something here we haven't warned - # about. - $dbh->bz_start_transaction(); - - Bugzilla->params->{'allowuserdeletion'} - || ThrowUserError('users_deletion_disabled'); - $editusers || ThrowUserError('auth_failure', - {group => "editusers", - action => "delete", - object => "users"}); - @{$otherUser->product_responsibilities()} - && ThrowUserError('user_has_responsibility'); - - Bugzilla->logout_user($otherUser); - - # Get the named query list so we can delete namedquery_group_map entries. - my $namedqueries_as_string = join(', ', @{$dbh->selectcol_arrayref( - 'SELECT id FROM namedqueries WHERE userid = ?', undef, $otherUserID)}); - - # Get the timestamp for LogActivityEntry. - my $timestamp = $dbh->selectrow_array('SELECT NOW()'); - - # When we update a bug_activity entry, we update the bug timestamp, too. - my $sth_set_bug_timestamp = - $dbh->prepare('UPDATE bugs SET delta_ts = ? WHERE bug_id = ?'); - - # Flags - my $flag_ids = - $dbh->selectcol_arrayref('SELECT id FROM flags WHERE requestee_id = ?', - undef, $otherUserID); - - my $flags = Bugzilla::Flag->new_from_list($flag_ids); - - $dbh->do('UPDATE flags SET requestee_id = NULL, modification_date = ? - WHERE requestee_id = ?', undef, ($timestamp, $otherUserID)); - - # We want to remove the requestee but leave the requester alone, - # so we have to log these changes manually. - my %bugs; - push(@{$bugs{$_->bug_id}->{$_->attach_id || 0}}, $_) foreach @$flags; - foreach my $bug_id (keys %bugs) { - foreach my $attach_id (keys %{$bugs{$bug_id}}) { - my @old_summaries = Bugzilla::Flag->snapshot($bugs{$bug_id}->{$attach_id}); - $_->_set_requestee() foreach @{$bugs{$bug_id}->{$attach_id}}; - my @new_summaries = Bugzilla::Flag->snapshot($bugs{$bug_id}->{$attach_id}); - my ($removed, $added) = - Bugzilla::Flag->update_activity(\@old_summaries, \@new_summaries); - LogActivityEntry($bug_id, 'flagtypes.name', $removed, $added, - $userid, $timestamp, undef, $attach_id); - } - $sth_set_bug_timestamp->execute($timestamp, $bug_id); - $updatedbugs{$bug_id} = 1; - } - - # Simple deletions in referred tables. - $dbh->do('DELETE FROM email_setting WHERE user_id = ?', undef, - $otherUserID); - $dbh->do('DELETE FROM logincookies WHERE userid = ?', undef, $otherUserID); - $dbh->do('DELETE FROM namedqueries WHERE userid = ?', undef, $otherUserID); - $dbh->do('DELETE FROM namedqueries_link_in_footer WHERE user_id = ?', undef, - $otherUserID); - if ($namedqueries_as_string) { - $dbh->do('DELETE FROM namedquery_group_map WHERE namedquery_id IN ' . - "($namedqueries_as_string)"); - } - $dbh->do('DELETE FROM profile_setting WHERE user_id = ?', undef, - $otherUserID); - $dbh->do('DELETE FROM profiles_activity WHERE userid = ? OR who = ?', undef, - ($otherUserID, $otherUserID)); - $dbh->do('DELETE FROM tokens WHERE userid = ?', undef, $otherUserID); - $dbh->do('DELETE FROM user_group_map WHERE user_id = ?', undef, - $otherUserID); - $dbh->do('DELETE FROM watch WHERE watcher = ? OR watched = ?', undef, - ($otherUserID, $otherUserID)); - - # Deletions in referred tables which need LogActivityEntry. - my $buglist = $dbh->selectcol_arrayref('SELECT bug_id FROM cc WHERE who = ?', - undef, $otherUserID); - $dbh->do('DELETE FROM cc WHERE who = ?', undef, $otherUserID); - foreach my $bug_id (@$buglist) { - LogActivityEntry($bug_id, 'cc', $otherUser->login, '', $userid, - $timestamp); - $sth_set_bug_timestamp->execute($timestamp, $bug_id); - $updatedbugs{$bug_id} = 1; +} +elsif ($action eq 'delete') { + check_token_data($token, 'delete_user'); + my $otherUser = check_user($otherUserID, $otherUserLogin); + $otherUserID = $otherUser->id; + + # Cache for user accounts. + my %usercache = (0 => new Bugzilla::User()); + my %updatedbugs; + + # Lock tables during the check+removal session. + # XXX: if there was some change on these tables after the deletion + # confirmation checks, we may do something here we haven't warned + # about. + $dbh->bz_start_transaction(); + + Bugzilla->params->{'allowuserdeletion'} + || ThrowUserError('users_deletion_disabled'); + $editusers + || ThrowUserError('auth_failure', + {group => "editusers", action => "delete", object => "users"}); + @{$otherUser->product_responsibilities()} + && ThrowUserError('user_has_responsibility'); + + Bugzilla->logout_user($otherUser); + + # Get the named query list so we can delete namedquery_group_map entries. + my $namedqueries_as_string = join( + ', ', + @{ + $dbh->selectcol_arrayref('SELECT id FROM namedqueries WHERE userid = ?', + undef, $otherUserID) } - - # Even more complex deletions in referred tables. - my $id; - - # 1) Series - my $sth_seriesid = $dbh->prepare( - 'SELECT series_id FROM series WHERE creator = ?'); - my $sth_deleteSeries = $dbh->prepare( - 'DELETE FROM series WHERE series_id = ?'); - my $sth_deleteSeriesData = $dbh->prepare( - 'DELETE FROM series_data WHERE series_id = ?'); - - $sth_seriesid->execute($otherUserID); - while ($id = $sth_seriesid->fetchrow_array()) { - $sth_deleteSeriesData->execute($id); - $sth_deleteSeries->execute($id); + ); + + # Get the timestamp for LogActivityEntry. + my $timestamp = $dbh->selectrow_array('SELECT NOW()'); + + # When we update a bug_activity entry, we update the bug timestamp, too. + my $sth_set_bug_timestamp + = $dbh->prepare('UPDATE bugs SET delta_ts = ? WHERE bug_id = ?'); + + # Flags + my $flag_ids + = $dbh->selectcol_arrayref('SELECT id FROM flags WHERE requestee_id = ?', + undef, $otherUserID); + + my $flags = Bugzilla::Flag->new_from_list($flag_ids); + + $dbh->do( + 'UPDATE flags SET requestee_id = NULL, modification_date = ? + WHERE requestee_id = ?', undef, ($timestamp, $otherUserID) + ); + + # We want to remove the requestee but leave the requester alone, + # so we have to log these changes manually. + my %bugs; + push(@{$bugs{$_->bug_id}->{$_->attach_id || 0}}, $_) foreach @$flags; + foreach my $bug_id (keys %bugs) { + foreach my $attach_id (keys %{$bugs{$bug_id}}) { + my @old_summaries = Bugzilla::Flag->snapshot($bugs{$bug_id}->{$attach_id}); + $_->_set_requestee() foreach @{$bugs{$bug_id}->{$attach_id}}; + my @new_summaries = Bugzilla::Flag->snapshot($bugs{$bug_id}->{$attach_id}); + my ($removed, $added) + = Bugzilla::Flag->update_activity(\@old_summaries, \@new_summaries); + LogActivityEntry($bug_id, 'flagtypes.name', $removed, $added, $userid, + $timestamp, undef, $attach_id); } - - # 2) Whines - my $sth_whineidFromEvents = $dbh->prepare( - 'SELECT id FROM whine_events WHERE owner_userid = ?'); - my $sth_deleteWhineEvent = $dbh->prepare( - 'DELETE FROM whine_events WHERE id = ?'); - my $sth_deleteWhineQuery = $dbh->prepare( - 'DELETE FROM whine_queries WHERE eventid = ?'); - my $sth_deleteWhineSchedule = $dbh->prepare( - 'DELETE FROM whine_schedules WHERE eventid = ?'); - - $dbh->do('DELETE FROM whine_schedules WHERE mailto = ? AND mailto_type = ?', - undef, ($otherUserID, MAILTO_USER)); - - $sth_whineidFromEvents->execute($otherUserID); - while ($id = $sth_whineidFromEvents->fetchrow_array()) { - $sth_deleteWhineQuery->execute($id); - $sth_deleteWhineSchedule->execute($id); - $sth_deleteWhineEvent->execute($id); - } - - # 3) Bugs - # 3.1) fall back to the default assignee - $buglist = $dbh->selectall_arrayref( - 'SELECT bug_id, initialowner + $sth_set_bug_timestamp->execute($timestamp, $bug_id); + $updatedbugs{$bug_id} = 1; + } + + # Simple deletions in referred tables. + $dbh->do('DELETE FROM email_setting WHERE user_id = ?', undef, $otherUserID); + $dbh->do('DELETE FROM logincookies WHERE userid = ?', undef, $otherUserID); + $dbh->do('DELETE FROM namedqueries WHERE userid = ?', undef, $otherUserID); + $dbh->do('DELETE FROM namedqueries_link_in_footer WHERE user_id = ?', + undef, $otherUserID); + if ($namedqueries_as_string) { + $dbh->do('DELETE FROM namedquery_group_map WHERE namedquery_id IN ' + . "($namedqueries_as_string)"); + } + $dbh->do('DELETE FROM profile_setting WHERE user_id = ?', undef, $otherUserID); + $dbh->do('DELETE FROM profiles_activity WHERE userid = ? OR who = ?', + undef, ($otherUserID, $otherUserID)); + $dbh->do('DELETE FROM tokens WHERE userid = ?', undef, $otherUserID); + $dbh->do('DELETE FROM user_group_map WHERE user_id = ?', undef, $otherUserID); + $dbh->do('DELETE FROM watch WHERE watcher = ? OR watched = ?', + undef, ($otherUserID, $otherUserID)); + + # Deletions in referred tables which need LogActivityEntry. + my $buglist = $dbh->selectcol_arrayref('SELECT bug_id FROM cc WHERE who = ?', + undef, $otherUserID); + $dbh->do('DELETE FROM cc WHERE who = ?', undef, $otherUserID); + foreach my $bug_id (@$buglist) { + LogActivityEntry($bug_id, 'cc', $otherUser->login, '', $userid, $timestamp); + $sth_set_bug_timestamp->execute($timestamp, $bug_id); + $updatedbugs{$bug_id} = 1; + } + + # Even more complex deletions in referred tables. + my $id; + + # 1) Series + my $sth_seriesid + = $dbh->prepare('SELECT series_id FROM series WHERE creator = ?'); + my $sth_deleteSeries = $dbh->prepare('DELETE FROM series WHERE series_id = ?'); + my $sth_deleteSeriesData + = $dbh->prepare('DELETE FROM series_data WHERE series_id = ?'); + + $sth_seriesid->execute($otherUserID); + while ($id = $sth_seriesid->fetchrow_array()) { + $sth_deleteSeriesData->execute($id); + $sth_deleteSeries->execute($id); + } + + # 2) Whines + my $sth_whineidFromEvents + = $dbh->prepare('SELECT id FROM whine_events WHERE owner_userid = ?'); + my $sth_deleteWhineEvent + = $dbh->prepare('DELETE FROM whine_events WHERE id = ?'); + my $sth_deleteWhineQuery + = $dbh->prepare('DELETE FROM whine_queries WHERE eventid = ?'); + my $sth_deleteWhineSchedule + = $dbh->prepare('DELETE FROM whine_schedules WHERE eventid = ?'); + + $dbh->do('DELETE FROM whine_schedules WHERE mailto = ? AND mailto_type = ?', + undef, ($otherUserID, MAILTO_USER)); + + $sth_whineidFromEvents->execute($otherUserID); + while ($id = $sth_whineidFromEvents->fetchrow_array()) { + $sth_deleteWhineQuery->execute($id); + $sth_deleteWhineSchedule->execute($id); + $sth_deleteWhineEvent->execute($id); + } + + # 3) Bugs + # 3.1) fall back to the default assignee + $buglist = $dbh->selectall_arrayref( + 'SELECT bug_id, initialowner FROM bugs INNER JOIN components ON components.id = bugs.component_id - WHERE assigned_to = ?', undef, $otherUserID); - - my $sth_updateAssignee = $dbh->prepare( - 'UPDATE bugs SET assigned_to = ?, delta_ts = ? WHERE bug_id = ?'); - - foreach my $bug (@$buglist) { - my ($bug_id, $default_assignee_id) = @$bug; - $sth_updateAssignee->execute($default_assignee_id, - $timestamp, $bug_id); - $updatedbugs{$bug_id} = 1; - $default_assignee_id ||= 0; - $usercache{$default_assignee_id} ||= - new Bugzilla::User($default_assignee_id); - LogActivityEntry($bug_id, 'assigned_to', $otherUser->login, - $usercache{$default_assignee_id}->login, - $userid, $timestamp); - } - - # 3.2) fall back to the default QA contact - $buglist = $dbh->selectall_arrayref( - 'SELECT bug_id, initialqacontact + WHERE assigned_to = ?', undef, $otherUserID + ); + + my $sth_updateAssignee = $dbh->prepare( + 'UPDATE bugs SET assigned_to = ?, delta_ts = ? WHERE bug_id = ?'); + + foreach my $bug (@$buglist) { + my ($bug_id, $default_assignee_id) = @$bug; + $sth_updateAssignee->execute($default_assignee_id, $timestamp, $bug_id); + $updatedbugs{$bug_id} = 1; + $default_assignee_id ||= 0; + $usercache{$default_assignee_id} ||= new Bugzilla::User($default_assignee_id); + LogActivityEntry($bug_id, 'assigned_to', $otherUser->login, + $usercache{$default_assignee_id}->login, + $userid, $timestamp); + } + + # 3.2) fall back to the default QA contact + $buglist = $dbh->selectall_arrayref( + 'SELECT bug_id, initialqacontact FROM bugs INNER JOIN components ON components.id = bugs.component_id - WHERE qa_contact = ?', undef, $otherUserID); - - my $sth_updateQAcontact = $dbh->prepare( - 'UPDATE bugs SET qa_contact = ?, delta_ts = ? WHERE bug_id = ?'); - - foreach my $bug (@$buglist) { - my ($bug_id, $default_qa_contact_id) = @$bug; - $sth_updateQAcontact->execute($default_qa_contact_id, - $timestamp, $bug_id); - $updatedbugs{$bug_id} = 1; - $default_qa_contact_id ||= 0; - $usercache{$default_qa_contact_id} ||= - new Bugzilla::User($default_qa_contact_id); - LogActivityEntry($bug_id, 'qa_contact', $otherUser->login, - $usercache{$default_qa_contact_id}->login, - $userid, $timestamp); - } - - # Finally, remove the user account itself. - $dbh->do('DELETE FROM profiles WHERE userid = ?', undef, $otherUserID); - - $dbh->bz_commit_transaction(); - delete_token($token); - - # It's complex to determine which items now need to be flushed from - # memcached. As user deletion is expected to be a rare event, we just - # flush the entire cache when a user is deleted. - Bugzilla->memcached->clear_all(); - - $vars->{'message'} = 'account_deleted'; - $vars->{'otheruser'}{'login'} = $otherUser->login; - $vars->{'restrictablegroups'} = $user->bless_groups(); - $template->process('admin/users/search.html.tmpl', $vars) - || ThrowTemplateError($template->error()); - - # Send mail about what we've done to bugs. - # The deleted user is not notified of the changes. - foreach (keys(%updatedbugs)) { - Bugzilla::BugMail::Send($_, {'changer' => $user} ); - } + WHERE qa_contact = ?', undef, $otherUserID + ); + + my $sth_updateQAcontact = $dbh->prepare( + 'UPDATE bugs SET qa_contact = ?, delta_ts = ? WHERE bug_id = ?'); + + foreach my $bug (@$buglist) { + my ($bug_id, $default_qa_contact_id) = @$bug; + $sth_updateQAcontact->execute($default_qa_contact_id, $timestamp, $bug_id); + $updatedbugs{$bug_id} = 1; + $default_qa_contact_id ||= 0; + $usercache{$default_qa_contact_id} + ||= new Bugzilla::User($default_qa_contact_id); + LogActivityEntry($bug_id, 'qa_contact', $otherUser->login, + $usercache{$default_qa_contact_id}->login, + $userid, $timestamp); + } + + # Finally, remove the user account itself. + $dbh->do('DELETE FROM profiles WHERE userid = ?', undef, $otherUserID); + + $dbh->bz_commit_transaction(); + delete_token($token); + + # It's complex to determine which items now need to be flushed from + # memcached. As user deletion is expected to be a rare event, we just + # flush the entire cache when a user is deleted. + Bugzilla->memcached->clear_all(); + + $vars->{'message'} = 'account_deleted'; + $vars->{'otheruser'}{'login'} = $otherUser->login; + $vars->{'restrictablegroups'} = $user->bless_groups(); + $template->process('admin/users/search.html.tmpl', $vars) + || ThrowTemplateError($template->error()); + + # Send mail about what we've done to bugs. + # The deleted user is not notified of the changes. + foreach (keys(%updatedbugs)) { + Bugzilla::BugMail::Send($_, {'changer' => $user}); + } ########################################################################### -} elsif ($action eq 'activity' || $action eq 'admin_activity') { - my $otherUser = check_user($otherUserID, $otherUserLogin); - my $activity_who = "profiles_activity.who"; - my $activity_userid = "profiles_activity.userid"; - - if ($action eq 'admin_activity') { - $editusers || ThrowUserError("auth_failure", { group => "editusers", - action => "admin_activity", - object => "users" }); - ($activity_userid, $activity_who) = ($activity_who, $activity_userid); - } - - my $sql = " +} +elsif ($action eq 'activity' || $action eq 'admin_activity') { + my $otherUser = check_user($otherUserID, $otherUserLogin); + my $activity_who = "profiles_activity.who"; + my $activity_userid = "profiles_activity.userid"; + + if ($action eq 'admin_activity') { + $editusers + || ThrowUserError("auth_failure", + {group => "editusers", action => "admin_activity", object => "users"}); + ($activity_userid, $activity_who) = ($activity_who, $activity_userid); + } + + my $sql = " SELECT profiles.login_name AS who, - " . $dbh->sql_date_format('profiles_activity.profiles_when') . " AS activity_when, + " + . $dbh->sql_date_format('profiles_activity.profiles_when') + . " AS activity_when, fielddefs.name AS what, profiles_activity.oldvalue AS removed, profiles_activity.newvalue AS added @@ -691,10 +730,10 @@ if ($action eq 'search') { WHERE $activity_userid = ? "; - my @values = ($otherUser->id); + my @values = ($otherUser->id); - if ($action ne 'admin_activity') { - $sql .= " + if ($action ne 'admin_activity') { + $sql .= " UNION ALL SELECT @@ -711,35 +750,36 @@ if ($action eq 'search') { AND audit_log.class = 'Bugzilla::User' AND audit_log.field != 'last_activity_ts' "; - push @values, $otherUser->id; + push @values, $otherUser->id; + } + + $sql .= " ORDER BY activity_when"; + + # massage some fields to improve readability + my $profile_changes = $dbh->selectall_arrayref($sql, {Slice => {}}, @values); + foreach my $change (@$profile_changes) { + if ($change->{what} eq 'cryptpassword') { + $change->{what} = 'password'; + $change->{removed} = ''; + $change->{added} = '(updated)'; } - - $sql .= " ORDER BY activity_when"; - - # massage some fields to improve readability - my $profile_changes = $dbh->selectall_arrayref($sql, { Slice => {} }, @values); - foreach my $change (@$profile_changes) { - if ($change->{what} eq 'cryptpassword') { - $change->{what} = 'password'; - $change->{removed} = ''; - $change->{added} = '(updated)'; - } - elsif ($change->{what} eq 'public_key') { - $change->{removed} = '(updated)' if $change->{removed} ne ''; - $change->{added} = '(updated)' if $change->{added} ne ''; - } + elsif ($change->{what} eq 'public_key') { + $change->{removed} = '(updated)' if $change->{removed} ne ''; + $change->{added} = '(updated)' if $change->{added} ne ''; } + } - $vars->{'profile_changes'} = $profile_changes; - $vars->{'otheruser'} = $otherUser; - $vars->{'action'} = $action; + $vars->{'profile_changes'} = $profile_changes; + $vars->{'otheruser'} = $otherUser; + $vars->{'action'} = $action; - $template->process("account/profile-activity.html.tmpl", $vars) - || ThrowTemplateError($template->error()); + $template->process("account/profile-activity.html.tmpl", $vars) + || ThrowTemplateError($template->error()); ########################################################################### -} else { - ThrowUserError('unknown_action', {action => $action}); +} +else { + ThrowUserError('unknown_action', {action => $action}); } exit; @@ -751,63 +791,61 @@ exit; # Try to build a user object using its ID, else its login name, and throw # an error if the user does not exist. sub check_user { - my ($otherUserID, $otherUserLogin) = @_; - - my $otherUser; - my $vars = {}; - - if ($otherUserID) { - $otherUser = Bugzilla::User->new($otherUserID); - $vars->{'user_id'} = $otherUserID; - } - elsif ($otherUserLogin) { - $otherUser = new Bugzilla::User({ name => $otherUserLogin }); - $vars->{'user_login'} = $otherUserLogin; - } - ($otherUser && $otherUser->id) || ThrowCodeError('invalid_user', $vars); - - if (!$user->in_group('admin')) { - my $insider_group = Bugzilla->params->{insidergroup}; - my $can_edit_insider = $user->in_group($insider_group) || $user->in_group('servicedesk'); - if ($otherUser->in_group('admin') - || ($otherUser->in_group($insider_group) && !$can_edit_insider) - ) { - ThrowUserError('auth_failure', { - action => 'modify', - object => 'user' - }); - } + my ($otherUserID, $otherUserLogin) = @_; + + my $otherUser; + my $vars = {}; + + if ($otherUserID) { + $otherUser = Bugzilla::User->new($otherUserID); + $vars->{'user_id'} = $otherUserID; + } + elsif ($otherUserLogin) { + $otherUser = new Bugzilla::User({name => $otherUserLogin}); + $vars->{'user_login'} = $otherUserLogin; + } + ($otherUser && $otherUser->id) || ThrowCodeError('invalid_user', $vars); + + if (!$user->in_group('admin')) { + my $insider_group = Bugzilla->params->{insidergroup}; + my $can_edit_insider + = $user->in_group($insider_group) || $user->in_group('servicedesk'); + if ($otherUser->in_group('admin') + || ($otherUser->in_group($insider_group) && !$can_edit_insider)) + { + ThrowUserError('auth_failure', {action => 'modify', object => 'user'}); } + } - return $otherUser; + return $otherUser; } # Copy incoming list selection values from CGI params to template variables. sub mirrorListSelectionValues { - my $cgi = Bugzilla->cgi; - if (defined($cgi->param('matchtype'))) { - foreach ('matchvalue', 'matchstr', 'matchtype', 'grouprestrict', 'groupid') { - $vars->{'listselectionvalues'}{$_} = $cgi->param($_); - } + my $cgi = Bugzilla->cgi; + if (defined($cgi->param('matchtype'))) { + foreach ('matchvalue', 'matchstr', 'matchtype', 'grouprestrict', 'groupid') { + $vars->{'listselectionvalues'}{$_} = $cgi->param($_); } + } } # Retrieve user data for the user editing form. User creation and user # editing code rely on this to call derive_groups(). sub userDataToVars { - my $otheruserid = shift; - my $otheruser = new Bugzilla::User($otheruserid); - my $query; - my $user = Bugzilla->user; - my $dbh = Bugzilla->dbh; + my $otheruserid = shift; + my $otheruser = new Bugzilla::User($otheruserid); + my $query; + my $user = Bugzilla->user; + my $dbh = Bugzilla->dbh; - my $grouplist = $otheruser->groups_as_string; + my $grouplist = $otheruser->groups_as_string; - $vars->{'otheruser'} = $otheruser; - $vars->{'groups'} = $user->bless_groups(); + $vars->{'otheruser'} = $otheruser; + $vars->{'groups'} = $user->bless_groups(); - $vars->{'permissions'} = $dbh->selectall_hashref( - qq{SELECT id, + $vars->{'permissions'} = $dbh->selectall_hashref( + qq{SELECT id, COUNT(directmember.group_id) AS directmember, COUNT(regexpmember.group_id) AS regexpmember, (CASE WHEN (groups.id IN ($grouplist) @@ -833,40 +871,41 @@ sub userDataToVars { AND directbless.isbless = 1 AND directbless.grant_type = ? } . $dbh->sql_group_by('id'), - 'id', undef, - ($otheruserid, GRANT_DIRECT, - $otheruserid, GRANT_REGEXP, - $otheruserid, GRANT_DIRECT)); - - # Find indirect bless permission. - $query = qq{SELECT groups.id + 'id', undef, + ( + $otheruserid, GRANT_DIRECT, $otheruserid, GRANT_REGEXP, + $otheruserid, GRANT_DIRECT + ) + ); + + # Find indirect bless permission. + $query = qq{SELECT groups.id FROM groups, group_group_map AS ggm WHERE groups.id = ggm.grantor_id AND ggm.member_id IN ($grouplist) AND ggm.grant_type = ? } . $dbh->sql_group_by('id'); - foreach (@{$dbh->selectall_arrayref($query, undef, - (GROUP_BLESS))}) { - # Merge indirect bless permissions into permission variable. - $vars->{'permissions'}{${$_}[0]}{'indirectbless'} = 1; - } + foreach (@{$dbh->selectall_arrayref($query, undef, (GROUP_BLESS))}) { + + # Merge indirect bless permissions into permission variable. + $vars->{'permissions'}{${$_}[0]}{'indirectbless'} = 1; + } } sub edit_processing { - my $otherUser = shift; - my $user = Bugzilla->user; - my $template = Bugzilla->template; - - $user->in_group('editusers') - || $user->in_group('disableusers') - || $user->can_see_user($otherUser) - || ThrowUserError('auth_failure', {reason => "not_visible", - action => "modify", - object => "user"}); - - userDataToVars($otherUser->id); - $vars->{'token'} = issue_session_token('edit_user'); - - $template->process('admin/users/edit.html.tmpl', $vars) - || ThrowTemplateError($template->error()); + my $otherUser = shift; + my $user = Bugzilla->user; + my $template = Bugzilla->template; + + $user->in_group('editusers') + || $user->in_group('disableusers') + || $user->can_see_user($otherUser) + || ThrowUserError('auth_failure', + {reason => "not_visible", action => "modify", object => "user"}); + + userDataToVars($otherUser->id); + $vars->{'token'} = issue_session_token('edit_user'); + + $template->process('admin/users/edit.html.tmpl', $vars) + || ThrowTemplateError($template->error()); } |