summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rwxr-xr-xBug.pm502
-rwxr-xr-xBugzilla/Bug.pm502
-rw-r--r--Bugzilla/User.pm2
-rw-r--r--bug_form.pl398
-rwxr-xr-xchecksetup.pl10
-rw-r--r--globals.pl19
-rwxr-xr-xpost_bug.cgi45
-rwxr-xr-xprocess_bug.cgi48
-rwxr-xr-xshow_bug.cgi38
-rw-r--r--t/004template.t2
-rw-r--r--template/en/default/bug/comments.html.tmpl2
-rw-r--r--template/en/default/bug/create/created.html.tmpl20
-rw-r--r--template/en/default/bug/edit.html.tmpl101
-rw-r--r--template/en/default/bug/process/next.html.tmpl13
-rw-r--r--template/en/default/bug/show.html.tmpl46
-rw-r--r--template/en/default/global/code-error.html.tmpl4
-rw-r--r--template/en/default/global/site-navigation.html.tmpl4
-rw-r--r--template/en/default/pages/linked.html.tmpl4
18 files changed, 808 insertions, 952 deletions
diff --git a/Bug.pm b/Bug.pm
index 11eb43af1..91c20780a 100755
--- a/Bug.pm
+++ b/Bug.pm
@@ -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;
- }
-
- &::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;
- }
+ $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_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/&/&amp;/g;
$_[0] =~ s/</&lt;/g;
$_[0] =~ s/>/&gt;/g;
- $_[0] =~ s/'/&apos;/g;
- $_[0] =~ s/"/&quot;/g;
+ $_[0] =~ s/\'/&apos;/g;
+ $_[0] =~ s/\"/&quot;/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;
diff --git a/Bugzilla/Bug.pm b/Bugzilla/Bug.pm
index 11eb43af1..91c20780a 100755
--- a/Bugzilla/Bug.pm
+++ b/Bugzilla/Bug.pm
@@ -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;
- }
-
- &::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;
- }
+ $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_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/&/&amp;/g;
$_[0] =~ s/</&lt;/g;
$_[0] =~ s/>/&gt;/g;
- $_[0] =~ s/'/&apos;/g;
- $_[0] =~ s/"/&quot;/g;
+ $_[0] =~ s/\'/&apos;/g;
+ $_[0] =~ s/\"/&quot;/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;
diff --git a/Bugzilla/User.pm b/Bugzilla/User.pm
index a45cf0976..46f520b77 100644
--- a/Bugzilla/User.pm
+++ b/Bugzilla/User.pm
@@ -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
diff --git a/bug_form.pl b/bug_form.pl
deleted file mode 100644
index b4a2ef678..000000000
--- a/bug_form.pl
+++ /dev/null
@@ -1,398 +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): Terry Weissman <terry@mozilla.org>
-# Dave Miller <justdave@syndicomm.com>
-# Vaskin Kissoyan <vkissoyan@yahoo.com>
-
-use strict;
-
-use RelationSet;
-use Bugzilla::Constants;
-# Use the Attachment module to display attachments for the bug.
-use Attachment;
-
-# Use the Flag modules to display flags on the bug.
-use Bugzilla::Flag;
-use Bugzilla::FlagType;
-
-sub show_bug {
- # Shut up misguided -w warnings about "used only once". For some reason,
- # "use vars" chokes on me when I try it here.
- sub bug_form_pl_sillyness {
- my $zz;
- $zz = %::FORM;
- $zz = %::proddesc;
- $zz = %::prodmaxvotes;
- $zz = @::enterable_products;
- $zz = @::settable_resolution;
- $zz = $::unconfirmedstate;
- $zz = $::milestoneurl;
- $zz = $::template;
- $zz = $::vars;
- $zz = @::legal_priority;
- $zz = @::legal_platform;
- $zz = @::legal_severity;
- $zz = @::legal_bug_status;
- $zz = @::target_milestone;
- $zz = @::components;
- $zz = @::legal_keywords;
- $zz = @::versions;
- $zz = @::legal_opsys;
- }
-
- # Use templates
- my $template = $::template;
- my $vars = $::vars;
-
- $vars->{'GetBugLink'} = \&GetBugLink;
- $vars->{'lsearch'} = \&lsearch,
- $vars->{'header_done'} = (@_),
-
- quietly_check_login();
-
- my $id = $::FORM{'id'};
-
- if (!defined($id)) {
- $template->process("bug/choose.html.tmpl", $vars)
- || ThrowTemplateError($template->error());
- exit;
- }
-
- my %user = %{$vars->{'user'}};
- my %bug;
-
- # Populate the bug hash with the info we get directly from the DB.
- 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, sum(votes.count),
- estimated_time, remaining_time
- FROM bugs LEFT JOIN votes USING(bug_id), products, components
- WHERE bugs.bug_id = $id
- AND bugs.product_id = products.id
- AND bugs.component_id = components.id
- GROUP BY bugs.bug_id";
-
- SendSQL($query);
-
- # The caller is meant to have checked this. Abort here so that
- # we don't get obscure SQL errors, below
- if (!MoreSQLData()) {
- $vars->{'bug_id'} = $id;
- ThrowCodeError("no_bug_data");
- }
-
- my $value;
- my $disp_date;
- my @row = FetchSQLData();
- 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",
- "estimated_time", "remaining_time")
- {
- $value = shift(@row);
- $bug{$field} = defined($value) ? $value : "";
- }
-
- # General arrays of info about the database state
- GetVersionTable();
-
- # Fiddle the product list.
- my $seen_curr_prod;
- my @prodlist;
-
- foreach my $product (@::enterable_products) {
- if ($product eq $bug{'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, $bug{'product'});
- @prodlist = sort @prodlist;
- }
-
- $vars->{'product'} = \@prodlist;
- $vars->{'rep_platform'} = \@::legal_platform;
- $vars->{'priority'} = \@::legal_priority;
- $vars->{'bug_severity'} = \@::legal_severity;
- $vars->{'op_sys'} = \@::legal_opsys;
- $vars->{'bug_status'} = \@::legal_bug_status;
-
- # Hack - this array contains "" for some reason. See bug 106589.
- shift @::settable_resolution;
- $vars->{'resolution'} = \@::settable_resolution;
-
- $vars->{'component_'} = $::components{$bug{'product'}};
- $vars->{'version'} = $::versions{$bug{'product'}};
- $vars->{'target_milestone'} = $::target_milestone{$bug{'product'}};
- $bug{'milestoneurl'} = $::milestoneurl{$bug{'product'}} ||
- "notargetmilestone.html";
-
- $vars->{'use_votes'} = Param('usevotes')
- && $::prodmaxvotes{$bug{'product'}} > 0;
-
- # Add additional, calculated fields to the bug hash
- if (@::legal_keywords) {
- $vars->{'use_keywords'} = 1;
-
- SendSQL("SELECT keyworddefs.name
- FROM keyworddefs, keywords
- WHERE keywords.bug_id = $id
- AND keyworddefs.id = keywords.keywordid
- ORDER BY keyworddefs.name");
- my @keywords;
- while (MoreSQLData()) {
- push(@keywords, FetchOneColumn());
- }
-
- $bug{'keywords'} = \@keywords;
- }
-
- # Attachments
- $bug{'attachments'} = Attachment::query($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' => $bug{'product_id'},
- 'component_id' => $bug{'component_id'} });
- foreach my $flag_type (@$flag_types) {
- $flag_type->{'flags'} =
- Bugzilla::Flag::match({ 'bug_id' => $id ,
- 'type_id' => $flag_type->{'id'} ,
- 'target_type' => 'bug' });
- }
- $vars->{'flag_types'} = $flag_types;
- $vars->{'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' => $bug{'product_id'},
- 'component_id' => $bug{'component_id'},
- 'is_active' => 1 });
- my $num_attachment_flags =
- Bugzilla::Flag::count({ 'target_type' => 'attachment',
- 'bug_id' => $id });
-
- $vars->{'show_attachment_flags'}
- = $num_attachment_flag_types || $num_attachment_flags;
-
- # Dependencies
- my @list;
- SendSQL("SELECT dependson FROM dependencies WHERE
- blocked = $id ORDER BY dependson");
- while (MoreSQLData()) {
- my ($i) = FetchSQLData();
- push(@list, $i);
- }
-
- if (UserInGroup(Param("timetrackinggroup"))) {
-
- SendSQL("SELECT SUM(work_time)
- FROM longdescs WHERE longdescs.bug_id=$id");
- $bug{'actual_time'} = FetchSQLData();
-
- }
-
- $bug{'dependson'} = \@list;
-
- my @list2;
- SendSQL("SELECT blocked FROM dependencies WHERE
- dependson = $id ORDER BY blocked");
- while (MoreSQLData()) {
- my ($i) = FetchSQLData();
- push(@list2, $i);
- }
-
- $bug{'blocked'} = \@list2;
-
- # Groups
- my @groups;
-
- # 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 = $bug{'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 = " . $bug{'product_id'} .
- " WHERE isbuggroup");
-
- $user{'inallgroups'} = 1;
-
- while (MoreSQLData()) {
- my ($groupid, $name, $description, $ison, $ingroup, $isactive,
- $membercontrol, $othercontrol) = FetchSQLData();
-
- $bug{'inagroup'} = 1 if ($ison);
- $membercontrol ||= 0;
-
- if ($isactive && ($membercontrol == CONTROLMAPMANDATORY)) {
- $bug{'inagroup'} = 1;
- }
- # For product groups, we only want to display the checkbox 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))
- ))
- {
- $user{'inallgroups'} &= $ingroup;
-
- my $mandatory;
- if ($isactive && ($membercontrol == CONTROLMAPMANDATORY)) {
- $mandatory = 1;
- } else {
- $mandatory = 0;
- }
- if (($ison) || ($ingroup)) {
- push (@groups, { "bit" => $groupid,
- "ison" => $ison,
- "ingroup" => $ingroup,
- "mandatory" => $mandatory,
- "description" => $description });
- }
- }
- }
-
- # If the bug is restricted to a group, get flags that allow
- # the user to set whether or not the reporter
- # and cc list can see the bug even if they are not members of all
- # groups to which the bug is restricted.
- if ($bug{'inagroup'}) {
-
- # Determine whether or not the bug is always accessible by the
- # reporter, QA contact, and/or users on the cc: list.
- SendSQL("SELECT reporter_accessible, cclist_accessible
- FROM bugs
- WHERE bug_id = $id
- ");
- ($bug{'reporter_accessible'},
- $bug{'cclist_accessible'}) = FetchSQLData();
- }
- $vars->{'groups'} = \@groups;
-
- my $movers = Param("movers");
- $user{'canmove'} = Param("move-enabled")
- && (defined $::COOKIE{"Bugzilla_login"})
- && ($::COOKIE{"Bugzilla_login"} =~ /$movers/);
-
- # User permissions
-
- # 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.
- $user{'canedit'} = $::userid == 0
- || $::userid == $bug{'reporter'}
- || $::userid == $bug{'qa_contact'}
- || $::userid == $bug{'assigned_to'}
- || UserInGroup("editbugs");
- $user{'canconfirm'} = ($::userid == 0)
- || UserInGroup("canconfirm")
- || UserInGroup("editbugs");
-
- # Bug states
- $bug{'isunconfirmed'} = ($bug{'bug_status'} eq $::unconfirmedstate);
- $bug{'isopened'} = IsOpenedState($bug{'bug_status'});
-
- # People involved with the bug
- $bug{'assigned_to_email'} = DBID_to_name($bug{'assigned_to'});
- $bug{'assigned_to'} = DBID_to_real_or_loginname($bug{'assigned_to'});
- $bug{'reporter'} = DBID_to_real_or_loginname($bug{'reporter'});
- $bug{'qa_contact'} = $bug{'qa_contact'} > 0 ?
- DBID_to_name($bug{'qa_contact'}) : "";
-
- my $ccset = new RelationSet;
- $ccset->mergeFromDB("SELECT who FROM cc WHERE bug_id=$id");
-
- my @cc = $ccset->toArrayOfStrings();
- $bug{'cc'} = \@cc if $cc[0];
-
- # Next bug in list (if there is one)
- my @bug_list;
- if ($::COOKIE{"BUGLIST"} && $id)
- {
- @bug_list = split(/:/, $::COOKIE{"BUGLIST"});
- }
- $vars->{'bug_list'} = \@bug_list;
-
- $bug{'comments'} = GetComments($bug{'bug_id'});
-
- # This is length in number of comments
- $bug{'longdesclength'} = scalar(@{$bug{'comments'}});
-
- # Add the bug and user hashes to the variables
- $vars->{'bug'} = \%bug;
- $vars->{'user'} = \%user;
-
- # Generate and return the UI (HTML page) from the appropriate template.
- $template->process("bug/edit.html.tmpl", $vars)
- || ThrowTemplateError($template->error());
-}
-
-1;
-
diff --git a/checksetup.pl b/checksetup.pl
index 101583096..aceb6a706 100755
--- a/checksetup.pl
+++ b/checksetup.pl
@@ -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 $_; },
},
diff --git a/globals.pl b/globals.pl
index 547fd1b95..79c2f92b4 100644
--- a/globals.pl
+++ b/globals.pl
@@ -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 => \&quoteUrls ,
+
+ 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' => \&quoteUrls ,
-
# UserInGroup - you probably want to cache this
'UserInGroup' => \&UserInGroup ,
diff --git a/post_bug.cgi b/post_bug.cgi
index 3ddfbe689..2a65c2436 100755
--- a/post_bug.cgi
+++ b/post_bug.cgi
@@ -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;
-print "Content-type: text/html\n\n";
-$template->process("bug/create/created.html.tmpl", $vars)
- || ThrowTemplateError($template->error());
+ThrowCodeError("bug_error") if $bug->error;
+
+$vars->{'sentmail'} = [];
+
+push (@{$vars->{'sentmail'}}, { type => 'created',
+ id => $id,
+ mail => $mailresults
+ });
foreach my $i (@all_deps) {
- $vars->{'mail'} = "";
- open(PMAIL, "-|") or exec('./processmail', $i, $::COOKIE{'Bugzilla_login'}); $vars->{'mail'} .= $_ while <PMAIL>;
+ my $mail = "";
+ open(PMAIL, "-|") or exec('./processmail', $i, $::COOKIE{'Bugzilla_login'});
+ $mail .= $_ while <PMAIL>;
close(PMAIL);
- $vars->{'id'} = $i;
- $vars->{'type'} = "dep";
+ push (@{$vars->{'sentmail'}}, { type => 'dep',
+ id => $i,
+ mail => $mail
+ });
+}
- # 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());
+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());
-$::FORM{'id'} = $id;
-show_bug("header is already done");
diff --git a/process_bug.cgi b/process_bug.cgi
index a59e439dc..80b318a74 100755
--- a/process_bug.cgi
+++ b/process_bug.cgi
@@ -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;
}
}
diff --git a/show_bug.cgi b/show_bug.cgi
index 6711ff7e6..377c7905d 100755
--- a/show_bug.cgi
+++ b/show_bug.cgi
@@ -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();
diff --git a/t/004template.t b/t/004template.t
index 6c44fca48..b3fdcc8b7 100644
--- a/t/004template.t
+++ b/t/004template.t
@@ -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 $_ } ,
},
diff --git a/template/en/default/bug/comments.html.tmpl b/template/en/default/bug/comments.html.tmpl
index 42971b327..98d7ae386 100644
--- a/template/en/default/bug/comments.html.tmpl
+++ b/template/en/default/bug/comments.html.tmpl
@@ -68,7 +68,7 @@
# generated HTML
#%]
<pre>
- [%- quoteUrls(comment.body) -%]
+ [%- comment.body FILTER quoteUrls -%]
</pre>
</div>
[% END %]
diff --git a/template/en/default/bug/create/created.html.tmpl b/template/en/default/bug/create/created.html.tmpl
index 0264413a7..5966e4e0e 100644
--- a/template/en/default/bug/create/created.html.tmpl
+++ b/template/en/default/bug/create/created.html.tmpl
@@ -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 %]
diff --git a/template/en/default/bug/edit.html.tmpl b/template/en/default/bug/edit.html.tmpl
index aa56678dd..56483a779 100644
--- a/template/en/default/bug/edit.html.tmpl
+++ b/template/en/default/bug/edit.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>&nbsp;</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&nbsp;To</a>:
</b>
</td>
- <td>[% bug.assigned_to FILTER html %]</td>
+ <td>[% bug.assigned_to.identity FILTER html %]</td>
<td>&nbsp;</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 %]
&nbsp;&nbsp;&nbsp;&nbsp;<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 %]
&nbsp;&nbsp;&nbsp;&nbsp;<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 %]
&nbsp; <font size="+1"><b> | </b></font> &nbsp;
<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>
diff --git a/template/en/default/bug/process/next.html.tmpl b/template/en/default/bug/process/next.html.tmpl
index b7a2605e9..1eeb9f367 100644
--- a/template/en/default/bug/process/next.html.tmpl
+++ b/template/en/default/bug/process/next.html.tmpl
@@ -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 %]
diff --git a/template/en/default/bug/show.html.tmpl b/template/en/default/bug/show.html.tmpl
new file mode 100644
index 000000000..46f8c4674
--- /dev/null
+++ b/template/en/default/bug/show.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 %]
diff --git a/template/en/default/global/code-error.html.tmpl b/template/en/default/global/code-error.html.tmpl
index d23234adc..4b37ee4f1 100644
--- a/template/en/default/global/code-error.html.tmpl
+++ b/template/en/default/global/code-error.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;
diff --git a/template/en/default/global/site-navigation.html.tmpl b/template/en/default/global/site-navigation.html.tmpl
index 118f356c0..77611b465 100644
--- a/template/en/default/global/site-navigation.html.tmpl
+++ b/template/en/default/global/site-navigation.html.tmpl
@@ -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")) %]
diff --git a/template/en/default/pages/linked.html.tmpl b/template/en/default/pages/linked.html.tmpl
index c3d02885c..941c18cc7 100644
--- a/template/en/default/pages/linked.html.tmpl
+++ b/template/en/default/pages/linked.html.tmpl
@@ -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>