代码拉取完成,页面将自动刷新
#!/usr/bin/env perl
# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
#
# This Source Code Form is "Incompatible With Secondary Licenses", as
# defined by the Mozilla Public License, v. 2.0.
use 5.10.1;
use strict;
use warnings;
use lib qw(. lib local/lib/perl5);
use Bugzilla;
use Bugzilla::Constants;
use Bugzilla::Util;
use Bugzilla::Error;
use Bugzilla::User;
use Bugzilla::Bug;
use Bugzilla::BugMail;
use Bugzilla::Flag;
use Bugzilla::Field;
use Bugzilla::Group;
use Bugzilla::Token;
local our $user = Bugzilla->login(LOGIN_REQUIRED);
my $cgi = Bugzilla->cgi;
my $template = Bugzilla->template;
my $dbh = Bugzilla->dbh;
my $userid = $user->id;
my $editusers = $user->in_group('editusers');
my $disableusers = $user->in_group('disableusers');
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"
}
);
print $cgi->header();
# Common CGI params
my $action = $cgi->param('action') || 'search';
my $otherUserID = $cgi->param('userid');
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->{'disableusers'} = $disableusers;
mirrorListSelectionValues();
Bugzilla::Hook::process('admin_editusers_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');
}
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
WHERE ugm.user_id = profiles.userid
AND ugm.isbless = 0
};
$nextCondition = 'AND';
}
else {
$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;
}
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';
$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());
}
###########################################################################
}
elsif ($action eq 'add') {
$editusers
|| ThrowUserError("auth_failure",
{group => "editusers", action => "add", object => "users"});
$vars->{'token'} = issue_session_token('add_user');
$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"});
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;
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);
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());
###########################################################################
}
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;
# Preload otherUser groups with old membership for Duo requirement check later
$otherUser->groups;
# 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"});
$vars->{'loginold'} = $otherUser->login;
# Update profiles table entry; silently skip doing this if the user
# is not authorized.
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'));
$otherUser->set_bounce_count(0) if $cgi->param('reset_bounce');
}
my @groups_added_to;
my @groups_removed_from;
my @groups_granted_rights_to_bless;
my @groups_denied_rights_to_bless;
# 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) {
push @groups_removed_from, $name;
}
else {
push @groups_added_to, $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) {
push @groups_denied_rights_to_bless, $name;
}
else {
push @groups_granted_rights_to_bless, $name;
}
}
}
}
if (@groups_added_to || @groups_removed_from) {
$otherUser->set_groups({add => \@groups_added_to, remove => \@groups_removed_from});
}
if (@groups_granted_rights_to_bless || @groups_denied_rights_to_bless) {
$otherUser->set_bless_groups(
{
add => \@groups_granted_rights_to_bless,
remove => \@groups_denied_rights_to_bless
}
);
}
my $changes = $otherUser->update();
Bugzilla->memcached->clear_config({key => "user_groups.$otherUserID"});
$dbh->bz_commit_transaction();
# XXX: userDataToVars may be off when editing ourselves.
userDataToVars($otherUserID);
delete_token($token);
$vars->{'message'} = 'account_updated';
$vars->{'changes'} = $changes;
$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(*)
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)
FROM whine_schedules
WHERE mailto = ?
AND mailto_type = ?
}, undef, ($otherUserID, MAILTO_USER)
);
$vars->{'token'} = issue_session_token('delete_user');
$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;
}
# 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
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});
}
###########################################################################
}
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,
fielddefs.name AS what,
profiles_activity.oldvalue AS removed,
profiles_activity.newvalue AS added
FROM
profiles_activity
INNER JOIN profiles ON $activity_who = profiles.userid
INNER JOIN fielddefs ON fielddefs.id = profiles_activity.fieldid
WHERE
$activity_userid = ?
";
my @values = ($otherUser->id);
if ($action ne 'admin_activity') {
$sql .= "
UNION ALL
SELECT
COALESCE(profiles.login_name, '-') AS who,
" . $dbh->sql_date_format('audit_log.at_time') . " AS activity_when,
field AS what,
removed,
added
FROM
audit_log
LEFT JOIN profiles ON profiles.userid = audit_log.user_id
WHERE
audit_log.object_id = ?
AND audit_log.class = 'Bugzilla::User'
AND audit_log.field != 'last_activity_ts'
";
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)';
}
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;
$template->process("account/profile-activity.html.tmpl", $vars)
|| ThrowTemplateError($template->error());
###########################################################################
}
else {
ThrowUserError('unknown_action', {action => $action});
}
exit;
###########################################################################
# Helpers
###########################################################################
# 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'});
}
}
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($_);
}
}
}
# 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 $grouplist = $otheruser->groups_as_string;
$vars->{'otheruser'} = $otheruser;
$vars->{'groups'} = $user->bless_groups();
$vars->{'permissions'} = $dbh->selectall_hashref(
'SELECT id,
COUNT(directmember.group_id) AS directmember,
COUNT(regexpmember.group_id) AS regexpmember,
(CASE WHEN (groups.id IN (' . $grouplist . ')
AND COUNT(directmember.group_id) = 0
AND COUNT(regexpmember.group_id) = 0
) THEN 1 ELSE 0 END)
AS derivedmember,
COUNT(directbless.group_id) AS directbless
FROM ' . $dbh->quote_identifier('groups') . '
LEFT JOIN user_group_map AS directmember
ON directmember.group_id = id
AND directmember.user_id = ?
AND directmember.isbless = 0
AND directmember.grant_type = ?
LEFT JOIN user_group_map AS regexpmember
ON regexpmember.group_id = id
AND regexpmember.user_id = ?
AND regexpmember.isbless = 0
AND regexpmember.grant_type = ?
LEFT JOIN user_group_map AS directbless
ON directbless.group_id = id
AND directbless.user_id = ?
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 = 'SELECT groups.id
FROM '
. $dbh->quote_identifier('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;
}
}
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());
}
此处可能存在不合适展示的内容,页面不予展示。您可通过相关编辑功能自查并修改。
如您确认内容无涉及 不当用语 / 纯广告导流 / 暴力 / 低俗色情 / 侵权 / 盗版 / 虚假 / 无价值内容或违法国家有关法律法规的内容,可点击提交进行申诉,我们将尽快为您处理。