diff options
Diffstat (limited to 'Bug.pm')
-rwxr-xr-x | Bug.pm | 510 |
1 files changed, 0 insertions, 510 deletions
diff --git a/Bug.pm b/Bug.pm deleted file mode 100755 index 94bd628e2..000000000 --- a/Bug.pm +++ /dev/null @@ -1,510 +0,0 @@ -# -*- Mode: perl; indent-tabs-mode: nil -*- -# -# The contents of this file are subject to the Mozilla Public -# License Version 1.1 (the "License"); you may not use this file -# except in compliance with the License. You may obtain a copy of -# the License at http://www.mozilla.org/MPL/ -# -# Software distributed under the License is distributed on an "AS -# IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or -# implied. See the License for the specific language governing -# rights and limitations under the License. -# -# The Original Code is the Bugzilla Bug Tracking System. -# -# The Initial Developer of the Original Code is Netscape Communications -# Corporation. Portions created by Netscape are -# Copyright (C) 1998 Netscape Communications Corporation. All -# Rights Reserved. -# -# Contributor(s): Dawn Endico <endico@mozilla.org> -# Terry Weissman <terry@mozilla.org> -# Chris Yeh <cyeh@bluemartini.com> - -package Bug; - -use strict; - -use RelationSet; -use vars qw($unconfirmedstate $legal_keywords @legal_platform - @legal_priority @legal_severity @legal_opsys @legal_bugs_status - @settable_resolution %components %versions %target_milestone - @enterable_products %milestoneurl %prodmaxvotes); - -use CGI::Carp qw(fatalsToBrowser); - -use Attachment; -use Bugzilla::Config; -use Bugzilla::Constants; -use Bugzilla::Flag; -use Bugzilla::FlagType; -use Bugzilla::User; -use Bugzilla::Util; - -sub fields { - # Keep this ordering in sync with bugzilla.dtd - my @fields = qw(bug_id alias creation_ts short_desc delta_ts - reporter_accessible cclist_accessible - product component version rep_platform op_sys - bug_status resolution - bug_file_loc status_whiteboard keywords - priority bug_severity target_milestone - dependson blocked votes - reporter assigned_to cc - ); - - if (Param('useqacontact')) { - push @fields, "qa_contact"; - } - - if (Param('timetrackinggroup')) { - push @fields, qw(estimated_time remaining_time actual_time); - } - - return @fields; -} - -my %ok_field; -foreach my $key (qw(error groups - longdescs milestoneurl attachments - isopened isunconfirmed - flag_types num_attachment_flag_types - show_attachment_flags use_keywords any_flags_requesteeble - ), - fields()) { - $ok_field{$key}++; -} - -# create a new empty bug -# -sub new { - my $type = shift(); - my %bug; - - # create a ref to an empty hash and bless it - # - my $self = {%bug}; - bless $self, $type; - - # construct from a hash containing a bug's info - # - if ($#_ == 1) { - $self->initBug(@_); - } else { - confess("invalid number of arguments \($#_\)($_)"); - } - - # bless as a Bug - # - return $self; -} - -# dump info about bug into hash unless user doesn't have permission -# user_id 0 is used when person is not logged in. -# -sub initBug { - my $self = shift(); - my ($bug_id, $user_id) = (@_); - - $bug_id = trim($bug_id); - - my $old_bug_id = $bug_id; - - # If the bug ID isn't numeric, it might be an alias, so try to convert it. - $bug_id = &::BugAliasToID($bug_id) if $bug_id !~ /^[1-9][0-9]*$/; - - if ((! defined $bug_id) || (!$bug_id) || (!detaint_natural($bug_id))) { - # no bug number given or the alias didn't match a bug - $self->{'bug_id'} = $old_bug_id; - $self->{'error'} = "InvalidBugId"; - return $self; - } - -# default userid 0, or get DBID if you used an email address - unless (defined $user_id) { - $user_id = 0; - } - else { - if ($user_id =~ /^\@/) { - $user_id = &::DBname_to_id($user_id); - } - } - - $self->{'whoid'} = $user_id; - - my $query = " - SELECT - bugs.bug_id, alias, bugs.product_id, products.name, version, - rep_platform, op_sys, bug_status, resolution, priority, - bug_severity, bugs.component_id, components.name, assigned_to, - reporter, bug_file_loc, short_desc, target_milestone, - qa_contact, status_whiteboard, - DATE_FORMAT(creation_ts,'%Y.%m.%d %H:%i'), - delta_ts, ifnull(sum(votes.vote_count),0), - reporter_accessible, cclist_accessible, - estimated_time, remaining_time - from bugs left join votes using(bug_id), - products, components - where bugs.bug_id = $bug_id - AND products.id = bugs.product_id - AND components.id = bugs.component_id - group by bugs.bug_id"; - - &::SendSQL($query); - my @row = (); - - if ((@row = &::FetchSQLData()) && &::CanSeeBug($bug_id, $self->{'whoid'})) { - my $count = 0; - my %fields; - foreach my $field ("bug_id", "alias", "product_id", "product", "version", - "rep_platform", "op_sys", "bug_status", "resolution", - "priority", "bug_severity", "component_id", "component", - "assigned_to", "reporter", "bug_file_loc", "short_desc", - "target_milestone", "qa_contact", "status_whiteboard", - "creation_ts", "delta_ts", "votes", - "reporter_accessible", "cclist_accessible", - "estimated_time", "remaining_time") - { - $fields{$field} = shift @row; - if (defined $fields{$field}) { - $self->{$field} = $fields{$field}; - } - $count++; - } - } elsif (@row) { - $self->{'bug_id'} = $bug_id; - $self->{'error'} = "NotPermitted"; - return $self; - } else { - $self->{'bug_id'} = $bug_id; - $self->{'error'} = "NotFound"; - return $self; - } - - $self->{'assigned_to'} = new Bugzilla::User($self->{'assigned_to'}); - $self->{'reporter'} = new Bugzilla::User($self->{'reporter'}); - - if (Param('useqacontact') && $self->{'qa_contact'} > 0) { - $self->{'qa_contact'} = new Bugzilla::User($self->{'qa_contact'}); - } else { - $self->{'qa_contact'} = undef; - } - - my $ccSet = new RelationSet; - $ccSet->mergeFromDB("select who from cc where bug_id=$bug_id"); - my @cc = $ccSet->toArrayOfStrings(); - if (@cc) { - $self->{'cc'} = \@cc; - } - - if (@::legal_keywords) { - &::SendSQL("SELECT keyworddefs.name - FROM keyworddefs, keywords - WHERE keywords.bug_id = $bug_id - AND keyworddefs.id = keywords.keywordid - ORDER BY keyworddefs.name"); - my @list; - while (&::MoreSQLData()) { - push(@list, &::FetchOneColumn()); - } - if (@list) { - $self->{'keywords'} = join(', ', @list); - } - } - - $self->{'attachments'} = Attachment::query($self->{bug_id}); - - # The types of flags that can be set on this bug. - # If none, no UI for setting flags will be displayed. - my $flag_types = - Bugzilla::FlagType::match({ 'target_type' => 'bug', - 'product_id' => $self->{'product_id'}, - 'component_id' => $self->{'component_id'} }); - foreach my $flag_type (@$flag_types) { - $flag_type->{'flags'} = - Bugzilla::Flag::match({ 'bug_id' => $self->{bug_id}, - 'type_id' => $flag_type->{'id'}, - 'target_type' => 'bug' }); - } - $self->{'flag_types'} = $flag_types; - $self->{'any_flags_requesteeble'} = grep($_->{'is_requesteeble'}, @$flag_types); - - # The number of types of flags that can be set on attachments to this bug - # and the number of flags on those attachments. One of these counts must be - # greater than zero in order for the "flags" column to appear in the table - # of attachments. - my $num_attachment_flag_types = - Bugzilla::FlagType::count({ 'target_type' => 'attachment', - 'product_id' => $self->{'product_id'}, - 'component_id' => $self->{'component_id'}, - 'is_active' => 1 }); - my $num_attachment_flags = - Bugzilla::Flag::count({ 'target_type' => 'attachment', - 'bug_id' => $self->{bug_id} }); - - $self->{'show_attachment_flags'} - = $num_attachment_flag_types || $num_attachment_flags; - - $self->{'milestoneurl'} = $::milestoneurl{$self->{product}}; - - $self->{'isunconfirmed'} = ($self->{bug_status} eq $::unconfirmedstate); - $self->{'isopened'} = &::IsOpenedState($self->{bug_status}); - - my @depends = EmitDependList("blocked", "dependson", $bug_id); - if (@depends) { - $self->{'dependson'} = \@depends; - } - my @blocked = EmitDependList("dependson", "blocked", $bug_id); - if (@blocked) { - $self->{'blocked'} = \@blocked; - } - - return $self; -} - -sub dup_id { - my ($self) = @_; - - return $self->{'dup_id'} if exists $self->{'dup_id'}; - - $self->{'dup_id'} = undef; - if ($self->{'resolution'} eq 'DUPLICATE') { - my $dbh = Bugzilla->dbh; - $self->{'dup_id'} = - $dbh->selectrow_array(q{SELECT dupe_of - FROM duplicates - WHERE dupe = ?}, - undef, - $self->{'bug_id'}); - } - return $self->{'dup_id'}; -} - -sub actual_time { - my ($self) = @_; - - return $self->{'actual_time'} if exists $self->{'actual_time'}; - - if (&::UserInGroup(Param("timetrackinggroup"))) { - &::SendSQL("SELECT SUM(work_time) - FROM longdescs WHERE longdescs.bug_id=$self->{bug_id}"); - $self->{'actual_time'} = &::FetchSQLData(); - } - - return $self->{'actual_time'}; -} - -sub longdescs { - my ($self) = @_; - - return $self->{'longdescs'} if exists $self->{'longdescs'}; - - $self->{'longdescs'} = &::GetComments($self->{bug_id}); - - return $self->{'longdescs'}; -} - -sub use_keywords { - return @::legal_keywords; -} - -sub use_votes { - my ($self) = @_; - - return Param('usevotes') - && $::prodmaxvotes{$self->{product}} > 0; -} - -sub groups { - my $self = shift; - - return $self->{'groups'} if exists $self->{'groups'}; - - my @groups; - - # Some of this stuff needs to go into Bugzilla::User - - # For every group, we need to know if there is ANY bug_group_map - # record putting the current bug in that group and if there is ANY - # user_group_map record putting the user in that group. - # The LEFT JOINs are checking for record existence. - # - &::SendSQL("SELECT DISTINCT groups.id, name, description," . - " bug_group_map.group_id IS NOT NULL," . - " user_group_map.group_id IS NOT NULL," . - " isactive, membercontrol, othercontrol" . - " FROM groups" . - " LEFT JOIN bug_group_map" . - " ON bug_group_map.group_id = groups.id" . - " AND bug_id = $self->{'bug_id'}" . - " LEFT JOIN user_group_map" . - " ON user_group_map.group_id = groups.id" . - " AND user_id = $::userid" . - " AND NOT isbless" . - " LEFT JOIN group_control_map" . - " ON group_control_map.group_id = groups.id" . - " AND group_control_map.product_id = " . $self->{'product_id'} . - " WHERE isbuggroup"); - - while (&::MoreSQLData()) { - my ($groupid, $name, $description, $ison, $ingroup, $isactive, - $membercontrol, $othercontrol) = &::FetchSQLData(); - - $membercontrol ||= 0; - - # For product groups, we only want to use the group if either - # (1) The bit is set and not required, or - # (2) The group is Shown or Default for members and - # the user is a member of the group. - if ($ison || - ($isactive && $ingroup - && (($membercontrol == CONTROLMAPDEFAULT) - || ($membercontrol == CONTROLMAPSHOWN)) - )) - { - my $ismandatory = $isactive - && ($membercontrol == CONTROLMAPMANDATORY); - - push (@groups, { "bit" => $groupid, - "name" => $name, - "ison" => $ison, - "ingroup" => $ingroup, - "mandatory" => $ismandatory, - "description" => $description }); - } - } - - $self->{'groups'} = \@groups; - - return $self->{'groups'}; -} - -sub user { - my $self = shift; - return $self->{'user'} if exists $self->{'user'}; - - $self->{'user'} = {}; - - my $movers = Param("movers"); - $movers =~ s/\s?,\s?/|/g; - $movers =~ s/@/\@/g; - $self->{'user'}->{'canmove'} = Param("move-enabled") - && (defined $::COOKIE{"Bugzilla_login"}) - && ($::COOKIE{"Bugzilla_login"} =~ /$movers/); - - # In the below, if the person hasn't logged in ($::userid == 0), then - # we treat them as if they can do anything. That's because we don't - # know why they haven't logged in; it may just be because they don't - # use cookies. Display everything as if they have all the permissions - # in the world; their permissions will get checked when they log in - # and actually try to make the change. - $self->{'user'}->{'canedit'} = $::userid == 0 - || $::userid == $self->{'reporter'}{'id'} - || (Param('useqacontact') && $self->{'qa_contact'} && $::userid == $self->{'qa_contact'}{'id'}) - || $::userid == $self->{'assigned_to'}{'id'} - || &::UserInGroup("editbugs"); - $self->{'user'}->{'canconfirm'} = $::userid == 0 - || ($self->{'qa_contact'} && $::userid == $self->{'qa_contact'}{'id'}) - || $::userid == $self->{'assigned_to'}{'id'} - || &::UserInGroup("editbugs") - || &::UserInGroup("canconfirm"); - - return $self->{'user'}; -} - -sub choices { - my $self = shift; - return $self->{'choices'} if exists $self->{'choices'}; - - &::GetVersionTable(); - - $self->{'choices'} = {}; - - # Fiddle the product list. - my $seen_curr_prod; - my @prodlist; - - foreach my $product (@::enterable_products) { - if ($product eq $self->{'product'}) { - # if it's the product the bug is already in, it's ALWAYS in - # the popup, period, whether the user can see it or not, and - # regardless of the disallownew setting. - $seen_curr_prod = 1; - push(@prodlist, $product); - next; - } - - if (!&::CanEnterProduct($product)) { - # If we're using bug groups to restrict entry on products, and - # this product has an entry group, and the user is not in that - # group, we don't want to include that product in this list. - next; - } - - push(@prodlist, $product); - } - - # The current product is part of the popup, even if new bugs are no longer - # allowed for that product - if (!$seen_curr_prod) { - push (@prodlist, $self->{'product'}); - @prodlist = sort @prodlist; - } - - # Hack - this array contains "". See bug 106589. - my @res = grep ($_, @::settable_resolution); - - $self->{'choices'} = - { - 'product' => \@prodlist, - 'rep_platform' => \@::legal_platform, - 'priority' => \@::legal_priority, - 'bug_severity' => \@::legal_severity, - 'op_sys' => \@::legal_opsys, - 'bug_status' => \@::legal_bugs_status, - 'resolution' => \@res, - 'component' => $::components{$self->{product}}, - 'version' => $::versions{$self->{product}}, - 'target_milestone' => $::target_milestone{$self->{product}}, - }; - - return $self->{'choices'}; -} - -sub EmitDependList { - my ($myfield, $targetfield, $bug_id) = (@_); - my @list; - &::SendSQL("select dependencies.$targetfield, bugs.bug_status - from dependencies, bugs - where dependencies.$myfield = $bug_id - and bugs.bug_id = dependencies.$targetfield - order by dependencies.$targetfield"); - while (&::MoreSQLData()) { - my ($i, $stat) = (&::FetchSQLData()); - push @list, $i; - } - return @list; -} - -sub AUTOLOAD { - use vars qw($AUTOLOAD); - my $attr = $AUTOLOAD; - - $attr =~ s/.*:://; - return unless $attr=~ /[^A-Z]/; - confess ("invalid bug attribute $attr") unless $ok_field{$attr}; - - no strict 'refs'; - *$AUTOLOAD = sub { - my $self = shift; - if (defined $self->{$attr}) { - return $self->{$attr}; - } else { - return ''; - } - }; - - goto &$AUTOLOAD; -} - -1; |