must go first:
+ $text =~ s{ ( (?<=\W) __ (?=\S) (.+?[*_]*) (?<=\S) __ (?!\S) ) }
+ {
+ my $result = _has_multiple_underscores($2) ? $1 : "$2";
+ $result;
+ }gsxe;
+
+
+ $text =~ s{ (?<=\W) \*\* (?=\S) (.+?[*_]*) (?<=\S) \*\* }{$1}gsx;
+
+ $text =~ s{ ( (?<=\W) _ (?=\S) (.+?) (?<=\S) _ (?!\S) ) }
+ {
+ my $result = _has_multiple_underscores($2) ? $1 : "$2";
+ $result;
+ }gsxe;
+
+ $text =~ s{ (?<=\W) \* (?=\S) (.+?) (?<=\S) \* }{$1}gsx;
+
+ # And now, a second pass to catch nested strong and emphasis special cases
+ $text =~ s{ ( (?<=\W) __ (?=\S) (.+?[*_]*) (?<=\S) __ (\S*) ) }
+ {
+ my $result = _has_multiple_underscores($3) ? $1 : "$2$3";
+ $result;
+ }gsxe;
+
+ $text =~ s{ (?<=\W) \*\* (?=\S) (.+?[*_]*) (?<=\S) \*\* }{$1}gsx;
+ $text =~ s{ ( (?<=\W) _ (?=\S) (.+?) (?<=\S) _ (\S*) ) }
+ {
+ my $result = _has_multiple_underscores($3) ? $1 : "$2$3";
+ $result;
+ }gsxe;
+
+ $text =~ s{ (?<=\W) \* (?=\S) (.+?) (?<=\S) \* }{$1}gsx;
+
+ return $text;
+}
+
+sub _DoStrikethroughs {
+ my ($self, $text) = @_;
+
+ $text =~ s{ ^ ~~ (?=\S) ([^~]+?) (?<=\S) ~~ (?!~) }{$1}gsx;
+ $text =~ s{ (?<=_|[^~\w]) ~~ (?=\S) ([^~]+?) (?<=\S) ~~ (?!~) }{$1}gsx;
+
+ return $text;
+}
+
+# The original _DoCodeSpans() uses the 's' modifier in its regex
+# which prevents _DoCodeBlocks() to match GFM fenced code blocks.
+# We copy the code from the original implementation and remove the
+# 's' modifier from it.
+sub _DoCodeSpans {
+ my ($self, $text) = @_;
+
+ $text =~ s@
+ (?_EncodeCode($c);
+ "$c";
+ @egx;
+
+ return $text;
+}
+
+# Override to add GFM Fenced Code Blocks
+sub _DoCodeBlocks {
+ my ($self, $text) = @_;
+
+ $text =~ s{
+ ^ `{3,} [\s\t]* \n
+ ( # $1 = the entire code block
+ (?: .* \n+)+?
+ )
+ `{3,} [\s\t]* $
+ }{
+ my $codeblock = $1;
+ my $result;
+
+ $codeblock = $self->_EncodeCode($codeblock);
+ $codeblock = $self->_Detab($codeblock);
+ $codeblock =~ s/\n\z//; # remove the trailing newline
+
+ $result = "\n\n" . $codeblock . "
\n\n";
+ $result;
+ }egmx;
+
+ # And now do the standard code blocks
+ $text = $self->SUPER::_DoCodeBlocks($text);
+
+ return $text;
+}
+
+sub _DoBlockQuotes {
+ my ($self, $text) = @_;
+
+ $text =~ s{
+ ( # Wrap whole match in $1
+ (?:
+ ^[ \t]*>[ \t]? # '>' at the start of a line
+ .+\n # rest of the first line
+ (?:.+\n)* # subsequent consecutive lines
+ \n* # blanks
+ )+
+ )
+ }{
+ my $bq = $1;
+ $bq =~ s/^[ \t]*>[ \t]?//gm; # trim one level of quoting
+ $bq =~ s/^[ \t]+$//mg; # trim whitespace-only lines
+ $bq = $self->_RunBlockGamut($bq, {wrap_in_p_tags => 1}); # recurse
+ $bq =~ s/^/ /mg;
+ # These leading spaces screw with content, so we need to fix that:
+ $bq =~ s{(\s*.+?
)}{
+ my $pre = $1;
+ $pre =~ s/^ //mg;
+ $pre;
+ }egs;
+ "\n$bq\n
\n\n";
+ }egmx;
+
+ return $text;
+}
+
+sub _EncodeCode {
+ my ($self, $text) = @_;
+
+ # We need to unescape the escaped HTML characters in code blocks.
+ # These are the reverse of the escapings done in Bugzilla::Util::html_quote()
+ $text =~ s/<//g;
+ $text =~ s/"/"/g;
+ $text =~ s/@/@/g;
+ # '&' substitution must be the last one, otherwise a literal like '>'
+ # will turn to '>' because '&' is already changed to '&' in Bugzilla::Util::html_quote().
+ # In other words, html_quote() will change '>' to '>' and then we will
+ # change '>' -> '>' -> '>' if we write this substitution as the first one.
+ $text =~ s/&/&/g;
+ $text =~ s{ \1 }{$1}xmgi;
+ $text = $self->SUPER::_EncodeCode($text);
+ $text =~ s/~/$g_escape_table{'~'}/go;
+ # Encode '<' to prevent URLs from getting linkified in code spans
+ $text =~ s/</$g_escape_table{'<'}/go;
+
+ return $text;
+}
+
+sub _EncodeBackslashEscapes {
+ my ($self, $text) = @_;
+
+ $text = $self->SUPER::_EncodeBackslashEscapes($text);
+ $text =~ s/\\~/$g_escape_table{'~'}/go;
+
+ return $text;
+}
+
+sub _UnescapeSpecialChars {
+ my ($self, $text) = @_;
+
+ $text = $self->SUPER::_UnescapeSpecialChars($text);
+ $text =~ s/$g_escape_table{'~'}/~/go;
+ $text =~ s/$g_escape_table{'<'}/</go;
+
+ return $text;
+}
+
+# Check if the passed string is of the form multiple_underscores_in_a_word.
+# To check that, we first need to make sure that the string does not contain
+# any white-space. Then, if the string is composed of non-space chunks which
+# are bound together with underscores, the string has the desired form.
+sub _has_multiple_underscores {
+ my $string = shift;
+ return 0 unless defined($string) && length($string);
+ return 0 if $string =~ /[\t\s]+/;
+ return 1 if scalar (split /_/, $string) > 1;
+ return 0;
+}
+
+1;
+
+__END__
+
+=head1 NAME
+
+Bugzilla::Markdown - Generates HTML output from structured plain-text input.
+
+=head1 SYNOPSIS
+
+ use Bugzilla::Markdown;
+
+ my $markdown = Bugzilla::Markdown->new();
+ print $markdown->markdown($text);
+
+=head1 DESCRIPTION
+
+Bugzilla::Markdown implements a Markdown engine that produces
+an HTML-based output from a given plain-text input.
+
+The majority of the implementation is done by C
+CPAN module. It also applies the linkifications done in L
+to the input resulting in an output which is a combination of both Markdown
+structures and those defined by Bugzilla itself.
+
+=head2 Accessors
+
+=over
+
+=item C
+
+C Produces an HTML-based output string based on the structures
+and format defined in the given plain-text input.
+
+=over
+
+=item B
+
+=over
+
+=item C
+
+C A plain-text string which includes Markdown structures.
+
+=back
+
+=back
+
+=back
diff --git a/mozilla/webtools/bugzilla/Bugzilla/Memcached.pm b/mozilla/webtools/bugzilla/Bugzilla/Memcached.pm
index 1464b6c003e..df90fef9342 100644
--- a/mozilla/webtools/bugzilla/Bugzilla/Memcached.pm
+++ b/mozilla/webtools/bugzilla/Bugzilla/Memcached.pm
@@ -254,10 +254,13 @@ sub _get {
elsif (ref($value) eq 'ARRAY') {
foreach my $value (@$value) {
next unless defined $value;
- # arrays of hashes are common
+ # arrays of hashes and arrays are common
if (ref($value) eq 'HASH') {
_detaint_hashref($value);
}
+ elsif (ref($value) eq 'ARRAY') {
+ _detaint_arrayref($value);
+ }
elsif (!ref($value)) {
trick_taint($value);
}
@@ -278,6 +281,15 @@ sub _detaint_hashref {
}
}
+sub _detaint_arrayref {
+ my ($arrayref) = @_;
+ foreach my $value (@$arrayref) {
+ if (defined($value) && !ref($value)) {
+ trick_taint($value);
+ }
+ }
+}
+
sub _delete {
my ($self, $key) = @_;
$key = $self->_encode_key($key)
diff --git a/mozilla/webtools/bugzilla/Bugzilla/Migrate.pm b/mozilla/webtools/bugzilla/Bugzilla/Migrate.pm
index 2763ecb2bd4..0731d4fedf9 100644
--- a/mozilla/webtools/bugzilla/Bugzilla/Migrate.pm
+++ b/mozilla/webtools/bugzilla/Bugzilla/Migrate.pm
@@ -9,6 +9,7 @@ package Bugzilla::Migrate;
use 5.10.1;
use strict;
+use warnings;
use Bugzilla::Attachment;
use Bugzilla::Bug qw(LogActivityEntry);
diff --git a/mozilla/webtools/bugzilla/Bugzilla/Migrate/Gnats.pm b/mozilla/webtools/bugzilla/Bugzilla/Migrate/Gnats.pm
index 2778d28cc8a..5feda4b8db3 100644
--- a/mozilla/webtools/bugzilla/Bugzilla/Migrate/Gnats.pm
+++ b/mozilla/webtools/bugzilla/Bugzilla/Migrate/Gnats.pm
@@ -9,6 +9,7 @@ package Bugzilla::Migrate::Gnats;
use 5.10.1;
use strict;
+use warnings;
use parent qw(Bugzilla::Migrate);
diff --git a/mozilla/webtools/bugzilla/Bugzilla/Milestone.pm b/mozilla/webtools/bugzilla/Bugzilla/Milestone.pm
index 83438e7c683..cf7e3e35f18 100644
--- a/mozilla/webtools/bugzilla/Bugzilla/Milestone.pm
+++ b/mozilla/webtools/bugzilla/Bugzilla/Milestone.pm
@@ -9,6 +9,7 @@ package Bugzilla::Milestone;
use 5.10.1;
use strict;
+use warnings;
use parent qw(Bugzilla::Object);
diff --git a/mozilla/webtools/bugzilla/Bugzilla/Object.pm b/mozilla/webtools/bugzilla/Bugzilla/Object.pm
index f2080363299..8f25e2b20c2 100644
--- a/mozilla/webtools/bugzilla/Bugzilla/Object.pm
+++ b/mozilla/webtools/bugzilla/Bugzilla/Object.pm
@@ -9,6 +9,7 @@ package Bugzilla::Object;
use 5.10.1;
use strict;
+use warnings;
use Bugzilla::Constants;
use Bugzilla::Hook;
diff --git a/mozilla/webtools/bugzilla/Bugzilla/Product.pm b/mozilla/webtools/bugzilla/Bugzilla/Product.pm
index 3d4de7430aa..30ebc7c6cd5 100644
--- a/mozilla/webtools/bugzilla/Bugzilla/Product.pm
+++ b/mozilla/webtools/bugzilla/Bugzilla/Product.pm
@@ -9,6 +9,7 @@ package Bugzilla::Product;
use 5.10.1;
use strict;
+use warnings;
use parent qw(Bugzilla::Field::ChoiceInterface Bugzilla::Object);
diff --git a/mozilla/webtools/bugzilla/Bugzilla/RNG.pm b/mozilla/webtools/bugzilla/Bugzilla/RNG.pm
index 14b83167222..96e442fa032 100644
--- a/mozilla/webtools/bugzilla/Bugzilla/RNG.pm
+++ b/mozilla/webtools/bugzilla/Bugzilla/RNG.pm
@@ -9,6 +9,7 @@ package Bugzilla::RNG;
use 5.10.1;
use strict;
+use warnings;
use parent qw(Exporter);
use Bugzilla::Constants qw(ON_WINDOWS);
diff --git a/mozilla/webtools/bugzilla/Bugzilla/Report.pm b/mozilla/webtools/bugzilla/Bugzilla/Report.pm
index fe2b826614f..10af2ea9efc 100644
--- a/mozilla/webtools/bugzilla/Bugzilla/Report.pm
+++ b/mozilla/webtools/bugzilla/Bugzilla/Report.pm
@@ -9,6 +9,7 @@ package Bugzilla::Report;
use 5.10.1;
use strict;
+use warnings;
use parent qw(Bugzilla::Object);
diff --git a/mozilla/webtools/bugzilla/Bugzilla/Search.pm b/mozilla/webtools/bugzilla/Bugzilla/Search.pm
index 036e0a60581..0395d08eefb 100644
--- a/mozilla/webtools/bugzilla/Bugzilla/Search.pm
+++ b/mozilla/webtools/bugzilla/Bugzilla/Search.pm
@@ -9,6 +9,7 @@ package Bugzilla::Search;
use 5.10.1;
use strict;
+use warnings;
use parent qw(Exporter);
@Bugzilla::Search::EXPORT = qw(
@@ -264,7 +265,7 @@ use constant OPERATOR_FIELD_OVERRIDE => {
},
# General Bug Fields
- alias => { _non_changed => \&_nullable },
+ alias => { _non_changed => \&_alias_nonchanged },
'attach_data.thedata' => MULTI_SELECT_OVERRIDE,
# We check all attachment fields against this.
attachments => MULTI_SELECT_OVERRIDE,
@@ -455,6 +456,10 @@ sub COLUMN_JOINS {
. ' FROM longdescs GROUP BY bug_id)',
join => 'INNER',
},
+ alias => {
+ table => 'bugs_aliases',
+ as => 'map_alias',
+ },
assigned_to => {
from => 'assigned_to',
to => 'userid',
@@ -585,6 +590,7 @@ sub COLUMNS {
# like "bugs.bug_id".
my $total_time = "(map_actual_time.total + bugs.remaining_time)";
my %special_sql = (
+ alias => $dbh->sql_group_concat('DISTINCT map_alias.alias'),
deadline => $dbh->sql_date_format('bugs.deadline', '%Y-%m-%d'),
actual_time => 'map_actual_time.total',
@@ -755,7 +761,7 @@ sub data {
my @orig_fields = $self->_input_columns;
my $all_in_bugs_table = 1;
foreach my $field (@orig_fields) {
- next if $self->COLUMNS->{$field}->{name} =~ /^bugs\.\w+$/;
+ next if ($self->COLUMNS->{$field}->{name} // $field) =~ /^bugs\.\w+$/;
$self->{fields} = ['bug_id'];
$all_in_bugs_table = 0;
last;
@@ -1007,10 +1013,16 @@ sub _sql_select {
my ($self) = @_;
my @sql_fields;
foreach my $column ($self->_display_columns) {
- my $alias = $column;
- # Aliases cannot contain dots in them. We convert them to underscores.
- $alias =~ s/\./_/g;
- my $sql = $self->COLUMNS->{$column}->{name} . " AS $alias";
+ my $sql = $self->COLUMNS->{$column}->{name} // '';
+ if ($sql) {
+ my $alias = $column;
+ # Aliases cannot contain dots in them. We convert them to underscores.
+ $alias =~ tr/./_/;
+ $sql .= " AS $alias";
+ }
+ else {
+ $sql = $column;
+ }
push(@sql_fields, $sql);
}
return @sql_fields;
@@ -1387,7 +1399,7 @@ sub _sql_group_by {
my @extra_group_by;
foreach my $column ($self->_select_columns) {
next if $self->_skip_group_by->{$column};
- my $sql = $self->COLUMNS->{$column}->{name};
+ my $sql = $self->COLUMNS->{$column}->{name} // $column;
push(@extra_group_by, $sql);
}
@@ -2726,6 +2738,15 @@ sub _product_nonchanged {
"products.id", "products", $term);
}
+sub _alias_nonchanged {
+ my ($self, $args) = @_;
+
+ $args->{full_field} = "bugs_aliases.alias";
+ $self->_do_operator_function($args);
+ $args->{term} = build_subselect("bugs.bug_id",
+ "bugs_aliases.bug_id", "bugs_aliases", $args->{term});
+}
+
sub _classification_nonchanged {
my ($self, $args) = @_;
my $joins = $args->{joins};
diff --git a/mozilla/webtools/bugzilla/Bugzilla/Search/Clause.pm b/mozilla/webtools/bugzilla/Bugzilla/Search/Clause.pm
index 9d3d690a393..1d7872c7857 100644
--- a/mozilla/webtools/bugzilla/Bugzilla/Search/Clause.pm
+++ b/mozilla/webtools/bugzilla/Bugzilla/Search/Clause.pm
@@ -9,6 +9,7 @@ package Bugzilla::Search::Clause;
use 5.10.1;
use strict;
+use warnings;
use Bugzilla::Error;
use Bugzilla::Search::Condition qw(condition);
diff --git a/mozilla/webtools/bugzilla/Bugzilla/Search/ClauseGroup.pm b/mozilla/webtools/bugzilla/Bugzilla/Search/ClauseGroup.pm
index eb306525c2b..590c737fad0 100644
--- a/mozilla/webtools/bugzilla/Bugzilla/Search/ClauseGroup.pm
+++ b/mozilla/webtools/bugzilla/Bugzilla/Search/ClauseGroup.pm
@@ -9,6 +9,7 @@ package Bugzilla::Search::ClauseGroup;
use 5.10.1;
use strict;
+use warnings;
use parent qw(Bugzilla::Search::Clause);
diff --git a/mozilla/webtools/bugzilla/Bugzilla/Search/Condition.pm b/mozilla/webtools/bugzilla/Bugzilla/Search/Condition.pm
index eab4ab79d24..306a63eed3c 100644
--- a/mozilla/webtools/bugzilla/Bugzilla/Search/Condition.pm
+++ b/mozilla/webtools/bugzilla/Bugzilla/Search/Condition.pm
@@ -9,6 +9,7 @@ package Bugzilla::Search::Condition;
use 5.10.1;
use strict;
+use warnings;
use parent qw(Exporter);
our @EXPORT_OK = qw(condition);
diff --git a/mozilla/webtools/bugzilla/Bugzilla/Search/Quicksearch.pm b/mozilla/webtools/bugzilla/Bugzilla/Search/Quicksearch.pm
index 98e8a648274..830177f8b51 100644
--- a/mozilla/webtools/bugzilla/Bugzilla/Search/Quicksearch.pm
+++ b/mozilla/webtools/bugzilla/Bugzilla/Search/Quicksearch.pm
@@ -9,6 +9,7 @@ package Bugzilla::Search::Quicksearch;
use 5.10.1;
use strict;
+use warnings;
use Bugzilla::Error;
use Bugzilla::Constants;
@@ -321,7 +322,7 @@ sub _handle_alias {
my $alias = $1;
# We use this direct SQL because we want quicksearch to be VERY fast.
my $bug_id = Bugzilla->dbh->selectrow_array(
- q{SELECT bug_id FROM bugs WHERE alias = ?}, undef, $alias);
+ q{SELECT bug_id FROM bugs_aliases WHERE alias = ?}, undef, $alias);
# If the user cannot see the bug or if we are using a webservice,
# do not resolve its alias.
if ($bug_id && Bugzilla->user->can_see_bug($bug_id) && !i_am_webservice()) {
diff --git a/mozilla/webtools/bugzilla/Bugzilla/Search/Recent.pm b/mozilla/webtools/bugzilla/Bugzilla/Search/Recent.pm
index cc1c3c582e8..e774c7fe059 100644
--- a/mozilla/webtools/bugzilla/Bugzilla/Search/Recent.pm
+++ b/mozilla/webtools/bugzilla/Bugzilla/Search/Recent.pm
@@ -9,6 +9,7 @@ package Bugzilla::Search::Recent;
use 5.10.1;
use strict;
+use warnings;
use parent qw(Bugzilla::Object);
diff --git a/mozilla/webtools/bugzilla/Bugzilla/Search/Saved.pm b/mozilla/webtools/bugzilla/Bugzilla/Search/Saved.pm
index 2e4c4a33617..50a9cdd6721 100644
--- a/mozilla/webtools/bugzilla/Bugzilla/Search/Saved.pm
+++ b/mozilla/webtools/bugzilla/Bugzilla/Search/Saved.pm
@@ -9,6 +9,7 @@ package Bugzilla::Search::Saved;
use 5.10.1;
use strict;
+use warnings;
use parent qw(Bugzilla::Object);
diff --git a/mozilla/webtools/bugzilla/Bugzilla/Send/Sendmail.pm b/mozilla/webtools/bugzilla/Bugzilla/Sender/Transport/Sendmail.pm
similarity index 64%
rename from mozilla/webtools/bugzilla/Bugzilla/Send/Sendmail.pm
rename to mozilla/webtools/bugzilla/Bugzilla/Sender/Transport/Sendmail.pm
index 9496ff97cf9..49f00777fc1 100644
--- a/mozilla/webtools/bugzilla/Bugzilla/Send/Sendmail.pm
+++ b/mozilla/webtools/bugzilla/Bugzilla/Sender/Transport/Sendmail.pm
@@ -5,57 +5,49 @@
# This Source Code Form is "Incompatible With Secondary Licenses", as
# defined by the Mozilla Public License, v. 2.0.
-package Bugzilla::Send::Sendmail;
+package Bugzilla::Sender::Transport::Sendmail;
use 5.10.1;
use strict;
+use warnings;
-use parent qw(Email::Send::Sendmail);
+use parent qw(Email::Sender::Transport::Sendmail);
-use Return::Value;
-use Symbol qw(gensym);
+use Email::Sender::Failure;
-sub send {
- my ($class, $message, @args) = @_;
- my $mailer = $class->_find_sendmail;
+sub send_email {
+ my ($self, $email, $envelope) = @_;
- return failure "Couldn't find 'sendmail' executable in your PATH"
- ." and Email::Send::Sendmail::SENDMAIL is not set"
- unless $mailer;
+ my $pipe = $self->_sendmail_pipe($envelope);
- return failure "Found $mailer but cannot execute it"
- unless -x $mailer;
-
- local $SIG{'CHLD'} = 'DEFAULT';
+ my $string = $email->as_string;
+ $string =~ s/\x0D\x0A/\x0A/g unless $^O eq 'MSWin32';
- my $pipe = gensym;
+ print $pipe $string
+ or Email::Sender::Failure->throw("couldn't send message to sendmail: $!");
- open($pipe, "| $mailer -t -oi @args")
- || return failure "Error executing $mailer: $!";
- print($pipe $message->as_string)
- || return failure "Error printing via pipe to $mailer: $!";
unless (close $pipe) {
- return failure "error when closing pipe to $mailer: $!" if $!;
+ Email::Sender::Failure->throw("error when closing pipe to sendmail: $!") if $!;
my ($error_message, $is_transient) = _map_exitcode($? >> 8);
if (Bugzilla->params->{'use_mailer_queue'}) {
# Return success for errors which are fatal so Bugzilla knows to
- # remove them from the queue
+ # remove them from the queue.
if ($is_transient) {
- return failure "error when closing pipe to $mailer: $error_message";
+ Email::Sender::Failure->throw("error when closing pipe to sendmail: $error_message");
} else {
- warn "error when closing pipe to $mailer: $error_message\n";
- return success;
+ warn "error when closing pipe to sendmail: $error_message\n";
+ return $self->success;
}
} else {
- return failure "error when closing pipe to $mailer: $error_message";
+ Email::Sender::Failure->throw("error when closing pipe to sendmail: $error_message");
}
}
- return success;
+ return $self->success;
}
sub _map_exitcode {
# Returns (error message, is_transient)
- # from the sendmail source (sendmail/sysexit.h)
+ # from the sendmail source (sendmail/sysexits.h)
my $code = shift;
if ($code == 64) {
return ("Command line usage error (EX_USAGE)", 1);
@@ -98,6 +90,6 @@ sub _map_exitcode {
=over
-=item send
+=item send_email
=back
diff --git a/mozilla/webtools/bugzilla/Bugzilla/Series.pm b/mozilla/webtools/bugzilla/Bugzilla/Series.pm
index 6c11f5dbcfd..22202c6f18d 100644
--- a/mozilla/webtools/bugzilla/Bugzilla/Series.pm
+++ b/mozilla/webtools/bugzilla/Bugzilla/Series.pm
@@ -16,6 +16,7 @@ package Bugzilla::Series;
use 5.10.1;
use strict;
+use warnings;
use Bugzilla::Error;
use Bugzilla::Util;
diff --git a/mozilla/webtools/bugzilla/Bugzilla/Status.pm b/mozilla/webtools/bugzilla/Bugzilla/Status.pm
index 1f8862a36a0..27551021604 100644
--- a/mozilla/webtools/bugzilla/Bugzilla/Status.pm
+++ b/mozilla/webtools/bugzilla/Bugzilla/Status.pm
@@ -9,6 +9,7 @@ package Bugzilla::Status;
use 5.10.1;
use strict;
+use warnings;
# This subclasses Bugzilla::Field::Choice instead of implementing
# ChoiceInterface, because a bug status literally is a special type
diff --git a/mozilla/webtools/bugzilla/Bugzilla/Template.pm b/mozilla/webtools/bugzilla/Bugzilla/Template.pm
index 8fe50fa4f8b..7ce1be72bc6 100644
--- a/mozilla/webtools/bugzilla/Bugzilla/Template.pm
+++ b/mozilla/webtools/bugzilla/Bugzilla/Template.pm
@@ -10,6 +10,7 @@ package Bugzilla::Template;
use 5.10.1;
use strict;
+use warnings;
use Bugzilla::Constants;
use Bugzilla::WebService::Constants;
@@ -147,10 +148,11 @@ sub get_format {
# If you want to modify this routine, read the comments carefully
sub quoteUrls {
- my ($text, $bug, $comment, $user, $bug_link_func) = @_;
+ my ($text, $bug, $comment, $user, $bug_link_func, $for_markdown) = @_;
return $text unless $text;
$user ||= Bugzilla->user;
$bug_link_func ||= \&get_bug_link;
+ $for_markdown ||= 0;
# We use /g for speed, but uris can have other things inside them
# (http://foo/bug#3 for example). Filtering that out filters valid
@@ -221,10 +223,11 @@ sub quoteUrls {
$text = html_quote($text);
- # Color quoted text
- $text =~ s~^(>.+)$~$1~mg;
- $text =~ s~\n~\n~g;
-
+ unless ($for_markdown) {
+ # Color quoted text
+ $text =~ s~^(>.+)$~$1~mg;
+ $text =~ s~\n~\n~g;
+ }
# mailto:
# Use | so that $1 is defined regardless
# @ is the encoded '@' character.
@@ -262,28 +265,23 @@ sub quoteUrls {
my $bugs_re = qr/\Q$bugs_word\E$s*\#?$s*
\d+(?:$s*,$s*\#?$s*\d+)+/ix;
- while ($text =~ m/($bugs_re)/g) {
- my $offset = $-[0];
- my $length = $+[0] - $-[0];
- my $match = $1;
+ $text =~ s{($bugs_re)}{
+ my $match = $1;
$match =~ s/((?:#$s*)?(\d+))/$bug_link_func->($2, $1);/eg;
- # Replace the old string with the linkified one.
- substr($text, $offset, $length) = $match;
- }
+ $match;
+ }eg;
my $comments_word = template_var('terms')->{comments};
my $comments_re = qr/(?:comments|\Q$comments_word\E)$s*\#?$s*
\d+(?:$s*,$s*\#?$s*\d+)+/ix;
- while ($text =~ m/($comments_re)/g) {
- my $offset = $-[0];
- my $length = $+[0] - $-[0];
- my $match = $1;
+ $text =~ s{($comments_re)}{
+ my $match = $1;
$match =~ s|((?:#$s*)?(\d+))|$1|g;
- substr($text, $offset, $length) = $match;
- }
+ $match;
+ }eg;
# Old duplicate markers. These don't use $bug_word because they are old
# and were never customizable.
@@ -534,7 +532,7 @@ sub _concatenate_css {
write_file($file, $content);
}
- $file =~ s/^\Q$cgi_path\E\///;
+ $file =~ s/^\Q$cgi_path\E\///o;
return mtime_filter($file);
}
@@ -547,6 +545,55 @@ sub _css_url_rewrite {
return 'url(../../' . dirname($source) . '/' . $url . ')';
}
+sub _concatenate_js {
+ return @_ unless CONCATENATE_ASSETS;
+ my ($sources) = @_;
+ return [] unless $sources;
+ $sources = ref($sources) ? $sources : [ $sources ];
+
+ my %files =
+ map {
+ (my $file = $_) =~ s/(^[^\?]+)\?.+/$1/;
+ $_ => $file;
+ } @$sources;
+
+ my $cgi_path = bz_locations()->{cgi_path};
+ my $skins_path = bz_locations()->{assetsdir};
+
+ # build minified files
+ my @minified;
+ foreach my $source (@$sources) {
+ next unless -e "$cgi_path/$files{$source}";
+ my $file = $skins_path . '/' . md5_hex($source) . '.js';
+ if (!-e $file) {
+ my $content = read_file("$cgi_path/$files{$source}");
+
+ # minimal minification
+ $content =~ s#/\*.*?\*/##sg; # block comments
+ $content =~ s#(^ +| +$)##gm; # leading/trailing spaces
+ $content =~ s#^//.+$##gm; # single line comments
+ $content =~ s#\n{2,}#\n#g; # blank lines
+ $content =~ s#(^\s+|\s+$)##g; # whitespace at the start/end of file
+
+ write_file($file, ";/* $files{$source} */\n" . $content . "\n");
+ }
+ push @minified, $file;
+ }
+
+ # concat files
+ my $file = $skins_path . '/' . md5_hex(join(' ', @$sources)) . '.js';
+ if (!-e $file) {
+ my $content = '';
+ foreach my $source (@minified) {
+ $content .= read_file($source);
+ }
+ write_file($file, $content);
+ }
+
+ $file =~ s/^\Q$cgi_path\E\///o;
+ return [ $file ];
+}
+
# YUI dependency resolution
sub yui_resolve_deps {
my ($yui, $yui_deps) = @_;
@@ -611,6 +658,21 @@ $Template::Stash::LIST_OPS->{ clone } =
return [@$list];
};
+# Allow us to sort the list of fields correctly
+$Template::Stash::LIST_OPS->{ sort_by_field_name } =
+ sub {
+ sub field_name {
+ if ($_[0] eq 'noop') {
+ # Sort --- first
+ return '';
+ }
+ # Otherwise sort by field_desc or description
+ return $_[1]{$_[0]} || $_[0];
+ }
+ my ($list, $field_desc) = @_;
+ return [ sort { lc field_name($a, $field_desc) cmp lc field_name($b, $field_desc) } @$list ];
+ };
+
# Allow us to still get the scalar if we use the list operation ".0" on it,
# as we often do for defaults in query.cgi and other places.
$Template::Stash::SCALAR_OPS->{ 0 } =
@@ -796,6 +858,24 @@ sub create {
1
],
+ markdown => [ sub {
+ my ($context, $bug, $comment, $user) = @_;
+ return sub {
+ my $text = shift;
+ return unless $text;
+
+ if (Bugzilla->feature('markdown')
+ && ((ref($comment) eq 'HASH' && $comment->{is_markdown})
+ || (ref($comment) eq 'Bugzilla::Comment' && $comment->is_markdown)))
+ {
+ return Bugzilla->markdown->markdown($text);
+ }
+ return quoteUrls($text, $bug, $comment, $user);
+ };
+ },
+ 1
+ ],
+
bug_link => [ sub {
my ($context, $bug, $options) = @_;
return sub {
@@ -812,10 +892,12 @@ sub create {
},
# In CSV, quotes are doubled, and any value containing a quote or a
- # comma is enclosed in quotes.
+ # comma is enclosed in quotes. If a field starts with an equals
+ # sign, it is proceed by a space.
csv => sub
{
my ($var) = @_;
+ $var = ' ' . $var if substr($var, 0, 1) eq '=';
$var =~ s/\"/\"\"/g;
if ($var !~ /^-?(\d+\.)?\d*$/) {
$var = "\"$var\"";
@@ -1001,6 +1083,12 @@ sub create {
return $cookie ? issue_hash_token(['login_request', $cookie]) : '';
},
+ 'get_api_token' => sub {
+ return '' unless Bugzilla->user->id;
+ my $cache = Bugzilla->request_cache;
+ return $cache->{api_token} //= issue_api_token();
+ },
+
# A way for all templates to get at Field data, cached.
'bug_fields' => sub {
my $cache = Bugzilla->request_cache;
@@ -1019,6 +1107,7 @@ sub create {
'css_files' => \&css_files,
yui_resolve_deps => \&yui_resolve_deps,
+ concatenate_js => \&_concatenate_js,
# All classifications (sorted by sortkey, name)
'all_classifications' => sub {
diff --git a/mozilla/webtools/bugzilla/Bugzilla/Template/Context.pm b/mozilla/webtools/bugzilla/Bugzilla/Template/Context.pm
index 1e75d1d6f1a..470e6a9ee1f 100644
--- a/mozilla/webtools/bugzilla/Bugzilla/Template/Context.pm
+++ b/mozilla/webtools/bugzilla/Bugzilla/Template/Context.pm
@@ -10,6 +10,7 @@ package Bugzilla::Template::Context;
use 5.10.1;
use strict;
+use warnings;
use parent qw(Template::Context);
diff --git a/mozilla/webtools/bugzilla/Bugzilla/Template/Plugin/Bugzilla.pm b/mozilla/webtools/bugzilla/Bugzilla/Template/Plugin/Bugzilla.pm
index f0de2ed4d18..806dd903b68 100644
--- a/mozilla/webtools/bugzilla/Bugzilla/Template/Plugin/Bugzilla.pm
+++ b/mozilla/webtools/bugzilla/Bugzilla/Template/Plugin/Bugzilla.pm
@@ -9,6 +9,7 @@ package Bugzilla::Template::Plugin::Bugzilla;
use 5.10.1;
use strict;
+use warnings;
use parent qw(Template::Plugin);
diff --git a/mozilla/webtools/bugzilla/Bugzilla/Template/Plugin/Hook.pm b/mozilla/webtools/bugzilla/Bugzilla/Template/Plugin/Hook.pm
index 19260f0057f..669c77614ce 100644
--- a/mozilla/webtools/bugzilla/Bugzilla/Template/Plugin/Hook.pm
+++ b/mozilla/webtools/bugzilla/Bugzilla/Template/Plugin/Hook.pm
@@ -9,6 +9,7 @@ package Bugzilla::Template::Plugin::Hook;
use 5.10.1;
use strict;
+use warnings;
use parent qw(Template::Plugin);
diff --git a/mozilla/webtools/bugzilla/Bugzilla/Token.pm b/mozilla/webtools/bugzilla/Bugzilla/Token.pm
index 5352638682b..24ffad3c34a 100644
--- a/mozilla/webtools/bugzilla/Bugzilla/Token.pm
+++ b/mozilla/webtools/bugzilla/Bugzilla/Token.pm
@@ -9,6 +9,7 @@ package Bugzilla::Token;
use 5.10.1;
use strict;
+use warnings;
use Bugzilla::Constants;
use Bugzilla::Error;
@@ -23,13 +24,28 @@ use Digest::SHA qw(hmac_sha256_base64);
use parent qw(Exporter);
-@Bugzilla::Token::EXPORT = qw(issue_session_token check_token_data delete_token
+@Bugzilla::Token::EXPORT = qw(issue_api_token issue_session_token
+ check_token_data delete_token
issue_hash_token check_hash_token);
################################################################################
# Public Functions
################################################################################
+# Create a token used for internal API authentication
+sub issue_api_token {
+ # Generates a random token, adds it to the tokens table if one does not
+ # already exist, and returns the token to the caller.
+ my $dbh = Bugzilla->dbh;
+ my $user = Bugzilla->user;
+ my ($token) = $dbh->selectrow_array("
+ SELECT token FROM tokens
+ WHERE userid = ? AND tokentype = 'api_token'
+ AND (" . $dbh->sql_date_math('issuedate', '+', (MAX_TOKEN_AGE * 24 - 12), 'HOUR') . ") > NOW()",
+ undef, $user->id);
+ return $token // _create_token($user->id, 'api_token', '');
+}
+
# Creates and sends a token to create a new user account.
# It assumes that the login has the correct format and is not already in use.
sub issue_new_user_account_token {
@@ -466,6 +482,14 @@ Bugzilla::Token - Provides different routines to manage tokens.
=over
+=item C
+
+ Description: Creates a token that can be used for API calls on the web page.
+
+ Params: None.
+
+ Returns: The token.
+
=item C
Description: Creates and sends a token per email to the email address
diff --git a/mozilla/webtools/bugzilla/Bugzilla/Update.pm b/mozilla/webtools/bugzilla/Bugzilla/Update.pm
index 6a101219956..72a7108a8e3 100644
--- a/mozilla/webtools/bugzilla/Bugzilla/Update.pm
+++ b/mozilla/webtools/bugzilla/Bugzilla/Update.pm
@@ -9,6 +9,7 @@ package Bugzilla::Update;
use 5.10.1;
use strict;
+use warnings;
use Bugzilla::Constants;
diff --git a/mozilla/webtools/bugzilla/Bugzilla/User.pm b/mozilla/webtools/bugzilla/Bugzilla/User.pm
index 3efe02633f9..fa267436618 100644
--- a/mozilla/webtools/bugzilla/Bugzilla/User.pm
+++ b/mozilla/webtools/bugzilla/Bugzilla/User.pm
@@ -9,6 +9,7 @@ package Bugzilla::User;
use 5.10.1;
use strict;
+use warnings;
use Bugzilla::Error;
use Bugzilla::Util;
@@ -31,7 +32,7 @@ use URI::QueryParam;
use parent qw(Bugzilla::Object Exporter);
@Bugzilla::User::EXPORT = qw(is_available_username
- login_to_id validate_password
+ login_to_id validate_password validate_password_check
USER_MATCH_MULTIPLE USER_MATCH_FAILED USER_MATCH_SUCCESS
MATCH_SKIP_CONFIRM
);
@@ -631,6 +632,14 @@ sub is_bug_ignored {
return (grep {$_->{'id'} == $bug_id} @{$self->bugs_ignored}) ? 1 : 0;
}
+sub use_markdown {
+ my ($self, $comment) = @_;
+ return Bugzilla->feature('markdown')
+ && $self->settings->{use_markdown}->{is_enabled}
+ && $self->settings->{use_markdown}->{value} eq 'on'
+ && (!defined $comment || $comment->is_markdown);
+}
+
##########################
# Saved Recent Bug Lists #
##########################
@@ -2448,29 +2457,35 @@ sub login_to_id {
}
sub validate_password {
+ my $check = validate_password_check(@_);
+ ThrowUserError($check) if $check;
+ return 1;
+}
+
+sub validate_password_check {
my ($password, $matchpassword) = @_;
if (length($password) < USER_PASSWORD_MIN_LENGTH) {
- ThrowUserError('password_too_short');
+ return 'password_too_short';
} elsif ((defined $matchpassword) && ($password ne $matchpassword)) {
- ThrowUserError('passwords_dont_match');
+ return 'passwords_dont_match';
}
-
+
my $complexity_level = Bugzilla->params->{password_complexity};
if ($complexity_level eq 'letters_numbers_specialchars') {
- ThrowUserError('password_not_complex')
+ return 'password_not_complex'
if ($password !~ /[[:alpha:]]/ || $password !~ /\d/ || $password !~ /[[:punct:]]/);
} elsif ($complexity_level eq 'letters_numbers') {
- ThrowUserError('password_not_complex')
+ return 'password_not_complex'
if ($password !~ /[[:lower:]]/ || $password !~ /[[:upper:]]/ || $password !~ /\d/);
} elsif ($complexity_level eq 'mixed_letters') {
- ThrowUserError('password_not_complex')
+ return 'password_not_complex'
if ($password !~ /[[:lower:]]/ || $password !~ /[[:upper:]]/);
}
# Having done these checks makes us consider the password untainted.
trick_taint($_[0]);
- return 1;
+ return;
}
@@ -2616,6 +2631,12 @@ C The current summary of the bug.
Returns true if the user does not want email notifications for the
specified bug ID, else returns false.
+=item C
+
+Returns true if the user has set their preferences to use Markdown
+for rendering comments. If an optional C object is passed
+then it returns true if the comment has markdown enabled.
+
=back
=head2 Saved Recent Bug Lists
@@ -3141,12 +3162,23 @@ if you need more information about the user than just their ID.
=item C
Returns true if a password is valid (i.e. meets Bugzilla's
-requirements for length and content), else returns false.
+requirements for length and content), else throws an error.
Untaints C<$passwd1> if successful.
If a second password is passed in, this function also verifies that
the two passwords match.
+=item C
+
+This sub routine is similair to C, except that it allows
+the calling code to handle its own errors.
+
+Returns undef and untaints C<$passwd1> if a password is valid (i.e. meets
+Bugzilla's requirements for length and content), else returns the error.
+
+If a second password is passed in, this function also verifies that
+the two passwords match.
+
=item C
=over
diff --git a/mozilla/webtools/bugzilla/Bugzilla/User/APIKey.pm b/mozilla/webtools/bugzilla/Bugzilla/User/APIKey.pm
new file mode 100644
index 00000000000..d268a0a93c4
--- /dev/null
+++ b/mozilla/webtools/bugzilla/Bugzilla/User/APIKey.pm
@@ -0,0 +1,155 @@
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+#
+# This Source Code Form is "Incompatible With Secondary Licenses", as
+# defined by the Mozilla Public License, v. 2.0.
+
+package Bugzilla::User::APIKey;
+
+use 5.10.1;
+use strict;
+use warnings;
+
+use parent qw(Bugzilla::Object);
+
+use Bugzilla::User;
+use Bugzilla::Util qw(generate_random_password trim);
+
+#####################################################################
+# Overriden Constants that are used as methods
+#####################################################################
+
+use constant DB_TABLE => 'user_api_keys';
+use constant DB_COLUMNS => qw(
+ id
+ user_id
+ api_key
+ description
+ revoked
+ last_used
+);
+
+use constant UPDATE_COLUMNS => qw(description revoked last_used);
+use constant VALIDATORS => {
+ api_key => \&_check_api_key,
+ description => \&_check_description,
+ revoked => \&Bugzilla::Object::check_boolean,
+};
+use constant LIST_ORDER => 'id';
+use constant NAME_FIELD => 'api_key';
+
+# turn off auditing and exclude these objects from memcached
+use constant { AUDIT_CREATES => 0,
+ AUDIT_UPDATES => 0,
+ AUDIT_REMOVES => 0,
+ USE_MEMCACHED => 0 };
+
+# Accessors
+sub id { return $_[0]->{id} }
+sub user_id { return $_[0]->{user_id} }
+sub api_key { return $_[0]->{api_key} }
+sub description { return $_[0]->{description} }
+sub revoked { return $_[0]->{revoked} }
+sub last_used { return $_[0]->{last_used} }
+
+# Helpers
+sub user {
+ my $self = shift;
+ $self->{user} //= Bugzilla::User->new({name => $self->user_id, cache => 1});
+ return $self->{user};
+}
+
+sub update_last_used {
+ my $self = shift;
+ my $timestamp = shift
+ || Bugzilla->dbh->selectrow_array('SELECT LOCALTIMESTAMP(0)');
+ $self->set('last_used', $timestamp);
+ $self->update;
+}
+
+# Setters
+sub set_description { $_[0]->set('description', $_[1]); }
+sub set_revoked { $_[0]->set('revoked', $_[1]); }
+
+# Validators
+sub _check_api_key { return generate_random_password(40); }
+sub _check_description { return trim($_[1]) || ''; }
+1;
+
+__END__
+
+=head1 NAME
+
+Bugzilla::User::APIKey - Model for an api key belonging to a user.
+
+=head1 SYNOPSIS
+
+ use Bugzilla::User::APIKey;
+
+ my $api_key = Bugzilla::User::APIKey->new($id);
+ my $api_key = Bugzilla::User::APIKey->new({ name => $api_key });
+
+ # Class Functions
+ $user_api_key = Bugzilla::User::APIKey->create({
+ description => $description,
+ });
+
+=head1 DESCRIPTION
+
+This package handles Bugzilla User::APIKey.
+
+C is an implementation of L, and
+thus provides all the methods of L in addition to the methods
+listed below.
+
+=head1 METHODS
+
+=head2 Accessor Methods
+
+=over
+
+=item C
+
+The internal id of the api key.
+
+=item C
+
+The Bugzilla::User object that this api key belongs to.
+
+=item C
+
+The user id that this api key belongs to.
+
+=item C
+
+The API key, which is a random string.
+
+=item C
+
+An optional string that lets the user describe what a key is used for.
+For example: "Dashboard key", "Application X key".
+
+=item C
+
+If true, this api key cannot be used.
+
+=item C
+
+The date that this key was last used. undef if never used.
+
+=item C
+
+Updates the last used value to the current timestamp. This is updated even
+if the RPC call resulted in an error. It is not updated when the description
+or the revoked flag is changed.
+
+=item C
+
+Sets the new description
+
+=item C
+
+Sets the revoked flag
+
+=back
diff --git a/mozilla/webtools/bugzilla/Bugzilla/User/Setting.pm b/mozilla/webtools/bugzilla/Bugzilla/User/Setting.pm
index 451e946f774..ea3bbfb5423 100644
--- a/mozilla/webtools/bugzilla/Bugzilla/User/Setting.pm
+++ b/mozilla/webtools/bugzilla/Bugzilla/User/Setting.pm
@@ -10,13 +10,18 @@ package Bugzilla::User::Setting;
use 5.10.1;
use strict;
+use warnings;
use parent qw(Exporter);
# Module stuff
-@Bugzilla::User::Setting::EXPORT = qw(get_all_settings get_defaults
- add_setting);
+@Bugzilla::User::Setting::EXPORT = qw(
+ get_all_settings
+ get_defaults
+ add_setting
+ clear_settings_cache
+);
use Bugzilla::Error;
use Bugzilla::Util qw(trick_taint get_text);
@@ -159,15 +164,20 @@ sub get_all_settings {
my $settings = {};
my $dbh = Bugzilla->dbh;
- my $rows = $dbh->selectall_arrayref(
- q{SELECT name, default_value, is_enabled, setting_value, subclass
- FROM setting
- LEFT JOIN profile_setting
- ON setting.name = profile_setting.setting_name
- AND profile_setting.user_id = ?}, undef, ($user_id));
+ my $cache_key = "user_settings.$user_id";
+ my $rows = Bugzilla->memcached->get_config({ key => $cache_key });
+ if (!$rows) {
+ $rows = $dbh->selectall_arrayref(
+ q{SELECT name, default_value, is_enabled, setting_value, subclass
+ FROM setting
+ LEFT JOIN profile_setting
+ ON setting.name = profile_setting.setting_name
+ AND profile_setting.user_id = ?}, undef, ($user_id));
+ Bugzilla->memcached->set_config({ key => $cache_key, data => $rows });
+ }
foreach my $row (@$rows) {
- my ($name, $default_value, $is_enabled, $value, $subclass) = @$row;
+ my ($name, $default_value, $is_enabled, $value, $subclass) = @$row;
my $is_default;
@@ -179,13 +189,18 @@ sub get_all_settings {
}
$settings->{$name} = new Bugzilla::User::Setting(
- $name, $user_id, $is_enabled,
+ $name, $user_id, $is_enabled,
$default_value, $value, $is_default, $subclass);
}
return $settings;
}
+sub clear_settings_cache {
+ my ($user_id) = @_;
+ Bugzilla->memcached->clear_config({ key => "user_settings.$user_id" });
+}
+
sub get_defaults {
my ($user_id) = @_;
my $dbh = Bugzilla->dbh;
@@ -368,6 +383,13 @@ Params: C<$setting_name> - string - the name of the setting
C<$is_enabled> - boolean - if false, all users must use the global default
Returns: nothing
+=item C
+
+Description: Clears cached settings data for the specified user. Must be
+ called after updating any user's setting.
+Params: C<$user_id> - integer - the user id.
+Returns: nothing
+
=begin private
=item C<_setting_exists>
diff --git a/mozilla/webtools/bugzilla/Bugzilla/User/Setting/Lang.pm b/mozilla/webtools/bugzilla/Bugzilla/User/Setting/Lang.pm
index 4465185e3ff..d980b7a92e0 100644
--- a/mozilla/webtools/bugzilla/Bugzilla/User/Setting/Lang.pm
+++ b/mozilla/webtools/bugzilla/Bugzilla/User/Setting/Lang.pm
@@ -9,6 +9,7 @@ package Bugzilla::User::Setting::Lang;
use 5.10.1;
use strict;
+use warnings;
use parent qw(Bugzilla::User::Setting);
diff --git a/mozilla/webtools/bugzilla/Bugzilla/User/Setting/Skin.pm b/mozilla/webtools/bugzilla/Bugzilla/User/Setting/Skin.pm
index 1e4e95a03e3..7b0688c0c83 100644
--- a/mozilla/webtools/bugzilla/Bugzilla/User/Setting/Skin.pm
+++ b/mozilla/webtools/bugzilla/Bugzilla/User/Setting/Skin.pm
@@ -10,6 +10,7 @@ package Bugzilla::User::Setting::Skin;
use 5.10.1;
use strict;
+use warnings;
use parent qw(Bugzilla::User::Setting);
diff --git a/mozilla/webtools/bugzilla/Bugzilla/User/Setting/Timezone.pm b/mozilla/webtools/bugzilla/Bugzilla/User/Setting/Timezone.pm
index 848fa418f8b..8959d1ddace 100644
--- a/mozilla/webtools/bugzilla/Bugzilla/User/Setting/Timezone.pm
+++ b/mozilla/webtools/bugzilla/Bugzilla/User/Setting/Timezone.pm
@@ -9,6 +9,7 @@ package Bugzilla::User::Setting::Timezone;
use 5.10.1;
use strict;
+use warnings;
use DateTime::TimeZone;
diff --git a/mozilla/webtools/bugzilla/Bugzilla/UserAgent.pm b/mozilla/webtools/bugzilla/Bugzilla/UserAgent.pm
index 4e685cacc75..963e3051139 100644
--- a/mozilla/webtools/bugzilla/Bugzilla/UserAgent.pm
+++ b/mozilla/webtools/bugzilla/Bugzilla/UserAgent.pm
@@ -9,6 +9,7 @@ package Bugzilla::UserAgent;
use 5.10.1;
use strict;
+use warnings;
use parent qw(Exporter);
our @EXPORT = qw(detect_platform detect_op_sys);
diff --git a/mozilla/webtools/bugzilla/Bugzilla/Util.pm b/mozilla/webtools/bugzilla/Bugzilla/Util.pm
index 4f0711b7e0c..670f5f8f28b 100644
--- a/mozilla/webtools/bugzilla/Bugzilla/Util.pm
+++ b/mozilla/webtools/bugzilla/Bugzilla/Util.pm
@@ -9,6 +9,7 @@ package Bugzilla::Util;
use 5.10.1;
use strict;
+use warnings;
use parent qw(Exporter);
@Bugzilla::Util::EXPORT = qw(trick_taint detaint_natural detaint_signed
@@ -551,9 +552,14 @@ sub datetime_from {
# In the database, this is the "0" date.
return undef if $date =~ /^0000/;
- # strptime($date) returns an empty array if $date has an invalid
- # date format.
- my @time = strptime($date);
+ my @time;
+ # Most dates will be in this format, avoid strptime's generic parser
+ if ($date =~ /^(\d{4})[\.-](\d{2})[\.-](\d{2})(?: (\d{2}):(\d{2}):(\d{2}))?$/) {
+ @time = ($6, $5, $4, $3, $2 - 1, $1 - 1900, undef);
+ }
+ else {
+ @time = strptime($date);
+ }
unless (scalar @time) {
# If an unknown timezone is passed (such as MSK, for Moskow),
@@ -565,10 +571,14 @@ sub datetime_from {
return undef if !@time;
- # strptime() counts years from 1900, and months from 0 (January).
- # We have to fix both values.
+ # strptime() counts years from 1900, except if they are older than 1901
+ # in which case it returns the full year (so 1890 -> 1890, but 1984 -> 84,
+ # and 3790 -> 1890). We make a guess and assume that 1100 <= year < 3000.
+ $time[5] += 1900 if $time[5] < 1100;
+
my %args = (
- year => $time[5] + 1900,
+ year => $time[5],
+ # Months start from 0 (January).
month => $time[4] + 1,
day => $time[3],
hour => $time[2],
diff --git a/mozilla/webtools/bugzilla/Bugzilla/Version.pm b/mozilla/webtools/bugzilla/Bugzilla/Version.pm
index c6b178a8ab9..4b332ff2bc9 100644
--- a/mozilla/webtools/bugzilla/Bugzilla/Version.pm
+++ b/mozilla/webtools/bugzilla/Bugzilla/Version.pm
@@ -9,6 +9,7 @@ package Bugzilla::Version;
use 5.10.1;
use strict;
+use warnings;
use parent qw(Bugzilla::Object Exporter);
diff --git a/mozilla/webtools/bugzilla/Bugzilla/WebService.pm b/mozilla/webtools/bugzilla/Bugzilla/WebService.pm
index 1dc04c1f6c9..1bdeb49d1f6 100644
--- a/mozilla/webtools/bugzilla/Bugzilla/WebService.pm
+++ b/mozilla/webtools/bugzilla/Bugzilla/WebService.pm
@@ -11,6 +11,7 @@ package Bugzilla::WebService;
use 5.10.1;
use strict;
+use warnings;
use Bugzilla::WebService::Server;
@@ -134,14 +135,22 @@ how this is implemented for those frontends.
=head1 LOGGING IN
-There are various ways to log in:
+Some methods do not require you to log in. An example of this is Bug.get.
+However, authenticating yourself allows you to see non public information. For
+example, a bug that is not publicly visible.
+
+There are two ways to authenticate yourself:
=over
-=item C
+=item C
-You can use L to log in as a Bugzilla
-user. This issues a token that you must then use in future calls.
+B
+
+You can specify C as an argument to any WebService method, and
+you will be logged in as that user if the key is correct, and has not been
+revoked. You can set up an API key by using the 'API Key' tab in the
+Preferences pages.
=item C and C
@@ -164,15 +173,29 @@ then your login will only be valid for your IP address.
=back
The C option is only used when you have also
-specified C and C.
+specified C and C. This value will be
+deprecated in the release after Bugzilla 5.0 and you will be required to
+pass the Bugzilla_login and Bugzilla_password for every call.
For REST, you may also use the C and C variable
names instead of C and C as a
convenience. You may also use C instead of C.
+=back
+
+There are also two deprecreated methods of authentications. This will be
+removed in the version after Bugzilla 5.0.
+
+=over
+
+=item C
+
+You can use L to log in as a Bugzilla
+user. This issues a token that you must then use in future calls.
+
=item C
-B
+B
You can specify C as argument to any WebService method,
and you will be logged in as that user if the token is correct. This is
@@ -292,7 +315,7 @@ hashes.
Some RPC calls support specifying sub fields. If an RPC call states that
it support sub field restrictions, you can restrict what information is
-returned within the first field. For example, if you call Products.get
+returned within the first field. For example, if you call Product.get
with an include_fields of components.name, then only the component name
would be returned (and nothing else). You can include the main field,
and exclude a sub field.
@@ -367,6 +390,8 @@ objects.
=item L
+=item L
+
=item L
=item L
diff --git a/mozilla/webtools/bugzilla/Bugzilla/WebService/Bug.pm b/mozilla/webtools/bugzilla/Bugzilla/WebService/Bug.pm
index 0346511a943..f50bb6aee36 100644
--- a/mozilla/webtools/bugzilla/Bugzilla/WebService/Bug.pm
+++ b/mozilla/webtools/bugzilla/Bugzilla/WebService/Bug.pm
@@ -9,6 +9,7 @@ package Bugzilla::WebService::Bug;
use 5.10.1;
use strict;
+use warnings;
use parent qw(Bugzilla::WebService);
@@ -330,7 +331,9 @@ sub render_comment {
Bugzilla->switch_to_shadow_db();
my $bug = $params->{id} ? Bugzilla::Bug->check($params->{id}) : undef;
- my $tmpl = '[% text FILTER quoteUrls(bug) %]';
+ my $markdown = $params->{markdown} ? 1 : 0;
+ my $tmpl = $markdown ? '[% text FILTER markdown(bug, { is_markdown => 1 }) %]' : '[% text FILTER markdown(bug) %]';
+
my $html;
my $template = Bugzilla->template;
$template->process(
@@ -349,15 +352,16 @@ sub _translate_comment {
: undef;
my $comment_hash = {
- id => $self->type('int', $comment->id),
- bug_id => $self->type('int', $comment->bug_id),
- creator => $self->type('email', $comment->author->login),
- time => $self->type('dateTime', $comment->creation_ts),
+ id => $self->type('int', $comment->id),
+ bug_id => $self->type('int', $comment->bug_id),
+ creator => $self->type('email', $comment->author->login),
+ time => $self->type('dateTime', $comment->creation_ts),
creation_time => $self->type('dateTime', $comment->creation_ts),
- is_private => $self->type('boolean', $comment->is_private),
- text => $self->type('string', $comment->body_full),
+ is_private => $self->type('boolean', $comment->is_private),
+ is_markdown => $self->type('boolean', $comment->is_markdown),
+ text => $self->type('string', $comment->body_full),
attachment_id => $self->type('int', $attach_id),
- count => $self->type('int', $comment->count),
+ count => $self->type('int', $comment->count),
};
# Don't load comment tags unless enabled
@@ -467,7 +471,7 @@ sub history {
# alias is returned in case users passes a mixture of ids and aliases
# then they get to know which bug activity relates to which value
# they passed
- $item{alias} = $self->type('string', $bug->alias);
+ $item{alias} = [ map { $self->type('string', $_) } @{ $bug->alias } ];
push(@return, \%item);
}
@@ -631,6 +635,16 @@ sub update {
# called using those field names.
delete $values{dependencies};
+ # For backwards compatibility, treat alias string or array as a set action
+ if (exists $values{alias}) {
+ if (not ref $values{alias}) {
+ $values{alias} = { set => [ $values{alias} ] };
+ }
+ elsif (ref $values{alias} eq 'ARRAY') {
+ $values{alias} = { set => $values{alias} };
+ }
+ }
+
my $flags = delete $values{flags};
foreach my $bug (@bugs) {
@@ -668,7 +682,7 @@ sub update {
# alias is returned in case users pass a mixture of ids and aliases,
# so that they can know which set of changes relates to which value
# they passed.
- $hash{alias} = $self->type('string', $bug->alias);
+ $hash{alias} = [ map { $self->type('string', $_) } @{ $bug->alias } ];
my %changes = %{ $all_changes{$bug->id} };
foreach my $field (keys %changes) {
@@ -811,10 +825,20 @@ sub add_attachment {
$attachment->update($timestamp);
my $comment = $params->{comment} || '';
- $attachment->bug->add_comment($comment,
- { isprivate => $attachment->isprivate,
- type => CMT_ATTACHMENT_CREATED,
- extra_data => $attachment->id });
+
+ my $is_markdown = 0;
+ if (ref $params->{comment} eq 'HASH') {
+ $is_markdown = $params->{comment}->{is_markdown};
+ $comment = $params->{comment}->{body};
+ }
+
+ ThrowUserError('markdown_disabled') if $is_markdown && !_is_markdown_enabled();
+
+ $attachment->bug->add_comment($comment,
+ { is_markdown => $is_markdown,
+ isprivate => $attachment->isprivate,
+ type => CMT_ATTACHMENT_CREATED,
+ extra_data => $attachment->id });
push(@created, $attachment);
}
$_->bug->update($timestamp) foreach @created;
@@ -860,6 +884,14 @@ sub update_attachment {
my $flags = delete $params->{flags};
my $comment = delete $params->{comment};
+ my $is_markdown = 0;
+
+ if (ref $comment eq 'HASH') {
+ $is_markdown = $comment->{is_markdown};
+ $comment = $comment->{body};
+ }
+
+ ThrowUserError('markdown_disabled') if $is_markdown && !_is_markdown_enabled();
# Update the values
foreach my $attachment (@attachments) {
@@ -879,9 +911,10 @@ sub update_attachment {
if ($comment = trim($comment)) {
$attachment->bug->add_comment($comment,
- { isprivate => $attachment->isprivate,
- type => CMT_ATTACHMENT_UPDATED,
- extra_data => $attachment->id });
+ { is_markdown => $is_markdown,
+ isprivate => $attachment->isprivate,
+ type => CMT_ATTACHMENT_UPDATED,
+ extra_data => $attachment->id });
}
$changes = translate($changes, ATTACHMENT_MAPPED_RETURNS);
@@ -938,9 +971,13 @@ sub add_comment {
if (defined $params->{private}) {
$params->{is_private} = delete $params->{private};
}
+
+ ThrowUserError('markdown_disabled') if $params->{is_markdown} && !_is_markdown_enabled();
+
# Append comment
- $bug->add_comment($comment, { isprivate => $params->{is_private},
- work_time => $params->{work_time} });
+ $bug->add_comment($comment, { isprivate => $params->{is_private},
+ is_markdown => $params->{is_markdown},
+ work_time => $params->{work_time} });
# Capture the call to bug->update (which creates the new comment) in
# a transaction so we're sure to get the correct comment_id.
@@ -1135,7 +1172,11 @@ sub search_comment_tags {
my $query = $params->{query};
$query
// ThrowCodeError('param_required', { param => 'query' });
- my $limit = detaint_natural($params->{limit}) || 7;
+ my $limit = $params->{limit} || 7;
+ detaint_natural($limit)
+ || ThrowCodeError('param_must_be_numeric', { param => 'limit',
+ function => 'Bug.search_comment_tags' });
+
my $tags = Bugzilla::Comment::TagWeights->match({
WHERE => {
@@ -1162,14 +1203,11 @@ sub _bug_to_hash {
# A bug attribute is "basic" if it doesn't require an additional
# database call to get the info.
my %item = %{ filter $params, {
- alias => $self->type('string', $bug->alias),
- creation_time => $self->type('dateTime', $bug->creation_ts),
# No need to format $bug->deadline specially, because Bugzilla::Bug
# already does it for us.
deadline => $self->type('string', $bug->deadline),
id => $self->type('int', $bug->bug_id),
is_confirmed => $self->type('boolean', $bug->everconfirmed),
- last_change_time => $self->type('dateTime', $bug->delta_ts),
op_sys => $self->type('string', $bug->op_sys),
platform => $self->type('string', $bug->rep_platform),
priority => $self->type('string', $bug->priority),
@@ -1183,9 +1221,11 @@ sub _bug_to_hash {
whiteboard => $self->type('string', $bug->status_whiteboard),
} };
- # First we handle any fields that require extra SQL calls.
- # We don't do the SQL calls at all if the filter would just
- # eliminate them anyway.
+ # First we handle any fields that require extra work (such as date parsing
+ # or SQL calls).
+ if (filter_wants $params, 'alias') {
+ $item{alias} = [ map { $self->type('string', $_) } @{ $bug->alias } ];
+ }
if (filter_wants $params, 'assigned_to') {
$item{'assigned_to'} = $self->type('email', $bug->assigned_to->login);
$item{'assigned_to_detail'} = $self->_user_to_hash($bug->assigned_to, $params, undef, 'assigned_to');
@@ -1205,6 +1245,9 @@ sub _bug_to_hash {
$item{'cc'} = \@cc;
$item{'cc_detail'} = [ map { $self->_user_to_hash($_, $params, undef, 'cc') } @{ $bug->cc_users } ];
}
+ if (filter_wants $params, 'creation_time') {
+ $item{'creation_time'} = $self->type('dateTime', $bug->creation_ts);
+ }
if (filter_wants $params, 'creator') {
$item{'creator'} = $self->type('email', $bug->reporter->login);
$item{'creator_detail'} = $self->_user_to_hash($bug->reporter, $params, undef, 'creator');
@@ -1229,6 +1272,9 @@ sub _bug_to_hash {
@{ $bug->keyword_objects };
$item{'keywords'} = \@keywords;
}
+ if (filter_wants $params, 'last_change_time') {
+ $item{'last_change_time'} = $self->type('dateTime', $bug->delta_ts);
+ }
if (filter_wants $params, 'product') {
$item{product} = $self->type('string', $bug->product);
}
@@ -1379,6 +1425,14 @@ sub _add_update_tokens {
}
}
+sub _is_markdown_enabled {
+ my $user = Bugzilla->user;
+
+ return Bugzilla->feature('markdown')
+ && $user->settings->{use_markdown}->{is_enabled}
+ && $user->setting('use_markdown') eq 'on';
+}
+
1;
__END__
@@ -1482,6 +1536,12 @@ C The number of the fieldtype. The following values are defined:
=item C<7> Bug URLs ("See Also")
+=item C<8> Keywords
+
+=item C<9> Date
+
+=item C<10> Integer value
+
=back
=item C
@@ -2050,6 +2110,10 @@ may be deprecated and removed in a future release.
C True if this comment is private (only visible to a certain
group called the "insidergroup"), False otherwise.
+=item is_markdown
+
+C True if this comment needs Markdown processing, false otherwise.
+
=back
=item B
@@ -2167,7 +2231,8 @@ in the return value.
=item C
-C The unique alias of this bug.
+C of Cs The unique aliases of this bug. An empty array will be
+returned if this bug has no aliases.
=item C
@@ -2612,7 +2677,8 @@ C The numeric id of the bug.
=item alias
-C The alias of this bug. If there is no alias, this will be undef.
+C of Cs The unique aliases of this bug. An empty array will be
+returned if this bug has no aliases.
=item history
@@ -2795,7 +2861,8 @@ just reuse the query parameter portion in the REST call itself.
=item C
-C The unique alias for this bug.
+C of Cs The unique aliases of this bug. An empty array will be
+returned if this bug has no aliases.
=item C
@@ -3052,7 +3119,7 @@ in by the developer, compared to the developer's other bugs.
=item C (string) B - How severe the bug is.
-=item C (string) - A brief alias for the bug that can be used
+=item C (array) - A brief alias for the bug that can be used
instead of a bug number when accessing this bug. Must be unique in
all of this Bugzilla.
@@ -3064,6 +3131,9 @@ don't want it to be assigned to the component owner.
=item C (boolean) - If set to true, the description
is private, otherwise it is assumed to be public.
+=item C (boolean) - If set to true, the description
+has Markdown structures, otherwise it is a normal text.
+
=item C (array) - An array of group names to put this
bug into. You can see valid group names on the Permissions
tab of the Preferences screen, or, if you are an administrator,
@@ -3219,6 +3289,8 @@ Bugzilla B<4.4>.
=item REST API call added in Bugzilla B<5.0>.
+=item C option added in Bugzilla B<5.0>.
+
=back
=back
@@ -3278,7 +3350,21 @@ C or C.
=item C
-C A comment to add along with this attachment.
+C or hash. A comment to add along with this attachment. If C
+is a hash, it has the following keys:
+
+=over
+
+=item C
+
+C The body of the comment.
+
+=item C
+
+C If set to true, the comment has Markdown structures; otherwise, it
+is an ordinary text.
+
+=back
=item C
@@ -3356,6 +3442,10 @@ the type id value to update or add a flag.
The flag type is inactive and cannot be used to create new flags.
+=item 140 (Markdown Disabled)
+
+You tried to set the C flag of the comment to true but the Markdown feature is not enabled.
+
=item 600 (Attachment Too Large)
You tried to attach a file that was larger than Bugzilla will accept.
@@ -3391,6 +3481,8 @@ You set the "data" field to an empty string.
=item REST API call added in Bugzilla B<5.0>.
+=item C added in Bugzilla B<5.0>.
+
=back
=back
@@ -3437,7 +3529,21 @@ attachment.
=item C
-C An optional comment to add to the attachment's bug.
+C or hash: An optional comment to add to the attachment's bug. If C is
+a hash, it has the following keys:
+
+=over
+
+=item C
+
+C The body of the comment to be added.
+
+=item C
+
+C If set to true, the comment has Markdown structures; otherwise it is a normal
+text.
+
+=back
=item C
@@ -3586,6 +3692,11 @@ the type id value to update or add a flag.
The flag type is inactive and cannot be used to create new flags.
+=item 140 (Markdown Disabled)
+
+You tried to set the C flag of the C to true but Markdown feature is
+not enabled.
+
=item 601 (Invalid MIME Type)
You specified a C argument that was blank, not a valid
@@ -3646,6 +3757,9 @@ you did not set the C parameter.
=item C (boolean) - If set to true, the comment is private,
otherwise it is assumed to be public.
+=item C (boolean) - If set to true, the comment has Markdown
+structures, otherwise it is a normal text.
+
=item C (double) - Adds this many hours to the "Hours Worked"
on the bug. If you are not in the time tracking group, this value will
be ignored.
@@ -3687,6 +3801,11 @@ You tried to add a private comment, but don't have the necessary rights.
You tried to add a comment longer than the maximum allowed length
(65,535 characters).
+=item 140 (Markdown Disabled)
+
+You tried to set the C flag to true but the Markdown feature
+is not enabled.
+
=back
=item B
@@ -3709,6 +3828,8 @@ code of 32000.
=item REST API call added in Bugzilla B<5.0>.
+=item C option added in Bugzilla B<5.0>.
+
=back
=back
@@ -3753,9 +3874,29 @@ bugs you are updating.
=item C
-(string) The alias of the bug. You can only set this if you are modifying
-a single bug. If there is more than one bug specified in C, passing in
-a value for C will cause an error to be thrown.
+C These specify the aliases of a bug that can be used instead of a bug
+number when acessing this bug. To set these, you should pass a hash as the
+value. The hash may contain the following fields:
+
+=over
+
+=item C An array of Cs. Aliases to add to this field.
+
+=item C An array of Cs. Aliases to remove from this field.
+If the aliases are not already in the field, they will be ignored.
+
+=item C An array of Cs. An exact set of aliases to set this
+field to, overriding the current value. If you specify C, then C
+and C will be ignored.
+
+=back
+
+You can only set this if you are modifying a single bug. If there is more
+than one bug specified in C, passing in a value for C will cause
+an error to be thrown.
+
+For backwards compatibility, you can also specify a single string. This will
+be treated as if you specified the set key above.
=item C
@@ -4074,7 +4215,8 @@ C The id of the bug that was updated.
=item C
-C The alias of the bug that was updated, if this bug has an alias.
+C of Cs The aliases of the bug that was updated, if this bug
+has any alias.
=item C
@@ -4108,7 +4250,7 @@ Here's an example of what a return value might look like:
bugs => [
{
id => 123,
- alias => 'foo',
+ alias => [ 'foo' ],
last_change_time => '2010-01-01T12:34:56',
changes => {
status => {
diff --git a/mozilla/webtools/bugzilla/Bugzilla/WebService/BugUserLastVisit.pm b/mozilla/webtools/bugzilla/Bugzilla/WebService/BugUserLastVisit.pm
index 71b637fef65..a29d2633b83 100644
--- a/mozilla/webtools/bugzilla/Bugzilla/WebService/BugUserLastVisit.pm
+++ b/mozilla/webtools/bugzilla/Bugzilla/WebService/BugUserLastVisit.pm
@@ -9,6 +9,7 @@ package Bugzilla::WebService::BugUserLastVisit;
use 5.10.1;
use strict;
+use warnings;
use parent qw(Bugzilla::WebService);
@@ -68,10 +69,10 @@ sub get {
$user->visible_bugs([grep /^[0-9]$/, @$ids]);
}
- my @last_visits = @{ $user->last_visits };
+ my @last_visits = @{ $user->last_visited };
if ($ids) {
- # remove bugs that we arn't interested in if ids is passed in.
+ # remove bugs that we are not interested in if ids is passed in.
my %id_set = map { ($_ => 1) } @$ids;
@last_visits = grep { $id_set{ $_->bug_id } } @last_visits;
}
@@ -166,20 +167,13 @@ B
=item B
-Get the last visited timestamp for one or more specified bug ids or get a
-list of the last 20 visited bugs and their timestamps.
+Get the last visited timestamp for one or more specified bug ids.
=item B
To return the last visited timestamp for a single bug id:
-GET /rest/bug_visit/
-
-To return more than one bug timestamp or the last 20:
-
-GET /rest/bug_visit
-
-The returned data format is the same as below.
+ GET /rest/bug_user_last_visit/
=item B
diff --git a/mozilla/webtools/bugzilla/Bugzilla/WebService/Bugzilla.pm b/mozilla/webtools/bugzilla/Bugzilla/WebService/Bugzilla.pm
index 6b5f9844ffc..8333f99c480 100644
--- a/mozilla/webtools/bugzilla/Bugzilla/WebService/Bugzilla.pm
+++ b/mozilla/webtools/bugzilla/Bugzilla/WebService/Bugzilla.pm
@@ -9,6 +9,7 @@ package Bugzilla::WebService::Bugzilla;
use 5.10.1;
use strict;
+use warnings;
use parent qw(Bugzilla::WebService);
use Bugzilla::Constants;
diff --git a/mozilla/webtools/bugzilla/Bugzilla/WebService/Classification.pm b/mozilla/webtools/bugzilla/Bugzilla/WebService/Classification.pm
index bbc967ce7ac..8e1b3ae8a6e 100644
--- a/mozilla/webtools/bugzilla/Bugzilla/WebService/Classification.pm
+++ b/mozilla/webtools/bugzilla/Bugzilla/WebService/Classification.pm
@@ -9,6 +9,7 @@ package Bugzilla::WebService::Classification;
use 5.10.1;
use strict;
+use warnings;
use parent qw (Bugzilla::WebService);
diff --git a/mozilla/webtools/bugzilla/Bugzilla/WebService/Component.pm b/mozilla/webtools/bugzilla/Bugzilla/WebService/Component.pm
new file mode 100644
index 00000000000..893e244b892
--- /dev/null
+++ b/mozilla/webtools/bugzilla/Bugzilla/WebService/Component.pm
@@ -0,0 +1,149 @@
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+#
+# This Source Code Form is "Incompatible With Secondary Licenses", as
+# defined by the Mozilla Public License, v. 2.0.
+
+package Bugzilla::WebService::Component;
+
+use 5.10.1;
+use strict;
+use warnings;
+
+use base qw(Bugzilla::WebService);
+
+use Bugzilla::Component;
+use Bugzilla::Constants;
+use Bugzilla::Error;
+use Bugzilla::WebService::Constants;
+use Bugzilla::WebService::Util qw(translate params_to_objects validate);
+
+use constant MAPPED_FIELDS => {
+ default_assignee => 'initialowner',
+ default_qa_contact => 'initialqacontact',
+ default_cc => 'initial_cc',
+ is_open => 'isactive',
+};
+
+sub create {
+ my ($self, $params) = @_;
+
+ my $user = Bugzilla->login(LOGIN_REQUIRED);
+
+ $user->in_group('editcomponents')
+ || scalar @{ $user->get_products_by_permission('editcomponents') }
+ || ThrowUserError('auth_failure', { group => 'editcomponents',
+ action => 'edit',
+ object => 'components' });
+
+ my $product = $user->check_can_admin_product($params->{product});
+
+ # Translate the fields
+ my $values = translate($params, MAPPED_FIELDS);
+ $values->{product} = $product;
+
+ # Create the component and return the newly created id.
+ my $component = Bugzilla::Component->create($values);
+ return { id => $self->type('int', $component->id) };
+}
+
+1;
+
+__END__
+
+=head1 NAME
+
+Bugzilla::Webservice::Component - The Component API
+
+=head1 DESCRIPTION
+
+This part of the Bugzilla API allows you to deal with the available product components.
+You will be able to get information about them as well as manipulate them.
+
+=head1 METHODS
+
+See L for a description of how parameters are passed,
+and what B, B, and B mean.
+
+=head1 Component Creation and Modification
+
+=head2 create
+
+B
+
+=over
+
+=item B
+
+This allows you to create a new component in Bugzilla.
+
+=item B
+
+Some params must be set, or an error will be thrown. These params are
+marked B.
+
+=over
+
+=item C
+
+B C The name of the new component.
+
+=item C
+
+B C The name of the product that the component must be
+added to. This product must already exist, and the user have the necessary
+permissions to edit components for it.
+
+=item C
+
+B C The description of the new component.
+
+=item C
+
+B C The login name of the default assignee of the component.
+
+=item C
+
+C An array of strings with each element representing one login name of the default CC list.
+
+=item C
+
+C The login name of the default QA contact for the component.
+
+=item C
+
+C 1 if you want to enable the component for bug creations. 0 otherwise. Default is 1.
+
+=back
+
+=item B
+
+A hash with one key: C. This will represent the ID of the newly-added
+component.
+
+=item B
+
+=over
+
+=item 304 (Authorization Failure)
+
+You are not authorized to create a new component.
+
+=item 1200 (Component already exists)
+
+The name that you specified for the new component already exists in the
+specified product.
+
+=back
+
+=item B
+
+=over
+
+=item Added in Bugzilla B<5.0>.
+
+=back
+
+=back
+
diff --git a/mozilla/webtools/bugzilla/Bugzilla/WebService/Constants.pm b/mozilla/webtools/bugzilla/Bugzilla/WebService/Constants.pm
index 2c21de15e8e..db50611cbf6 100644
--- a/mozilla/webtools/bugzilla/Bugzilla/WebService/Constants.pm
+++ b/mozilla/webtools/bugzilla/Bugzilla/WebService/Constants.pm
@@ -9,6 +9,7 @@ package Bugzilla::WebService::Constants;
use 5.10.1;
use strict;
+use warnings;
use parent qw(Exporter);
@@ -100,6 +101,7 @@ use constant WS_ERROR_CODE => {
comment_id_invalid => 111,
comment_too_long => 114,
comment_invalid_isprivate => 117,
+ markdown_disabled => 140,
# Comment tagging
comment_tag_disabled => 125,
comment_tag_invalid => 126,
@@ -141,7 +143,11 @@ use constant WS_ERROR_CODE => {
auth_invalid_email => 302,
extern_id_conflict => -303,
auth_failure => 304,
- password_current_too_short => 305,
+ password_too_short => 305,
+ password_not_complex => 305,
+ api_key_not_valid => 306,
+ api_key_revoked => 306,
+ auth_invalid_token => 307,
# Except, historically, AUTH_NODATA, which is 410.
login_required => 410,
@@ -200,6 +206,11 @@ use constant WS_ERROR_CODE => {
flag_type_sortkey_invalid => 1104,
flag_type_not_editable => 1105,
+ # Component errors are 1200-1300
+ component_already_exists => 1200,
+ component_is_last => 1201,
+ component_has_bugs => 1202,
+
# Errors thrown by the WebService itself. The ones that are negative
# conform to http://xmlrpc-epi.sourceforge.net/specs/rfc.fault_codes.php
xmlrpc_invalid_value => -32600,
@@ -279,6 +290,7 @@ sub WS_DISPATCH {
'Bugzilla' => 'Bugzilla::WebService::Bugzilla',
'Bug' => 'Bugzilla::WebService::Bug',
'Classification' => 'Bugzilla::WebService::Classification',
+ 'Component' => 'Bugzilla::WebService::Component',
'FlagType' => 'Bugzilla::WebService::FlagType',
'Group' => 'Bugzilla::WebService::Group',
'Product' => 'Bugzilla::WebService::Product',
diff --git a/mozilla/webtools/bugzilla/Bugzilla/WebService/FlagType.pm b/mozilla/webtools/bugzilla/Bugzilla/WebService/FlagType.pm
index b6b8aba8938..cf654e6592d 100644
--- a/mozilla/webtools/bugzilla/Bugzilla/WebService/FlagType.pm
+++ b/mozilla/webtools/bugzilla/Bugzilla/WebService/FlagType.pm
@@ -9,6 +9,7 @@ package Bugzilla::WebService::FlagType;
use 5.10.1;
use strict;
+use warnings;
use parent qw(Bugzilla::WebService);
use Bugzilla::Component;
diff --git a/mozilla/webtools/bugzilla/Bugzilla/WebService/Group.pm b/mozilla/webtools/bugzilla/Bugzilla/WebService/Group.pm
index d24d0539b0b..d0ee6fdbad9 100644
--- a/mozilla/webtools/bugzilla/Bugzilla/WebService/Group.pm
+++ b/mozilla/webtools/bugzilla/Bugzilla/WebService/Group.pm
@@ -9,6 +9,7 @@ package Bugzilla::WebService::Group;
use 5.10.1;
use strict;
+use warnings;
use parent qw(Bugzilla::WebService);
use Bugzilla::Constants;
@@ -101,8 +102,8 @@ sub get {
# Reject access if there is no sense in continuing.
my $user = Bugzilla->user;
- my $all_groups = $user->in_group('edituser') || $user->in_group('creategroups');
- if (!$all_groups && ! scalar(@{$user->bless_groups})) {
+ my $all_groups = $user->in_group('editusers') || $user->in_group('creategroups');
+ if (!$all_groups && !$user->can_bless) {
ThrowUserError('group_cannot_view');
}
diff --git a/mozilla/webtools/bugzilla/Bugzilla/WebService/Product.pm b/mozilla/webtools/bugzilla/Bugzilla/WebService/Product.pm
index 2def7788633..0e78836bf1a 100644
--- a/mozilla/webtools/bugzilla/Bugzilla/WebService/Product.pm
+++ b/mozilla/webtools/bugzilla/Bugzilla/WebService/Product.pm
@@ -9,6 +9,7 @@ package Bugzilla::WebService::Product;
use 5.10.1;
use strict;
+use warnings;
use parent qw(Bugzilla::WebService);
use Bugzilla::Product;
diff --git a/mozilla/webtools/bugzilla/Bugzilla/WebService/Server.pm b/mozilla/webtools/bugzilla/Bugzilla/WebService/Server.pm
index 89cb1a130ac..7950c7a3b92 100644
--- a/mozilla/webtools/bugzilla/Bugzilla/WebService/Server.pm
+++ b/mozilla/webtools/bugzilla/Bugzilla/WebService/Server.pm
@@ -9,6 +9,7 @@ package Bugzilla::WebService::Server;
use 5.10.1;
use strict;
+use warnings;
use Bugzilla::Error;
use Bugzilla::Util qw(datetime_from);
diff --git a/mozilla/webtools/bugzilla/Bugzilla/WebService/Server/JSONRPC.pm b/mozilla/webtools/bugzilla/Bugzilla/WebService/Server/JSONRPC.pm
index 5290caa5d08..6cda4748055 100644
--- a/mozilla/webtools/bugzilla/Bugzilla/WebService/Server/JSONRPC.pm
+++ b/mozilla/webtools/bugzilla/Bugzilla/WebService/Server/JSONRPC.pm
@@ -9,6 +9,7 @@ package Bugzilla::WebService::Server::JSONRPC;
use 5.10.1;
use strict;
+use warnings;
use Bugzilla::WebService::Server;
BEGIN {
@@ -80,7 +81,9 @@ sub response {
# Implement JSONP.
if (my $callback = $self->_bz_callback) {
my $content = $response->content;
- $response->content("$callback($content)");
+ # Prepend the JSONP response with /**/ in order to protect
+ # against possible encoding attacks (e.g., affecting Flash).
+ $response->content("/**/$callback($content)");
}
# Use $cgi->header properly instead of just printing text directly.
diff --git a/mozilla/webtools/bugzilla/Bugzilla/WebService/Server/REST.pm b/mozilla/webtools/bugzilla/Bugzilla/WebService/Server/REST.pm
index 2f1b80c45d5..83a796daf08 100644
--- a/mozilla/webtools/bugzilla/Bugzilla/WebService/Server/REST.pm
+++ b/mozilla/webtools/bugzilla/Bugzilla/WebService/Server/REST.pm
@@ -9,6 +9,7 @@ package Bugzilla::WebService::Server::REST;
use 5.10.1;
use strict;
+use warnings;
use parent qw(Bugzilla::WebService::Server::JSONRPC);
@@ -23,6 +24,7 @@ use Bugzilla::WebService::Util qw(taint_data fix_credentials);
use Bugzilla::WebService::Server::REST::Resources::Bug;
use Bugzilla::WebService::Server::REST::Resources::Bugzilla;
use Bugzilla::WebService::Server::REST::Resources::Classification;
+use Bugzilla::WebService::Server::REST::Resources::Component;
use Bugzilla::WebService::Server::REST::Resources::FlagType;
use Bugzilla::WebService::Server::REST::Resources::Group;
use Bugzilla::WebService::Server::REST::Resources::Product;
@@ -335,11 +337,28 @@ sub _retrieve_json_params {
my $params = {};
%{$params} = %{ Bugzilla->input_params };
- # First add any params we were able to pull out of the path
- # based on the resource regexp
- %{$params} = (%{$params}, %{$self->bz_rest_params}) if $self->bz_rest_params;
+ # First add any parameters we were able to pull out of the path
+ # based on the resource regexp and combine with the normal URL
+ # parameters.
+ if (my $rest_params = $self->bz_rest_params) {
+ foreach my $param (keys %$rest_params) {
+ if (!exists $params->{$param}) {
+ $params->{$param} = $rest_params->{$param};
+ next;
+ }
+ my @values = ref $rest_params->{$param}
+ ? @{ $rest_params->{$param} }
+ : ($rest_params->{$param});
+ if (ref $params->{$param}) {
+ push(@{ $params->{$param} }, @values);
+ }
+ else {
+ $params->{$param} = [ $params->{$param}, @values ];
+ }
+ }
+ }
- # Merge any additional query key/values with $obj->{params} if not a GET request
+ # Merge any additional query key/values from the request body if non-GET.
# We do this manually cause CGI.pm doesn't understand JSON strings.
if ($self->request->method ne 'GET') {
my $extra_params = {};
@@ -350,14 +369,6 @@ sub _retrieve_json_params {
ThrowUserError('json_rpc_invalid_params', { err_msg => $@ });
}
}
-
- # Allow parameters in the query string if request was not GET.
- # Note: query string parameters will override any matching params
- # also specified in the request body.
- foreach my $param ($self->cgi->url_param()) {
- $extra_params->{$param} = $self->cgi->url_param($param);
- }
-
%{$params} = (%{$params}, %{$extra_params}) if %{$extra_params};
}
diff --git a/mozilla/webtools/bugzilla/Bugzilla/WebService/Server/REST/Resources/Bug.pm b/mozilla/webtools/bugzilla/Bugzilla/WebService/Server/REST/Resources/Bug.pm
index 7ab111d86ce..3fa8b65cf5d 100644
--- a/mozilla/webtools/bugzilla/Bugzilla/WebService/Server/REST/Resources/Bug.pm
+++ b/mozilla/webtools/bugzilla/Bugzilla/WebService/Server/REST/Resources/Bug.pm
@@ -9,6 +9,7 @@ package Bugzilla::WebService::Server::REST::Resources::Bug;
use 5.10.1;
use strict;
+use warnings;
use Bugzilla::WebService::Constants;
use Bugzilla::WebService::Bug;
@@ -28,6 +29,11 @@ sub _rest_resources {
status_code => STATUS_CREATED
}
},
+ qr{^/bug/$}, {
+ GET => {
+ method => 'get'
+ }
+ },
qr{^/bug/([^/]+)$}, {
GET => {
method => 'get',
diff --git a/mozilla/webtools/bugzilla/Bugzilla/WebService/Server/REST/Resources/Bugzilla.pm b/mozilla/webtools/bugzilla/Bugzilla/WebService/Server/REST/Resources/Bugzilla.pm
index 1c86f77bce3..a8f3f9330ed 100644
--- a/mozilla/webtools/bugzilla/Bugzilla/WebService/Server/REST/Resources/Bugzilla.pm
+++ b/mozilla/webtools/bugzilla/Bugzilla/WebService/Server/REST/Resources/Bugzilla.pm
@@ -9,6 +9,7 @@ package Bugzilla::WebService::Server::REST::Resources::Bugzilla;
use 5.10.1;
use strict;
+use warnings;
use Bugzilla::WebService::Constants;
use Bugzilla::WebService::Bugzilla;
diff --git a/mozilla/webtools/bugzilla/Bugzilla/WebService/Server/REST/Resources/Classification.pm b/mozilla/webtools/bugzilla/Bugzilla/WebService/Server/REST/Resources/Classification.pm
index 2bbc05c72c8..3f8d32a0361 100644
--- a/mozilla/webtools/bugzilla/Bugzilla/WebService/Server/REST/Resources/Classification.pm
+++ b/mozilla/webtools/bugzilla/Bugzilla/WebService/Server/REST/Resources/Classification.pm
@@ -9,6 +9,7 @@ package Bugzilla::WebService::Server::REST::Resources::Classification;
use 5.10.1;
use strict;
+use warnings;
use Bugzilla::WebService::Constants;
use Bugzilla::WebService::Classification;
diff --git a/mozilla/webtools/bugzilla/Bugzilla/WebService/Server/REST/Resources/Component.pm b/mozilla/webtools/bugzilla/Bugzilla/WebService/Server/REST/Resources/Component.pm
new file mode 100644
index 00000000000..198c0933294
--- /dev/null
+++ b/mozilla/webtools/bugzilla/Bugzilla/WebService/Server/REST/Resources/Component.pm
@@ -0,0 +1,48 @@
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+#
+# This Source Code Form is "Incompatible With Secondary Licenses", as
+# defined by the Mozilla Public License, v. 2.0.
+
+package Bugzilla::WebService::Server::REST::Resources::Component;
+
+use 5.10.1;
+use strict;
+use warnings;
+
+use Bugzilla::WebService::Constants;
+use Bugzilla::WebService::Component;
+
+use Bugzilla::Error;
+
+BEGIN {
+ *Bugzilla::WebService::Component::rest_resources = \&_rest_resources;
+};
+
+sub _rest_resources {
+ my $rest_resources = [
+ qr{^/component$}, {
+ POST => {
+ method => 'create',
+ success_code => STATUS_CREATED
+ }
+ },
+ ];
+ return $rest_resources;
+}
+
+1;
+
+__END__
+
+=head1 NAME
+
+Bugzilla::Webservice::Server::REST::Resources::Component - The Component REST API
+
+=head1 DESCRIPTION
+
+This part of the Bugzilla REST API allows you create Components.
+
+See L for more details on how to use this
+part of the REST API.
diff --git a/mozilla/webtools/bugzilla/Bugzilla/WebService/Server/REST/Resources/FlagType.pm b/mozilla/webtools/bugzilla/Bugzilla/WebService/Server/REST/Resources/FlagType.pm
index 1de5b126453..21dad0f73a8 100644
--- a/mozilla/webtools/bugzilla/Bugzilla/WebService/Server/REST/Resources/FlagType.pm
+++ b/mozilla/webtools/bugzilla/Bugzilla/WebService/Server/REST/Resources/FlagType.pm
@@ -9,6 +9,7 @@ package Bugzilla::WebService::Server::REST::Resources::FlagType;
use 5.10.1;
use strict;
+use warnings;
use Bugzilla::WebService::Constants;
use Bugzilla::WebService::FlagType;
diff --git a/mozilla/webtools/bugzilla/Bugzilla/WebService/Server/REST/Resources/Group.pm b/mozilla/webtools/bugzilla/Bugzilla/WebService/Server/REST/Resources/Group.pm
index 62f8af6dd62..b052e384b47 100644
--- a/mozilla/webtools/bugzilla/Bugzilla/WebService/Server/REST/Resources/Group.pm
+++ b/mozilla/webtools/bugzilla/Bugzilla/WebService/Server/REST/Resources/Group.pm
@@ -9,6 +9,7 @@ package Bugzilla::WebService::Server::REST::Resources::Group;
use 5.10.1;
use strict;
+use warnings;
use Bugzilla::WebService::Constants;
use Bugzilla::WebService::Group;
diff --git a/mozilla/webtools/bugzilla/Bugzilla/WebService/Server/REST/Resources/Product.pm b/mozilla/webtools/bugzilla/Bugzilla/WebService/Server/REST/Resources/Product.pm
index fef7c6174c9..607b94b538a 100644
--- a/mozilla/webtools/bugzilla/Bugzilla/WebService/Server/REST/Resources/Product.pm
+++ b/mozilla/webtools/bugzilla/Bugzilla/WebService/Server/REST/Resources/Product.pm
@@ -9,6 +9,7 @@ package Bugzilla::WebService::Server::REST::Resources::Product;
use 5.10.1;
use strict;
+use warnings;
use Bugzilla::WebService::Constants;
use Bugzilla::WebService::Product;
diff --git a/mozilla/webtools/bugzilla/Bugzilla/WebService/Server/REST/Resources/User.pm b/mozilla/webtools/bugzilla/Bugzilla/WebService/Server/REST/Resources/User.pm
index 539a9313a52..a83109e7370 100644
--- a/mozilla/webtools/bugzilla/Bugzilla/WebService/Server/REST/Resources/User.pm
+++ b/mozilla/webtools/bugzilla/Bugzilla/WebService/Server/REST/Resources/User.pm
@@ -9,6 +9,7 @@ package Bugzilla::WebService::Server::REST::Resources::User;
use 5.10.1;
use strict;
+use warnings;
use Bugzilla::WebService::Constants;
use Bugzilla::WebService::User;
diff --git a/mozilla/webtools/bugzilla/Bugzilla/WebService/Server/XMLRPC.pm b/mozilla/webtools/bugzilla/Bugzilla/WebService/Server/XMLRPC.pm
index 40c66a8f95b..8f9070ae76b 100644
--- a/mozilla/webtools/bugzilla/Bugzilla/WebService/Server/XMLRPC.pm
+++ b/mozilla/webtools/bugzilla/Bugzilla/WebService/Server/XMLRPC.pm
@@ -9,6 +9,7 @@ package Bugzilla::WebService::Server::XMLRPC;
use 5.10.1;
use strict;
+use warnings;
use XMLRPC::Transport::HTTP;
use Bugzilla::WebService::Server;
@@ -107,6 +108,7 @@ package Bugzilla::XMLRPC::Deserializer;
use 5.10.1;
use strict;
+use warnings;
# We can't use "use parent" because XMLRPC::Serializer doesn't return
# a true value.
@@ -205,6 +207,7 @@ package Bugzilla::XMLRPC::SOM;
use 5.10.1;
use strict;
+use warnings;
use XMLRPC::Lite;
our @ISA = qw(XMLRPC::SOM);
@@ -231,6 +234,7 @@ package Bugzilla::XMLRPC::Serializer;
use 5.10.1;
use strict;
+use warnings;
use Scalar::Util qw(blessed reftype);
# We can't use "use parent" because XMLRPC::Serializer doesn't return
diff --git a/mozilla/webtools/bugzilla/Bugzilla/WebService/User.pm b/mozilla/webtools/bugzilla/Bugzilla/WebService/User.pm
index f05b2b247f8..4c8af7f6c2d 100644
--- a/mozilla/webtools/bugzilla/Bugzilla/WebService/User.pm
+++ b/mozilla/webtools/bugzilla/Bugzilla/WebService/User.pm
@@ -9,6 +9,7 @@ package Bugzilla::WebService::User;
use 5.10.1;
use strict;
+use warnings;
use parent qw(Bugzilla::WebService);
@@ -432,9 +433,13 @@ where applicable.
=head1 Logging In and Out
+These method are now deprecated, and will be removed in the release after
+Bugzilla 5.0. The correct way of use these REST and RPC calls is noted in
+L
+
=head2 login
-B
+B
=over
@@ -499,7 +504,9 @@ creates a login cookie.
=item C was added in Bugzilla B<5.0>.
-=item C was added in Bugzilla B<5.0>.
+=item C was added in Bugzilla B<4.4.3>.
+
+=item This function will be removed in the release after Bugzilla 5.0, in favour of API keys.
=back
@@ -507,7 +514,7 @@ creates a login cookie.
=head2 logout
-B
+B
=over
@@ -525,7 +532,7 @@ Log out the user. Does nothing if there is no user logged in.
=head2 valid_login
-B
+B
=over
@@ -563,6 +570,8 @@ for the provided username.
=item Added in Bugzilla B<5.0>.
+=item This function will be removed in the release after Bugzilla 5.0, in favour of API keys.
+
=back
=back
diff --git a/mozilla/webtools/bugzilla/Bugzilla/WebService/Util.pm b/mozilla/webtools/bugzilla/Bugzilla/WebService/Util.pm
index 26558fc6ac0..e2bc780026b 100644
--- a/mozilla/webtools/bugzilla/Bugzilla/WebService/Util.pm
+++ b/mozilla/webtools/bugzilla/Bugzilla/WebService/Util.pm
@@ -9,6 +9,7 @@ package Bugzilla::WebService::Util;
use 5.10.1;
use strict;
+use warnings;
use Bugzilla::Flag;
use Bugzilla::FlagType;
@@ -268,6 +269,11 @@ sub fix_credentials {
$params->{'Bugzilla_login'} = $params->{'login'};
$params->{'Bugzilla_password'} = $params->{'password'};
}
+ # Allow user to pass api_key=12345678 as a convenience which becomes
+ # "Bugzilla_api_key" which is what the auth code looks for.
+ if (exists $params->{api_key}) {
+ $params->{Bugzilla_api_key} = delete $params->{api_key};
+ }
# Allow user to pass token=12345678 as a convenience which becomes
# "Bugzilla_token" which is what the auth code looks for.
if (exists $params->{'token'}) {
diff --git a/mozilla/webtools/bugzilla/Bugzilla/Whine.pm b/mozilla/webtools/bugzilla/Bugzilla/Whine.pm
index 488127dfa9d..eeaea6da4e0 100644
--- a/mozilla/webtools/bugzilla/Bugzilla/Whine.pm
+++ b/mozilla/webtools/bugzilla/Bugzilla/Whine.pm
@@ -9,6 +9,7 @@ package Bugzilla::Whine;
use 5.10.1;
use strict;
+use warnings;
use parent qw(Bugzilla::Object);
diff --git a/mozilla/webtools/bugzilla/Bugzilla/Whine/Query.pm b/mozilla/webtools/bugzilla/Bugzilla/Whine/Query.pm
index a4fd54539a5..b2a2c9e0734 100644
--- a/mozilla/webtools/bugzilla/Bugzilla/Whine/Query.pm
+++ b/mozilla/webtools/bugzilla/Bugzilla/Whine/Query.pm
@@ -9,6 +9,7 @@ package Bugzilla::Whine::Query;
use 5.10.1;
use strict;
+use warnings;
use parent qw(Bugzilla::Object);
diff --git a/mozilla/webtools/bugzilla/Bugzilla/Whine/Schedule.pm b/mozilla/webtools/bugzilla/Bugzilla/Whine/Schedule.pm
index f16c629af48..11f0bf16f1f 100644
--- a/mozilla/webtools/bugzilla/Bugzilla/Whine/Schedule.pm
+++ b/mozilla/webtools/bugzilla/Bugzilla/Whine/Schedule.pm
@@ -9,6 +9,7 @@ package Bugzilla::Whine::Schedule;
use 5.10.1;
use strict;
+use warnings;
use parent qw(Bugzilla::Object);
diff --git a/mozilla/webtools/bugzilla/admin.cgi b/mozilla/webtools/bugzilla/admin.cgi
index 70a6aa20ec8..1dc9b2c1bd3 100755
--- a/mozilla/webtools/bugzilla/admin.cgi
+++ b/mozilla/webtools/bugzilla/admin.cgi
@@ -1,4 +1,4 @@
-#!/usr/bin/perl -wT
+#!/usr/bin/perl -T
# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
@@ -8,6 +8,8 @@
use 5.10.1;
use strict;
+use warnings;
+
use lib qw(. lib);
use Bugzilla;
diff --git a/mozilla/webtools/bugzilla/attachment.cgi b/mozilla/webtools/bugzilla/attachment.cgi
index 94510fb190f..61e6f58d8df 100755
--- a/mozilla/webtools/bugzilla/attachment.cgi
+++ b/mozilla/webtools/bugzilla/attachment.cgi
@@ -1,4 +1,4 @@
-#!/usr/bin/perl -wT
+#!/usr/bin/perl -T
# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
@@ -8,6 +8,8 @@
use 5.10.1;
use strict;
+use warnings;
+
use lib qw(. lib);
use Bugzilla;
@@ -24,6 +26,7 @@ use Bugzilla::Attachment::PatchReader;
use Bugzilla::Token;
use Encode qw(encode find_encoding);
+use Cwd qw(realpath);
# For most scripts we don't make $cgi and $template global variables. But
# when preparing Bugzilla for mod_perl, this script used these
@@ -188,19 +191,6 @@ sub validateFormat {
return $format;
}
-# Validates context of a diff/interdiff. Will throw an error if the context
-# is not number, "file" or "patch". Returns the validated, detainted context.
-sub validateContext
-{
- my $context = $cgi->param('context') || "patch";
- if ($context ne "file" && $context ne "patch") {
- detaint_natural($context)
- || ThrowUserError("invalid_context", { context => $cgi->param('context') });
- }
-
- return $context;
-}
-
# Gets the attachment object(s) generated by validateID, while ensuring
# attachbase and token authentication is used when required.
sub get_attachment {
@@ -372,9 +362,24 @@ sub view {
}
}
}
+ my $sendfile_header = {};
+ my $sendfile_param = Bugzilla->params->{'xsendfile_header'};
+ if ($attachment->is_on_filesystem && $sendfile_param ne 'off') {
+ # attachment is on filesystem and Admin turned on feature.
+ # This means we can let webserver handle the request and stream the file
+ # for us. This is called the X-Sendfile feature. see bug 1073264.
+ my $attachment_path = realpath($attachment->_get_local_filename());
+ $sendfile_header->{$sendfile_param} = $attachment_path;
+ }
print $cgi->header(-type=>"$contenttype; name=\"$filename\"",
-content_disposition=> "$disposition; filename=\"$filename\"",
- -content_length => $attachment->datasize);
+ -content_length => $attachment->datasize,
+ %$sendfile_header);
+ if ($attachment->is_on_filesystem && $sendfile_param ne 'off') {
+ # in case of X-Sendfile, we do not print the data.
+ # that is handled directly by the webserver.
+ return;
+ }
disable_utf8();
print $attachment->data;
}
@@ -389,17 +394,15 @@ sub interdiff {
$old_attachment = validateID('oldid');
$new_attachment = validateID('newid');
}
- my $context = validateContext();
Bugzilla::Attachment::PatchReader::process_interdiff(
- $old_attachment, $new_attachment, $format, $context);
+ $old_attachment, $new_attachment, $format);
}
sub diff {
# Retrieve and validate parameters
my $format = validateFormat('html', 'raw');
my $attachment = $format eq 'raw' ? get_attachment() : validateID();
- my $context = validateContext();
# If it is not a patch, view normally.
if (!$attachment->ispatch) {
@@ -407,7 +410,7 @@ sub diff {
return;
}
- Bugzilla::Attachment::PatchReader::process_diff($attachment, $format, $context);
+ Bugzilla::Attachment::PatchReader::process_diff($attachment, $format);
}
# Display all attachments for a given bug in a series of IFRAMEs within one
@@ -513,13 +516,14 @@ sub insert {
# Get the filehandle of the attachment.
my $data_fh = $cgi->upload('data');
+ my $attach_text = $cgi->param('attach_text');
my $attachment = Bugzilla::Attachment->create(
{bug => $bug,
creation_ts => $timestamp,
- data => scalar $cgi->param('attach_text') || $data_fh,
+ data => $attach_text || $data_fh,
description => scalar $cgi->param('description'),
- filename => $cgi->param('attach_text') ? "file_$bugid.txt" : scalar $cgi->upload('data'),
+ filename => $attach_text ? "file_$bugid.txt" : $data_fh,
ispatch => scalar $cgi->param('ispatch'),
isprivate => scalar $cgi->param('isprivate'),
mimetype => $content_type,
@@ -536,7 +540,6 @@ sub insert {
my ($flags, $new_flags) = Bugzilla::Flag->extract_flags_from_cgi(
$bug, $attachment, $vars, SKIP_REQUESTEE_ON_ERROR);
$attachment->set_flags($flags, $new_flags);
- $attachment->update($timestamp);
# Insert a comment about the new attachment into the database.
my $comment = $cgi->param('comment');
@@ -545,45 +548,50 @@ sub insert {
type => CMT_ATTACHMENT_CREATED,
extra_data => $attachment->id });
- # Assign the bug to the user, if they are allowed to take it
- my $owner = "";
- if ($cgi->param('takebug') && $user->in_group('editbugs', $bug->product_id)) {
- # When taking a bug, we have to follow the workflow.
- my $bug_status = $cgi->param('bug_status') || '';
- ($bug_status) = grep {$_->name eq $bug_status} @{$bug->status->can_change_to};
+ # Assign the bug to the user, if they are allowed to take it
+ my $owner = "";
+ if ($cgi->param('takebug') && $user->in_group('editbugs', $bug->product_id)) {
+ # When taking a bug, we have to follow the workflow.
+ my $bug_status = $cgi->param('bug_status') || '';
+ ($bug_status) = grep { $_->name eq $bug_status }
+ @{ $bug->status->can_change_to };
- if ($bug_status && $bug_status->is_open
- && ($bug_status->name ne 'UNCONFIRMED'
- || $bug->product_obj->allows_unconfirmed))
- {
- $bug->set_bug_status($bug_status->name);
- $bug->clear_resolution();
- }
- # Make sure the person we are taking the bug from gets mail.
- $owner = $bug->assigned_to->login;
- $bug->set_assigned_to($user);
- }
+ if ($bug_status && $bug_status->is_open
+ && ($bug_status->name ne 'UNCONFIRMED'
+ || $bug->product_obj->allows_unconfirmed))
+ {
+ $bug->set_bug_status($bug_status->name);
+ $bug->clear_resolution();
+ }
+ # Make sure the person we are taking the bug from gets mail.
+ $owner = $bug->assigned_to->login;
+ $bug->set_assigned_to($user);
+ }
- $bug->add_cc($user) if $cgi->param('addselfcc');
- $bug->update($timestamp);
+ $bug->add_cc($user) if $cgi->param('addselfcc');
+ $bug->update($timestamp);
- $dbh->bz_commit_transaction;
+ # We have to update the attachment after updating the bug, to ensure new
+ # comments are available.
+ $attachment->update($timestamp);
- # Define the variables and functions that will be passed to the UI template.
- $vars->{'attachment'} = $attachment;
- # We cannot reuse the $bug object as delta_ts has eventually been updated
- # since the object was created.
- $vars->{'bugs'} = [new Bugzilla::Bug($bugid)];
- $vars->{'header_done'} = 1;
- $vars->{'contenttypemethod'} = $cgi->param('contenttypemethod');
+ $dbh->bz_commit_transaction;
- my $recipients = { 'changer' => $user, 'owner' => $owner };
- $vars->{'sent_bugmail'} = Bugzilla::BugMail::Send($bugid, $recipients);
+ # Define the variables and functions that will be passed to the UI template.
+ $vars->{'attachment'} = $attachment;
+ # We cannot reuse the $bug object as delta_ts has eventually been updated
+ # since the object was created.
+ $vars->{'bugs'} = [new Bugzilla::Bug($bugid)];
+ $vars->{'header_done'} = 1;
+ $vars->{'contenttypemethod'} = $cgi->param('contenttypemethod');
- print $cgi->header();
- # Generate and return the UI (HTML page) from the appropriate template.
- $template->process("attachment/created.html.tmpl", $vars)
- || ThrowTemplateError($template->error());
+ my $recipients = { 'changer' => $user, 'owner' => $owner };
+ $vars->{'sent_bugmail'} = Bugzilla::BugMail::Send($bugid, $recipients);
+
+ print $cgi->header();
+ # Generate and return the UI (HTML page) from the appropriate template.
+ $template->process("attachment/created.html.tmpl", $vars)
+ || ThrowTemplateError($template->error());
}
# Displays a form for editing attachment properties.
@@ -591,25 +599,25 @@ sub insert {
# is private and the user does not belong to the insider group.
# Validations are done later when the user submits changes.
sub edit {
- my $attachment = validateID();
+ my $attachment = validateID();
- my $bugattachments =
- Bugzilla::Attachment->get_attachments_by_bug($attachment->bug);
+ my $bugattachments =
+ Bugzilla::Attachment->get_attachments_by_bug($attachment->bug);
- my $any_flags_requesteeble =
- grep { $_->is_requestable && $_->is_requesteeble } @{$attachment->flag_types};
- # Useful in case a flagtype is no longer requestable but a requestee
- # has been set before we turned off that bit.
- $any_flags_requesteeble ||= grep { $_->requestee_id } @{$attachment->flags};
- $vars->{'any_flags_requesteeble'} = $any_flags_requesteeble;
- $vars->{'attachment'} = $attachment;
- $vars->{'attachments'} = $bugattachments;
+ my $any_flags_requesteeble = grep { $_->is_requestable && $_->is_requesteeble }
+ @{ $attachment->flag_types };
+ # Useful in case a flagtype is no longer requestable but a requestee
+ # has been set before we turned off that bit.
+ $any_flags_requesteeble ||= grep { $_->requestee_id } @{ $attachment->flags };
+ $vars->{'any_flags_requesteeble'} = $any_flags_requesteeble;
+ $vars->{'attachment'} = $attachment;
+ $vars->{'attachments'} = $bugattachments;
- print $cgi->header();
+ print $cgi->header();
- # Generate and return the UI (HTML page) from the appropriate template.
- $template->process("attachment/edit.html.tmpl", $vars)
- || ThrowTemplateError($template->error());
+ # Generate and return the UI (HTML page) from the appropriate template.
+ $template->process("attachment/edit.html.tmpl", $vars)
+ || ThrowTemplateError($template->error());
}
# Updates an attachment record. Only users with "editbugs" privileges,
@@ -711,6 +719,11 @@ sub update {
# Figure out when the changes were made.
my $timestamp = $dbh->selectrow_array('SELECT LOCALTIMESTAMP(0)');
+ # Commit the comment, if any.
+ # This has to happen before updating the attachment, to ensure new comments
+ # are available to $attachment->update.
+ $bug->update($timestamp);
+
if ($can_edit) {
my $changes = $attachment->update($timestamp);
# If there are changes, we updated delta_ts in the DB. We have to
@@ -718,9 +731,6 @@ sub update {
$bug->{delta_ts} = $timestamp if scalar(keys %$changes);
}
- # Commit the comment, if any.
- $bug->update($timestamp);
-
# Commit the transaction now that we are finished updating the database.
$dbh->bz_commit_transaction();
diff --git a/mozilla/webtools/bugzilla/buglist.cgi b/mozilla/webtools/bugzilla/buglist.cgi
index d88939171fd..daee34c9bc6 100755
--- a/mozilla/webtools/bugzilla/buglist.cgi
+++ b/mozilla/webtools/bugzilla/buglist.cgi
@@ -1,4 +1,4 @@
-#!/usr/bin/perl -wT
+#!/usr/bin/perl -T
# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
@@ -8,6 +8,8 @@
use 5.10.1;
use strict;
+use warnings;
+
use lib qw(. lib);
use Bugzilla;
@@ -279,6 +281,37 @@ sub GetGroups {
return [values %legal_groups];
}
+sub _get_common_flag_types {
+ my $component_ids = shift;
+ my $user = Bugzilla->user;
+
+ # Get all the different components in the bug list
+ my $components = Bugzilla::Component->new_from_list($component_ids);
+ my %flag_types;
+ my @flag_types_ids;
+ foreach my $component (@$components) {
+ foreach my $flag_type (@{$component->flag_types->{'bug'}}) {
+ push @flag_types_ids, $flag_type->id;
+ $flag_types{$flag_type->id} = $flag_type;
+ }
+ }
+
+ # We only want flags that appear in all components
+ my %common_flag_types;
+ foreach my $id (keys %flag_types) {
+ my $flag_type_count = scalar grep { $_ == $id } @flag_types_ids;
+ $common_flag_types{$id} = $flag_types{$id}
+ if $flag_type_count == scalar @$components;
+ }
+
+ # We only show flags that a user can request.
+ my @show_flag_types
+ = grep { $user->can_request_flag($_) } values %common_flag_types;
+ my $any_flags_requesteeble = grep { $_->is_requesteeble } @show_flag_types;
+
+ return(\@show_flag_types, $any_flags_requesteeble);
+}
+
################################################################################
# Command Execution
################################################################################
@@ -508,7 +541,6 @@ if (grep('relevance', @displaycolumns) && !$fulltext) {
@displaycolumns = grep($_ ne 'relevance', @displaycolumns);
}
-
################################################################################
# Select Column Determination
################################################################################
@@ -549,6 +581,7 @@ foreach my $col (@displaycolumns) {
# has for modifying the bugs.
if ($dotweak) {
push(@selectcolumns, "bug_status") if !grep($_ eq 'bug_status', @selectcolumns);
+ push(@selectcolumns, "bugs.component_id");
}
if ($format->{'extension'} eq 'ics') {
@@ -751,9 +784,10 @@ my $time_info = { 'estimated_time' => 0,
'time_present' => ($estimated_time || $remaining_time ||
$actual_time || $percentage_complete),
};
-
+
my $bugowners = {};
my $bugproducts = {};
+my $bugcomponentids = {};
my $bugcomponents = {};
my $bugstatuses = {};
my @bugidlist;
@@ -787,6 +821,7 @@ foreach my $row (@$data) {
# Record the assignee, product, and status in the big hashes of those things.
$bugowners->{$bug->{'assigned_to'}} = 1 if $bug->{'assigned_to'};
$bugproducts->{$bug->{'product'}} = 1 if $bug->{'product'};
+ $bugcomponentids->{$bug->{'bugs.component_id'}} = 1 if $bug->{'bugs.component_id'};
$bugcomponents->{$bug->{'component'}} = 1 if $bug->{'component'};
$bugstatuses->{$bug->{'bug_status'}} = 1 if $bug->{'bug_status'};
@@ -910,7 +945,7 @@ if (scalar(@products) == 1) {
# This is used in the "Zarroo Boogs" case.
elsif (my @product_input = $cgi->param('product')) {
if (scalar(@product_input) == 1 and $product_input[0] ne '') {
- $one_product = Bugzilla::Product->new({ name => $cgi->param('product'), cache => 1 });
+ $one_product = Bugzilla::Product->new({ name => $product_input[0], cache => 1 });
}
}
# We only want the template to use it if the user can actually
@@ -954,6 +989,9 @@ if ($dotweak && scalar @bugs) {
$vars->{'severities'} = get_legal_field_values('bug_severity');
$vars->{'resolutions'} = get_legal_field_values('resolution');
+ ($vars->{'flag_types'}, $vars->{any_flags_requesteeble})
+ = _get_common_flag_types([keys %$bugcomponentids]);
+
# Convert bug statuses to their ID.
my @bug_statuses = map {$dbh->quote($_)} keys %$bugstatuses;
my $bug_status_ids =
diff --git a/mozilla/webtools/bugzilla/chart.cgi b/mozilla/webtools/bugzilla/chart.cgi
index 015077650f0..96ac9e1cf70 100755
--- a/mozilla/webtools/bugzilla/chart.cgi
+++ b/mozilla/webtools/bugzilla/chart.cgi
@@ -1,4 +1,4 @@
-#!/usr/bin/perl -wT
+#!/usr/bin/perl -T
# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
@@ -29,6 +29,8 @@
use 5.10.1;
use strict;
+use warnings;
+
use lib qw(. lib);
use Bugzilla;
diff --git a/mozilla/webtools/bugzilla/checksetup.pl b/mozilla/webtools/bugzilla/checksetup.pl
index 145faf04e30..50ca8bda878 100755
--- a/mozilla/webtools/bugzilla/checksetup.pl
+++ b/mozilla/webtools/bugzilla/checksetup.pl
@@ -1,4 +1,4 @@
-#!/usr/bin/perl -w
+#!/usr/bin/perl
# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
@@ -12,8 +12,10 @@
# Initialization
######################################################################
-use strict;
use 5.10.1;
+use strict;
+use warnings;
+
use File::Basename;
use Getopt::Long qw(:config bundling);
use Pod::Usage;
@@ -107,7 +109,7 @@ my $lc_hash = Bugzilla->localconfig;
# At this point, localconfig is defined and is readable. So we know
# everything we need to create the DB. We have to create it early,
-# because some data required to populate data/params is stored in the DB.
+# because some data required to populate data/params.json is stored in the DB.
Bugzilla::DB::bz_check_requirements(!$silent);
Bugzilla::DB::bz_create_database() if $lc_hash->{'db_check'};
@@ -362,7 +364,7 @@ L.
=item 9
-Updates the system parameters (stored in F), using
+Updates the system parameters (stored in F), using
L.
=item 10
diff --git a/mozilla/webtools/bugzilla/clean-bug-user-last-visit.pl b/mozilla/webtools/bugzilla/clean-bug-user-last-visit.pl
index 9884b7c48fb..57486bfed8e 100644
--- a/mozilla/webtools/bugzilla/clean-bug-user-last-visit.pl
+++ b/mozilla/webtools/bugzilla/clean-bug-user-last-visit.pl
@@ -1,4 +1,4 @@
-#!/usr/bin/perl -wT
+#!/usr/bin/perl
# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
diff --git a/mozilla/webtools/bugzilla/colchange.cgi b/mozilla/webtools/bugzilla/colchange.cgi
index 66b661e5a91..77d9f11eef1 100755
--- a/mozilla/webtools/bugzilla/colchange.cgi
+++ b/mozilla/webtools/bugzilla/colchange.cgi
@@ -1,4 +1,4 @@
-#!/usr/bin/perl -wT
+#!/usr/bin/perl -T
# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
@@ -8,6 +8,8 @@
use 5.10.1;
use strict;
+use warnings;
+
use lib qw(. lib);
use Bugzilla;
diff --git a/mozilla/webtools/bugzilla/collectstats.pl b/mozilla/webtools/bugzilla/collectstats.pl
index 330fae5b39f..3473c9e7189 100755
--- a/mozilla/webtools/bugzilla/collectstats.pl
+++ b/mozilla/webtools/bugzilla/collectstats.pl
@@ -1,4 +1,4 @@
-#!/usr/bin/perl -w
+#!/usr/bin/perl
# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
@@ -8,6 +8,8 @@
use 5.10.1;
use strict;
+use warnings;
+
use lib qw(. lib);
use Getopt::Long qw(:config bundling);
diff --git a/mozilla/webtools/bugzilla/config.cgi b/mozilla/webtools/bugzilla/config.cgi
index 02f95472625..56a9a3f8a18 100755
--- a/mozilla/webtools/bugzilla/config.cgi
+++ b/mozilla/webtools/bugzilla/config.cgi
@@ -1,4 +1,4 @@
-#!/usr/bin/perl -wT
+#!/usr/bin/perl -T
# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
@@ -8,6 +8,8 @@
use 5.10.1;
use strict;
+use warnings;
+
use lib qw(. lib);
use Bugzilla;
diff --git a/mozilla/webtools/bugzilla/contrib/Bugzilla.pm b/mozilla/webtools/bugzilla/contrib/Bugzilla.pm
index fbae60de4a3..31e0a0f6d0b 100644
--- a/mozilla/webtools/bugzilla/contrib/Bugzilla.pm
+++ b/mozilla/webtools/bugzilla/contrib/Bugzilla.pm
@@ -6,6 +6,7 @@ package Bugzilla;
use 5.10.1;
use strict;
+use warnings;
#######################################################################
# The goal of this tiny module is to let Bugzilla packagers of #
diff --git a/mozilla/webtools/bugzilla/contrib/README b/mozilla/webtools/bugzilla/contrib/README
index f8206292523..f0d83086a24 100644
--- a/mozilla/webtools/bugzilla/contrib/README
+++ b/mozilla/webtools/bugzilla/contrib/README
@@ -33,6 +33,10 @@ bz_webservice_demo.pl -- An example script that demonstrates how to talk to
recode.pl -- Script to convert a database from one encoding
(or multiple encodings) to UTF-8.
+ replyrc -- A config file for Reply (a perl shell) that loads
+ Bugzilla, extensions and provides a few utility
+ functions for manipulating Bugzilla data.
+
sendbugmail.pl -- This script is a drop-in replacement for the
'processmail' script which used to be shipped
with Bugzilla, but was replaced by the
diff --git a/mozilla/webtools/bugzilla/contrib/bz_webservice_demo.pl b/mozilla/webtools/bugzilla/contrib/bz_webservice_demo.pl
index 8850d642ad3..af8c253084f 100755
--- a/mozilla/webtools/bugzilla/contrib/bz_webservice_demo.pl
+++ b/mozilla/webtools/bugzilla/contrib/bz_webservice_demo.pl
@@ -1,4 +1,4 @@
-#!/usr/bin/perl -w
+#!/usr/bin/perl
# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
@@ -18,7 +18,10 @@ C for detailed help
=cut
+use 5.10.1;
use strict;
+use warnings;
+
use lib qw(lib);
use Getopt::Long;
use Pod::Usage;
diff --git a/mozilla/webtools/bugzilla/contrib/bzdbcopy.pl b/mozilla/webtools/bugzilla/contrib/bzdbcopy.pl
index f50002e85c2..fcdbefd56d3 100755
--- a/mozilla/webtools/bugzilla/contrib/bzdbcopy.pl
+++ b/mozilla/webtools/bugzilla/contrib/bzdbcopy.pl
@@ -1,4 +1,4 @@
-#!/usr/bin/perl -w
+#!/usr/bin/perl
# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
@@ -6,7 +6,10 @@
# This Source Code Form is "Incompatible With Secondary Licenses", as
# defined by the Mozilla Public License, v. 2.0.
+use 5.10.1;
use strict;
+use warnings;
+
use lib qw(. lib);
use Bugzilla;
use Bugzilla::Constants;
diff --git a/mozilla/webtools/bugzilla/contrib/console.pl b/mozilla/webtools/bugzilla/contrib/console.pl
index dbd514ebdfb..fe2342cd9b0 100644
--- a/mozilla/webtools/bugzilla/contrib/console.pl
+++ b/mozilla/webtools/bugzilla/contrib/console.pl
@@ -1,4 +1,4 @@
-#!/usr/bin/perl -w
+#!/usr/bin/perl
# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
@@ -6,6 +6,8 @@
# This Source Code Form is "Incompatible With Secondary Licenses", as
# defined by the Mozilla Public License, v. 2.0.
+use warnings;
+
use File::Basename;
BEGIN { chdir dirname($0) . "/.."; }
use lib qw(. lib);
@@ -51,7 +53,7 @@ sub d {
# p: print as a single string (normal behavior puts list items on separate lines)
sub p {
- local $^W=0; # suppress possible undefined var message
+ no warnings; # suppress possible undefined var message
print(@_, "\n");
return ();
}
diff --git a/mozilla/webtools/bugzilla/contrib/convert-workflow.pl b/mozilla/webtools/bugzilla/contrib/convert-workflow.pl
index 8f76dac7f6d..d9bffb7bbed 100644
--- a/mozilla/webtools/bugzilla/contrib/convert-workflow.pl
+++ b/mozilla/webtools/bugzilla/contrib/convert-workflow.pl
@@ -1,4 +1,4 @@
-#!/usr/bin/perl -w
+#!/usr/bin/perl
# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
@@ -6,7 +6,10 @@
# This Source Code Form is "Incompatible With Secondary Licenses", as
# defined by the Mozilla Public License, v. 2.0.
+use 5.10.1;
use strict;
+use warnings;
+
use lib qw(. lib);
use Bugzilla;
diff --git a/mozilla/webtools/bugzilla/contrib/extension-convert.pl b/mozilla/webtools/bugzilla/contrib/extension-convert.pl
index 4e24b614ac8..91a77b83943 100644
--- a/mozilla/webtools/bugzilla/contrib/extension-convert.pl
+++ b/mozilla/webtools/bugzilla/contrib/extension-convert.pl
@@ -1,4 +1,4 @@
-#!/usr/bin/perl -w
+#!/usr/bin/perl
# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
@@ -6,8 +6,10 @@
# This Source Code Form is "Incompatible With Secondary Licenses", as
# defined by the Mozilla Public License, v. 2.0.
+use 5.10.1;
use strict;
use warnings;
+
use lib qw(. lib);
use Bugzilla;
@@ -68,6 +70,8 @@ my ($modules, $subs) = code_files_to_subroutines($to_dir);
my $config_pm = < '$extension_name';
$install_requirements
__PACKAGE__->NAME;
@@ -76,6 +80,8 @@ END
my $extension_pm = <selectcol_arrayref("
SELECT earlier.id
FROM bug_user_last_visit as earlier
INNER JOIN bug_user_last_visit as later
- ON (earlier.user_id != later.user_id AND earlier.last_visit_ts < later.last_visit_ts
+ ON (earlier.user_id != later.user_id
+ AND earlier.last_visit_ts < later.last_visit_ts
AND earlier.bug_id = later.bug_id)
WHERE (earlier.user_id = ? OR earlier.user_id = ?)
AND (later.user_id = ? OR later.user_id = ?)",
undef, $old_id, $new_id, $old_id, $new_id);
-$dbh->do("DELETE FROM bug_user_last_visit WHERE " . $dbh->sql_in('id', $dupe_ids));
+
+if (@$dupe_ids) {
+ $dbh->do("DELETE FROM bug_user_last_visit WHERE " .
+ $dbh->sql_in('id', $dupe_ids));
+}
# Migrate records from old user to new user.
foreach my $table (keys %changes) {
diff --git a/mozilla/webtools/bugzilla/contrib/mysqld-watcher.pl b/mozilla/webtools/bugzilla/contrib/mysqld-watcher.pl
index 08a87b5fe73..be93dcbb5df 100755
--- a/mozilla/webtools/bugzilla/contrib/mysqld-watcher.pl
+++ b/mozilla/webtools/bugzilla/contrib/mysqld-watcher.pl
@@ -1,4 +1,4 @@
-#!/usr/bin/perl -w
+#!/usr/bin/perl
# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
@@ -9,7 +9,9 @@
# mysqld-watcher.pl - a script that watches the running instance of
# mysqld and kills off any long-running SELECTs against the shadow_db
#
+use 5.10.1;
use strict;
+use warnings;
# some configurables:
diff --git a/mozilla/webtools/bugzilla/contrib/recode.pl b/mozilla/webtools/bugzilla/contrib/recode.pl
index de204f15568..e6da47b924a 100755
--- a/mozilla/webtools/bugzilla/contrib/recode.pl
+++ b/mozilla/webtools/bugzilla/contrib/recode.pl
@@ -1,4 +1,4 @@
-#!/usr/bin/perl -w
+#!/usr/bin/perl
# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
@@ -6,7 +6,10 @@
# This Source Code Form is "Incompatible With Secondary Licenses", as
# defined by the Mozilla Public License, v. 2.0.
+use 5.10.1;
use strict;
+use warnings;
+
use lib qw(. lib);
use Bugzilla;
diff --git a/mozilla/webtools/bugzilla/contrib/replyrc b/mozilla/webtools/bugzilla/contrib/replyrc
new file mode 100644
index 00000000000..2c5541e4c8f
--- /dev/null
+++ b/mozilla/webtools/bugzilla/contrib/replyrc
@@ -0,0 +1,30 @@
+# This is a config file for Reply,
+# which is a cpan distribution. You can install it with "cpan Reply" or "cpanm Reply".
+# To use this config file, either copy as ~/.replyrc or run the following command:
+# reply --cfg `pwd`/contrib/replyrc
+
+script_line1 = use strict;
+script_line2 = use warnings;
+script_line3 = use v5.10;
+script_line4 = use Bugzilla;
+script_line5 = Bugzilla->extensions; 1;
+script_line6 = sub filter { Bugzilla->template->{SERVICE}->{CONTEXT}->{CONFIG}->{FILTERS}->{$_[0]} }
+script_line7 = sub b { Bugzilla::Bug->new(@_) }
+script_line8 = sub u { Bugzilla::User->new(@_) }
+script_line9 = sub f { Bugzilla::Field->new(@_) }
+
+[Interrupt]
+[FancyPrompt]
+[DataDumper]
+[Colors]
+[ReadLine]
+[Hints]
+[Packages]
+[LexicalPersistence]
+[ResultCache]
+[Autocomplete::Packages]
+[Autocomplete::Lexicals]
+[Autocomplete::Functions]
+[Autocomplete::Globals]
+[Autocomplete::Methods]
+[Autocomplete::Commands]
diff --git a/mozilla/webtools/bugzilla/contrib/sendbugmail.pl b/mozilla/webtools/bugzilla/contrib/sendbugmail.pl
index da0eafd30f0..223d91f6c6d 100755
--- a/mozilla/webtools/bugzilla/contrib/sendbugmail.pl
+++ b/mozilla/webtools/bugzilla/contrib/sendbugmail.pl
@@ -1,4 +1,4 @@
-#!/usr/bin/perl -wT
+#!/usr/bin/perl -T
# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
@@ -8,6 +8,8 @@
use 5.10.1;
use strict;
+use warnings;
+
use lib qw(. lib);
use Bugzilla;
diff --git a/mozilla/webtools/bugzilla/contrib/sendunsentbugmail.pl b/mozilla/webtools/bugzilla/contrib/sendunsentbugmail.pl
index 47455413562..b9034aa8de2 100755
--- a/mozilla/webtools/bugzilla/contrib/sendunsentbugmail.pl
+++ b/mozilla/webtools/bugzilla/contrib/sendunsentbugmail.pl
@@ -1,4 +1,4 @@
-#!/usr/bin/perl -wT
+#!/usr/bin/perl -T
# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
@@ -8,6 +8,8 @@
use 5.10.1;
use strict;
+use warnings;
+
use lib qw(. lib);
use Bugzilla;
diff --git a/mozilla/webtools/bugzilla/contrib/syncLDAP.pl b/mozilla/webtools/bugzilla/contrib/syncLDAP.pl
index 6ad96477bbe..f618624ec31 100755
--- a/mozilla/webtools/bugzilla/contrib/syncLDAP.pl
+++ b/mozilla/webtools/bugzilla/contrib/syncLDAP.pl
@@ -1,4 +1,4 @@
-#!/usr/bin/perl -wT
+#!/usr/bin/perl -T
# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
@@ -6,7 +6,9 @@
# This Source Code Form is "Incompatible With Secondary Licenses", as
# defined by the Mozilla Public License, v. 2.0.
+use 5.10.1;
use strict;
+use warnings;
use lib qw(. lib);
diff --git a/mozilla/webtools/bugzilla/createaccount.cgi b/mozilla/webtools/bugzilla/createaccount.cgi
index c9516ab00fc..21d6cc8db34 100755
--- a/mozilla/webtools/bugzilla/createaccount.cgi
+++ b/mozilla/webtools/bugzilla/createaccount.cgi
@@ -1,4 +1,4 @@
-#!/usr/bin/perl -wT
+#!/usr/bin/perl -T
# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
@@ -8,6 +8,8 @@
use 5.10.1;
use strict;
+use warnings;
+
use lib qw(. lib);
use Bugzilla;
diff --git a/mozilla/webtools/bugzilla/describecomponents.cgi b/mozilla/webtools/bugzilla/describecomponents.cgi
index db8260b5d47..f74dc75f43b 100755
--- a/mozilla/webtools/bugzilla/describecomponents.cgi
+++ b/mozilla/webtools/bugzilla/describecomponents.cgi
@@ -1,4 +1,4 @@
-#!/usr/bin/perl -wT
+#!/usr/bin/perl -T
# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
@@ -8,6 +8,8 @@
use 5.10.1;
use strict;
+use warnings;
+
use lib qw(. lib);
use Bugzilla;
diff --git a/mozilla/webtools/bugzilla/describekeywords.cgi b/mozilla/webtools/bugzilla/describekeywords.cgi
index 2147ac47dc0..31bf0c13e11 100755
--- a/mozilla/webtools/bugzilla/describekeywords.cgi
+++ b/mozilla/webtools/bugzilla/describekeywords.cgi
@@ -1,4 +1,4 @@
-#!/usr/bin/perl -wT
+#!/usr/bin/perl -T
# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
@@ -8,6 +8,8 @@
use 5.10.1;
use strict;
+use warnings;
+
use lib qw(. lib);
use Bugzilla;
diff --git a/mozilla/webtools/bugzilla/docs/en/rst/about/index.rst b/mozilla/webtools/bugzilla/docs/en/rst/about/index.rst
index 3c0d19ca5ef..985f09a7461 100644
--- a/mozilla/webtools/bugzilla/docs/en/rst/about/index.rst
+++ b/mozilla/webtools/bugzilla/docs/en/rst/about/index.rst
@@ -46,7 +46,7 @@ Document Conventions
This document uses the following conventions:
-.. warning:: This is a warning—something you should be aware of.
+.. warning:: This is a warning - something you should be aware of.
.. note:: This is just a note, for your information.
@@ -68,7 +68,7 @@ This documentation is maintained in
`reStructured Text