summaryrefslogtreecommitdiffstats
path: root/Bugzilla
diff options
context:
space:
mode:
Diffstat (limited to 'Bugzilla')
-rw-r--r--Bugzilla/BugMail.pm33
-rw-r--r--Bugzilla/Error.pm3
-rw-r--r--Bugzilla/Flag.pm40
-rw-r--r--Bugzilla/FlagType.pm15
-rw-r--r--Bugzilla/Search.pm21
-rw-r--r--Bugzilla/Template.pm5
-rw-r--r--Bugzilla/User.pm502
7 files changed, 505 insertions, 114 deletions
diff --git a/Bugzilla/BugMail.pm b/Bugzilla/BugMail.pm
index da25b6a70..16b44d6ff 100644
--- a/Bugzilla/BugMail.pm
+++ b/Bugzilla/BugMail.pm
@@ -111,14 +111,6 @@ sub Send($;$) {
# require abuse we do.
GetVersionTable();
- # Since any email recipients must be rederived if the user has not
- # been rederived since the most recent group change, figure out when that
- # is once and determine the need to rederive users using the same DB
- # access that gets the user's email address each time a person is
- # processed.
- SendSQL("SELECT MAX(last_changed) FROM groups");
- ($last_changed) = FetchSQLData();
-
# Make sure to clean up _all_ package vars here. Yuck...
$nametoexclude = $recipients->{'changer'} || "";
@{$force{'CClist'}} = (exists $recipients->{'cc'} &&
@@ -710,19 +702,13 @@ sub NewProcessOnePerson ($$$$$$$$$$$$$) {
return;
}
-
- SendSQL("SELECT userid, (refreshed_when > " . SqlQuote($last_changed) .
- ") FROM profiles WHERE login_name = " . SqlQuote($person));
- my ($userid, $current) = (FetchSQLData());
+ # This routine should really get passed a userid
+ # This rederives groups as a side effect
+ my $user = Bugzilla::User->new_from_login($person);
+ my $userid = $user->id;
$seen{$person} = 1;
- detaint_natural($userid);
-
- if (!$current) {
- DeriveGroup($userid);
- }
-
# if this person doesn't have permission to see info on this bug,
# return.
#
@@ -732,12 +718,11 @@ sub NewProcessOnePerson ($$$$$$$$$$$$$) {
# quietly disappear from their radar.
#
return unless CanSeeBug($id, $userid);
-
# Drop any non-insiders if the comment is private
- return if (Param("insidergroup") &&
+ return if (Param("insidergroup") &&
($anyprivate != 0) &&
- (!UserInGroup(Param("insidergroup"), $userid)));
+ (!$user->groups->{Param("insidergroup")}));
# We shouldn't send changedmail if this is a dependency mail, and any of
# the depending bugs is not visible to the user.
@@ -761,8 +746,8 @@ sub NewProcessOnePerson ($$$$$$$$$$$$$) {
}
# Don't send estimated_time if user not in the group, or not enabled
if ($f ne 'estimated_time' ||
- UserInGroup(Param('timetrackinggroup'), $userid)) {
-
+ $user->groups->{Param('timetrackinggroup')}) {
+
my $desc = $fielddescription{$f};
$head .= FormatDouble($desc, $value);
}
@@ -781,7 +766,7 @@ sub NewProcessOnePerson ($$$$$$$$$$$$$) {
($diff->{'fieldname'} eq 'estimated_time' ||
$diff->{'fieldname'} eq 'remaining_time' ||
$diff->{'fieldname'} eq 'work_time')) {
- if (UserInGroup(Param("timetrackinggroup"), $userid)) {
+ if ($user->groups->{Param("timetrackinggroup")}) {
$add_diff = 1;
}
} else {
diff --git a/Bugzilla/Error.pm b/Bugzilla/Error.pm
index 485646274..a23d6db15 100644
--- a/Bugzilla/Error.pm
+++ b/Bugzilla/Error.pm
@@ -34,9 +34,6 @@ sub ThrowUserError {
$vars->{error} = $error;
- # Need to do this until User.pm goes in, so that the footer is correct
- $vars->{user} = $::vars->{user};
-
Bugzilla->dbh->do("UNLOCK TABLES") if $unlock_tables;
print Bugzilla->cgi->header();
diff --git a/Bugzilla/Flag.pm b/Bugzilla/Flag.pm
index f8eb8a4a4..4a1752cd0 100644
--- a/Bugzilla/Flag.pm
+++ b/Bugzilla/Flag.pm
@@ -177,18 +177,14 @@ sub validate {
if ($requestee_email ne $flag->{'requestee'}->{'email'}) {
# We know the requestee exists because we ran
# Bugzilla::User::match_field before getting here.
- # ConfirmGroup makes sure their group settings
- # are up-to-date or calls DeriveGroups to update them.
- my $requestee_id = &::DBname_to_id($requestee_email);
- &::ConfirmGroup($requestee_id);
+ my $requestee = Bugzilla::User->new_from_login($requestee_email);
# Throw an error if the user can't see the bug.
- if (!&::CanSeeBug($bug_id, $requestee_id))
+ if (!&::CanSeeBug($bug_id, $requestee->id))
{
ThrowUserError("flag_requestee_unauthorized",
{ flag_type => $flag->{'type'},
- requestee =>
- new Bugzilla::User($requestee_id),
+ requestee => $requestee,
bug_id => $bug_id,
attach_id =>
$flag->{target}->{attachment}->{id} });
@@ -198,13 +194,12 @@ sub validate {
# the requestee isn't in the group of insiders who can see it.
if ($flag->{target}->{attachment}->{exists}
&& $data->{'isprivate'}
- && &::Param("insidergroup")
- && !&::UserInGroup(&::Param("insidergroup"), $requestee_id))
+ && Param("insidergroup")
+ && !$requestee->in_group(Param("insidergroup")))
{
ThrowUserError("flag_requestee_unauthorized_attachment",
{ flag_type => $flag->{'type'},
- requestee =>
- new Bugzilla::User($requestee_id),
+ requestee => $requestee,
bug_id => $bug_id,
attach_id =>
$flag->{target}->{attachment}->{id} });
@@ -236,7 +231,7 @@ sub process {
my @old_summaries;
foreach my $flag (@$flags) {
my $summary = $flag->{'type'}->{'name'} . $flag->{'status'};
- $summary .= "($flag->{'requestee'}->{'email'})" if $flag->{'requestee'};
+ $summary .= "(" . $flag->{'requestee'}->login . ")" if $flag->{'requestee'};
push(@old_summaries, $summary);
}
@@ -275,7 +270,7 @@ sub process {
my @new_summaries;
foreach my $flag (@$flags) {
my $summary = $flag->{'type'}->{'name'} . $flag->{'status'};
- $summary .= "($flag->{'requestee'}->{'email'})" if $flag->{'requestee'};
+ $summary .= "(" . $flag->{'requestee'}->login . ")" if $flag->{'requestee'};
push(@new_summaries, $summary);
}
@@ -307,7 +302,7 @@ sub create {
# Insert a record for the flag into the flags table.
my $attach_id = $flag->{'target'}->{'attachment'}->{'id'} || "NULL";
- my $requestee_id = $flag->{'requestee'} ? $flag->{'requestee'}->{'id'} : "NULL";
+ my $requestee_id = $flag->{'requestee'} ? $flag->{'requestee'}->id : "NULL";
&::SendSQL("INSERT INTO flags (id, type_id,
bug_id, attach_id,
requestee_id, setter_id, status,
@@ -317,7 +312,7 @@ sub create {
$flag->{'target'}->{'bug'}->{'id'},
$attach_id,
$requestee_id,
- $flag->{'setter'}->{'id'},
+ " . $flag->{'setter'}->id . ",
'$flag->{'status'}',
$timestamp,
$timestamp)");
@@ -380,7 +375,7 @@ sub modify {
# the flag isn't specifically requestable
|| $status ne "?" # or the flag isn't being requested
|| ($flag->{'requestee'} # or the requestee hasn't changed
- && ($requestee_email eq $flag->{'requestee'}->{'email'})));
+ && ($requestee_email eq $flag->{'requestee'}->login)));
# Since the status is validated, we know it's safe, but it's still
# tainted, so we have to detaint it before using it in a query.
@@ -568,14 +563,15 @@ sub notify {
{
my @new_cc_list;
foreach my $cc (split(/[, ]+/, $flag->{'type'}->{'cc_list'})) {
- my $user_id = &::DBname_to_id($cc) || next;
- # re-derive permissions if necessary
- &::ConfirmGroup($user_id, TABLES_ALREADY_LOCKED);
+ my $ccuser = Bugzilla::User->new_from_login($cc,
+ TABLES_ALREADY_LOCKED)
+ || next;
+
next if $flag->{'target'}->{'bug'}->{'restricted'}
- && !&::CanSeeBug($flag->{'target'}->{'bug'}->{'id'}, $user_id);
+ && !&::CanSeeBug($flag->{'target'}->{'bug'}->{'id'}, $ccuser->id);
next if $flag->{'target'}->{'attachment'}->{'isprivate'}
&& Param("insidergroup")
- && !&::UserInGroup(Param("insidergroup"), $user_id);
+ && !$ccuser->in_group(Param("insidergroup"));
push(@new_cc_list, $cc);
}
$flag->{'type'}->{'cc_list'} = join(", ", @new_cc_list);
@@ -646,7 +642,7 @@ sub perlify_record {
id => $id ,
type => Bugzilla::FlagType::get($type_id) ,
target => GetTarget($bug_id, $attach_id) ,
- requestee => new Bugzilla::User($requestee_id) ,
+ requestee => $requestee_id ? new Bugzilla::User($requestee_id) : undef,
setter => new Bugzilla::User($setter_id) ,
status => $status ,
};
diff --git a/Bugzilla/FlagType.pm b/Bugzilla/FlagType.pm
index 523f60190..7fbe1f142 100644
--- a/Bugzilla/FlagType.pm
+++ b/Bugzilla/FlagType.pm
@@ -219,20 +219,17 @@ sub validate {
&& trim($data->{"requestee_type-$id"}))
{
my $requestee_email = trim($data->{"requestee_type-$id"});
- my $requestee_id = &::DBname_to_id($requestee_email);
# We know the requestee exists because we ran
# Bugzilla::User::match_field before getting here.
- # ConfirmGroup makes sure their group settings
- # are up-to-date or calls DeriveGroups to update them.
- &::ConfirmGroup($requestee_id);
+ my $requestee = Bugzilla::User->new_from_login($requestee_email);
# Throw an error if the user can't see the bug.
- if (!&::CanSeeBug($bug_id, $requestee_id))
+ if (!&::CanSeeBug($bug_id, $requestee->id))
{
ThrowUserError("flag_requestee_unauthorized",
{ flag_type => $flag_type,
- requestee => new Bugzilla::User($requestee_id),
+ requestee => $requestee,
bug_id => $bug_id,
attach_id => $attach_id });
}
@@ -240,13 +237,13 @@ sub validate {
# Throw an error if the target is a private attachment and
# the requestee isn't in the group of insiders who can see it.
if ($attach_id
- && &::Param("insidergroup")
+ && Param("insidergroup")
&& $data->{'isprivate'}
- && !&::UserInGroup(&::Param("insidergroup"), $requestee_id))
+ && !$requestee->in_group(Param("insidergroup")))
{
ThrowUserError("flag_requestee_unauthorized_attachment",
{ flag_type => $flag_type,
- requestee => new Bugzilla::User($requestee_id),
+ requestee => $requestee,
bug_id => $bug_id,
attach_id => $attach_id });
}
diff --git a/Bugzilla/Search.pm b/Bugzilla/Search.pm
index 45c26fdf2..df2ab58e3 100644
--- a/Bugzilla/Search.pm
+++ b/Bugzilla/Search.pm
@@ -926,28 +926,31 @@ sub init {
# Make sure we create a legal SQL query.
@andlist = ("1 = 1") if !@andlist;
+ my $user = Bugzilla->user;
+
my $query = "SELECT " . join(', ', @fields) .
" FROM $suppstring" .
" LEFT JOIN bug_group_map " .
" ON bug_group_map.bug_id = bugs.bug_id ";
- if (defined @{$::vars->{user}{groupids}} && @{$::vars->{user}{groupids}} > 0) {
- $query .= " AND bug_group_map.group_id NOT IN (" . join(',', @{$::vars->{user}{groupids}}) . ") ";
- }
+ if ($user) {
+ if (%{$user->groups}) {
+ $query .= " AND bug_group_map.group_id NOT IN (" . join(',', values(%{$user->groups})) . ") ";
+ }
- if ($::vars->{user}{userid}) {
- $query .= " LEFT JOIN cc ON cc.bug_id = bugs.bug_id AND cc.who = $::userid ";
+ $query .= " LEFT JOIN cc ON cc.bug_id = bugs.bug_id AND cc.who = " . $user->id;
}
$query .= " WHERE " . join(' AND ', (@wherepart, @andlist)) .
" AND ((bug_group_map.group_id IS NULL)";
- if ($::vars->{user}{userid}) {
- $query .= " OR (bugs.reporter_accessible = 1 AND bugs.reporter = $::userid) " .
+ if ($user) {
+ my $userid = $user->id;
+ $query .= " OR (bugs.reporter_accessible = 1 AND bugs.reporter = $userid) " .
" OR (bugs.cclist_accessible = 1 AND cc.who IS NOT NULL) " .
- " OR (bugs.assigned_to = $::userid) ";
+ " OR (bugs.assigned_to = $userid) ";
if (Param('useqacontact')) {
- $query .= "OR (bugs.qa_contact = $::userid) ";
+ $query .= "OR (bugs.qa_contact = $userid) ";
}
}
diff --git a/Bugzilla/Template.pm b/Bugzilla/Template.pm
index e596af226..7c084ecb9 100644
--- a/Bugzilla/Template.pm
+++ b/Bugzilla/Template.pm
@@ -256,7 +256,10 @@ sub create {
# Generic linear search function
'lsearch' => \&Bugzilla::Util::lsearch,
- # UserInGroup - you probably want to cache this
+ # Currently logged in user, if any
+ 'user' => sub { return Bugzilla->user; },
+
+ # UserInGroup. Deprecated - use the user.* functions instead
'UserInGroup' => \&::UserInGroup,
# SendBugMail - sends mail about a bug, using Bugzilla::BugMail.pm
diff --git a/Bugzilla/User.pm b/Bugzilla/User.pm
index fde9d336b..f5df92063 100644
--- a/Bugzilla/User.pm
+++ b/Bugzilla/User.pm
@@ -19,6 +19,8 @@
#
# Contributor(s): Myk Melez <myk@mozilla.org>
# Erik Stambaugh <not_erik@dasbistro.com>
+# Bradley Baetz <bbaetz@acm.org>
+# Joel Peshkin <bugreport@peshkin.net>
################################################################################
# Module Initialization
@@ -30,57 +32,311 @@ use strict;
# This module implements utilities for dealing with Bugzilla users.
package Bugzilla::User;
+use Bugzilla::Config;
+use Bugzilla::Util;
+
################################################################################
# Functions
################################################################################
-my $user_cache = {};
sub new {
- # Returns a hash of information about a particular user.
+ my $invocant = shift;
+ return $invocant->_create("userid=?", @_);
+}
+# This routine is sort of evil. Nothing except the login stuff should
+# be dealing with addresses as an input, and they can get the id as a
+# side effect of the other sql they have to do anyway.
+# Bugzilla::BugMail still does this, probably as a left over from the
+# pre-id days. Provide this as a helper, but don't document it, and hope
+# that it can go away.
+# The request flag stuff also does this, but it really should be passing
+# in the id its already had to validate (or the User.pm object, of course)
+sub new_from_login {
+ my $invocant = shift;
+ return $invocant->_create("login_name=?", @_);
+}
+
+# Internal helper for the above |new| methods
+# $cond is a string (including a placeholder ?) for the search
+# requirement for the profiles table
+sub _create {
my $invocant = shift;
my $class = ref($invocant) || $invocant;
-
- my $exists = 1;
- my ($id, $name, $email) = @_;
-
- return undef if !$id;
- return $user_cache->{$id} if exists($user_cache->{$id});
-
- my $self = { 'id' => $id };
-
- bless($self, $class);
-
- if (!$name && !$email) {
- &::PushGlobalSQLState();
- &::SendSQL("SELECT 1, realname, login_name FROM profiles WHERE userid = $id");
- ($exists, $name, $email) = &::FetchSQLData();
- &::PopGlobalSQLState();
+
+ my $cond = shift;
+ my $val = shift;
+
+ # We're checking for validity here, so any value is OK
+ trick_taint($val);
+
+ my $tables_locked_for_derive_groups = shift;
+
+ my $dbh = Bugzilla->dbh;
+
+ my ($id,
+ $login,
+ $name,
+ $mybugslink) = $dbh->selectrow_array(qq{SELECT userid,
+ login_name,
+ realname,
+ mybugslink
+ FROM profiles
+ WHERE $cond},
+ undef,
+ $val);
+
+ return undef unless defined $id;
+
+ my $self = { id => $id,
+ name => $name,
+ login => $login,
+ showmybugslink => $mybugslink,
+ };
+
+ bless ($self, $class);
+
+ # Now update any old group information if needed
+ my $result = $dbh->selectrow_array(q{SELECT 1
+ FROM profiles, groups
+ WHERE userid=?
+ AND profiles.refreshed_when <=
+ groups.last_changed},
+ undef,
+ $id);
+
+ if ($result) {
+ $self->derive_groups($tables_locked_for_derive_groups);
}
-
- $self->{'name'} = $name;
- $self->{'email'} = $email || "__UNKNOWN__";
- $self->{'exists'} = $exists;
-
- # Generate a string to identify the user by name + email if the user
- # has a name or by email only if she doesn't.
- $self->{'identity'} = $name ? "$name <$email>" : $email;
-
- # Generate a user "nickname" -- i.e. a shorter, not-necessarily-unique name
- # by which to identify the user. Currently the part of the user's email
- # address before the at sign (@), but that could change, especially if we
- # implement usernames not dependent on email address.
- my @email_components = split("@", $email);
- $self->{'nick'} = $email_components[0];
-
- $user_cache->{$id} = $self;
-
+
return $self;
}
+# Accessors for user attributes
+sub id { $_[0]->{id}; }
+sub login { $_[0]->{login}; }
+sub email { $_[0]->{login}; }
+sub name { $_[0]->{name}; }
+sub showmybugslink { $_[0]->{showmybugslink}; }
+
+# Generate a string to identify the user by name + email if the user
+# has a name or by email only if she doesn't.
+sub identity {
+ my $self = shift;
+
+ if (!defined $self->{identity}) {
+ $self->{identity} =
+ $self->{name} ? "$self->{name} <$self->{login}>" : $self->{login};
+ }
+
+ return $self->{identity};
+}
+
+sub nick {
+ my $self = shift;
+
+ if (!defined $self->{nick}) {
+ $self->{nick} = (split(/@/, $self->{login}, 2))[0];
+ }
+
+ return $self->{nick};
+}
+
+sub queries {
+ my $self = shift;
+
+ return $self->{queries} if defined $self->{queries};
+
+ my $dbh = Bugzilla->dbh;
+ my $sth = $dbh->prepare(q{ SELECT name, query, linkinfooter
+ FROM namedqueries
+ WHERE userid=?
+ ORDER BY UPPER(name)});
+ $sth->execute($self->{id});
+
+ my @queries;
+ while (my $row = $sth->fetch) {
+ push (@queries, {
+ name => $row->[0],
+ query => $row->[1],
+ linkinfooter => $row->[2],
+ });
+ }
+ $self->{queries} = \@queries;
+
+ return $self->{queries};
+}
+
+sub flush_queries_cache {
+ my $self = shift;
+
+ delete $self->{queries};
+}
+
+sub groups {
+ my $self = shift;
+
+ return $self->{groups} if defined $self->{groups};
+
+ my $dbh = Bugzilla->dbh;
+ my $groups = $dbh->selectcol_arrayref(q{SELECT DISTINCT groups.name, group_id
+ FROM groups, user_group_map
+ WHERE groups.id=user_group_map.group_id
+ AND user_id=?
+ AND isbless=0},
+ { Columns=>[1,2] },
+ $self->{id});
+
+ # The above gives us an arrayref [name, id, name, id, ...]
+ # Convert that into a hashref
+ my %groups = @$groups;
+ $self->{groups} = \%groups;
+
+ return $self->{groups};
+}
+
+sub in_group {
+ my ($self, $group) = @_;
+
+ # If we already have the info, just return it.
+ return defined($self->{groups}->{$group}) if defined $self->{groups};
+
+ # Otherwise, go check for it
+
+ my $dbh = Bugzilla->dbh;
+
+ my $res = $dbh->selectrow(q{SELECT 1
+ FROM groups, user_group_map
+ WHERE groups.id=user_group_map.group_id
+ AND user_group_map.user_id=?
+ AND isbless=0
+ AND groups.name=?},
+ undef,
+ $self->id,
+ $group);
+
+ return defined($res);
+}
+
+sub derive_groups {
+ my ($self, $already_locked) = @_;
+
+ my $id = $self->id;
+
+ my $dbh = Bugzilla->dbh;
+
+ my $sth;
+
+ $dbh->do(q{LOCK TABLES profiles WRITE,
+ user_group_map WRITE,
+ group_group_map READ,
+ groups READ}) unless $already_locked;
+
+ # avoid races, we are only up to date as of the BEGINNING of this process
+ my $time = $dbh->selectrow_array("SELECT NOW()");
+
+ # first remove any old derived stuff for this user
+ $dbh->do(q{DELETE FROM user_group_map
+ WHERE user_id = ?
+ AND isderived = 1},
+ undef,
+ $id);
+
+ my %groupidsadded = ();
+ # add derived records for any matching regexps
+
+ $sth = $dbh->prepare("SELECT id, userregexp FROM groups WHERE userregexp != ''");
+ $sth->execute;
+
+ my $group_insert;
+ while (my $row = $sth->fetch) {
+ if ($self->{login} =~ m/$row->[1]/i) {
+ $group_insert ||= $dbh->prepare(q{INSERT INTO user_group_map
+ (user_id, group_id, isbless, isderived)
+ VALUES (?, ?, 0, 1)});
+ $groupidsadded{$row->[0]} = 1;
+ $group_insert->execute($id, $row->[0]);
+ }
+ }
+
+ # Get a list of the groups of which the user is a member.
+ my %groupidschecked = ();
+
+ my @groupidstocheck = @{$dbh->selectcol_arrayref(q{SELECT group_id
+ FROM user_group_map
+ WHERE user_id=?},
+ undef,
+ $id)};
+
+ # Each group needs to be checked for inherited memberships once.
+ my $group_sth;
+ while (@groupidstocheck) {
+ my $group = shift @groupidstocheck;
+ if (!defined($groupidschecked{"$group"})) {
+ $groupidschecked{"$group"} = 1;
+ $group_sth ||= $dbh->prepare(q{SELECT grantor_id
+ FROM group_group_map
+ WHERE member_id=?
+ AND isbless=0});
+ $group_sth->execute($group);
+ while (my $groupid = $group_sth->fetchrow_array) {
+ if (!defined($groupidschecked{"$groupid"})) {
+ push(@groupidstocheck,$groupid);
+ }
+ if (!$groupidsadded{$groupid}) {
+ $groupidsadded{$groupid} = 1;
+ $group_insert ||= $dbh->prepare(q{INSERT INTO user_group_map
+ (user_id, group_id, isbless, isderived)
+ VALUES (?, ?, 0, 1)});
+ $group_insert->execute($id, $groupid);
+ }
+ }
+ }
+ }
+
+ $dbh->do(q{UPDATE profiles
+ SET refreshed_when = ?
+ WHERE userid=?},
+ undef,
+ $time,
+ $id);
+ $dbh->do("UNLOCK TABLES") unless $already_locked;
+}
+
+sub can_bless {
+ my $self = shift;
+
+ return $self->{can_bless} if defined $self->{can_bless};
+
+ my $dbh = Bugzilla->dbh;
+ # First check if the user can explicitly bless a group
+ my $res = $dbh->selectrow_arrayref(q{SELECT 1
+ FROM user_group_map
+ WHERE user_id=?
+ AND isbless=1},
+ undef,
+ $self->{id});
+ if (!$res) {
+ # Now check if user is a member of a group that can bless a group
+ $res = $dbh->selectrow_arrayref(q{SELECT 1
+ FROM user_group_map, group_group_map
+ WHERE user_group_map.user_id=?
+ AND user_group_map.group_id=member_id
+ AND group_group_map.isbless=1},
+ undef,
+ $self->{id});
+ }
+
+ $self->{can_bless} = $res ? 1 : 0;
+
+ return $self->{can_bless};
+}
+
sub match {
# Generates a list of users whose login name (email address) or real name
# matches a substring or wildcard.
+ # This is also called if matches are disabled (for error checking), but
+ # in this case only the exact match code will end up running.
# $str contains the string to match, while $limit contains the
# maximum number of records to retrieve.
@@ -99,7 +355,8 @@ sub match {
my $wildstr = $str;
- if ($wildstr =~ s/\*/\%/g) { # don't do wildcards if no '*' in the string
+ if ($wildstr =~ s/\*/\%/g && # don't do wildcards if no '*' in the string
+ Param('usermatchmode') ne 'off') { # or if we only want exact matches
# Build the query.
my $sqlstr = &::SqlQuote($wildstr);
@@ -159,7 +416,7 @@ sub match {
# order @users by alpha
- @users = sort { uc($a->{'email'}) cmp uc($b->{'email'}) } @users;
+ @users = sort { uc($a->login) cmp uc($b->login) } @users;
return \@users;
}
@@ -251,9 +508,6 @@ sub match_field {
}
$fields = $expanded_fields;
- # Skip all of this if the option has been turned off
- return 1 if (&::Param('usermatchmode') eq 'off');
-
for my $field (keys %{$fields}) {
# Tolerate fields that do not exist.
@@ -312,14 +566,14 @@ sub match_field {
# skip confirmation for exact matches
if ((scalar(@{$users}) == 1)
- && (@{$users}[0]->{'email'} eq $query))
+ && (@{$users}[0]->{'login'} eq $query))
{
# delimit with spaces if necessary
if ($vars->{'form'}->{$field}) {
$vars->{'form'}->{$field} .= " ";
}
- $vars->{'form'}->{$field} .= @{$users}[0]->{'email'};
- push @{$vars->{'mform'}->{$field}}, @{$users}[0]->{'email'};
+ $vars->{'form'}->{$field} .= @{$users}[0]->{'login'};
+ push @{$vars->{'mform'}->{$field}}, @{$users}[0]->{'login'};
next;
}
@@ -333,8 +587,8 @@ sub match_field {
if ($vars->{'form'}->{$field}) {
$vars->{'form'}->{$field} .= " ";
}
- $vars->{'form'}->{$field} .= @{$users}[0]->{'email'};
- push @{$vars->{'mform'}->{$field}}, @{$users}[0]->{'email'};
+ $vars->{'form'}->{$field} .= @{$users}[0]->{'login'};
+ push @{$vars->{'mform'}->{$field}}, @{$users}[0]->{'login'};
$need_confirm = 1 if &::Param('confirmuniqueusermatch');
}
@@ -443,3 +697,159 @@ sub email_prefs {
}
1;
+
+__END__
+
+=head1 NAME
+
+Bugzilla::User - Object for a Bugzilla user
+
+=head1 SYNOPSIS
+
+ use Bugzilla::User;
+
+ my $user = new Bugzilla::User($id);
+
+=head1 DESCRIPTION
+
+This package handles Bugzilla users. Data obtained from here is read-only;
+there is currently no way to modify a user from this package.
+
+Note that the currently logged in user (if any) is available via
+L<Bugzilla-E<gt>user|Bugzilla/"user">.
+
+=head1 METHODS
+
+=over 4
+
+=item C<new($userid)>
+
+Creates a new C<Bugzilla::User> object for the given user id. Returns
+C<undef> if no matching user is found.
+
+=begin undocumented
+
+=item C<new_from_login($login)>
+
+Creates a new C<Bugzilla::User> object given the provided login. Returns
+C<undef> if no matching user is found.
+
+This routine should not be required in general; most scripts should be using
+userids instead.
+
+This routine and C<new> both take an extra optional argument, which is
+passed as the argument to C<derive_groups> to avoid locking. See that
+routine's documentation for details.
+
+=end undocumented
+
+=item C<id>
+
+Returns the userid for this user.
+
+=item C<login>
+
+Returns the login name for this user.
+
+=item C<email>
+
+Returns the user's email address. Currently this is the same value as the
+login.
+
+=item C<name>
+
+Returns the 'real' name for this user, if any.
+
+=item C<showmybugslink>
+
+Returns C<1> if the user has set his preference to show the 'My Bugs' link in
+the page footer, and C<0> otherwise.
+
+=item C<identity>
+
+Retruns a string for the identity of the user. This will be of the form
+C<name E<lt>emailE<gt>> if the user has specified a name, and C<email>
+otherwise.
+
+=item C<nick>
+
+Returns a user "nickname" -- i.e. a shorter, not-necessarily-unique name by
+which to identify the user. Currently the part of the user's email address
+before the at sign (@), but that could change, especially if we implement
+usernames not dependent on email address.
+
+=item C<queries>
+
+Returns an array of the user's named queries, sorted in a case-insensitive
+order by name. Each entry is a hash with three keys:
+
+=over
+
+=item *
+
+name - The name of the query
+
+=item *
+
+query - The text for the query
+
+=item *
+
+linkinfooter - Whether or not the query should be displayed in the footer.
+
+=back
+
+=item C<flush_queries_cache>
+
+Some code modifies the set of stored queries. Because C<Bugzilla::User> does
+not handle these modifications, but does cache the result of calling C<queries>
+internally, such code must call this method to flush the cached result.
+
+=item C<groups>
+
+Returns a hashref of group names for groups the user is a member of. The keys
+are the names of the groups, whilst the values are the respective group ids.
+(This is so that a set of all groupids for groups the user is in can be
+obtained by C<values(%{$user->groups})>.)
+
+=item C<in_group>
+
+Determines whether or not a user is in the given group. This method is mainly
+intended for cases where we are not looking at the currently logged in user,
+and only need to make a quick check for the group, where calling C<groups>
+and getting all of the groups would be overkill.
+
+=item C<derive_groups>
+
+Bugzilla allows for group inheritance. When data about the user (or any of the
+groups) changes, the database must be updated. Handling updated groups is taken
+care of by the constructor. However, when updating the email address, the
+user may be placed into different groups, based on a new email regexp. This
+method should be called in such a case to force reresolution of these groups.
+
+=begin undocumented
+
+This routine takes an optional argument. If true, then this routine will not
+lock the tables, but will rely on the caller to ahve done so itsself.
+
+This is required because mysql will only execute a query if all of the tables
+are locked, or if none of them are, not a mixture. If the caller has already
+done some locking, then this routine would fail. Thus the caller needs to lock
+all the tables required by this method, and then C<derive_groups> won't do
+any locking.
+
+This is a really ugly solution, and when Bugzilla supports transactions
+instead of using the explicit table locking we were forced to do when thats
+all MySQL supported, this will go away.
+
+=end undocumented
+
+=item C<can_bless>
+
+Returns C<1> if the user can bless at least one group. Otherwise returns C<0>.
+
+=back
+
+=head1 SEE ALSO
+
+L<Bugzilla|Bugzilla>