зеркало из https://github.com/mozilla/pjs.git
Bug 171493 - make show_bug use Bug.pm and remove bug_form.pl
r=justdave, joel a=justdave
This commit is contained in:
Родитель
a7226fbaa6
Коммит
4709340695
|
@ -21,26 +21,41 @@
|
|||
# Terry Weissman <terry@mozilla.org>
|
||||
# Chris Yeh <cyeh@bluemartini.com>
|
||||
|
||||
package Bug;
|
||||
|
||||
use strict;
|
||||
|
||||
use DBI;
|
||||
use RelationSet;
|
||||
use vars qw($unconfirmedstate $legal_keywords);
|
||||
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);
|
||||
|
||||
package Bug;
|
||||
use CGI::Carp qw(fatalsToBrowser);
|
||||
my %ok_field;
|
||||
|
||||
use Attachment;
|
||||
use Bugzilla::Config;
|
||||
use Bugzilla::Constants;
|
||||
use Bugzilla::Flag;
|
||||
use Bugzilla::FlagType;
|
||||
use Bugzilla::User;
|
||||
use Bugzilla::Util;
|
||||
|
||||
for my $key (qw (bug_id alias product version rep_platform op_sys bug_status
|
||||
resolution priority bug_severity component assigned_to
|
||||
reporter bug_file_loc short_desc target_milestone
|
||||
qa_contact status_whiteboard creation_ts
|
||||
delta_ts votes whoid comment query error) ){
|
||||
resolution priority bug_severity component assigned_to
|
||||
reporter bug_file_loc short_desc target_milestone
|
||||
qa_contact status_whiteboard creation_ts keywords
|
||||
delta_ts votes whoid usergroupset comment query error
|
||||
longdescs cc milestoneurl attachments dependson blocked
|
||||
cclist_accessible reporter_accessible
|
||||
isopened isunconfirmed assigned_to_name assigned_to_email
|
||||
qa_contact_name qa_contact_email reporter_name
|
||||
reporter_email flag_types num_attachment_flag_types
|
||||
show_attachment_flags use_keywords any_flags_requesteeble
|
||||
estimated_time remaining_time actual_time) ) {
|
||||
$ok_field{$key}++;
|
||||
}
|
||||
}
|
||||
|
||||
# create a new empty bug
|
||||
#
|
||||
|
@ -95,16 +110,20 @@ sub initBug {
|
|||
$user_id = &::DBname_to_id($user_id);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
$self->{'whoid'} = $user_id;
|
||||
|
||||
my $query = "
|
||||
select
|
||||
bugs.bug_id, alias, products.name, version, rep_platform, op_sys, bug_status,
|
||||
resolution, priority, bug_severity, 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, sum(votes.count)
|
||||
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, sum(votes.count),
|
||||
reporter_accessible, cclist_accessible,
|
||||
estimated_time, remaining_time
|
||||
from bugs left join votes using(bug_id),
|
||||
products, components
|
||||
where bugs.bug_id = $bug_id
|
||||
|
@ -118,14 +137,17 @@ sub initBug {
|
|||
if ((@row = &::FetchSQLData()) && &::CanSeeBug($bug_id, $self->{'whoid'})) {
|
||||
my $count = 0;
|
||||
my %fields;
|
||||
foreach my $field ("bug_id", "alias", "product", "version", "rep_platform",
|
||||
"op_sys", "bug_status", "resolution", "priority",
|
||||
"bug_severity", "component", "assigned_to", "reporter",
|
||||
"bug_file_loc", "short_desc", "target_milestone",
|
||||
"qa_contact", "status_whiteboard", "creation_ts",
|
||||
"delta_ts", "votes") {
|
||||
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 ($fields{$field}) {
|
||||
if (defined $fields{$field}) {
|
||||
$self->{$field} = $fields{$field};
|
||||
}
|
||||
$count++;
|
||||
|
@ -140,8 +162,12 @@ sub initBug {
|
|||
return $self;
|
||||
}
|
||||
|
||||
$self->{'assigned_to'} = &::DBID_to_name($self->{'assigned_to'});
|
||||
$self->{'reporter'} = &::DBID_to_name($self->{'reporter'});
|
||||
$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'});
|
||||
}
|
||||
|
||||
my $ccSet = new RelationSet;
|
||||
$ccSet->mergeFromDB("select who from cc where bug_id=$bug_id");
|
||||
|
@ -150,13 +176,6 @@ sub initBug {
|
|||
$self->{'cc'} = \@cc;
|
||||
}
|
||||
|
||||
if (Param("useqacontact") && (defined $self->{'qa_contact'}) ) {
|
||||
my $name = $self->{'qa_contact'} > 0 ? &::DBID_to_name($self->{'qa_contact'}) :"";
|
||||
if ($name) {
|
||||
$self->{'qa_contact'} = $name;
|
||||
}
|
||||
}
|
||||
|
||||
if (@::legal_keywords) {
|
||||
&::SendSQL("SELECT keyworddefs.name
|
||||
FROM keyworddefs, keywords
|
||||
|
@ -172,39 +191,43 @@ sub initBug {
|
|||
}
|
||||
}
|
||||
|
||||
&::SendSQL("select attach_id, creation_ts, isprivate, description
|
||||
from attachments
|
||||
where bug_id = $bug_id");
|
||||
my @attachments;
|
||||
while (&::MoreSQLData()) {
|
||||
my ($attachid, $date, $isprivate, $desc) = (&::FetchSQLData());
|
||||
my %attach;
|
||||
$attach{'attachid'} = $attachid;
|
||||
$attach{'isprivate'} = $isprivate;
|
||||
$attach{'date'} = $date;
|
||||
$attach{'desc'} = $desc;
|
||||
push @attachments, \%attach;
|
||||
}
|
||||
if (@attachments) {
|
||||
$self->{'attachments'} = \@attachments;
|
||||
}
|
||||
$self->{'attachments'} = Attachment::query($self->{bug_id});
|
||||
|
||||
&::SendSQL("select bug_id, who, bug_when, isprivate, thetext
|
||||
from longdescs
|
||||
where bug_id = $bug_id");
|
||||
my @longdescs;
|
||||
while (&::MoreSQLData()) {
|
||||
my ($bug_id, $who, $bug_when, $isprivate, $thetext) = (&::FetchSQLData());
|
||||
my %longdesc;
|
||||
$longdesc{'who'} = $who;
|
||||
$longdesc{'bug_when'} = $bug_when;
|
||||
$longdesc{'isprivate'} = $isprivate;
|
||||
$longdesc{'thetext'} = $thetext;
|
||||
push @longdescs, \%longdesc;
|
||||
}
|
||||
if (@longdescs) {
|
||||
$self->{'longdescs'} = \@longdescs;
|
||||
}
|
||||
# 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_requesteeable'} = 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) {
|
||||
|
@ -218,7 +241,191 @@ sub initBug {
|
|||
return $self;
|
||||
}
|
||||
|
||||
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,
|
||||
"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");
|
||||
$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'}
|
||||
|| $::userid == $self->{'qa_contact'}
|
||||
|| $::userid == $self->{'assigned_to'}
|
||||
|| &::UserInGroup("editbugs");
|
||||
$self->{'user'}->{'canconfirm'} = ($::userid == 0)
|
||||
|| &::UserInGroup("canconfirm")
|
||||
|| &::UserInGroup("editbugs");
|
||||
|
||||
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'};
|
||||
}
|
||||
|
||||
# given a bug hash, emit xml for it. with file header provided by caller
|
||||
#
|
||||
|
@ -261,11 +468,11 @@ sub emitXML {
|
|||
&& Param("insidergroup")
|
||||
&& !&::UserInGroup(Param("insidergroup")));
|
||||
$xml .= " <long_desc>\n";
|
||||
$xml .= " <who>" . &::DBID_to_name($self->{'longdescs'}[$i]->{'who'})
|
||||
$xml .= " <who>" . $self->{'longdescs'}[$i]->{'email'}
|
||||
. "</who>\n";
|
||||
$xml .= " <bug_when>" . $self->{'longdescs'}[$i]->{'bug_when'}
|
||||
$xml .= " <bug_when>" . $self->{'longdescs'}[$i]->{'time'}
|
||||
. "</bug_when>\n";
|
||||
$xml .= " <thetext>" . QuoteXMLChars($self->{'longdescs'}[$i]->{'thetext'})
|
||||
$xml .= " <thetext>" . QuoteXMLChars($self->{'longdescs'}[$i]->{'body'})
|
||||
. "</thetext>\n";
|
||||
$xml .= " </long_desc>\n";
|
||||
}
|
||||
|
@ -280,7 +487,7 @@ sub emitXML {
|
|||
$xml .= " <attachid>" . $self->{'attachments'}[$i]->{'attachid'}
|
||||
. "</attachid>\n";
|
||||
$xml .= " <date>" . $self->{'attachments'}[$i]->{'date'} . "</date>\n";
|
||||
$xml .= " <desc>" . QuoteXMLChars($self->{'attachments'}[$i]->{'desc'}) . "</desc>\n";
|
||||
$xml .= " <desc>" . QuoteXMLChars($self->{'attachments'}[$i]->{'description'}) . "</desc>\n";
|
||||
# $xml .= " <type>" . $self->{'attachments'}[$i]->{'type'} . "</type>\n";
|
||||
# $xml .= " <data>" . $self->{'attachments'}[$i]->{'data'} . "</data>\n";
|
||||
$xml .= " </attachment>\n";
|
||||
|
@ -310,8 +517,8 @@ sub QuoteXMLChars {
|
|||
$_[0] =~ s/&/&/g;
|
||||
$_[0] =~ s/</</g;
|
||||
$_[0] =~ s/>/>/g;
|
||||
$_[0] =~ s/'/'/g;
|
||||
$_[0] =~ s/"/"/g;
|
||||
$_[0] =~ s/\'/'/g;
|
||||
$_[0] =~ s/\"/"/g;
|
||||
# $_[0] =~ s/([\x80-\xFF])/&XmlUtf8Encode(ord($1))/ge;
|
||||
return($_[0]);
|
||||
}
|
||||
|
@ -341,156 +548,25 @@ sub XML_Footer {
|
|||
return ("</bugzilla>\n");
|
||||
}
|
||||
|
||||
sub CanChangeField {
|
||||
my $self = shift();
|
||||
my ($f, $oldvalue, $newvalue) = (@_);
|
||||
my $UserInEditGroupSet = -1;
|
||||
my $UserInCanConfirmGroupSet = -1;
|
||||
my $ownerid;
|
||||
my $reporterid;
|
||||
my $qacontactid;
|
||||
|
||||
if ($f eq "assigned_to" || $f eq "reporter" || $f eq "qa_contact") {
|
||||
if ($oldvalue =~ /^\d+$/) {
|
||||
if ($oldvalue == 0) {
|
||||
$oldvalue = "";
|
||||
} else {
|
||||
$oldvalue = &::DBID_to_name($oldvalue);
|
||||
}
|
||||
}
|
||||
}
|
||||
if ($oldvalue eq $newvalue) {
|
||||
return 1;
|
||||
}
|
||||
if (trim($oldvalue) eq trim($newvalue)) {
|
||||
return 1;
|
||||
}
|
||||
if ($f =~ /^longdesc/) {
|
||||
return 1;
|
||||
}
|
||||
if ($UserInEditGroupSet < 0) {
|
||||
$UserInEditGroupSet = UserInGroup($self, "editbugs");
|
||||
}
|
||||
if ($UserInEditGroupSet) {
|
||||
return 1;
|
||||
}
|
||||
&::SendSQL("SELECT reporter, assigned_to, qa_contact FROM bugs " .
|
||||
"WHERE bug_id = $self->{'bug_id'}");
|
||||
($reporterid, $ownerid, $qacontactid) = (&::FetchSQLData());
|
||||
|
||||
# Let reporter change bug status, even if they can't edit bugs.
|
||||
# If reporter can't re-open their bug they will just file a duplicate.
|
||||
# While we're at it, let them close their own bugs as well.
|
||||
if ( ($f eq "bug_status") && ($self->{'whoid'} eq $reporterid) ) {
|
||||
return 1;
|
||||
}
|
||||
if ($f eq "bug_status" && $newvalue ne $::unconfirmedstate &&
|
||||
&::IsOpenedState($newvalue)) {
|
||||
|
||||
# Hmm. They are trying to set this bug to some opened state
|
||||
# that isn't the UNCONFIRMED state. Are they in the right
|
||||
# group? Or, has it ever been confirmed? If not, then this
|
||||
# isn't legal.
|
||||
|
||||
if ($UserInCanConfirmGroupSet < 0) {
|
||||
$UserInCanConfirmGroupSet = &::UserInGroup("canconfirm");
|
||||
}
|
||||
if ($UserInCanConfirmGroupSet) {
|
||||
return 1;
|
||||
}
|
||||
&::SendSQL("SELECT everconfirmed FROM bugs WHERE bug_id = $self->{'bug_id'}");
|
||||
my $everconfirmed = FetchOneColumn();
|
||||
if ($everconfirmed) {
|
||||
return 1;
|
||||
}
|
||||
} elsif ($reporterid eq $self->{'whoid'} || $ownerid eq $self->{'whoid'} ||
|
||||
$qacontactid eq $self->{'whoid'}) {
|
||||
return 1;
|
||||
}
|
||||
$self->{'error'} = "
|
||||
Only the owner or submitter of the bug, or a sufficiently
|
||||
empowered user, may make that change to the $f field."
|
||||
}
|
||||
|
||||
sub Collision {
|
||||
my $self = shift();
|
||||
my $write = "WRITE"; # Might want to make a param to control
|
||||
# whether we do LOW_PRIORITY ...
|
||||
&::SendSQL("LOCK TABLES bugs $write, bugs_activity $write, cc $write, " .
|
||||
"cc AS selectVisible_cc $write, " .
|
||||
"profiles $write, dependencies $write, votes $write, " .
|
||||
"keywords $write, longdescs $write, fielddefs $write, " .
|
||||
"keyworddefs READ, groups READ, attachments READ, products READ");
|
||||
&::SendSQL("SELECT delta_ts FROM bugs where bug_id=$self->{'bug_id'}");
|
||||
my $delta_ts = &::FetchOneColumn();
|
||||
&::SendSQL("unlock tables");
|
||||
if ($self->{'delta_ts'} ne $delta_ts) {
|
||||
return 1;
|
||||
}
|
||||
else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
sub AppendComment {
|
||||
my $self = shift();
|
||||
my ($comment) = (@_);
|
||||
$comment =~ s/\r\n/\n/g; # Get rid of windows-style line endings.
|
||||
$comment =~ s/\r/\n/g; # Get rid of mac-style line endings.
|
||||
if ($comment =~ /^\s*$/) { # Nothin' but whitespace.
|
||||
return;
|
||||
}
|
||||
|
||||
&::SendSQL("INSERT INTO longdescs (bug_id, who, bug_when, thetext) " .
|
||||
"VALUES($self->{'bug_id'}, $self->{'whoid'}, now(), " . &::SqlQuote($comment) . ")");
|
||||
|
||||
&::SendSQL("UPDATE bugs SET delta_ts = now() WHERE bug_id = $self->{'bug_id'}");
|
||||
}
|
||||
|
||||
|
||||
#from o'reilley's Programming Perl
|
||||
sub display {
|
||||
my $self = shift;
|
||||
my @keys;
|
||||
if (@_ == 0) { # no further arguments
|
||||
@keys = sort keys(%$self);
|
||||
} else {
|
||||
@keys = @_; # use the ones given
|
||||
}
|
||||
foreach my $key (@keys) {
|
||||
print "\t$key => $self->{$key}\n";
|
||||
}
|
||||
}
|
||||
|
||||
sub CommitChanges {
|
||||
|
||||
#snapshot bug
|
||||
#snapshot dependencies
|
||||
#check can change fields
|
||||
#check collision
|
||||
#lock and change fields
|
||||
#notify through mail
|
||||
|
||||
}
|
||||
|
||||
sub AUTOLOAD {
|
||||
use vars qw($AUTOLOAD);
|
||||
my $self = shift;
|
||||
my $type = ref($self) || $self;
|
||||
my $attr = $AUTOLOAD;
|
||||
|
||||
$attr =~ s/.*:://;
|
||||
return unless $attr=~ /[^A-Z]/;
|
||||
if (@_) {
|
||||
$self->{$attr} = shift;
|
||||
return;
|
||||
}
|
||||
confess ("invalid bug attribute $attr") unless $ok_field{$attr};
|
||||
if (defined $self->{$attr}) {
|
||||
return $self->{$attr};
|
||||
} else {
|
||||
return '';
|
||||
}
|
||||
|
||||
no strict 'refs';
|
||||
*$AUTOLOAD = sub {
|
||||
my $self = shift;
|
||||
if (defined $self->{$attr}) {
|
||||
return $self->{$attr};
|
||||
} else {
|
||||
return '';
|
||||
}
|
||||
};
|
||||
|
||||
goto &$AUTOLOAD;
|
||||
}
|
||||
|
||||
1;
|
||||
|
|
|
@ -21,26 +21,41 @@
|
|||
# Terry Weissman <terry@mozilla.org>
|
||||
# Chris Yeh <cyeh@bluemartini.com>
|
||||
|
||||
package Bug;
|
||||
|
||||
use strict;
|
||||
|
||||
use DBI;
|
||||
use RelationSet;
|
||||
use vars qw($unconfirmedstate $legal_keywords);
|
||||
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);
|
||||
|
||||
package Bug;
|
||||
use CGI::Carp qw(fatalsToBrowser);
|
||||
my %ok_field;
|
||||
|
||||
use Attachment;
|
||||
use Bugzilla::Config;
|
||||
use Bugzilla::Constants;
|
||||
use Bugzilla::Flag;
|
||||
use Bugzilla::FlagType;
|
||||
use Bugzilla::User;
|
||||
use Bugzilla::Util;
|
||||
|
||||
for my $key (qw (bug_id alias product version rep_platform op_sys bug_status
|
||||
resolution priority bug_severity component assigned_to
|
||||
reporter bug_file_loc short_desc target_milestone
|
||||
qa_contact status_whiteboard creation_ts
|
||||
delta_ts votes whoid comment query error) ){
|
||||
resolution priority bug_severity component assigned_to
|
||||
reporter bug_file_loc short_desc target_milestone
|
||||
qa_contact status_whiteboard creation_ts keywords
|
||||
delta_ts votes whoid usergroupset comment query error
|
||||
longdescs cc milestoneurl attachments dependson blocked
|
||||
cclist_accessible reporter_accessible
|
||||
isopened isunconfirmed assigned_to_name assigned_to_email
|
||||
qa_contact_name qa_contact_email reporter_name
|
||||
reporter_email flag_types num_attachment_flag_types
|
||||
show_attachment_flags use_keywords any_flags_requesteeble
|
||||
estimated_time remaining_time actual_time) ) {
|
||||
$ok_field{$key}++;
|
||||
}
|
||||
}
|
||||
|
||||
# create a new empty bug
|
||||
#
|
||||
|
@ -95,16 +110,20 @@ sub initBug {
|
|||
$user_id = &::DBname_to_id($user_id);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
$self->{'whoid'} = $user_id;
|
||||
|
||||
my $query = "
|
||||
select
|
||||
bugs.bug_id, alias, products.name, version, rep_platform, op_sys, bug_status,
|
||||
resolution, priority, bug_severity, 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, sum(votes.count)
|
||||
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, sum(votes.count),
|
||||
reporter_accessible, cclist_accessible,
|
||||
estimated_time, remaining_time
|
||||
from bugs left join votes using(bug_id),
|
||||
products, components
|
||||
where bugs.bug_id = $bug_id
|
||||
|
@ -118,14 +137,17 @@ sub initBug {
|
|||
if ((@row = &::FetchSQLData()) && &::CanSeeBug($bug_id, $self->{'whoid'})) {
|
||||
my $count = 0;
|
||||
my %fields;
|
||||
foreach my $field ("bug_id", "alias", "product", "version", "rep_platform",
|
||||
"op_sys", "bug_status", "resolution", "priority",
|
||||
"bug_severity", "component", "assigned_to", "reporter",
|
||||
"bug_file_loc", "short_desc", "target_milestone",
|
||||
"qa_contact", "status_whiteboard", "creation_ts",
|
||||
"delta_ts", "votes") {
|
||||
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 ($fields{$field}) {
|
||||
if (defined $fields{$field}) {
|
||||
$self->{$field} = $fields{$field};
|
||||
}
|
||||
$count++;
|
||||
|
@ -140,8 +162,12 @@ sub initBug {
|
|||
return $self;
|
||||
}
|
||||
|
||||
$self->{'assigned_to'} = &::DBID_to_name($self->{'assigned_to'});
|
||||
$self->{'reporter'} = &::DBID_to_name($self->{'reporter'});
|
||||
$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'});
|
||||
}
|
||||
|
||||
my $ccSet = new RelationSet;
|
||||
$ccSet->mergeFromDB("select who from cc where bug_id=$bug_id");
|
||||
|
@ -150,13 +176,6 @@ sub initBug {
|
|||
$self->{'cc'} = \@cc;
|
||||
}
|
||||
|
||||
if (Param("useqacontact") && (defined $self->{'qa_contact'}) ) {
|
||||
my $name = $self->{'qa_contact'} > 0 ? &::DBID_to_name($self->{'qa_contact'}) :"";
|
||||
if ($name) {
|
||||
$self->{'qa_contact'} = $name;
|
||||
}
|
||||
}
|
||||
|
||||
if (@::legal_keywords) {
|
||||
&::SendSQL("SELECT keyworddefs.name
|
||||
FROM keyworddefs, keywords
|
||||
|
@ -172,39 +191,43 @@ sub initBug {
|
|||
}
|
||||
}
|
||||
|
||||
&::SendSQL("select attach_id, creation_ts, isprivate, description
|
||||
from attachments
|
||||
where bug_id = $bug_id");
|
||||
my @attachments;
|
||||
while (&::MoreSQLData()) {
|
||||
my ($attachid, $date, $isprivate, $desc) = (&::FetchSQLData());
|
||||
my %attach;
|
||||
$attach{'attachid'} = $attachid;
|
||||
$attach{'isprivate'} = $isprivate;
|
||||
$attach{'date'} = $date;
|
||||
$attach{'desc'} = $desc;
|
||||
push @attachments, \%attach;
|
||||
}
|
||||
if (@attachments) {
|
||||
$self->{'attachments'} = \@attachments;
|
||||
}
|
||||
$self->{'attachments'} = Attachment::query($self->{bug_id});
|
||||
|
||||
&::SendSQL("select bug_id, who, bug_when, isprivate, thetext
|
||||
from longdescs
|
||||
where bug_id = $bug_id");
|
||||
my @longdescs;
|
||||
while (&::MoreSQLData()) {
|
||||
my ($bug_id, $who, $bug_when, $isprivate, $thetext) = (&::FetchSQLData());
|
||||
my %longdesc;
|
||||
$longdesc{'who'} = $who;
|
||||
$longdesc{'bug_when'} = $bug_when;
|
||||
$longdesc{'isprivate'} = $isprivate;
|
||||
$longdesc{'thetext'} = $thetext;
|
||||
push @longdescs, \%longdesc;
|
||||
}
|
||||
if (@longdescs) {
|
||||
$self->{'longdescs'} = \@longdescs;
|
||||
}
|
||||
# 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_requesteeable'} = 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) {
|
||||
|
@ -218,7 +241,191 @@ sub initBug {
|
|||
return $self;
|
||||
}
|
||||
|
||||
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,
|
||||
"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");
|
||||
$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'}
|
||||
|| $::userid == $self->{'qa_contact'}
|
||||
|| $::userid == $self->{'assigned_to'}
|
||||
|| &::UserInGroup("editbugs");
|
||||
$self->{'user'}->{'canconfirm'} = ($::userid == 0)
|
||||
|| &::UserInGroup("canconfirm")
|
||||
|| &::UserInGroup("editbugs");
|
||||
|
||||
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'};
|
||||
}
|
||||
|
||||
# given a bug hash, emit xml for it. with file header provided by caller
|
||||
#
|
||||
|
@ -261,11 +468,11 @@ sub emitXML {
|
|||
&& Param("insidergroup")
|
||||
&& !&::UserInGroup(Param("insidergroup")));
|
||||
$xml .= " <long_desc>\n";
|
||||
$xml .= " <who>" . &::DBID_to_name($self->{'longdescs'}[$i]->{'who'})
|
||||
$xml .= " <who>" . $self->{'longdescs'}[$i]->{'email'}
|
||||
. "</who>\n";
|
||||
$xml .= " <bug_when>" . $self->{'longdescs'}[$i]->{'bug_when'}
|
||||
$xml .= " <bug_when>" . $self->{'longdescs'}[$i]->{'time'}
|
||||
. "</bug_when>\n";
|
||||
$xml .= " <thetext>" . QuoteXMLChars($self->{'longdescs'}[$i]->{'thetext'})
|
||||
$xml .= " <thetext>" . QuoteXMLChars($self->{'longdescs'}[$i]->{'body'})
|
||||
. "</thetext>\n";
|
||||
$xml .= " </long_desc>\n";
|
||||
}
|
||||
|
@ -280,7 +487,7 @@ sub emitXML {
|
|||
$xml .= " <attachid>" . $self->{'attachments'}[$i]->{'attachid'}
|
||||
. "</attachid>\n";
|
||||
$xml .= " <date>" . $self->{'attachments'}[$i]->{'date'} . "</date>\n";
|
||||
$xml .= " <desc>" . QuoteXMLChars($self->{'attachments'}[$i]->{'desc'}) . "</desc>\n";
|
||||
$xml .= " <desc>" . QuoteXMLChars($self->{'attachments'}[$i]->{'description'}) . "</desc>\n";
|
||||
# $xml .= " <type>" . $self->{'attachments'}[$i]->{'type'} . "</type>\n";
|
||||
# $xml .= " <data>" . $self->{'attachments'}[$i]->{'data'} . "</data>\n";
|
||||
$xml .= " </attachment>\n";
|
||||
|
@ -310,8 +517,8 @@ sub QuoteXMLChars {
|
|||
$_[0] =~ s/&/&/g;
|
||||
$_[0] =~ s/</</g;
|
||||
$_[0] =~ s/>/>/g;
|
||||
$_[0] =~ s/'/'/g;
|
||||
$_[0] =~ s/"/"/g;
|
||||
$_[0] =~ s/\'/'/g;
|
||||
$_[0] =~ s/\"/"/g;
|
||||
# $_[0] =~ s/([\x80-\xFF])/&XmlUtf8Encode(ord($1))/ge;
|
||||
return($_[0]);
|
||||
}
|
||||
|
@ -341,156 +548,25 @@ sub XML_Footer {
|
|||
return ("</bugzilla>\n");
|
||||
}
|
||||
|
||||
sub CanChangeField {
|
||||
my $self = shift();
|
||||
my ($f, $oldvalue, $newvalue) = (@_);
|
||||
my $UserInEditGroupSet = -1;
|
||||
my $UserInCanConfirmGroupSet = -1;
|
||||
my $ownerid;
|
||||
my $reporterid;
|
||||
my $qacontactid;
|
||||
|
||||
if ($f eq "assigned_to" || $f eq "reporter" || $f eq "qa_contact") {
|
||||
if ($oldvalue =~ /^\d+$/) {
|
||||
if ($oldvalue == 0) {
|
||||
$oldvalue = "";
|
||||
} else {
|
||||
$oldvalue = &::DBID_to_name($oldvalue);
|
||||
}
|
||||
}
|
||||
}
|
||||
if ($oldvalue eq $newvalue) {
|
||||
return 1;
|
||||
}
|
||||
if (trim($oldvalue) eq trim($newvalue)) {
|
||||
return 1;
|
||||
}
|
||||
if ($f =~ /^longdesc/) {
|
||||
return 1;
|
||||
}
|
||||
if ($UserInEditGroupSet < 0) {
|
||||
$UserInEditGroupSet = UserInGroup($self, "editbugs");
|
||||
}
|
||||
if ($UserInEditGroupSet) {
|
||||
return 1;
|
||||
}
|
||||
&::SendSQL("SELECT reporter, assigned_to, qa_contact FROM bugs " .
|
||||
"WHERE bug_id = $self->{'bug_id'}");
|
||||
($reporterid, $ownerid, $qacontactid) = (&::FetchSQLData());
|
||||
|
||||
# Let reporter change bug status, even if they can't edit bugs.
|
||||
# If reporter can't re-open their bug they will just file a duplicate.
|
||||
# While we're at it, let them close their own bugs as well.
|
||||
if ( ($f eq "bug_status") && ($self->{'whoid'} eq $reporterid) ) {
|
||||
return 1;
|
||||
}
|
||||
if ($f eq "bug_status" && $newvalue ne $::unconfirmedstate &&
|
||||
&::IsOpenedState($newvalue)) {
|
||||
|
||||
# Hmm. They are trying to set this bug to some opened state
|
||||
# that isn't the UNCONFIRMED state. Are they in the right
|
||||
# group? Or, has it ever been confirmed? If not, then this
|
||||
# isn't legal.
|
||||
|
||||
if ($UserInCanConfirmGroupSet < 0) {
|
||||
$UserInCanConfirmGroupSet = &::UserInGroup("canconfirm");
|
||||
}
|
||||
if ($UserInCanConfirmGroupSet) {
|
||||
return 1;
|
||||
}
|
||||
&::SendSQL("SELECT everconfirmed FROM bugs WHERE bug_id = $self->{'bug_id'}");
|
||||
my $everconfirmed = FetchOneColumn();
|
||||
if ($everconfirmed) {
|
||||
return 1;
|
||||
}
|
||||
} elsif ($reporterid eq $self->{'whoid'} || $ownerid eq $self->{'whoid'} ||
|
||||
$qacontactid eq $self->{'whoid'}) {
|
||||
return 1;
|
||||
}
|
||||
$self->{'error'} = "
|
||||
Only the owner or submitter of the bug, or a sufficiently
|
||||
empowered user, may make that change to the $f field."
|
||||
}
|
||||
|
||||
sub Collision {
|
||||
my $self = shift();
|
||||
my $write = "WRITE"; # Might want to make a param to control
|
||||
# whether we do LOW_PRIORITY ...
|
||||
&::SendSQL("LOCK TABLES bugs $write, bugs_activity $write, cc $write, " .
|
||||
"cc AS selectVisible_cc $write, " .
|
||||
"profiles $write, dependencies $write, votes $write, " .
|
||||
"keywords $write, longdescs $write, fielddefs $write, " .
|
||||
"keyworddefs READ, groups READ, attachments READ, products READ");
|
||||
&::SendSQL("SELECT delta_ts FROM bugs where bug_id=$self->{'bug_id'}");
|
||||
my $delta_ts = &::FetchOneColumn();
|
||||
&::SendSQL("unlock tables");
|
||||
if ($self->{'delta_ts'} ne $delta_ts) {
|
||||
return 1;
|
||||
}
|
||||
else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
sub AppendComment {
|
||||
my $self = shift();
|
||||
my ($comment) = (@_);
|
||||
$comment =~ s/\r\n/\n/g; # Get rid of windows-style line endings.
|
||||
$comment =~ s/\r/\n/g; # Get rid of mac-style line endings.
|
||||
if ($comment =~ /^\s*$/) { # Nothin' but whitespace.
|
||||
return;
|
||||
}
|
||||
|
||||
&::SendSQL("INSERT INTO longdescs (bug_id, who, bug_when, thetext) " .
|
||||
"VALUES($self->{'bug_id'}, $self->{'whoid'}, now(), " . &::SqlQuote($comment) . ")");
|
||||
|
||||
&::SendSQL("UPDATE bugs SET delta_ts = now() WHERE bug_id = $self->{'bug_id'}");
|
||||
}
|
||||
|
||||
|
||||
#from o'reilley's Programming Perl
|
||||
sub display {
|
||||
my $self = shift;
|
||||
my @keys;
|
||||
if (@_ == 0) { # no further arguments
|
||||
@keys = sort keys(%$self);
|
||||
} else {
|
||||
@keys = @_; # use the ones given
|
||||
}
|
||||
foreach my $key (@keys) {
|
||||
print "\t$key => $self->{$key}\n";
|
||||
}
|
||||
}
|
||||
|
||||
sub CommitChanges {
|
||||
|
||||
#snapshot bug
|
||||
#snapshot dependencies
|
||||
#check can change fields
|
||||
#check collision
|
||||
#lock and change fields
|
||||
#notify through mail
|
||||
|
||||
}
|
||||
|
||||
sub AUTOLOAD {
|
||||
use vars qw($AUTOLOAD);
|
||||
my $self = shift;
|
||||
my $type = ref($self) || $self;
|
||||
my $attr = $AUTOLOAD;
|
||||
|
||||
$attr =~ s/.*:://;
|
||||
return unless $attr=~ /[^A-Z]/;
|
||||
if (@_) {
|
||||
$self->{$attr} = shift;
|
||||
return;
|
||||
}
|
||||
confess ("invalid bug attribute $attr") unless $ok_field{$attr};
|
||||
if (defined $self->{$attr}) {
|
||||
return $self->{$attr};
|
||||
} else {
|
||||
return '';
|
||||
}
|
||||
|
||||
no strict 'refs';
|
||||
*$AUTOLOAD = sub {
|
||||
my $self = shift;
|
||||
if (defined $self->{$attr}) {
|
||||
return $self->{$attr};
|
||||
} else {
|
||||
return '';
|
||||
}
|
||||
};
|
||||
|
||||
goto &$AUTOLOAD;
|
||||
}
|
||||
|
||||
1;
|
||||
|
|
|
@ -59,7 +59,7 @@ sub new {
|
|||
}
|
||||
|
||||
$self->{'name'} = $name;
|
||||
$self->{'email'} = $email;
|
||||
$self->{'email'} = $email || "__UNKNOWN__";
|
||||
$self->{'exists'} = $exists;
|
||||
|
||||
# Generate a string to identify the user by name + email if the user
|
||||
|
|
|
@ -921,14 +921,6 @@ END
|
|||
}
|
||||
|
||||
{
|
||||
eval("use Date::Parse");
|
||||
# Templates will be recompiled if the source changes, but not if the
|
||||
# settings in globals.pl change, so we need to be able to force a rebuild
|
||||
# if that happens
|
||||
|
||||
# The last time the global template params were changed. Keep in UTC,
|
||||
# YYYY-MM-DD
|
||||
my $lastTemplateParamChange = str2time("2002-04-27", "UTC");
|
||||
if (-e 'data/template') {
|
||||
print "Removing existing compiled templates ...\n" unless $silent;
|
||||
|
||||
|
@ -967,6 +959,8 @@ END
|
|||
js => sub { return $_; },
|
||||
html_linebreak => sub { return $_; },
|
||||
url_quote => sub { return $_; },
|
||||
quoteUrls => sub { return $_; },
|
||||
bug_link => [ sub { return sub { return $_; } }, 1],
|
||||
csv => sub { return $_; },
|
||||
time => sub { return $_; },
|
||||
},
|
||||
|
|
|
@ -1781,8 +1781,20 @@ $::template ||= Template->new(
|
|||
# characters NOT in the regex set: [a-zA-Z0-9_\-.]. The 'uri'
|
||||
# filter should be used for a full URL that may have
|
||||
# characters that need encoding.
|
||||
url_quote => \&Bugzilla::Util::url_quote,
|
||||
|
||||
url_quote => \&Bugzilla::Util::url_quote ,
|
||||
|
||||
quoteUrls => \"eUrls ,
|
||||
|
||||
bug_link => [ sub {
|
||||
my ($context, $bug) = @_;
|
||||
return sub {
|
||||
my $text = shift;
|
||||
return GetBugLink($text, $bug);
|
||||
};
|
||||
},
|
||||
1
|
||||
],
|
||||
|
||||
# In CSV, quotes are doubled, and we enclose the whole value in quotes
|
||||
csv => sub
|
||||
{
|
||||
|
@ -1892,9 +1904,6 @@ $::vars =
|
|||
# Generic linear search function
|
||||
'lsearch' => \&Bugzilla::Util::lsearch ,
|
||||
|
||||
# quoteUrls - autolinkifies text
|
||||
'quoteUrls' => \"eUrls ,
|
||||
|
||||
# UserInGroup - you probably want to cache this
|
||||
'UserInGroup' => \&UserInGroup ,
|
||||
|
||||
|
|
|
@ -28,7 +28,8 @@ use lib qw(.);
|
|||
|
||||
use Bugzilla::Constants;
|
||||
require "CGI.pl";
|
||||
require "bug_form.pl";
|
||||
|
||||
use Bug;
|
||||
|
||||
use Bugzilla::User;
|
||||
|
||||
|
@ -491,28 +492,38 @@ close(PMAIL);
|
|||
|
||||
# Tell the user all about it
|
||||
$vars->{'id'} = $id;
|
||||
$vars->{'mail'} = $mailresults;
|
||||
$vars->{'type'} = "created";
|
||||
my $bug = new Bug($id, $::userid);
|
||||
$vars->{'bug'} = $bug;
|
||||
|
||||
ThrowCodeError("bug_error") if $bug->error;
|
||||
|
||||
$vars->{'sentmail'} = [];
|
||||
|
||||
push (@{$vars->{'sentmail'}}, { type => 'created',
|
||||
id => $id,
|
||||
mail => $mailresults
|
||||
});
|
||||
|
||||
foreach my $i (@all_deps) {
|
||||
my $mail = "";
|
||||
open(PMAIL, "-|") or exec('./processmail', $i, $::COOKIE{'Bugzilla_login'});
|
||||
$mail .= $_ while <PMAIL>;
|
||||
close(PMAIL);
|
||||
|
||||
push (@{$vars->{'sentmail'}}, { type => 'dep',
|
||||
id => $i,
|
||||
mail => $mail
|
||||
});
|
||||
}
|
||||
|
||||
my @bug_list;
|
||||
if ($::COOKIE{"BUGLIST"}) {
|
||||
@bug_list = split(/:/, $::COOKIE{"BUGLIST"});
|
||||
}
|
||||
$vars->{'bug_list'} = \@bug_list;
|
||||
|
||||
print "Content-type: text/html\n\n";
|
||||
$template->process("bug/create/created.html.tmpl", $vars)
|
||||
|| ThrowTemplateError($template->error());
|
||||
|
||||
foreach my $i (@all_deps) {
|
||||
$vars->{'mail'} = "";
|
||||
open(PMAIL, "-|") or exec('./processmail', $i, $::COOKIE{'Bugzilla_login'}); $vars->{'mail'} .= $_ while <PMAIL>;
|
||||
close(PMAIL);
|
||||
|
||||
$vars->{'id'} = $i;
|
||||
$vars->{'type'} = "dep";
|
||||
|
||||
# Let the user know we checked to see if we should email notice
|
||||
# of this new bug to users with a relationship to the depenedant
|
||||
# bug and who did and didn't receive email about it
|
||||
$template->process("bug/process/results.html.tmpl", $vars)
|
||||
|| ThrowTemplateError($template->error());
|
||||
}
|
||||
|
||||
$::FORM{'id'} = $id;
|
||||
|
||||
show_bug("header is already done");
|
||||
|
|
|
@ -33,8 +33,8 @@ use lib qw(.);
|
|||
|
||||
use Bugzilla::Constants;
|
||||
require "CGI.pl";
|
||||
require "bug_form.pl";
|
||||
|
||||
use Bug;
|
||||
use Bugzilla::User;
|
||||
|
||||
use RelationSet;
|
||||
|
@ -53,7 +53,7 @@ use vars qw(%versions
|
|||
%settable_resolution
|
||||
%target_milestone
|
||||
%legal_severity
|
||||
$next_bug);
|
||||
);
|
||||
|
||||
ConnectToDatabase();
|
||||
my $whoid = confirm_login();
|
||||
|
@ -151,6 +151,23 @@ if (defined($::FORM{'id'})) {
|
|||
}
|
||||
}
|
||||
|
||||
# Set up the vars for nagiavtional <link> elements
|
||||
my $next_bug;
|
||||
if ($::COOKIE{"BUGLIST"} && $::FORM{'id'}) {
|
||||
my @bug_list = split(/:/, $::COOKIE{"BUGLIST"});
|
||||
$vars->{'bug_list'} = \@bug_list;
|
||||
my $cur = lsearch(\@bug_list, $::FORM{"id"});
|
||||
if ($cur >= 0 && $cur < $#bug_list) {
|
||||
$next_bug = $bug_list[$cur + 1];
|
||||
|
||||
# Note that we only bother with the bug_id here, and get
|
||||
# the full bug object at the end, before showing the edit
|
||||
# page. If you change this, remember that we have not
|
||||
# done the security checks on the next bug yet
|
||||
$vars->{'bug'} = { bug_id => $next_bug };
|
||||
}
|
||||
}
|
||||
|
||||
# Start displaying the response page.
|
||||
$template->process("bug/process/header.html.tmpl", $vars)
|
||||
|| ThrowTemplateError($template->error());
|
||||
|
@ -1725,26 +1742,17 @@ foreach my $id (@idlist) {
|
|||
}
|
||||
}
|
||||
|
||||
# Show next bug, if it exists.
|
||||
if ($::COOKIE{"BUGLIST"} && $::FORM{'id'}) {
|
||||
my @bugs = split(/:/, $::COOKIE{"BUGLIST"});
|
||||
$vars->{'bug_list'} = \@bugs;
|
||||
my $cur = lsearch(\@bugs, $::FORM{"id"});
|
||||
if ($cur >= 0 && $cur < $#bugs) {
|
||||
my $next_bug = $bugs[$cur + 1];
|
||||
if (detaint_natural($next_bug) && CanSeeBug($next_bug, $::userid)) {
|
||||
$::FORM{'id'} = $next_bug;
|
||||
|
||||
$vars->{'next_id'} = $next_bug;
|
||||
|
||||
# Let the user know we are about to display the next bug in their list.
|
||||
$template->process("bug/process/next.html.tmpl", $vars)
|
||||
|| ThrowTemplateError($template->error());
|
||||
# now show the next bug
|
||||
if ($next_bug) {
|
||||
if (detaint_natural($next_bug) && CanSeeBug($next_bug, $::userid)) {
|
||||
my $bug = new Bug($next_bug, $::userid);
|
||||
$vars->{'bug'} = $bug;
|
||||
ThrowCodeError("bug_error") if $bug->error;
|
||||
|
||||
show_bug("header is already done");
|
||||
$template->process("bug/process/next.html.tmpl", $vars)
|
||||
|| ThrowTemplateError($template->error());
|
||||
|
||||
exit;
|
||||
}
|
||||
exit;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -25,10 +25,13 @@ use strict;
|
|||
use lib qw(.);
|
||||
|
||||
require "CGI.pl";
|
||||
require "bug_form.pl";
|
||||
|
||||
ConnectToDatabase();
|
||||
|
||||
use vars qw($template $vars $userid);
|
||||
|
||||
use Bug;
|
||||
|
||||
if ($::FORM{'GoAheadAndLogIn'}) {
|
||||
confirm_login();
|
||||
} else {
|
||||
|
@ -39,11 +42,20 @@ if ($::FORM{'GoAheadAndLogIn'}) {
|
|||
# Begin Data/Security Validation
|
||||
######################################################################
|
||||
|
||||
unless (defined ($::FORM{'id'})) {
|
||||
my $format = GetFormat("bug/choose", $::FORM{'format'}, $::FORM{'ctype'});
|
||||
|
||||
print "Content-type: $format->{'contenttype'}\n\n";
|
||||
$template->process("$format->{'template'}", $vars) ||
|
||||
ThrowTemplateError($template->error());
|
||||
exit;
|
||||
}
|
||||
|
||||
my $format = GetFormat("bug/show", $::FORM{'format'}, $::FORM{'ctype'});
|
||||
|
||||
# Make sure the bug ID is a positive integer representing an existing
|
||||
# bug that the user is authorized to access.
|
||||
if (defined ($::FORM{'id'})) {
|
||||
ValidateBugID($::FORM{'id'});
|
||||
}
|
||||
ValidateBugID($::FORM{'id'});
|
||||
|
||||
######################################################################
|
||||
# End Data/Security Validation
|
||||
|
@ -51,6 +63,20 @@ if (defined ($::FORM{'id'})) {
|
|||
|
||||
GetVersionTable();
|
||||
|
||||
print "Content-type: text/html\n\n";
|
||||
my $bug = new Bug($::FORM{'id'}, $userid);
|
||||
|
||||
$vars->{'bug'} = $bug;
|
||||
|
||||
ThrowCodeError("bug_error") if $bug->error;
|
||||
|
||||
# Next bug in list (if there is one)
|
||||
my @bug_list;
|
||||
if ($::COOKIE{"BUGLIST"}) {
|
||||
@bug_list = split(/:/, $::COOKIE{"BUGLIST"});
|
||||
}
|
||||
$vars->{'bug_list'} = \@bug_list;
|
||||
|
||||
print "Content-type: $format->{'ctype'}\n\n";
|
||||
$template->process("$format->{'template'}", $vars)
|
||||
|| ThrowTemplateError($template->error());
|
||||
|
||||
show_bug();
|
||||
|
|
|
@ -81,6 +81,8 @@ my $provider = Template::Provider->new(
|
|||
js => sub { return $_ } ,
|
||||
strike => sub { return $_ } ,
|
||||
url_quote => sub { return $_ } ,
|
||||
quoteUrls => sub { return $_ } ,
|
||||
bug_link => [ sub { return sub { return $_; } }, 1] ,
|
||||
csv => sub { return $_ } ,
|
||||
time => sub { return $_ } ,
|
||||
},
|
||||
|
|
|
@ -68,7 +68,7 @@
|
|||
# generated HTML
|
||||
#%]
|
||||
<pre>
|
||||
[%- quoteUrls(comment.body) -%]
|
||||
[%- comment.body FILTER quoteUrls -%]
|
||||
</pre>
|
||||
</div>
|
||||
[% END %]
|
||||
|
|
|
@ -23,8 +23,24 @@
|
|||
title = "Bug $id Submitted"
|
||||
%]
|
||||
|
||||
[% PROCESS bug/process/results.html.tmpl %]
|
||||
[% FOREACH item = sentmail %]
|
||||
[% PROCESS bug/process/results.html.tmpl
|
||||
type = item.type
|
||||
id = item.id
|
||||
mail = item.mail
|
||||
%]
|
||||
[% END %]
|
||||
|
||||
<br>
|
||||
|
||||
[%# post_bug.cgi will add a copy of the filed bug below here %]
|
||||
<hr>
|
||||
|
||||
[% PROCESS bug/edit.html.tmpl %]
|
||||
|
||||
<hr>
|
||||
|
||||
[% PROCESS bug/navigate.html.tmpl %]
|
||||
|
||||
<br>
|
||||
|
||||
[% PROCESS global/footer.html.tmpl %]
|
||||
|
|
|
@ -20,19 +20,6 @@
|
|||
# Vaskin Kissoyan <vkissoyan@yahoo.com>
|
||||
#%]
|
||||
|
||||
[% filtered_desc = bug.short_desc FILTER html %]
|
||||
[% filtered_timestamp = bug.delta_ts FILTER time %]
|
||||
[% UNLESS header_done %]
|
||||
[% PROCESS global/header.html.tmpl
|
||||
title = "Bug $bug.bug_id - $bug.short_desc"
|
||||
h1 = "Bugzilla Bug $bug.bug_id"
|
||||
h2 = filtered_desc
|
||||
h3 = "Last modified: $filtered_timestamp"
|
||||
style_urls = [ "css/edit_bug.css" ]
|
||||
%]
|
||||
[% END %]
|
||||
|
||||
[% PROCESS bug/navigate.html.tmpl %]
|
||||
[% PROCESS bug/time.html.tmpl %]
|
||||
|
||||
[% IF UserInGroup(Param('timetrackinggroup')) %]
|
||||
|
@ -59,12 +46,10 @@
|
|||
</script>
|
||||
[% END %]
|
||||
|
||||
<hr>
|
||||
|
||||
<form name="changeform" method="post" action="process_bug.cgi">
|
||||
|
||||
<input type="hidden" name="delta_ts" value="[% bug.delta_ts %]">
|
||||
<input type="hidden" name="longdesclength" value="[% bug.longdesclength %]">
|
||||
<input type="hidden" name="longdesclength" value="[% bug.longdescs.size %]">
|
||||
<input type="hidden" name="id" value="[% bug.bug_id %]">
|
||||
|
||||
[%# *** Hardware Reporter Product OS AddCC *** %]
|
||||
|
@ -96,7 +81,7 @@
|
|||
<b>Reporter:</b>
|
||||
</td>
|
||||
<td>
|
||||
[% bug.reporter FILTER html %]
|
||||
[% bug.reporter.identity FILTER html %]
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
|
@ -128,19 +113,7 @@
|
|||
Co<u>m</u>ponent</a>:
|
||||
</b>
|
||||
</td>
|
||||
<td>
|
||||
<label for="component" accesskey="m">
|
||||
<select name="component" id="component">
|
||||
[% FOREACH x = component_ %]
|
||||
<option value="[% x FILTER html %]"
|
||||
[% " selected" IF x == bug.component %]>[% x FILTER html %]
|
||||
</option>
|
||||
[% END %]
|
||||
</select>
|
||||
</label>
|
||||
</td>
|
||||
|
||||
<td> </td>
|
||||
[% PROCESS select selname => "component" accesskey => "m" %]
|
||||
|
||||
<td align="right">
|
||||
<b><u>V</u>ersion:</b>
|
||||
|
@ -203,14 +176,17 @@
|
|||
<a href="bug_status.html#assigned_to">Assigned To</a>:
|
||||
</b>
|
||||
</td>
|
||||
<td>[% bug.assigned_to FILTER html %]</td>
|
||||
<td>[% bug.assigned_to.identity FILTER html %]</td>
|
||||
<td> </td>
|
||||
|
||||
[% IF Param("usetargetmilestone") && bug.target_milestone %]
|
||||
<td align="right">
|
||||
<b>
|
||||
<a href="[% bug.milestoneurl FILTER html %]"><u>T</u>arget
|
||||
Milestone</a>:
|
||||
[% IF bug.milestoneurl %]
|
||||
<a href="[% bug.milestoneurl FILTER html %]">
|
||||
[% END %]
|
||||
<u>T</u>arget Milestone</a>:
|
||||
[% "</a>" IF bug.milestoneurl %]
|
||||
</b>
|
||||
</td>
|
||||
[% PROCESS select selname = "target_milestone" accesskey => "t" %]
|
||||
|
@ -228,7 +204,7 @@
|
|||
</td>
|
||||
<td colspan="7">
|
||||
<input name="qa_contact" accesskey="q"
|
||||
value="[% bug.qa_contact FILTER html %]" size="60">
|
||||
value="[% bug.qa_contact.email FILTER html %]" size="60">
|
||||
</td>
|
||||
</tr>
|
||||
[% END %]
|
||||
|
@ -248,8 +224,10 @@
|
|||
value="[% bug.bug_file_loc FILTER html %]" size="60">
|
||||
</td>
|
||||
<td rowspan="4" colspan="2" valign="top">
|
||||
[% IF flag_types.size > 0 %]
|
||||
[% PROCESS "flag/list.html.tmpl" %]
|
||||
[% IF bug.flag_types.size > 0 %]
|
||||
[% PROCESS "flag/list.html.tmpl"
|
||||
flag_types = bug.flag_types
|
||||
any_flags_requesteeble = bug.any_flags_requesteeble %]
|
||||
[% END %]
|
||||
</td>
|
||||
</tr>
|
||||
|
@ -276,7 +254,7 @@
|
|||
</tr>
|
||||
[% END %]
|
||||
|
||||
[% IF use_keywords %]
|
||||
[% IF bug.use_keywords %]
|
||||
<tr>
|
||||
<td align="right">
|
||||
<b>
|
||||
|
@ -350,7 +328,10 @@
|
|||
|
||||
[% PROCESS attachment/list.html.tmpl
|
||||
attachments = bug.attachments
|
||||
bugid = bug.bug_id %]
|
||||
bugid = bug.bug_id
|
||||
num_attachment_flag_types = bug.num_attachment_flag_types
|
||||
show_attachment_flags = bug.show_attachment_flags
|
||||
%]
|
||||
|
||||
[%# *** Dependencies Votes *** %]
|
||||
|
||||
|
@ -405,9 +386,13 @@
|
|||
accesskey="c"></textarea>
|
||||
<br>
|
||||
|
||||
[% IF groups.size > 0 %]
|
||||
[% IF bug.groups.size > 0 %]
|
||||
[% inallgroups = 1 %]
|
||||
[% inagroup = 0 %]
|
||||
[% FOREACH group = bug.groups %]
|
||||
[% SET inallgroups = 0 IF NOT group.ingroup %]
|
||||
[% SET inagroup = 1 IF group.ison %]
|
||||
|
||||
[% FOREACH group = groups %]
|
||||
[% IF NOT group.mandatory %]
|
||||
[% IF NOT emitted_description %]
|
||||
[% emitted_description = 1 %]
|
||||
|
@ -430,7 +415,7 @@
|
|||
[% END %]
|
||||
[% END %]
|
||||
|
||||
[% IF NOT user.inallgroups %]
|
||||
[% IF NOT inallgroups %]
|
||||
<b>
|
||||
Only members of a group can change the visibility of a bug for
|
||||
that group
|
||||
|
@ -438,7 +423,7 @@
|
|||
<br>
|
||||
[% END %]
|
||||
|
||||
[% IF bug.inagroup %]
|
||||
[% IF inagroup %]
|
||||
<p>
|
||||
<b>Users in the roles selected below can always view this bug:</b>
|
||||
<br>
|
||||
|
@ -472,16 +457,16 @@
|
|||
[% knum = 1 %]
|
||||
|
||||
[% IF bug.bug_status == "UNCONFIRMED" &&
|
||||
user.canconfirm %]
|
||||
bug.user.canconfirm %]
|
||||
<input type="radio" name="knob" value="confirm">
|
||||
Confirm bug (change status to <b>NEW</b>)
|
||||
<br>
|
||||
[% knum = knum + 1 %]
|
||||
[% END %]
|
||||
|
||||
[% IF user.canedit %]
|
||||
[% IF bug.user.canedit %]
|
||||
[% IF bug.isopened %]
|
||||
[% IF bug.bug_status != "ASSIGNED" && user.canconfirm %]
|
||||
[% IF bug.bug_status != "ASSIGNED" && bug.user.canconfirm %]
|
||||
<input type="radio" name="knob" value="accept">
|
||||
Accept bug (
|
||||
[% "confirm bug, " IF bug.isunconfirmed %]change
|
||||
|
@ -501,7 +486,7 @@
|
|||
Resolve bug, changing <a href="bug_status.html">resolution</a> to
|
||||
<select name="resolution"
|
||||
onchange="document.changeform.knob[[% knum %]].checked=true">
|
||||
[% FOREACH r = resolution %]
|
||||
[% FOREACH r = bug.choices.resolution %]
|
||||
<option value="[% r FILTER html %]">[% r FILTER html %]</option>
|
||||
[% END %]
|
||||
</select>
|
||||
|
@ -523,9 +508,9 @@
|
|||
(this.value != '')) {
|
||||
document.changeform.knob[[% knum %]].checked=true;
|
||||
}"
|
||||
value="[% bug.assigned_to_email FILTER html %]">
|
||||
value="[% bug.assigned_to.email FILTER html %]">
|
||||
<br>
|
||||
[% IF bug.isunconfirmed && user.canconfirm %]
|
||||
[% IF bug.isunconfirmed && bug.user.canconfirm %]
|
||||
<input type="checkbox" name="andconfirm">
|
||||
and confirm bug (change status to <b>NEW</b>)
|
||||
<br>
|
||||
|
@ -537,7 +522,7 @@
|
|||
[% " and QA contact" IF Param('useqacontact') %]
|
||||
of selected component
|
||||
<br>
|
||||
[% IF bug.isunconfirmed && user.canconfirm %]
|
||||
[% IF bug.isunconfirmed && bug.user.canconfirm %]
|
||||
<input type="checkbox" name="compconfirm">
|
||||
and confirm bug (change status to <b>NEW</b>)
|
||||
<br>
|
||||
|
@ -545,7 +530,7 @@
|
|||
[% knum = knum + 1 %]
|
||||
[% ELSE %]
|
||||
[% IF bug.resolution != "MOVED" ||
|
||||
(bug.resolution == "MOVED" && user.canmove) %]
|
||||
(bug.resolution == "MOVED" && bug.user.canmove) %]
|
||||
<input type="radio" name="knob" value="reopen"> Reopen bug
|
||||
<br>
|
||||
[% knum = knum + 1 %]
|
||||
|
@ -574,7 +559,7 @@
|
|||
</b>
|
||||
</font>
|
||||
|
||||
[% IF user.canmove %]
|
||||
[% IF bug.user.canmove %]
|
||||
<font size="+1"><b> | </b></font>
|
||||
<input type="submit" name="action"
|
||||
value="[% Param("move-button-text") %]">
|
||||
|
@ -598,19 +583,11 @@
|
|||
<hr>
|
||||
|
||||
[% PROCESS bug/comments.html.tmpl
|
||||
comments = bug.comments
|
||||
comments = bug.longdescs
|
||||
mode = "edit"
|
||||
%]
|
||||
|
||||
</form>
|
||||
<hr>
|
||||
|
||||
[% PROCESS bug/navigate.html.tmpl %]
|
||||
|
||||
<br>
|
||||
|
||||
[% PROCESS global/footer.html.tmpl %]
|
||||
|
||||
|
||||
[%############################################################################%]
|
||||
[%# Block for dependencies #%]
|
||||
|
@ -620,7 +597,7 @@
|
|||
<th align="right">Bug [% bug.bug_id %] [%+ dep.title %]:</th>
|
||||
<td>
|
||||
[% FOREACH depbug = bug.${dep.fieldname} %]
|
||||
[% GetBugLink(depbug, depbug) %][% " " %]
|
||||
[% depbug FILTER bug_link(depbug) %][% " " %]
|
||||
[% END %]
|
||||
</td>
|
||||
<td>
|
||||
|
@ -638,7 +615,7 @@
|
|||
<td>
|
||||
<label for="[% selname %]" accesskey="[% accesskey %]">
|
||||
<select name="[% selname %]" id="[% selname %]">
|
||||
[% FOREACH x = ${selname} %]
|
||||
[% FOREACH x = bug.choices.${selname} %]
|
||||
<option value="[% x FILTER html %]"
|
||||
[% " selected" IF x == bug.${selname} %]>[% x FILTER html %]
|
||||
</option>
|
||||
|
|
|
@ -20,13 +20,22 @@
|
|||
#%]
|
||||
|
||||
[%# INTERFACE:
|
||||
# next_id : number; the ID of the next bug in the user's bug list.
|
||||
# bug : Bug object; the next bug to show
|
||||
#%]
|
||||
|
||||
<hr>
|
||||
|
||||
<p>
|
||||
The next bug in your list is bug
|
||||
<a href="show_bug.cgi?id=[% next_id %]">[% next_id %]</a>:
|
||||
<a href="show_bug.cgi?id=[% bug.bug_id %]">[% bug.bug_id %]</a>:
|
||||
</p>
|
||||
|
||||
[% PROCESS "bug/edit.html.tmpl" %]
|
||||
|
||||
<hr>
|
||||
|
||||
[% PROCESS bug/navigate.html.tmpl %]
|
||||
|
||||
<br>
|
||||
|
||||
[% PROCESS global/footer.html.tmpl %]
|
||||
|
|
|
@ -0,0 +1,46 @@
|
|||
<!-- 1.0@bugzilla.org -->
|
||||
[%# 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): Gervase Markham <gerv@gerv.net>
|
||||
# Vaskin Kissoyan <vkissoyan@yahoo.com>
|
||||
# Bradley Baetz <bbaetz@student.usyd.edu.au>
|
||||
#%]
|
||||
|
||||
[% filtered_desc = bug.short_desc FILTER html %]
|
||||
[% filtered_timestamp = bug.delta_ts FILTER time %]
|
||||
[% PROCESS global/header.html.tmpl
|
||||
title = "Bug $bug.bug_id - $bug.short_desc"
|
||||
h1 = "Bugzilla Bug $bug.bug_id"
|
||||
h2 = filtered_desc
|
||||
h3 = "Last modified: $filtered_timestamp"
|
||||
style_urls = [ "css/edit_bug.css" ]
|
||||
%]
|
||||
|
||||
[% PROCESS bug/navigate.html.tmpl %]
|
||||
|
||||
<hr>
|
||||
|
||||
[% PROCESS bug/edit.html.tmpl %]
|
||||
|
||||
<hr>
|
||||
|
||||
[% PROCESS bug/navigate.html.tmpl %]
|
||||
|
||||
<br>
|
||||
|
||||
[% PROCESS global/footer.html.tmpl %]
|
|
@ -48,6 +48,10 @@
|
|||
Attachment #[% attachid FILTER html %] ([% description FILTER html %])
|
||||
is already obsolete.
|
||||
|
||||
[% ELSIF error == "bug_error" %]
|
||||
Trying to retrieve bug [% bug.bug_id %] returned the error
|
||||
[% bug.error FILTER html %]
|
||||
|
||||
[% ELSIF error == "cgi_error" %]
|
||||
[% title = "CGI Error" %]
|
||||
Bugzilla has had trouble interpreting your CGI request;
|
||||
|
|
|
@ -21,8 +21,8 @@
|
|||
#%]
|
||||
|
||||
[%# INTERFACE:
|
||||
# bug_list: list of integers. List of bugs numbers of current query (if any).
|
||||
# bug: integer. Number of current bug.
|
||||
# bug_list: list of integers. List of bug numbers of current query (if any).
|
||||
# bug.bug_id: integer. Number of current bug (for navigation purposes)
|
||||
#%]
|
||||
|
||||
[% IF NOT (user_agent.match("MSIE [1-6]") OR user_agent.match("Mozilla/4")) %]
|
||||
|
|
|
@ -30,7 +30,7 @@
|
|||
|
||||
<p>
|
||||
<pre>
|
||||
[%- quoteUrls(form.text) FILTER html -%]
|
||||
[%- form.text FILTER quoteUrls FILTER html -%]
|
||||
</pre>
|
||||
</p>
|
||||
|
||||
|
@ -45,7 +45,7 @@
|
|||
|
||||
<p>
|
||||
<pre>
|
||||
[%- quoteUrls(form.text) -%]
|
||||
[%- form.text FILTER quoteUrls -%]
|
||||
</pre>
|
||||
</p>
|
||||
|
||||
|
|
Загрузка…
Ссылка в новой задаче