Merge with d5cc8b05e7
commit
6ab4d164d0
27
Bugzilla.pm
27
Bugzilla.pm
|
@ -330,17 +330,17 @@ sub get_mail_result {
|
|||
|
||||
sub template {
|
||||
my $class = shift;
|
||||
$class->request_cache->{language} = "";
|
||||
$class->request_cache->{template} ||= Bugzilla::Template->create();
|
||||
return $class->request_cache->{template};
|
||||
}
|
||||
|
||||
sub template_inner {
|
||||
my ($class, $lang) = @_;
|
||||
$lang = defined($lang) ? $lang : ($class->request_cache->{language} || "");
|
||||
$class->request_cache->{language} = $lang;
|
||||
my $cache = $class->request_cache;
|
||||
my $current_lang = $cache->{template_current_lang}->[0];
|
||||
$lang ||= $current_lang || '';
|
||||
$class->request_cache->{"template_inner_$lang"}
|
||||
||= Bugzilla::Template->create();
|
||||
||= Bugzilla::Template->create(language => $lang);
|
||||
return $class->request_cache->{"template_inner_$lang"};
|
||||
}
|
||||
|
||||
|
@ -618,22 +618,7 @@ sub dbh_main {
|
|||
|
||||
sub languages {
|
||||
my $class = shift;
|
||||
return $class->request_cache->{languages}
|
||||
if $class->request_cache->{languages};
|
||||
|
||||
my @files = glob(catdir(bz_locations->{'templatedir'}, '*'));
|
||||
my @languages;
|
||||
foreach my $dir_entry (@files) {
|
||||
# It's a language directory only if it contains "default" or
|
||||
# "custom". This auto-excludes CVS directories as well.
|
||||
next unless (-d catdir($dir_entry, 'default')
|
||||
|| -d catdir($dir_entry, 'custom'));
|
||||
$dir_entry = basename($dir_entry);
|
||||
# Check for language tag format conforming to RFC 1766.
|
||||
next unless $dir_entry =~ /^[a-zA-Z]{1,8}(-[a-zA-Z]{1,8})?$/;
|
||||
push(@languages, $dir_entry);
|
||||
}
|
||||
return $class->request_cache->{languages} = \@languages;
|
||||
return Bugzilla::Install::Util::supported_languages();
|
||||
}
|
||||
|
||||
sub error_mode {
|
||||
|
@ -921,7 +906,7 @@ sub has_flags {
|
|||
my $class = shift;
|
||||
|
||||
if (!defined $class->request_cache->{has_flags}) {
|
||||
$class->request_cache->{has_flags} = Bugzilla::Flag::has_flags();
|
||||
$class->request_cache->{has_flags} = Bugzilla::Flag->any_exist;
|
||||
}
|
||||
return $class->request_cache->{has_flags};
|
||||
}
|
||||
|
|
|
@ -51,7 +51,7 @@ use Bugzilla::Group;
|
|||
use Bugzilla::Status;
|
||||
use Bugzilla::Comment;
|
||||
|
||||
use List::Util qw(min);
|
||||
use List::Util qw(min first);
|
||||
use Storable qw(dclone);
|
||||
use URI;
|
||||
use URI::QueryParam;
|
||||
|
@ -2703,11 +2703,9 @@ sub add_group {
|
|||
return if !$group->is_active or !$group->is_bug_group;
|
||||
|
||||
# Make sure that bugs in this product can actually be restricted
|
||||
# to this group.
|
||||
grep($group->id == $_->id, @{$self->product_obj->groups_valid})
|
||||
# But during product change, verification happens anyway in update().
|
||||
|| $self->{_old_product_name}
|
||||
|| ThrowUserError('group_invalid_restriction',
|
||||
# to this group by the current user.
|
||||
$self->product_obj->group_is_settable($group)
|
||||
|| ThrowUserError('group_invalid_restriction',
|
||||
{ product => $self->product, group_id => $group->id });
|
||||
|
||||
# OtherControl people can add groups only during a product change,
|
||||
|
@ -2734,12 +2732,14 @@ sub remove_group {
|
|||
return unless $group;
|
||||
|
||||
# First, check if this is a valid group for this product.
|
||||
# You can *always* remove a group that is not valid for this product, so
|
||||
# we don't do any other checks if that's the case. (set_product does this.)
|
||||
# You can *always* remove a group that is not valid for this product
|
||||
# or that is not active, so we don't do any other checks if either of
|
||||
# those are the case. (Users might remove inactive groups, and set_product
|
||||
# removes groups that aren't valid for this product.)
|
||||
#
|
||||
# This particularly happens when isbuggroup is no longer 1, and we're
|
||||
# moving a bug to a new product.
|
||||
if (grep($_->id == $group->id, @{$self->product_obj->groups_valid})) {
|
||||
if ($group->is_active and $self->product_obj->group_is_valid($group)) {
|
||||
my $controls = $self->product_obj->group_controls->{$group->id};
|
||||
|
||||
# Nobody can ever remove a Mandatory group.
|
||||
|
@ -2819,41 +2819,18 @@ sub add_see_also {
|
|||
if ($uri->path =~ m|^/p/([^/]+)/issues/detail$|) {
|
||||
$project_name = $1;
|
||||
} else {
|
||||
ThrowUserError('bug_url_invalid',
|
||||
{ url => $input });
|
||||
ThrowUserError('bug_url_invalid', { url => $input });
|
||||
}
|
||||
my $bug_id = $uri->query_param('id');
|
||||
detaint_natural($bug_id);
|
||||
if (!$bug_id) {
|
||||
ThrowUserError('bug_url_invalid',
|
||||
{ url => $input, reason => 'id' });
|
||||
ThrowUserError('bug_url_invalid', { url => $input, reason => 'id' });
|
||||
}
|
||||
# While Google Code URLs can be either HTTP or HTTPS,
|
||||
# always go with the HTTP scheme, as that's the default.
|
||||
$result = "http://code.google.com/p/" . $project_name .
|
||||
"/issues/detail?id=" . $bug_id;
|
||||
}
|
||||
# Debian BTS URLs
|
||||
elsif ($uri->authority =~ /^bugs.debian.org$/i) {
|
||||
# Debian BTS URLs can look like various things:
|
||||
# http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=1234
|
||||
# http://bugs.debian.org/1234
|
||||
my $bug_id;
|
||||
if ($uri->path =~ m|^/(\d+)$|) {
|
||||
$bug_id = $1;
|
||||
}
|
||||
elsif ($uri->path =~ /bugreport\.cgi$/) {
|
||||
$bug_id = $uri->query_param('bug');
|
||||
detaint_natural($bug_id);
|
||||
}
|
||||
if (!$bug_id) {
|
||||
ThrowUserError('bug_url_invalid',
|
||||
{ url => $input, reason => 'id' });
|
||||
}
|
||||
# This is the shortest standard URL form for Debian BTS URLs,
|
||||
# and so we reduce all URLs to this.
|
||||
$result = "http://bugs.debian.org/" . $bug_id;
|
||||
}
|
||||
# Bugzilla URLs
|
||||
else {
|
||||
if ($uri->path !~ /show_bug\.cgi$/) {
|
||||
|
@ -3841,6 +3818,20 @@ sub check_can_change_field {
|
|||
return 1;
|
||||
}
|
||||
|
||||
my @priv_results;
|
||||
Bugzilla::Hook::process('bug_check_can_change_field',
|
||||
{ bug => $self, field => $field,
|
||||
new_value => $newvalue, old_value => $oldvalue,
|
||||
priv_results => \@priv_results });
|
||||
if (my $priv_required = first { $_ > 0 } @priv_results) {
|
||||
$$PrivilegesRequired = $priv_required;
|
||||
return 0;
|
||||
}
|
||||
my $allow_found = first { $_ == 0 } @priv_results;
|
||||
if (defined $allow_found) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
# Allow anyone to change comments.
|
||||
if ($field =~ /^longdesc/) {
|
||||
return 1;
|
||||
|
@ -3850,15 +3841,15 @@ sub check_can_change_field {
|
|||
# We store the required permission set into the $PrivilegesRequired
|
||||
# variable which gets passed to the error template.
|
||||
#
|
||||
# $PrivilegesRequired = 0 : no privileges required;
|
||||
# $PrivilegesRequired = 1 : the reporter, assignee or an empowered user;
|
||||
# $PrivilegesRequired = 2 : the assignee or an empowered user;
|
||||
# $PrivilegesRequired = 3 : an empowered user.
|
||||
|
||||
# $PrivilegesRequired = PRIVILEGES_REQUIRED_NONE : no privileges required;
|
||||
# $PrivilegesRequired = PRIVILEGES_REQUIRED_REPORTER : the reporter, assignee or an empowered user;
|
||||
# $PrivilegesRequired = PRIVILEGES_REQUIRED_ASSIGNEE : the assignee or an empowered user;
|
||||
# $PrivilegesRequired = PRIVILEGES_REQUIRED_EMPOWERED : an empowered user.
|
||||
|
||||
# Only users in the time-tracking group can change time-tracking fields.
|
||||
if ( grep($_ eq $field, qw(deadline estimated_time remaining_time)) ) {
|
||||
if (!$user->is_timetracker) {
|
||||
$$PrivilegesRequired = 3;
|
||||
$$PrivilegesRequired = PRIVILEGES_REQUIRED_EMPOWERED;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
@ -3870,7 +3861,7 @@ sub check_can_change_field {
|
|||
|
||||
# *Only* users with (product-specific) "canconfirm" privs can confirm bugs.
|
||||
if ($self->_changes_everconfirmed($field, $oldvalue, $newvalue)) {
|
||||
$$PrivilegesRequired = 3;
|
||||
$$PrivilegesRequired = PRIVILEGES_REQUIRED_EMPOWERED;
|
||||
return $user->in_group('canconfirm', $self->{'product_id'});
|
||||
}
|
||||
|
||||
|
@ -3901,36 +3892,36 @@ sub check_can_change_field {
|
|||
# in that case we will have already returned 1 above
|
||||
# when checking for the assignee of the bug.
|
||||
if ($field eq 'assigned_to') {
|
||||
$$PrivilegesRequired = 2;
|
||||
$$PrivilegesRequired = PRIVILEGES_REQUIRED_ASSIGNEE;
|
||||
return 0;
|
||||
}
|
||||
# - change the QA contact
|
||||
if ($field eq 'qa_contact') {
|
||||
$$PrivilegesRequired = 2;
|
||||
$$PrivilegesRequired = PRIVILEGES_REQUIRED_ASSIGNEE;
|
||||
return 0;
|
||||
}
|
||||
# - change the target milestone
|
||||
if ($field eq 'target_milestone') {
|
||||
$$PrivilegesRequired = 2;
|
||||
$$PrivilegesRequired = PRIVILEGES_REQUIRED_ASSIGNEE;
|
||||
return 0;
|
||||
}
|
||||
# - change the priority (unless he could have set it originally)
|
||||
if ($field eq 'priority'
|
||||
&& !Bugzilla->params->{'letsubmitterchoosepriority'})
|
||||
{
|
||||
$$PrivilegesRequired = 2;
|
||||
$$PrivilegesRequired = PRIVILEGES_REQUIRED_ASSIGNEE;
|
||||
return 0;
|
||||
}
|
||||
# - unconfirm bugs (confirming them is handled above)
|
||||
if ($field eq 'everconfirmed') {
|
||||
$$PrivilegesRequired = 2;
|
||||
$$PrivilegesRequired = PRIVILEGES_REQUIRED_ASSIGNEE;
|
||||
return 0;
|
||||
}
|
||||
# - change the status from one open state to another
|
||||
if ($field eq 'bug_status'
|
||||
&& is_open_state($oldvalue) && is_open_state($newvalue))
|
||||
{
|
||||
$$PrivilegesRequired = 2;
|
||||
$$PrivilegesRequired = PRIVILEGES_REQUIRED_ASSIGNEE;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -3941,7 +3932,7 @@ sub check_can_change_field {
|
|||
|
||||
# If we haven't returned by this point, then the user doesn't
|
||||
# have the necessary permissions to change this field.
|
||||
$$PrivilegesRequired = 1;
|
||||
$$PrivilegesRequired = PRIVILEGES_REQUIRED_REPORTER;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
@ -659,12 +659,10 @@ sub sendMail
|
|||
};
|
||||
|
||||
my $msg;
|
||||
my $tmpl = '';
|
||||
|
||||
my $template = Bugzilla->template_inner($user->settings->{lang}->{value});
|
||||
Bugzilla::Hook::process('bugmail-pre_template', { tmpl => \$tmpl, vars => $vars });
|
||||
$tmpl = "email/newchangedmail.txt.tmpl" unless $template->template_exists($tmpl);
|
||||
$template->process($tmpl, $vars, \$msg) || ThrowTemplateError($template->error());
|
||||
$template->process("email/newchangedmail.txt.tmpl", $vars, \$msg)
|
||||
|| ThrowTemplateError($template->error());
|
||||
Bugzilla->template_inner("");
|
||||
|
||||
MessageToMTA($msg);
|
||||
|
|
|
@ -182,8 +182,10 @@ use Cwd qw(abs_path);
|
|||
|
||||
CGI_URI_LIMIT
|
||||
|
||||
LANG_ISO_FULL
|
||||
LANG_FULL_ISO
|
||||
PRIVILEGES_REQUIRED_NONE
|
||||
PRIVILEGES_REQUIRED_REPORTER
|
||||
PRIVILEGES_REQUIRED_ASSIGNEE
|
||||
PRIVILEGES_REQUIRED_EMPOWERED
|
||||
|
||||
BUG_ID_ADD_TO_BLOCKED
|
||||
BUG_ID_ADD_TO_DEPENDSON
|
||||
|
@ -542,28 +544,14 @@ use constant PASSWORD_SALT_LENGTH => 8;
|
|||
# can be safely done or not based on the web server's URI length setting.
|
||||
use constant CGI_URI_LIMIT => 8000;
|
||||
|
||||
# Full language names corresponding to 2-letter ISO codes
|
||||
# Used to select stemming language in fulltext search
|
||||
use constant LANG_ISO_FULL => {
|
||||
da => 'danish',
|
||||
nl => 'dutch',
|
||||
en => 'english',
|
||||
fi => 'finnish',
|
||||
fr => 'french',
|
||||
de => 'german',
|
||||
hu => 'hungarian',
|
||||
it => 'italian',
|
||||
no => 'norwegian',
|
||||
pt => 'portuguese',
|
||||
ro => 'romanian',
|
||||
ru => 'russian',
|
||||
es => 'spanish',
|
||||
sv => 'swedish',
|
||||
tr => 'turkish',
|
||||
};
|
||||
# If the user isn't allowed to change a field, we must tell him who can.
|
||||
# We store the required permission set into the $PrivilegesRequired
|
||||
# variable which gets passed to the error template.
|
||||
|
||||
# The reverse of LANG_ISO_FULL
|
||||
use constant LANG_FULL_ISO => { reverse %{LANG_ISO_FULL()} };
|
||||
use constant PRIVILEGES_REQUIRED_NONE => 0;
|
||||
use constant PRIVILEGES_REQUIRED_REPORTER => 1;
|
||||
use constant PRIVILEGES_REQUIRED_ASSIGNEE => 2;
|
||||
use constant PRIVILEGES_REQUIRED_EMPOWERED => 3;
|
||||
|
||||
sub bz_locations {
|
||||
# We know that Bugzilla/Constants.pm must be in %INC at this point.
|
||||
|
|
|
@ -792,10 +792,10 @@ sub bz_drop_fk {
|
|||
|
||||
}
|
||||
|
||||
sub bz_drop_related_fks {
|
||||
sub bz_get_related_fks {
|
||||
my ($self, $table, $column) = @_;
|
||||
my @tables = $self->_bz_real_schema->get_table_list();
|
||||
my @dropped;
|
||||
my @related;
|
||||
foreach my $check_table (@tables) {
|
||||
my @columns = $self->bz_table_columns($check_table);
|
||||
foreach my $check_column (@columns) {
|
||||
|
@ -805,13 +805,22 @@ sub bz_drop_related_fks {
|
|||
and (($fk->{TABLE} eq $table and $fk->{COLUMN} eq $column)
|
||||
or ($check_column eq $column and $check_table eq $table)))
|
||||
{
|
||||
$self->bz_drop_fk($check_table, $check_column);
|
||||
push(@dropped, [$check_table, $check_column, $fk]);
|
||||
push(@related, [$check_table, $check_column, $fk]);
|
||||
}
|
||||
} # foreach $column
|
||||
} # foreach $table
|
||||
|
||||
return \@dropped;
|
||||
return \@related;
|
||||
}
|
||||
|
||||
sub bz_drop_related_fks {
|
||||
my $self = shift;
|
||||
my $related = $self->bz_get_related_fks(@_);
|
||||
foreach my $item (@$related) {
|
||||
my ($table, $column) = @$item;
|
||||
$self->bz_drop_fk($table, $column);
|
||||
}
|
||||
return $related;
|
||||
}
|
||||
|
||||
sub bz_drop_index {
|
||||
|
|
|
@ -249,7 +249,9 @@ sub _throw_error
|
|||
# higher than 999, but we do this to avoid conflicts with
|
||||
# the internal JSON::RPC error codes.
|
||||
$server->raise_error(code => 100000 + $code,
|
||||
message => $message);
|
||||
message => $message,
|
||||
id => $server->{_bz_request_id},
|
||||
version => $server->version);
|
||||
# We die with no message. JSON::RPC checks raise_error before
|
||||
# it checks $@, so it returns the proper error.
|
||||
die;
|
||||
|
|
|
@ -298,11 +298,344 @@ package name in a string, and it will be loaded automatically.
|
|||
|
||||
=head2 Hooks
|
||||
|
||||
A hook is a place in the code into which other code parts can be inserted.
|
||||
In Bugzilla, there are code hooks and template hooks.
|
||||
Extensions should use hooks for extending the functionality. The best
|
||||
is if you use predefined hooks, but you can also add your own and publish
|
||||
the patch which adds this hooks somewhere on L<http://wiki.4intra.net/>.
|
||||
In L<Bugzilla::Hook>, there is a L<list of hooks|Bugzilla::Hook/HOOKS>.
|
||||
These are the various areas of Bugzilla that an extension can "hook" into,
|
||||
which allow your extension to perform code during that point in Bugzilla's
|
||||
execution.
|
||||
|
||||
If your extension wants to implement a hook, all you have to do is
|
||||
write a subroutine in your hook package that has the same name as
|
||||
the hook. The subroutine will be called as a method on your extension,
|
||||
and it will get the arguments specified in the hook's documentation as
|
||||
named parameters in a hashref.
|
||||
|
||||
For example, here's an implementation of a hook named C<foo_start>
|
||||
that gets an argument named C<bar>:
|
||||
|
||||
sub foo_start {
|
||||
my ($self, $args) = @_;
|
||||
my $bar = $args->{bar};
|
||||
print "I got $bar!\n";
|
||||
}
|
||||
|
||||
And that would go into your extension's code file--the file that was
|
||||
described in the L</Where Extension Code Goes> section above.
|
||||
|
||||
During your subroutine, you may want to know what values were passed
|
||||
as CGI arguments to the current script, or what arguments were passed to
|
||||
the current WebService method. You can get that data via
|
||||
L<Bugzilla/input_params>.
|
||||
|
||||
=head3 Adding New Hooks To Bugzilla
|
||||
|
||||
If you need a new hook for your extension and you want that hook to be
|
||||
added to Bugzilla itself, see our development process at
|
||||
L<http://wiki.mozilla.org/Bugzilla:Developers>.
|
||||
|
||||
In order for a new hook to be accepted into Bugzilla, it has to work,
|
||||
it must have documentation in L<Bugzilla::Hook>, and it must have example
|
||||
code in F<extensions/Example/Extension.pm>.
|
||||
|
||||
One question that is often asked about new hooks is, "Is this the most
|
||||
flexible way to implement this hook?" That is, the more power extension
|
||||
authors get from a hook, the more likely it is to be accepted into Bugzilla.
|
||||
Hooks that only hook a very specific part of Bugzilla will not be accepted
|
||||
if their functionality can be accomplished equally well with a more generic
|
||||
hook.
|
||||
|
||||
=head2 If Your Extension Requires Certain Perl Modules
|
||||
|
||||
If there are certain Perl modules that your extension requires in order
|
||||
to run, there is a way you can tell Bugzilla this, and then L<checksetup>
|
||||
will make sure that those modules are installed, when you run L<checksetup>.
|
||||
|
||||
To do this, you need to specify a constant called C<REQUIRED_MODULES>
|
||||
in your extension. This constant has the same format as
|
||||
L<Bugzilla::Install::Requirements/REQUIRED_MODULES>.
|
||||
|
||||
If there are optional modules that add additional functionality to your
|
||||
application, you can specify them in a constant called OPTIONAL_MODULES,
|
||||
which has the same format as
|
||||
L<Bugzilla::Install::Requirements/OPTIONAL_MODULES>.
|
||||
|
||||
=head3 If Your Extension Needs Certain Modules In Order To Compile
|
||||
|
||||
If your extension needs a particular Perl module in order to
|
||||
I<compile>, then you have a "chicken and egg" problem--in order to
|
||||
read C<REQUIRED_MODULES>, we have to compile your extension. In order
|
||||
to compile your extension, we need to already have the modules in
|
||||
C<REQUIRED_MODULES>!
|
||||
|
||||
To get around this problem, Bugzilla allows you to have an additional
|
||||
file, besides F<Extension.pm>, called F<Config.pm>, that contains
|
||||
just C<REQUIRED_MODULES>. If you have a F<Config.pm>, it must also
|
||||
contain the C<NAME> constant, instead of your main F<Extension.pm>
|
||||
containing the C<NAME> constant.
|
||||
|
||||
The contents of the file would look something like this for an extension
|
||||
named C<Foo>:
|
||||
|
||||
package Bugzilla::Extension::Foo;
|
||||
use strict;
|
||||
use constant NAME => 'Foo';
|
||||
use constant REQUIRED_MODULES => [
|
||||
{
|
||||
package => 'Some-Package',
|
||||
module => 'Some::Module',
|
||||
version => 0,
|
||||
}
|
||||
];
|
||||
__PACKAGE__->NAME;
|
||||
|
||||
Note that it is I<not> a subclass of C<Bugzilla::Extension>, because
|
||||
at the time that module requirements are being checked in L<checksetup>,
|
||||
C<Bugzilla::Extension> cannot be loaded. Also, just like F<Extension.pm>,
|
||||
it ends with C<< __PACKAGE__->NAME; >>. Note also that it has the
|
||||
B<exact same> C<package> name as F<Extension.pm>.
|
||||
|
||||
This file may not use any Perl modules other than L<Bugzilla::Constants>,
|
||||
L<Bugzilla::Install::Util>, L<Bugzilla::Install::Requirements>, and
|
||||
modules that ship with Perl itself.
|
||||
|
||||
If you want to define both C<REQUIRED_MODULES> and C<OPTIONAL_MODULES>,
|
||||
they must both be in F<Config.pm> or both in F<Extension.pm>.
|
||||
|
||||
Every time your extension is loaded by Bugzilla, F<Config.pm> will be
|
||||
read and then F<Extension.pm> will be read, so your methods in F<Extension.pm>
|
||||
will have access to everything in F<Config.pm>. Don't define anything
|
||||
with an identical name in both files, or Perl may throw a warning that
|
||||
you are redefining things.
|
||||
|
||||
This method of setting C<REQUIRED_MODULES> is of course not available if
|
||||
your extension is a single file named C<Foo.pm>.
|
||||
|
||||
If any of this is confusing, just look at the code of the Example extension.
|
||||
It uses this method to specify requirements.
|
||||
|
||||
=head2 Libraries
|
||||
|
||||
Extensions often want to have their own Perl modules. Your extension
|
||||
can load any Perl module in its F<lib/> directory. (So, if your extension is
|
||||
F<extensions/Foo/>, then your Perl modules go into F<extensions/Foo/lib/>.)
|
||||
|
||||
However, the C<package> name of your libraries will not work quite
|
||||
like normal Perl modules do. F<extensions/Foo/lib/Bar.pm> is
|
||||
loaded as C<Bugzilla::Extension::Foo::Bar>. Or, to say it another way,
|
||||
C<use Bugzilla::Extension::Foo::Bar;> loads F<extensions/Foo/lib/Bar.pm>,
|
||||
which should have C<package Bugzilla::Extension::Foo::Bar;> as its package
|
||||
name.
|
||||
|
||||
This allows any place in Bugzilla to load your modules, which is important
|
||||
for some hooks. It even allows other extensions to load your modules, and
|
||||
allows you to install your modules into the global Perl install
|
||||
as F<Bugzilla/Extension/Foo/Bar.pm>, if you'd like, which helps allow CPAN
|
||||
distribution of Bugzilla extensions.
|
||||
|
||||
B<Note:> If you want to C<use> or C<require> a module that's in
|
||||
F<extensions/Foo/lib/> at the top level of your F<Extension.pm>,
|
||||
you must have a F<Config.pm> (see above) with at least the C<NAME>
|
||||
constant defined in it.
|
||||
|
||||
=head2 Templates
|
||||
|
||||
Extensions store templates in a C<template> subdirectory of the extension.
|
||||
(Obviously, this isn't available for extensions that aren't a directory.)
|
||||
|
||||
The format of this directory is exactly like the normal layout of Bugzilla's
|
||||
C<template> directory--in fact, your extension's C<template> directory
|
||||
becomes part of Bugzilla's template "search path" as described in
|
||||
L<Bugzilla::Install::Util/template_include_path>.
|
||||
|
||||
You can actually include templates in your extension without having any
|
||||
C<.pm> files in your extension at all, if you want. (That is, it's entirely
|
||||
valid to have an extension that's just template files and no code files.)
|
||||
|
||||
Bugzilla's templates are written in a language called Template Toolkit.
|
||||
You can find out more about Template Toolkit at L<http://template-toolkit.org>.
|
||||
|
||||
There are two ways to extend or modify Bugzilla's templates: you can use
|
||||
template hooks (described below) or you can override existing templates
|
||||
entirely (described further down).
|
||||
|
||||
=head2 Template Hooks
|
||||
|
||||
Templates can be extended using a system of "hooks" that add new UI elements
|
||||
to a particular area of Bugzilla without modifying the code of the existing
|
||||
templates. This is the recommended way for extensions to modify the user
|
||||
interface of Bugzilla.
|
||||
|
||||
=head3 Which Templates Can Be Hooked
|
||||
|
||||
There is no list of template hooks like there is for standard code hooks.
|
||||
To find what places in the user interface can be hooked, search for the
|
||||
string C<Hook.process> in Bugzilla's templates (in the
|
||||
F<template/en/default/> directory). That will also give you the name of
|
||||
the hooks--the first argument to C<Hook.process> is the name of the hook.
|
||||
(A later section in this document explains how to use that name).
|
||||
|
||||
For example, if you see C<Hook.process("additional_header")>, that means
|
||||
the name of the hook is C<additional_header>.
|
||||
|
||||
=head3 Where Template Hooks Go
|
||||
|
||||
To extend templates in your extension using template hooks, you put files into
|
||||
the F<template/en/default/hook> directory of your extension. So, if you had an
|
||||
extension called "Foo", your template extensions would go into
|
||||
F<extensions/Foo/template/en/default/hook/>.
|
||||
|
||||
(Note that the base F<template/en/default/hook> directory in Bugzilla itself
|
||||
also works, although you would never use that for an extension that you
|
||||
intended to distribute.)
|
||||
|
||||
The files that go into this directory have a certain name, based on the
|
||||
name of the template that is being hooked, and the name of the hook.
|
||||
For example, let's imagine that you have an extension named "Foo",
|
||||
and you want to use the C<additional_header> hook in
|
||||
F<template/en/default/global/header.html.tmpl>. Your code would go into
|
||||
F<extensions/Foo/template/en/default/hook/global/header-additional_header.html.tmpl>. Any code you put into that file will happen at the point that
|
||||
C<Hook.process("additional_header")> is called in
|
||||
F<template/en/default/global/header.html.tmpl>.
|
||||
|
||||
As you can see, template extension file names follow a pattern. The
|
||||
pattern looks like:
|
||||
|
||||
<templates>/hook/<template path>/<template name>-<hook name>.<template type>.tmpl
|
||||
|
||||
=over
|
||||
|
||||
=item <templates>
|
||||
|
||||
This is the full path to the template directory, like
|
||||
F<extensions/Foo/template/en/default>. This works much like normal templates
|
||||
do, in the sense that template extensions in C<custom> override template
|
||||
extensions in C<default> for your extension, templates for different languages
|
||||
can be supplied, etc. Template extensions are searched for and run in the
|
||||
order described in L<Bugzilla::Install::Util/template_include_path>.
|
||||
|
||||
The difference between normal templates and template hooks is that hooks
|
||||
will be run for I<every> extension, whereas for normal templates, Bugzilla
|
||||
just takes the first one it finds and stops searching. So while a template
|
||||
extension in the C<custom> directory may override the same-named template
|
||||
extension in the C<default> directory I<within your Bugzilla extension>,
|
||||
it will not override the same-named template extension in the C<default>
|
||||
directory of another Bugzilla extension.
|
||||
|
||||
=item <template path>
|
||||
|
||||
This is the part of the path (excluding the filename) that comes after
|
||||
F<template/en/default/> in a template's path. So, for
|
||||
F<template/en/default/global/header.html.tmpl>, this would simply be
|
||||
C<global>.
|
||||
|
||||
=item <template name>
|
||||
|
||||
This is the file name of the template, before the C<.html.tmpl> part.
|
||||
So, for F<template/en/default/global/header.html.tmpl>, this would be
|
||||
C<header>.
|
||||
|
||||
=item <hook name>
|
||||
|
||||
This is the name of the hook--what you saw in C<Hook.process> inside
|
||||
of the template you want to hook. In our example, this is
|
||||
C<additional_header>.
|
||||
|
||||
=item <template type>
|
||||
|
||||
This is what comes after the template name but before C<.tmpl> in the
|
||||
template's path. In most cases this is C<html>, but sometimes it's
|
||||
C<none>, C<txt>, C<js>, or various other formats, indicating what
|
||||
type of output the template has.
|
||||
|
||||
=back
|
||||
|
||||
=head3 Adding New Template Hooks to Bugzilla
|
||||
|
||||
Adding new template hooks is just like adding code hooks (see
|
||||
L</Adding New Hooks To Bugzilla>) except that you don't have to
|
||||
document them, and including example code is optional.
|
||||
|
||||
=head2 Overriding Existing Templates
|
||||
|
||||
Sometimes you don't want to extend a template, you just want to replace
|
||||
it entirely with your extension's template, or you want to add an entirely
|
||||
new template to Bugzilla for your extension to use.
|
||||
|
||||
To replace the F<template/en/default/global/banner.html.tmpl> template
|
||||
in an extension named "Foo", create a file called
|
||||
F<extensions/Foo/template/en/default/global/banner.html.tmpl>. Note that this
|
||||
is very similar to the path for a template hook, except that it excludes
|
||||
F<hook/>, and the template is named I<exactly> like the standard Bugzilla
|
||||
template.
|
||||
|
||||
You can also use this method to add entirely new templates. If you have
|
||||
an extension named "Foo", and you add a file named
|
||||
F<extensions/Foo/template/en/default/foo/bar.html.tmpl>, you can load
|
||||
that in your code using C<< $template->process('foo/bar.html.tmpl') >>.
|
||||
|
||||
=head3 A Warning About Extensions That You Want To Distribute
|
||||
|
||||
You should never override an existing Bugzilla template in an
|
||||
extension that you plan to distribute to others, because only one extension
|
||||
can override any given template, and which extension will "win" that war
|
||||
if there are multiple extensions installed is totally undefined.
|
||||
|
||||
However, adding new templates in an extension that you want to distribute
|
||||
is fine, though you have to be careful about how you name them, because
|
||||
any templates with an identical path and name (say, both called
|
||||
F<global/stuff.html.tmpl>) will conflict. The usual way to work around
|
||||
this is to put all your custom templates into a template path that's
|
||||
named after your extension (since the name of your extension has to be
|
||||
unique anyway). So if your extension was named Foo, your custom templates
|
||||
would go into F<extensions/Foo/template/en/default/foo/>. The only
|
||||
time that doesn't work is with the C<page_before_template> extension, in which
|
||||
case your templates should probably be in a directory like
|
||||
F<extensions/Foo/template/en/default/page/foo/> so as not to conflict with
|
||||
other pages that other extensions might add.
|
||||
|
||||
=head2 Disabling Your Extension
|
||||
|
||||
If you want your extension to be totally ignored by Bugzilla (it will
|
||||
not be compiled or seen to exist at all), then create a file called
|
||||
C<disabled> in your extension's directory. (If your extension is just
|
||||
a file, like F<extensions/Foo.pm>, you cannot use this method to disable
|
||||
your extension, and will just have to remove it from the directory if you
|
||||
want to totally disable it.) Note that if you are running under mod_perl,
|
||||
you may have to restart your web server for this to take effect.
|
||||
|
||||
If you want your extension to be compiled and have L<checksetup> check
|
||||
for its module pre-requisites, but you don't want the module to be used
|
||||
by Bugzilla, then you should make your extension's L</enabled> method
|
||||
return C<0> or some false value.
|
||||
|
||||
=head1 DISTRIBUTING EXTENSIONS
|
||||
|
||||
If you've made an extension and you want to publish it, the first
|
||||
thing you'll want to do is package up your extension's code and
|
||||
then put a link to it in the appropriate section of
|
||||
L<http://wiki.mozilla.org/Bugzilla:Addons>.
|
||||
|
||||
=head2 Distributing on CPAN
|
||||
|
||||
If you want a centralized distribution point that makes it easy
|
||||
for Bugzilla users to install your extension, it is possible to
|
||||
distribute your Bugzilla Extension through CPAN.
|
||||
|
||||
The details of making a standard CPAN module are too much to
|
||||
go into here, but a lot of it is covered in L<perlmodlib>
|
||||
and on L<http://www.cpan.org/> among other places.
|
||||
|
||||
When you distribute your extension via CPAN, your F<Extension.pm>
|
||||
should simply install itself as F<Bugzilla/Extension/Foo.pm>,
|
||||
where C<Foo> is the name of your module. You do not need a separate
|
||||
F<Config.pm> file, because CPAN itself will handle installing
|
||||
the prerequisites of your module, so Bugzilla doesn't have to
|
||||
worry about it.
|
||||
|
||||
=head3 Templates in extensions distributed on CPAN
|
||||
|
||||
If your extension is F</usr/lib/perl5/Bugzilla/Extension/Foo.pm>,
|
||||
then Bugzilla will look for templates in the directory
|
||||
F</usr/lib/perl5/Bugzilla/Extension/Foo/template/>.
|
||||
|
||||
Hook functions always get arguments through single hashref parameter ($args).
|
||||
Their return value is always a boolean value: when it's TRUE, other hooks
|
||||
|
|
|
@ -184,7 +184,8 @@ use constant DEFAULT_FIELDS => (
|
|||
buglist => 1},
|
||||
{name => 'rep_platform', desc => 'Platform', in_new_bugmail => 1,
|
||||
type => FIELD_TYPE_SINGLE_SELECT, buglist => 1},
|
||||
{name => 'bug_file_loc', desc => 'URL', in_new_bugmail => 1},
|
||||
{name => 'bug_file_loc', desc => 'URL', in_new_bugmail => 1,
|
||||
buglist => 1},
|
||||
{name => 'op_sys', desc => 'OS/Version', in_new_bugmail => 1,
|
||||
type => FIELD_TYPE_SINGLE_SELECT, buglist => 1},
|
||||
{name => 'bug_status', desc => 'Status', in_new_bugmail => 1,
|
||||
|
|
|
@ -230,26 +230,6 @@ sub bug {
|
|||
|
||||
=over
|
||||
|
||||
=item C<has_flags>
|
||||
|
||||
Returns 1 if at least one flag exists in the DB, else 0. This subroutine
|
||||
is mainly used to decide to display the "(My )Requests" link in the footer.
|
||||
|
||||
=back
|
||||
|
||||
=cut
|
||||
|
||||
sub has_flags {
|
||||
my $dbh = Bugzilla->dbh;
|
||||
|
||||
my $has_flags = $dbh->selectrow_array('SELECT 1 FROM flags ' . $dbh->sql_limit(1));
|
||||
return $has_flags || 0;
|
||||
}
|
||||
|
||||
=pod
|
||||
|
||||
=over
|
||||
|
||||
=item C<match($criteria)>
|
||||
|
||||
Queries the database for flags matching the given criteria
|
||||
|
@ -555,7 +535,7 @@ sub retarget {
|
|||
my $success = 0;
|
||||
foreach my $flagtype (@flagtypes) {
|
||||
next if !$flagtype->is_active;
|
||||
next if (!$flagtype->is_multiplicable && grep { $_->id != $self->id } @{$flagtype->{flags}});
|
||||
next if (!$flagtype->is_multiplicable && scalar @{$flagtype->{flags}});
|
||||
next unless (($self->status eq '?' && $self->setter->can_request_flag($flagtype))
|
||||
|| $self->setter->can_set_flag($flagtype));
|
||||
|
||||
|
|
|
@ -369,6 +369,66 @@ The hash of changed fields. C<< $changes->{field} = [old, new] >>
|
|||
|
||||
=back
|
||||
|
||||
=head2 bug_check_can_change_field
|
||||
|
||||
This hook controls what fields users are allowed to change. You can add code here for
|
||||
site-specific policy changes and other customizations. This hook is only
|
||||
executed if the field's new and old values differ. Any denies take priority over any allows.
|
||||
So, if another extension denies a change but yours allows the change, the other extension's
|
||||
deny will override your extension's allow.
|
||||
|
||||
Params:
|
||||
|
||||
=over
|
||||
|
||||
=item C<bug>
|
||||
|
||||
L<Bugzilla::Bug> - The current bug object that this field is changing on.
|
||||
|
||||
=item C<field>
|
||||
|
||||
The name (from the C<fielddefs> table) of the field that we are checking.
|
||||
|
||||
=item C<new_value>
|
||||
|
||||
The new value that the field is being changed to.
|
||||
|
||||
=item C<old_value>
|
||||
|
||||
The old value that the field is being changed from.
|
||||
|
||||
=item C<priv_results>
|
||||
|
||||
C<array> - This is how you explicitly allow or deny a change. You should only
|
||||
push something into this array if you want to explicitly allow or explicitly
|
||||
deny the change, and thus skip all other permission checks that would otherwise
|
||||
happen after this hook is called. If you don't care about the field change,
|
||||
then don't push anything into the array.
|
||||
|
||||
The pushed value should be a choice from the following constants:
|
||||
|
||||
=over
|
||||
|
||||
=item C<PRIVILEGES_REQUIRED_NONE>
|
||||
|
||||
No privileges required. This explicitly B<allows> a change.
|
||||
|
||||
=item C<PRIVILEGES_REQUIRED_REPORTER>
|
||||
|
||||
User is not the reporter, assignee or an empowered user, so B<deny>.
|
||||
|
||||
=item C<PRIVILEGES_REQUIRED_ASSIGNEE>
|
||||
|
||||
User is not the assignee or an empowered user, so B<deny>.
|
||||
|
||||
=item C<PRIVILEGES_REQUIRED_EMPOWERED>
|
||||
|
||||
User is not a sufficiently empowered user, so B<deny>.
|
||||
|
||||
=back
|
||||
|
||||
=back
|
||||
|
||||
=head2 bug_fields
|
||||
|
||||
Allows the addition of database fields from the bugs table to the standard
|
||||
|
@ -546,21 +606,6 @@ spaces.
|
|||
=back
|
||||
|
||||
|
||||
=head2 colchange_columns
|
||||
|
||||
This happens in F<colchange.cgi> right after the list of possible display
|
||||
columns have been defined and gives you the opportunity to add additional
|
||||
display columns to the list of selectable columns.
|
||||
|
||||
Params:
|
||||
|
||||
=over
|
||||
|
||||
=item C<columns> - An arrayref containing an array of column IDs. Any IDs
|
||||
added by this hook must have been defined in the the L</buglist_columns> hook.
|
||||
|
||||
=back
|
||||
|
||||
=head2 config_add_panels
|
||||
|
||||
If you want to add new panels to the Parameters administrative interface,
|
||||
|
|
|
@ -107,6 +107,8 @@ sub update_fielddefs_definition {
|
|||
#2008-08-26 elliotte_martin@yahoo.com - Bug 251556
|
||||
$dbh->bz_add_column('fielddefs', 'reverse_desc', {TYPE => 'TINYTEXT'});
|
||||
|
||||
$dbh->do('UPDATE fielddefs SET buglist = 1
|
||||
WHERE custom = 1 AND type = ' . FIELD_TYPE_MULTI_SELECT);
|
||||
|
||||
# Remember, this is not the function for adding general table changes.
|
||||
# That is below. Add new changes to the fielddefs table above this
|
||||
|
|
|
@ -150,7 +150,13 @@ sub extension_requirement_packages {
|
|||
# Bugzilla::Extension->load_all (because stuff has already been loaded).
|
||||
# (This matters because almost every page calls Bugzilla->feature, which
|
||||
# calls OPTIONAL_MODULES, which calls this method.)
|
||||
if (eval { Bugzilla->extensions }) {
|
||||
#
|
||||
# We check if Bugzilla.pm is already loaded, instead of doing a "require",
|
||||
# because we *do* want the code lower down to run during the Requirements
|
||||
# phase of checksetup.pl, instead of Bugzilla->extensions, and Bugzilla.pm
|
||||
# actually *can* be loaded during the Requirements phase if all the
|
||||
# requirements have already been installed.
|
||||
if ($INC{'Bugzilla.pm'}) {
|
||||
return Bugzilla->extensions;
|
||||
}
|
||||
my $packages = _cache()->{extension_requirement_packages};
|
||||
|
@ -262,6 +268,8 @@ sub install_string {
|
|||
|
||||
utf8::decode($string_template) if !utf8::is_utf8($string_template);
|
||||
|
||||
utf8::decode($string_template) if !utf8::is_utf8($string_template);
|
||||
|
||||
$vars ||= {};
|
||||
my @replace_keys = keys %$vars;
|
||||
foreach my $key (@replace_keys) {
|
||||
|
@ -282,91 +290,85 @@ sub install_string {
|
|||
return $string_template;
|
||||
}
|
||||
|
||||
sub include_languages {
|
||||
# If we are in CGI mode (not in checksetup.pl) and if the function has
|
||||
# been called without any parameter, then we cache the result of this
|
||||
# function in Bugzilla->request_cache. This is done to improve the
|
||||
# performance of the template processing.
|
||||
my $to_be_cached = 0;
|
||||
if (not @_) {
|
||||
my $cache = _cache();
|
||||
if (exists $cache->{include_languages}) {
|
||||
return @{ $cache->{include_languages} };
|
||||
}
|
||||
$to_be_cached = 1;
|
||||
}
|
||||
my ($params) = @_;
|
||||
$params ||= {};
|
||||
sub _wanted_languages {
|
||||
my ($requested, @wanted);
|
||||
|
||||
# Basically, the way this works is that we have a list of languages
|
||||
# that we *want*, and a list of languages that Bugzilla actually
|
||||
# supports. The caller tells us what languages they want, by setting
|
||||
# $ENV{HTTP_ACCEPT_LANGUAGE}, using the "LANG" cookie or setting
|
||||
# $params->{only_language}. The languages we support are those
|
||||
# specified in $params->{use_languages}. Otherwise we support every
|
||||
# language installed in the template/ directory.
|
||||
|
||||
my @wanted;
|
||||
if ($params->{only_language}) {
|
||||
# We can pass several languages at once as an arrayref
|
||||
# or a single language.
|
||||
if (ref $params->{only_language}) {
|
||||
@wanted = @{ $params->{only_language} };
|
||||
}
|
||||
else {
|
||||
@wanted = ($params->{only_language});
|
||||
}
|
||||
}
|
||||
# Checking SERVER_SOFTWARE is the same as i_am_cgi() in Bugzilla::Util.
|
||||
if (exists $ENV{'SERVER_SOFTWARE'}) {
|
||||
my $cgi = Bugzilla->cgi;
|
||||
$requested = $cgi->http('Accept-Language') || '';
|
||||
my $lang = $cgi->cookie('LANG');
|
||||
push(@wanted, $lang) if $lang;
|
||||
- }
|
||||
else {
|
||||
@wanted = _sort_accept_language($ENV{'HTTP_ACCEPT_LANGUAGE'} || '');
|
||||
# Don't use the cookie if we are in "checksetup.pl". The test
|
||||
# with $ENV{'SERVER_SOFTWARE'} is the same as in
|
||||
# Bugzilla:Util::i_am_cgi.
|
||||
if (exists $ENV{'SERVER_SOFTWARE'}) {
|
||||
my $cgi = Bugzilla->cgi;
|
||||
if (defined (my $lang = $cgi->cookie('LANG'))) {
|
||||
unshift @wanted, $lang;
|
||||
}
|
||||
}
|
||||
$requested = get_console_locale();
|
||||
}
|
||||
|
||||
my @supported;
|
||||
if (defined $params->{use_languages}) {
|
||||
@supported = @{$params->{use_languages}};
|
||||
}
|
||||
else {
|
||||
my @dirs = glob(bz_locations()->{'templatedir'} . "/*");
|
||||
@dirs = map(basename($_), @dirs);
|
||||
@supported = grep($_ ne 'CVS', @dirs);
|
||||
}
|
||||
|
||||
my @usedlanguages;
|
||||
foreach my $wanted (@wanted) {
|
||||
|
||||
push(@wanted, _sort_accept_language($requested));
|
||||
return \@wanted;
|
||||
}
|
||||
|
||||
sub _wanted_to_actual_languages {
|
||||
my ($wanted, $supported) = @_;
|
||||
|
||||
my @actual;
|
||||
foreach my $lang (@$wanted) {
|
||||
# If we support the language we want, or *any version* of
|
||||
# the language we want, it gets pushed into @usedlanguages.
|
||||
# the language we want, it gets pushed into @actual.
|
||||
#
|
||||
# Per RFC 1766 and RFC 2616, things like 'en' match 'en-us' and
|
||||
# 'en-uk', but not the other way around. (This is unfortunately
|
||||
# not very clearly stated in those RFC; see comment just over 14.5
|
||||
# in http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.4)
|
||||
if(my @found = grep /^\Q$wanted\E(-.+)?$/i, @supported) {
|
||||
push (@usedlanguages, @found);
|
||||
}
|
||||
my @found = grep(/^\Q$lang\E(-.+)?$/i, @$supported);
|
||||
push(@actual, @found) if @found;
|
||||
}
|
||||
|
||||
# We always include English at the bottom if it's not there, even if
|
||||
# somebody removed it from use_languages.
|
||||
if (!grep($_ eq 'en', @usedlanguages)) {
|
||||
push(@usedlanguages, 'en');
|
||||
# it wasn't selected by the user.
|
||||
if (!grep($_ eq 'en', @actual)) {
|
||||
push(@actual, 'en');
|
||||
}
|
||||
|
||||
# Cache the result if we are in CGI mode and called without parameter
|
||||
# (see the comment at the top of this function).
|
||||
if ($to_be_cached) {
|
||||
_cache()->{include_languages} = \@usedlanguages;
|
||||
return \@actual;
|
||||
}
|
||||
|
||||
sub supported_languages {
|
||||
my $cache = _cache();
|
||||
return $cache->{supported_languages} if $cache->{supported_languages};
|
||||
|
||||
my @dirs = glob(bz_locations()->{'templatedir'} . "/*");
|
||||
my @languages;
|
||||
foreach my $dir (@dirs) {
|
||||
# It's a language directory only if it contains "default" or
|
||||
# "custom". This auto-excludes CVS directories as well.
|
||||
next if (!-d "$dir/default" and !-d "$dir/custom");
|
||||
my $lang = basename($dir);
|
||||
# Check for language tag format conforming to RFC 1766.
|
||||
next unless $lang =~ /^[a-zA-Z]{1,8}(-[a-zA-Z]{1,8})?$/;
|
||||
push(@languages, $lang);
|
||||
}
|
||||
|
||||
return @usedlanguages;
|
||||
$cache->{supported_languages} = \@languages;
|
||||
return \@languages;
|
||||
}
|
||||
|
||||
sub include_languages {
|
||||
my ($params) = @_;
|
||||
|
||||
# Basically, the way this works is that we have a list of languages
|
||||
# that we *want*, and a list of languages that Bugzilla actually
|
||||
# supports.
|
||||
my $wanted;
|
||||
if ($params->{language}) {
|
||||
$wanted = [$params->{language}];
|
||||
}
|
||||
else {
|
||||
$wanted = _wanted_languages();
|
||||
}
|
||||
my $supported = supported_languages();
|
||||
my $actual = _wanted_to_actual_languages($wanted, $supported);
|
||||
return @$actual;
|
||||
}
|
||||
|
||||
# Used by template_include_path
|
||||
|
@ -551,7 +553,6 @@ sub get_console_locale {
|
|||
sub init_console {
|
||||
eval { ON_WINDOWS && require Win32::Console::ANSI; };
|
||||
$ENV{'ANSI_COLORS_DISABLED'} = 1 if ($@ || !-t *STDOUT);
|
||||
$ENV{'HTTP_ACCEPT_LANGUAGE'} ||= get_console_locale();
|
||||
prevent_windows_dialog_boxes();
|
||||
}
|
||||
|
||||
|
|
|
@ -749,8 +749,10 @@ sub groups_mandatory {
|
|||
# is Mandatory, the group is Mandatory for everybody, regardless of their
|
||||
# group membership.
|
||||
my $ids = Bugzilla->dbh->selectcol_arrayref(
|
||||
"SELECT group_id FROM group_control_map
|
||||
WHERE product_id = ?
|
||||
"SELECT group_id
|
||||
FROM group_control_map
|
||||
INNER JOIN groups ON group_control_map.group_id = groups.id
|
||||
WHERE product_id = ? AND isactive = 1
|
||||
AND (membercontrol = $mandatory
|
||||
OR (othercontrol = $mandatory
|
||||
AND group_id NOT IN ($groups)))",
|
||||
|
@ -760,8 +762,8 @@ sub groups_mandatory {
|
|||
}
|
||||
|
||||
# We don't just check groups_valid, because we want to know specifically
|
||||
# if this group is valid for the currently-logged-in user.
|
||||
sub group_is_valid {
|
||||
# if this group can be validly set by the currently-logged-in user.
|
||||
sub group_is_settable {
|
||||
my ($self, $group) = @_;
|
||||
my $group_id = blessed($group) ? $group->id : $group;
|
||||
my $is_mandatory = grep { $group_id == $_->id }
|
||||
|
@ -771,6 +773,11 @@ sub group_is_valid {
|
|||
return ($is_mandatory or $is_available) ? 1 : 0;
|
||||
}
|
||||
|
||||
sub group_is_valid {
|
||||
my ($self, $group) = @_;
|
||||
return grep($_->id == $group->id, @{ $self->groups_valid }) ? 1 : 0;
|
||||
}
|
||||
|
||||
sub groups_valid {
|
||||
my ($self) = @_;
|
||||
return $self->{groups_valid} if defined $self->{groups_valid};
|
||||
|
@ -1102,7 +1109,7 @@ is set to Default for the currently-logged-in user.
|
|||
Tells you what groups are mandatory for bugs in this product, for the
|
||||
currently-logged-in user. Returns an arrayref of C<Bugzilla::Group> objects.
|
||||
|
||||
=item C<group_is_valid>
|
||||
=item C<group_is_settable>
|
||||
|
||||
=over
|
||||
|
||||
|
@ -1138,7 +1145,9 @@ C<1> if the group is valid in this product, C<0> otherwise.
|
|||
|
||||
Returns an arrayref of L<Bugzilla::Group> objects, representing groups
|
||||
that bugs could validly be restricted to within this product. Used mostly
|
||||
by L<Bugzilla::Bug> to assure that you're adding valid groups to a bug.
|
||||
when you need the list of all possible groups that could be set in a product
|
||||
by anybody, disregarding whether or not the groups are active or who the
|
||||
currently logged-in user is.
|
||||
|
||||
B<Note>: This doesn't check whether or not the current user can add/remove
|
||||
bugs to/from these groups. It just tells you that bugs I<could be in> these
|
||||
|
@ -1150,6 +1159,13 @@ groups, in this product.
|
|||
|
||||
=back
|
||||
|
||||
=item C<group_is_valid>
|
||||
|
||||
Returns C<1> if the passed-in L<Bugzilla::Group> or group id could be set
|
||||
on a bug by I<anybody>, in this product. Even inactive groups are considered
|
||||
valid. (This is a shortcut for searching L</groups_valid> to find out if
|
||||
a group is valid in a particular product.)
|
||||
|
||||
=item C<versions>
|
||||
|
||||
Description: Returns all valid versions for that product.
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
|
||||
# Totally Rewritten Bugzilla4Intranet search engine
|
||||
# License: Dual-license GPL 3.0+ or MPL 1.1+
|
||||
# Contributor(s): Vitaliy Filippov <vitalif@mail.ru>
|
||||
|
@ -2095,6 +2096,9 @@ sub _long_desc_changedby
|
|||
sub _long_desc_changedbefore_after
|
||||
{
|
||||
my $self = shift;
|
||||
my %func_args = @_;
|
||||
my ($chartid, $supptables, $term, $groupby, $fields, $t, $v) =
|
||||
@func_args{qw(chartid supptables term groupby fields t v)};
|
||||
my $dbh = Bugzilla->dbh;
|
||||
my $operator = ($self->{type} =~ /before/) ? '<' : '>';
|
||||
my $table = "longdescs_".$self->{sequence};
|
||||
|
|
|
@ -31,6 +31,7 @@ use Bugzilla::Field;
|
|||
use Bugzilla::Util;
|
||||
|
||||
use List::Util qw(min max);
|
||||
use Text::ParseWords qw(quotewords);
|
||||
|
||||
use base qw(Exporter);
|
||||
@Bugzilla::Search::Quicksearch::EXPORT = qw(quicksearch);
|
||||
|
@ -164,6 +165,8 @@ sub quicksearch {
|
|||
$self->{content} = '';
|
||||
$self->{unknown_fields} = [];
|
||||
$self->{ambiguous_fields} = {};
|
||||
my @words = quotewords('\s+', 0, $searchstring);
|
||||
_handle_status_and_resolution(\@words);
|
||||
|
||||
$self->_handle_status_and_resolution;
|
||||
|
||||
|
@ -655,7 +658,7 @@ sub makeChart {
|
|||
my $cgi = Bugzilla->cgi;
|
||||
$cgi->param("field$expr", $field);
|
||||
$cgi->param("type$expr", $type);
|
||||
$cgi->param("value$expr", url_decode($value));
|
||||
$cgi->param("value$expr", $value);
|
||||
}
|
||||
|
||||
1;
|
||||
|
|
|
@ -89,12 +89,11 @@ sub _load_constants {
|
|||
# settings of the user and of the available languages
|
||||
# If no Accept-Language is present it uses the defined default
|
||||
# Templates may also be found in the extensions/ tree
|
||||
sub getTemplateIncludePath {
|
||||
sub _include_path {
|
||||
my $lang = shift || '';
|
||||
my $cache = Bugzilla->request_cache;
|
||||
my $lang = $cache->{'language'} || '';
|
||||
$cache->{"template_include_path_$lang"} ||= template_include_path({
|
||||
use_languages => Bugzilla->languages,
|
||||
only_language => $lang });
|
||||
$cache->{"template_include_path_$lang"} ||=
|
||||
template_include_path({ language => $lang });
|
||||
return $cache->{"template_include_path_$lang"};
|
||||
}
|
||||
|
||||
|
@ -350,7 +349,7 @@ sub quoteUrls {
|
|||
# we have to do this in one pattern, and so this is semi-messy.
|
||||
# Also, we can't use $bug_re?$comment_re? because that will match the
|
||||
# empty string
|
||||
my $bug_word = Bugzilla->messages->{terms}->{bug};
|
||||
my $bug_word = template_var('terms')->{bug};
|
||||
my $bug_re = qr/\Q$bug_word\E\s*\#?\s*(\d+)/i;
|
||||
my $comment_re = qr/comment\s*\#?\s*(\d+)/i;
|
||||
$text =~ s~\b($bug_re(?:\s*,?\s*$comment_re)?|$comment_re)
|
||||
|
@ -546,6 +545,17 @@ $Template::Stash::SCALAR_OPS->{ truncate } =
|
|||
|
||||
###############################################################################
|
||||
|
||||
sub process {
|
||||
my $self = shift;
|
||||
# All of this current_langs stuff allows template_inner to correctly
|
||||
# determine what-language Template object it should instantiate.
|
||||
my $current_langs = Bugzilla->request_cache->{template_current_lang} ||= [];
|
||||
unshift(@$current_langs, $self->context->{bz_language});
|
||||
my $retval = $self->SUPER::process(@_);
|
||||
shift @$current_langs;
|
||||
return $retval;
|
||||
}
|
||||
|
||||
# Construct the Template object
|
||||
|
||||
# Note that all of the failure cases here can't use templateable errors,
|
||||
|
@ -560,7 +570,8 @@ sub create {
|
|||
|
||||
my $config = {
|
||||
# Colon-separated list of directories containing templates.
|
||||
INCLUDE_PATH => $opts{'include_path'} || getTemplateIncludePath(),
|
||||
INCLUDE_PATH => $opts{'include_path'}
|
||||
|| _include_path($opts{'language'}),
|
||||
|
||||
# Remove white-space before template directives (PRE_CHOMP) and at the
|
||||
# beginning and end of templates and template blocks (TRIM) for better
|
||||
|
@ -830,6 +841,15 @@ sub create {
|
|||
# Now remove extra whitespace...
|
||||
my $collapse_filter = $Template::Filters::FILTERS->{collapse};
|
||||
$var = $collapse_filter->($var);
|
||||
# And if we're not in the WebService, wrap the message.
|
||||
# (Wrapping the message in the WebService is unnecessary
|
||||
# and causes awkward things like \n's appearing in error
|
||||
# messages in JSON-RPC.)
|
||||
unless (Bugzilla->usage_mode == USAGE_MODE_JSON
|
||||
or Bugzilla->usage_mode == USAGE_MODE_XMLRPC)
|
||||
{
|
||||
$var = wrap_comment($var, 72);
|
||||
}
|
||||
return $var;
|
||||
},
|
||||
|
||||
|
@ -1012,6 +1032,11 @@ sub create {
|
|||
|
||||
'feature_enabled' => sub { return Bugzilla->feature(@_); },
|
||||
|
||||
# field_descs can be somewhat slow to generate, so we generate
|
||||
# it only once per-language no matter how many times
|
||||
# $template->process() is called.
|
||||
'field_descs' => sub { return template_var('field_descs') },
|
||||
|
||||
'install_string' => \&Bugzilla::Install::Util::install_string,
|
||||
|
||||
# These don't work as normal constants.
|
||||
|
@ -1022,9 +1047,7 @@ sub create {
|
|||
my @optional = @{OPTIONAL_MODULES()};
|
||||
foreach my $item (@optional) {
|
||||
my @features;
|
||||
my $feat = $item->{feature};
|
||||
ref $feat or $feat = [ $feat ];
|
||||
foreach my $feat_id (@$feat) {
|
||||
foreach my $feat_id (@{ $item->{feature} }) {
|
||||
push(@features, install_string("feature_$feat_id"));
|
||||
}
|
||||
$item->{feature} = \@features;
|
||||
|
@ -1039,6 +1062,11 @@ sub create {
|
|||
Bugzilla::Hook::process('template_before_create', { config => $config });
|
||||
my $template = $class->new($config)
|
||||
|| die("Template creation failed: " . $class->error());
|
||||
|
||||
# Pass on our current language to any template hooks or inner templates
|
||||
# called by this Template object.
|
||||
$template->context->{bz_language} = $opts{language} || '';
|
||||
|
||||
return $template;
|
||||
}
|
||||
|
||||
|
@ -1071,8 +1099,7 @@ sub precompile_templates {
|
|||
|
||||
print install_string('template_precompile') if $output;
|
||||
|
||||
my $paths = template_include_path({ use_languages => Bugzilla->languages,
|
||||
only_language => Bugzilla->languages });
|
||||
my $paths = template_include_path();
|
||||
|
||||
foreach my $dir (@$paths) {
|
||||
my $template = Bugzilla::Template->create(include_path => [$dir]);
|
||||
|
|
|
@ -27,7 +27,7 @@ use strict;
|
|||
use base qw(Template::Plugin);
|
||||
|
||||
use Bugzilla::Constants;
|
||||
use Bugzilla::Install::Util qw(include_languages template_include_path);
|
||||
use Bugzilla::Install::Util qw(template_include_path);
|
||||
use Bugzilla::Util;
|
||||
use Bugzilla::Error;
|
||||
|
||||
|
@ -65,7 +65,7 @@ sub process {
|
|||
# Get the hooks out of the cache if they exist. Otherwise, read them
|
||||
# from the disk.
|
||||
my $cache = Bugzilla->request_cache->{template_plugin_hook_cache} ||= {};
|
||||
my $lang = Bugzilla->request_cache->{language} || '';
|
||||
my $lang = $context->{bz_language} || '';
|
||||
$cache->{"${lang}__$extension_template"}
|
||||
||= $self->_get_hooks($extension_template);
|
||||
|
||||
|
@ -78,7 +78,7 @@ sub process {
|
|||
sub _get_hooks {
|
||||
my ($self, $extension_template) = @_;
|
||||
|
||||
my $template_sets = _template_hook_include_path();
|
||||
my $template_sets = $self->_template_hook_include_path();
|
||||
my @hooks;
|
||||
foreach my $dir_set (@$template_sets) {
|
||||
foreach my $template_dir (@$dir_set) {
|
||||
|
@ -96,13 +96,13 @@ sub _get_hooks {
|
|||
}
|
||||
|
||||
sub _template_hook_include_path {
|
||||
my $self = shift;
|
||||
my $cache = Bugzilla->request_cache;
|
||||
my $language = $cache->{language} || '';
|
||||
my $language = $self->_context->{bz_language} || '';
|
||||
my $cache_key = "template_plugin_hook_include_path_$language";
|
||||
$cache->{$cache_key} ||= template_include_path({
|
||||
use_languages => Bugzilla->languages,
|
||||
only_language => $language,
|
||||
hook => 1,
|
||||
language => $language,
|
||||
hook => 1,
|
||||
});
|
||||
return $cache->{$cache_key};
|
||||
}
|
||||
|
|
|
@ -122,7 +122,6 @@ sub IssueEmailChangeToken {
|
|||
$template->process("account/email/change-new.txt.tmpl", $vars, \$message)
|
||||
|| ThrowTemplateError($template->error());
|
||||
|
||||
Bugzilla->template_inner("");
|
||||
MessageToMTA($message);
|
||||
}
|
||||
|
||||
|
@ -160,7 +159,6 @@ sub IssuePasswordToken {
|
|||
$vars, \$message)
|
||||
|| ThrowTemplateError($template->error());
|
||||
|
||||
Bugzilla->template_inner("");
|
||||
MessageToMTA($message);
|
||||
}
|
||||
|
||||
|
@ -300,7 +298,6 @@ sub Cancel {
|
|||
$template->process("account/cancel-token.txt.tmpl", $vars, \$message)
|
||||
|| ThrowTemplateError($template->error());
|
||||
|
||||
Bugzilla->template_inner("");
|
||||
MessageToMTA($message);
|
||||
|
||||
# Delete the token from the database.
|
||||
|
|
|
@ -32,21 +32,21 @@ use utf8;
|
|||
use strict;
|
||||
|
||||
use base qw(Exporter);
|
||||
@Bugzilla::Util::EXPORT = qw(
|
||||
trick_taint detaint_natural trick_taint_copy detaint_signed
|
||||
html_quote url_quote url_quote_noslash xml_quote css_class_quote html_light_quote url_decode
|
||||
i_am_cgi correct_urlbase remote_ip lsearch
|
||||
do_ssl_redirect_if_required use_attachbase
|
||||
diff_arrays list
|
||||
trim wrap_hard wrap_comment find_wrap_point makeCitations
|
||||
format_time format_time_decimal validate_date validate_time datetime_from
|
||||
file_mod_time is_7bit_clean
|
||||
bz_crypt generate_random_password
|
||||
validate_email_syntax clean_text
|
||||
stem_text intersect union
|
||||
get_text disable_utf8 bz_encode_json
|
||||
xml_element xml_element_quote xml_dump_simple xml_simple
|
||||
);
|
||||
@Bugzilla::Util::EXPORT = qw(trick_taint detaint_natural trick_taint_copy
|
||||
detaint_signed
|
||||
html_quote url_quote url_quote_noslash xml_quote
|
||||
css_class_quote html_light_quote url_decode
|
||||
i_am_cgi correct_urlbase remote_ip
|
||||
lsearch do_ssl_redirect_if_required use_attachbase
|
||||
diff_arrays list
|
||||
trim wrap_hard wrap_comment find_wrap_point makeCitations
|
||||
format_time format_time_decimal validate_date
|
||||
validate_time datetime_from
|
||||
file_mod_time is_7bit_clean
|
||||
bz_crypt generate_random_password
|
||||
validate_email_syntax clean_text stem_text bz_encode_json
|
||||
xml_element xml_element_quote xml_dump_simple xml_simple
|
||||
get_text template_var disable_utf8);
|
||||
|
||||
use Bugzilla::Constants;
|
||||
|
||||
|
@ -743,6 +743,26 @@ sub get_text
|
|||
return $message;
|
||||
}
|
||||
|
||||
sub template_var {
|
||||
my $name = shift;
|
||||
my $cache = Bugzilla->request_cache->{util_template_var} ||= {};
|
||||
my $template = Bugzilla->template_inner;
|
||||
my $lang = $template->context->{bz_language};
|
||||
return $cache->{$lang}->{$name} if defined $cache->{$lang};
|
||||
my %vars;
|
||||
# Note: If we suddenly start needing a lot of template_var variables,
|
||||
# they should move into their own template, not field-descs.
|
||||
my $result = $template->process('global/field-descs.none.tmpl',
|
||||
{ vars => \%vars, in_template_var => 1 });
|
||||
# Bugzilla::Error can't be "use"d in Bugzilla::Util.
|
||||
if (!$result) {
|
||||
require Bugzilla::Error;
|
||||
Bugzilla::Error::ThrowTemplateError($template->error);
|
||||
}
|
||||
$cache->{$lang} = \%vars;
|
||||
return $vars{$name};
|
||||
}
|
||||
|
||||
sub disable_utf8 {
|
||||
if (Bugzilla->params->{'utf8'}) {
|
||||
binmode STDOUT, ':bytes'; # Turn off UTF8 encoding.
|
||||
|
@ -1221,6 +1241,14 @@ A string.
|
|||
|
||||
=back
|
||||
|
||||
|
||||
=item C<template_var>
|
||||
|
||||
This is a method of getting the value of a variable from a template in
|
||||
Perl code. The available variables are in the C<global/field-descs.none.tmpl>
|
||||
template. Just pass in the name of the variable that you want the value of.
|
||||
|
||||
|
||||
=back
|
||||
|
||||
=head2 Formatting Time
|
||||
|
|
|
@ -94,7 +94,7 @@ sub fields {
|
|||
if (defined $params->{names}) {
|
||||
my $names = $params->{names};
|
||||
foreach my $field_name (@$names) {
|
||||
my $loop_field = Bugzilla->get_field($field_name, THROW_ERROR);
|
||||
my $loop_field = Bugzilla::Field->check($field_name);
|
||||
# Don't push in duplicate fields if we also asked for this field
|
||||
# in "ids".
|
||||
if (!grep($_->id == $loop_field->id, @fields)) {
|
||||
|
@ -111,7 +111,7 @@ sub fields {
|
|||
foreach my $field (@fields) {
|
||||
my $visibility_field = $field->visibility_field
|
||||
? $field->visibility_field->name : undef;
|
||||
my $vis_values = $field->visibility_values;
|
||||
my $vis_value = $field->visibility_value;
|
||||
my $value_field = $field->value_field
|
||||
? $field->value_field->name : undef;
|
||||
|
||||
|
@ -137,7 +137,9 @@ sub fields {
|
|||
# is_mandatory => $self->type('boolean', $field->is_mandatory),
|
||||
is_on_bug_entry => $self->type('boolean', $field->enter_bug),
|
||||
visibility_field => $self->type('string', $visibility_field),
|
||||
visibility_values => [ map { $self->type('string', $_->name) } @{ $vis_values || [] } ],
|
||||
visibility_values => [
|
||||
defined $vis_value ? $self->type('string', $vis_value->name) : ()
|
||||
],
|
||||
);
|
||||
if ($has_values) {
|
||||
$field_data{value_field} = $self->type('string', $value_field);
|
||||
|
@ -212,11 +214,14 @@ sub _legal_field_values {
|
|||
else {
|
||||
my @values = Bugzilla::Field::Choice->type($field)->get_all();
|
||||
foreach my $value (@values) {
|
||||
my $vis_values = $value->visibility_values;
|
||||
my $vis_val = $value->visibility_value;
|
||||
push(@result, {
|
||||
name => $self->type('string', $value->name),
|
||||
sortkey => $self->type('int' , $value->sortkey),
|
||||
visibility_values => [ map { $self->type('string', $_->name) } @{ $vis_values || [] } ],
|
||||
visibility_values => [
|
||||
defined $vis_val ? $self->type('string', $vis_val->name)
|
||||
: ()
|
||||
],
|
||||
});
|
||||
}
|
||||
}
|
||||
|
@ -1653,26 +1658,13 @@ take.
|
|||
If you are not in the time-tracking group, this field will not be included
|
||||
in the return value.
|
||||
|
||||
=item C<groups>
|
||||
=item internals B<DEPRECATED>
|
||||
|
||||
C<array> of C<string>s. The names of all the groups that this bug is in.
|
||||
|
||||
=item C<id>
|
||||
This will be disappearing in a future version of Bugzilla.
|
||||
|
||||
C<int> The unique numeric id of this bug.
|
||||
|
||||
=item C<is_cc_accessible>
|
||||
|
||||
C<boolean> If true, this bug can be accessed by members of the CC list,
|
||||
even if they are not in the groups the bug is restricted to.
|
||||
|
||||
=item C<is_confirmed>
|
||||
|
||||
C<boolean> True if the bug has been confirmed. Usually this means that
|
||||
the bug has at some point been moved out of the C<UNCONFIRMED> status
|
||||
and into another open status.
|
||||
|
||||
=item C<is_open>
|
||||
=item is_open
|
||||
|
||||
C<boolean> True if this bug is open, false if it is closed.
|
||||
|
||||
|
@ -2552,7 +2544,7 @@ code of 32000.
|
|||
|
||||
=item C<update>
|
||||
|
||||
B<UNSTABLE>
|
||||
B<EXPERIMENTAL>
|
||||
|
||||
=over
|
||||
|
||||
|
|
|
@ -107,6 +107,9 @@ use constant WS_ERROR_CODE => {
|
|||
# Except, historically, AUTH_NODATA, which is 410.
|
||||
login_required => 410,
|
||||
|
||||
# Except, historically, AUTH_NODATA, which is 410.
|
||||
login_required => 410,
|
||||
|
||||
# User errors are 500-600.
|
||||
account_exists => 500,
|
||||
illegal_email_address => 501,
|
||||
|
|
|
@ -42,7 +42,6 @@ sub datetime_format_inbound {
|
|||
|
||||
sub datetime_format_outbound {
|
||||
my ($self, $date) = @_;
|
||||
return '' if !$date;
|
||||
|
||||
my $time = $date;
|
||||
if (blessed($date)) {
|
||||
|
|
|
@ -27,7 +27,7 @@ use base qw(JSON::RPC::Legacy::Server::CGI Bugzilla::WebService::Server);
|
|||
use Bugzilla::Error;
|
||||
use Bugzilla::WebService::Constants;
|
||||
use Bugzilla::WebService::Util qw(taint_data);
|
||||
use Bugzilla::Util qw(datetime_from correct_urlbase trim);
|
||||
use Bugzilla::Util qw(correct_urlbase trim);
|
||||
use MIME::Base64 qw(decode_base64 encode_base64);
|
||||
|
||||
sub new {
|
||||
|
@ -44,33 +44,21 @@ sub create_json_coder {
|
|||
my $json = $self->SUPER::create_json_coder(@_);
|
||||
$json->allow_blessed(1);
|
||||
$json->convert_blessed(1);
|
||||
#*********************************************************************#
|
||||
# ïÒÉÇÉÎÁÌØÎÏÅ ÒÅÛÅÎÉÅ, ÎÏ ÐÒÉ×ÏÄÉÔ Ë ÏÛÉÂËÁÍ #
|
||||
# JSON::RPC::Server at line 170 (HTTP::Message content must be bytes) #
|
||||
## This may seem a little backwards, but what this really means is #
|
||||
## "don't convert our utf8 into byte strings, just leave it as a #
|
||||
## utf8 string." #
|
||||
#$json->utf8(0) if Bugzilla->params->{'utf8'}; #
|
||||
#*********************************************************************#
|
||||
# This may seem a little backwards, but what this really means is
|
||||
# "don't convert our utf8 into byte strings, just leave it as a
|
||||
# utf8 string."
|
||||
$json->utf8(0) if Bugzilla->params->{'utf8'};
|
||||
return $json;
|
||||
}
|
||||
|
||||
# Override the JSON::RPC method to return our CGI object instead of theirs.
|
||||
sub cgi { return Bugzilla->cgi; }
|
||||
|
||||
# Override the JSON::RPC method to use $cgi->header properly instead of
|
||||
# just printing text directly. This fixes various problems, including
|
||||
# sending Bugzilla's cookies properly.
|
||||
sub response {
|
||||
my ($self, $response) = @_;
|
||||
|
||||
# Implement JSONP.
|
||||
if (my $callback = $self->_bz_callback) {
|
||||
my $content = $response->content;
|
||||
$response->content("$callback($content)");
|
||||
|
||||
}
|
||||
|
||||
# Use $cgi->header properly instead of just printing text directly.
|
||||
# This fixes various problems, including sending Bugzilla's cookies
|
||||
# properly.
|
||||
my $headers = $response->headers;
|
||||
my @header_args;
|
||||
foreach my $name ($headers->header_field_names) {
|
||||
|
@ -81,89 +69,10 @@ sub response {
|
|||
}
|
||||
}
|
||||
my $cgi = $self->cgi;
|
||||
$cgi->send_header(-status => $response->code, @header_args);
|
||||
print $cgi->header(-status => $response->code, @header_args);
|
||||
print $response->content;
|
||||
}
|
||||
|
||||
# The JSON-RPC 1.1 GET specification is not so great--you can't specify
|
||||
# data structures as parameters. However, the JSON-RPC 2.0 "JSON-RPC over
|
||||
# HTTP" spec is excellent, so we are using that for GET requests, instead.
|
||||
# Spec: http://groups.google.com/group/json-rpc/web/json-rpc-over-http
|
||||
#
|
||||
# The one exception is that we don't require the "params" argument to be
|
||||
# Base64 encoded, because that is ridiculous and obnoxious for JavaScript
|
||||
# clients.
|
||||
sub retrieve_json_from_get {
|
||||
my $self = shift;
|
||||
my $cgi = $self->cgi;
|
||||
|
||||
my %input;
|
||||
|
||||
# Both version and id must be set before any errors are thrown.
|
||||
if ($cgi->param('version')) {
|
||||
$self->version(scalar $cgi->param('version'));
|
||||
$input{version} = $cgi->param('version');
|
||||
}
|
||||
else {
|
||||
$self->version('1.0');
|
||||
}
|
||||
|
||||
# The JSON-RPC 2.0 spec says that any request that omits an id doesn't
|
||||
# want a response. However, in an HTTP GET situation, it's stupid to
|
||||
# expect all clients to specify some id parameter just to get a response,
|
||||
# so we don't require it.
|
||||
my $id;
|
||||
if (defined $cgi->param('id')) {
|
||||
$id = $cgi->param('id');
|
||||
}
|
||||
# However, JSON::RPC does require that an id exist in most cases, in
|
||||
# order to throw proper errors. We use the installation's urlbase as
|
||||
# the id, in this case.
|
||||
else {
|
||||
$id = correct_urlbase();
|
||||
}
|
||||
# Setting _bz_request_id here is required in case we throw errors early,
|
||||
# before _handle.
|
||||
$self->{_bz_request_id} = $input{id} = $id;
|
||||
|
||||
# _bz_callback can throw an error, so we have to set it here, after we're
|
||||
# ready to throw errors.
|
||||
$self->_bz_callback(scalar $cgi->param('callback'));
|
||||
|
||||
if (!$cgi->param('method')) {
|
||||
ThrowUserError('json_rpc_get_method_required');
|
||||
}
|
||||
$input{method} = $cgi->param('method');
|
||||
|
||||
my $params;
|
||||
if (defined $cgi->param('params')) {
|
||||
local $@;
|
||||
$params = eval {
|
||||
$self->json->decode(scalar $cgi->param('params'))
|
||||
};
|
||||
if ($@) {
|
||||
ThrowUserError('json_rpc_invalid_params',
|
||||
{ params => scalar $cgi->param('params'),
|
||||
err_msg => $@ });
|
||||
}
|
||||
}
|
||||
elsif (!$self->version or $self->version ne '1.1') {
|
||||
$params = [];
|
||||
}
|
||||
else {
|
||||
$params = {};
|
||||
}
|
||||
|
||||
$input{params} = $params;
|
||||
|
||||
my $json = $self->json->encode(\%input);
|
||||
return $json;
|
||||
}
|
||||
|
||||
#######################################
|
||||
# Bugzilla::WebService Implementation #
|
||||
#######################################
|
||||
|
||||
sub type {
|
||||
my ($self, $type, $value) = @_;
|
||||
|
||||
|
@ -188,7 +97,7 @@ sub type {
|
|||
}
|
||||
elsif ($type eq 'dateTime') {
|
||||
# ISO-8601 "YYYYMMDDTHH:MM:SS" with a literal T
|
||||
$retval = $self->datetime_format($value);
|
||||
$retval = $self->datetime_format_outbound($value);
|
||||
}
|
||||
elsif ($type eq 'base64') {
|
||||
utf8::encode($value) if utf8::is_utf8($value);
|
||||
|
@ -198,13 +107,19 @@ sub type {
|
|||
return $retval;
|
||||
}
|
||||
|
||||
sub datetime_format {
|
||||
my ($self, $date_string) = @_;
|
||||
sub datetime_format_outbound {
|
||||
my $self = shift;
|
||||
# YUI expects ISO8601 in UTC time; including TZ specifier
|
||||
return $self->SUPER::datetime_format_outbound(@_) . 'Z';
|
||||
}
|
||||
|
||||
# YUI expects ISO8601 in UTC time; uncluding TZ specifier
|
||||
my $time = datetime_from($date_string, 'UTC');
|
||||
my $iso_datetime = $time->iso8601() . 'Z';
|
||||
return $iso_datetime;
|
||||
|
||||
# Store the ID of the current call, because Bugzilla::Error will need it.
|
||||
sub _handle {
|
||||
my $self = shift;
|
||||
my ($obj) = @_;
|
||||
$self->{_bz_request_id} = $obj->{id};
|
||||
return $self->SUPER::_handle(@_);
|
||||
}
|
||||
|
||||
# Make all error messages returned by JSON::RPC go into the 100000
|
||||
|
@ -228,7 +143,7 @@ sub _error {
|
|||
|
||||
# We want to always send the JSON-RPC 1.1 error format, although
|
||||
# If we're not in JSON-RPC 1.1, we don't need the silly "name" parameter.
|
||||
if (!$self->version) {
|
||||
if (!$self->version or $self->version ne '1.1') {
|
||||
my $object = $self->json->decode($json);
|
||||
my $message = $object->{error};
|
||||
# Just assure that future versions of JSON::RPC don't change the
|
||||
|
@ -411,14 +326,6 @@ sub _argument_type_check {
|
|||
return $params;
|
||||
}
|
||||
|
||||
sub _bz_convert_datetime {
|
||||
my ($self, $time) = @_;
|
||||
|
||||
my $converted = datetime_from($time, Bugzilla->local_timezone);
|
||||
$time = $converted->ymd() . ' ' . $converted->hms();
|
||||
return $time
|
||||
}
|
||||
|
||||
sub handle_login {
|
||||
my $self = shift;
|
||||
|
||||
|
|
|
@ -356,30 +356,19 @@ sub view {
|
|||
Encode::from_to($filename, 'utf-8', 'cp1251');
|
||||
}
|
||||
|
||||
# Don't send a charset header with attachments--they might not be UTF-8.
|
||||
# However, we do allow people to explicitly specify a charset if they
|
||||
# want.
|
||||
my $data = $attachment->data;
|
||||
if ($contenttype !~ /\bcharset=/i)
|
||||
{
|
||||
# Detect UTF-8 encoding
|
||||
my $is_utf8 = 0;
|
||||
if ($contenttype =~ m!^text/!iso)
|
||||
{
|
||||
Encode::_utf8_on($data);
|
||||
$is_utf8 = utf8::valid($data);
|
||||
Encode::_utf8_off($data);
|
||||
}
|
||||
# In order to prevent Apache from adding a charset, we have to send a
|
||||
# charset that's a single space.
|
||||
$cgi->charset($is_utf8 ? 'utf-8' : ' ');
|
||||
}
|
||||
$cgi->send_header(-type=>"$contenttype; name=\"$filename\"",
|
||||
-content_disposition=> "$disposition; filename=\"$filename\"",
|
||||
-content_length => $attachment->datasize);
|
||||
disable_utf8();
|
||||
print $data;
|
||||
# Don't send a charset header with attachments--they might not be UTF-8.
|
||||
# However, we do allow people to explicitly specify a charset if they
|
||||
# want.
|
||||
if ($contenttype !~ /\bcharset=/i) {
|
||||
# In order to prevent Apache from adding a charset, we have to send a
|
||||
# charset that's a single space.
|
||||
$cgi->charset(' ');
|
||||
}
|
||||
print $cgi->header(-type=>"$contenttype; name=\"$filename\"",
|
||||
-content_disposition=> "$disposition; filename=\"$filename\"",
|
||||
-content_length => $attachment->datasize);
|
||||
disable_utf8();
|
||||
print $attachment->data;
|
||||
}
|
||||
|
||||
sub interdiff {
|
||||
|
|
35
buglist.cgi
35
buglist.cgi
|
@ -470,10 +470,9 @@ if ($cmdtype eq "dorem") {
|
|||
}
|
||||
|
||||
# If we are here, then we can safely remove the saved search
|
||||
my ($query_id) = $dbh->selectrow_array('SELECT id FROM namedqueries
|
||||
WHERE userid = ?
|
||||
AND name = ?',
|
||||
undef, ($user->id, $qname));
|
||||
my $query_id;
|
||||
($buffer, $query_id) = LookupNamedQuery(scalar $cgi->param("namedcmd"),
|
||||
$user->id);
|
||||
if (!$query_id) {
|
||||
# The user has no query of this name. Play along.
|
||||
}
|
||||
|
@ -499,7 +498,7 @@ if ($cmdtype eq "dorem") {
|
|||
# Generate and return the UI (HTML page) from the appropriate template.
|
||||
$vars->{'message'} = "buglist_query_gone";
|
||||
$vars->{'namedcmd'} = $qname;
|
||||
$vars->{'url'} = "query.cgi";
|
||||
$vars->{'url'} = "buglist.cgi?newquery=" . url_quote($buffer) . "&cmdtype=doit&remtype=asnamed&newqueryname=" . url_quote($qname);
|
||||
$template->process("global/message.html.tmpl", $vars)
|
||||
|| ThrowTemplateError($template->error());
|
||||
exit;
|
||||
|
@ -727,19 +726,19 @@ if ($format->{'extension'} eq 'atom') {
|
|||
|
||||
# This is the list of fields that are needed by the Atom filter.
|
||||
my @required_atom_columns = (
|
||||
'short_desc',
|
||||
'creation_ts',
|
||||
'delta_ts',
|
||||
'reporter',
|
||||
'reporter_realname',
|
||||
'priority',
|
||||
'bug_severity',
|
||||
'assigned_to',
|
||||
'assigned_to_realname',
|
||||
'bug_status',
|
||||
'product',
|
||||
'component',
|
||||
'resolution'
|
||||
'short_desc',
|
||||
'creation_ts',
|
||||
'delta_ts',
|
||||
'reporter',
|
||||
'reporter_realname',
|
||||
'priority',
|
||||
'bug_severity',
|
||||
'assigned_to',
|
||||
'assigned_to_realname',
|
||||
'bug_status',
|
||||
'product',
|
||||
'component',
|
||||
'resolution'
|
||||
);
|
||||
push(@required_atom_columns, 'target_milestone') if Bugzilla->params->{'usetargetmilestone'};
|
||||
|
||||
|
|
|
@ -24,7 +24,6 @@
|
|||
# Pascal Held <paheld@gmail.com>
|
||||
|
||||
use strict;
|
||||
|
||||
use lib qw(. lib);
|
||||
|
||||
use Bugzilla;
|
||||
|
@ -35,7 +34,24 @@ use Bugzilla::Search;
|
|||
use Bugzilla::Search::Saved;
|
||||
use Bugzilla::Error;
|
||||
use Bugzilla::User;
|
||||
use Bugzilla::Keyword;
|
||||
|
||||
use Storable qw(dclone);
|
||||
|
||||
# Maps parameters that control columns to the names of columns.
|
||||
use constant COLUMN_PARAMS => {
|
||||
'useclassification' => ['classification'],
|
||||
'usebugaliases' => ['alias'],
|
||||
'usetargetmilestone' => ['target_milestone'],
|
||||
'useqacontact' => ['qa_contact', 'qa_contact_realname'],
|
||||
'usestatuswhiteboard' => ['status_whiteboard'],
|
||||
};
|
||||
|
||||
# We only show these columns if an object of this type exists in the
|
||||
# database.
|
||||
use constant COLUMN_CLASSES => {
|
||||
'Bugzilla::Flag' => 'flagtypes.name',
|
||||
'Bugzilla::Keyword' => 'keywords',
|
||||
};
|
||||
|
||||
Bugzilla->login();
|
||||
|
||||
|
@ -43,15 +59,31 @@ my $cgi = Bugzilla->cgi;
|
|||
my $template = Bugzilla->template;
|
||||
my $vars = {};
|
||||
|
||||
my @masterlist =
|
||||
map { $_->{id} }
|
||||
sort { $a->{title} cmp $b->{title} }
|
||||
grep { !$_->{nobuglist} }
|
||||
values %{ Bugzilla::Search->COLUMNS };
|
||||
my $columns = dclone(Bugzilla::Search::COLUMNS);
|
||||
|
||||
Bugzilla::Hook::process('colchange_columns', {'columns' => \@masterlist} );
|
||||
# You can't manually select "relevance" as a column you want to see.
|
||||
delete $columns->{'relevance'};
|
||||
|
||||
$vars->{'masterlist'} = \@masterlist;
|
||||
foreach my $param (keys %{ COLUMN_PARAMS() }) {
|
||||
next if Bugzilla->params->{$param};
|
||||
foreach my $column (@{ COLUMN_PARAMS->{$param} }) {
|
||||
delete $columns->{$column};
|
||||
}
|
||||
}
|
||||
|
||||
foreach my $class (keys %{ COLUMN_CLASSES() }) {
|
||||
eval("use $class; 1;") || die $@;
|
||||
my $column = COLUMN_CLASSES->{$class};
|
||||
delete $columns->{$column} if !$class->any_exist;
|
||||
}
|
||||
|
||||
if (!Bugzilla->user->is_timetracker) {
|
||||
foreach my $column (TIMETRACKING_FIELDS) {
|
||||
delete $columns->{$column};
|
||||
}
|
||||
}
|
||||
|
||||
$vars->{'columns'} = $columns;
|
||||
|
||||
my @collist;
|
||||
if (defined $cgi->param('rememberedquery')) {
|
||||
|
@ -60,8 +92,8 @@ if (defined $cgi->param('rememberedquery')) {
|
|||
@collist = DEFAULT_COLUMN_LIST;
|
||||
} else {
|
||||
if (defined $cgi->param("selected_columns")) {
|
||||
my %legal_list = map { $_ => 1 } @masterlist;
|
||||
@collist = grep { exists $legal_list{$_} } $cgi->param("selected_columns");
|
||||
@collist = grep { exists $columns->{$_} }
|
||||
$cgi->param("selected_columns");
|
||||
}
|
||||
if (defined $cgi->param('splitheader')) {
|
||||
$splitheader = $cgi->param('splitheader')? 1: 0;
|
||||
|
|
|
@ -0,0 +1,28 @@
|
|||
#!/usr/bin/perl -w
|
||||
#
|
||||
# The contents of this file are subject to the Mozilla Public
|
||||
# License Version 1.1 (the "License"); you may not use this file
|
||||
# except in compliance with the License. You may obtain a copy of
|
||||
# the License at http://www.mozilla.org/MPL/
|
||||
#
|
||||
# Software distributed under the License is distributed on an "AS
|
||||
# IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
|
||||
# implied. See the License for the specific language governing
|
||||
# rights and limitations under the License.
|
||||
#
|
||||
# The Original Code is the Bugzilla Bug Tracking System.
|
||||
#
|
||||
# The Initial Developer of the Original Code is Everything Solved, Inc.
|
||||
# Portions created by the Initial Developer are Copyright (C) 2010 the
|
||||
# Initial Developer. All Rights Reserved.
|
||||
#
|
||||
# Contributor(s):
|
||||
# Max Kanat-Alexander <mkanat@bugzilla.org>
|
||||
|
||||
use strict;
|
||||
use warnings;
|
||||
use lib qw(. lib);
|
||||
|
||||
use Bugzilla;
|
||||
use Bugzilla::Install::Filesystem qw(fix_all_file_permissions);
|
||||
fix_all_file_permissions(1);
|
|
@ -121,20 +121,13 @@ if ($old_id == $new_id) {
|
|||
# where fooN is the column to update, and barN1, barN2, ... are
|
||||
# the columns to take into account to avoid duplicated entries.
|
||||
# Note that the barNM columns are optional.
|
||||
my $changes = {
|
||||
# Tables affecting bugs.
|
||||
bugs => ['assigned_to', 'reporter', 'qa_contact'],
|
||||
bugs_activity => ['who'],
|
||||
attachments => ['submitter_id'],
|
||||
flags => ['setter_id', 'requestee_id'],
|
||||
#
|
||||
# We set the tables that require custom stuff (multiple columns to check)
|
||||
# here, but the simple stuff is all handled below by bz_get_related_fks.
|
||||
my %changes = (
|
||||
cc => ['who bug_id'],
|
||||
longdescs => ['who'],
|
||||
# Tables affecting global behavior / other users.
|
||||
components => ['initialowner', 'initialqacontact'],
|
||||
component_cc => ['user_id component_id'],
|
||||
quips => ['userid'],
|
||||
series => ['creator'],
|
||||
whine_events => ['owner_userid'],
|
||||
watch => ['watcher watched', 'watched watcher'],
|
||||
# Tables affecting the user directly.
|
||||
namedqueries => ['userid name'],
|
||||
|
@ -142,17 +135,23 @@ my $changes = {
|
|||
user_group_map => ['user_id group_id isbless grant_type'],
|
||||
email_setting => ['user_id relationship event'],
|
||||
profile_setting => ['user_id setting_name'],
|
||||
profiles_activity => ['userid', 'who'], # Should activity be migrated?
|
||||
|
||||
# Only do it if mailto_type = 0, i.e is pointing to a user account!
|
||||
# This requires to be done separately due to this condition.
|
||||
whine_schedules => [], # ['mailto'],
|
||||
);
|
||||
|
||||
# Delete all old records for these tables; no migration.
|
||||
logincookies => [], # ['userid'],
|
||||
tokens => [], # ['userid'],
|
||||
profiles => [], # ['userid'],
|
||||
};
|
||||
my $userid_fks = $dbh->bz_get_related_fks('profiles', 'userid');
|
||||
foreach my $item (@$userid_fks) {
|
||||
my ($table, $column) = @$item;
|
||||
$changes{$table} ||= [];
|
||||
push(@{ $changes{$table} }, $column);
|
||||
}
|
||||
|
||||
# Delete all old records for these tables; no migration.
|
||||
foreach my $table (qw(logincookies tokens profiles)) {
|
||||
$changes{$table} = [];
|
||||
}
|
||||
|
||||
# Start the transaction
|
||||
$dbh->bz_start_transaction();
|
||||
|
@ -162,8 +161,8 @@ $dbh->do('DELETE FROM logincookies WHERE userid = ?', undef, $old_id);
|
|||
$dbh->do('DELETE FROM tokens WHERE userid = ?', undef, $old_id);
|
||||
|
||||
# Migrate records from old user to new user.
|
||||
foreach my $table (keys(%$changes)) {
|
||||
foreach my $column_list (@{$changes->{$table}}) {
|
||||
foreach my $table (keys %changes) {
|
||||
foreach my $column_list (@{ $changes{$table} }) {
|
||||
# Get all columns to consider. There is always at least
|
||||
# one column given: the one to update.
|
||||
my @columns = split(/[\s]+/, $column_list);
|
||||
|
|
|
@ -3019,10 +3019,10 @@ known to us after the Bugzilla 2.14 release.
|
|||
*** USERS UPGRADING FROM 2.8 OR EARLIER ***
|
||||
*******************************************
|
||||
|
||||
Release notes were not compiled for versions of Bugzilla before
|
||||
2.12.
|
||||
|
||||
The file 'UPGRADING-pre-2.8' contains instructions you may
|
||||
need to perform in addition to running 'checksetup.pl' if you
|
||||
are running a pre 2.8 version.
|
||||
This version of Bugzilla cannot upgrade from version 2.8 (released
|
||||
November 19, 1999). You will first have to upgrade to Bugzilla 3.6 and
|
||||
then upgrade to the latest release.
|
||||
|
||||
If you are upgrading from a version earlier than 2.8, See the
|
||||
PGRADING-pre-2.8 file in Bugzilla 3.0 for information
|
||||
on upgrading from a version that is earlier than 2.8.
|
||||
|
|
|
@ -367,7 +367,8 @@
|
|||
|
||||
<listitem>
|
||||
<para>
|
||||
Template (&min-template-ver;)
|
||||
<link linkend="install-modules-template">Template</link>
|
||||
(&min-template-ver;)
|
||||
</para>
|
||||
</listitem>
|
||||
|
||||
|
@ -477,6 +478,20 @@
|
|||
</para>
|
||||
</listitem>
|
||||
|
||||
<listitem>
|
||||
<para>
|
||||
JSON::RPC
|
||||
(&min-json-rpc-ver;) for the JSON-RPC interface
|
||||
</para>
|
||||
</listitem>
|
||||
|
||||
<listitem>
|
||||
<para>
|
||||
Test::Taint
|
||||
(&min-test-taint-ver;) for the web service interface
|
||||
</para>
|
||||
</listitem>
|
||||
|
||||
<listitem>
|
||||
<para>
|
||||
HTML::Parser
|
||||
|
|
|
@ -68,7 +68,7 @@ elsif ($action eq 'new')
|
|||
clone_bug => scalar $cgi->param('clone_bug'),
|
||||
obsolete => scalar $cgi->param('obsolete'),
|
||||
custom => 1,
|
||||
buglist => 1, # FIXME remove non-editable 'buglist' field spec
|
||||
buglist => 1,
|
||||
visibility_field_id => scalar $cgi->param('visibility_field_id'),
|
||||
value_field_id => scalar $cgi->param('value_field_id'),
|
||||
add_to_deps => scalar $cgi->param('add_to_deps'),
|
||||
|
|
|
@ -29,6 +29,7 @@ use Bugzilla::Error;
|
|||
use Bugzilla::Group;
|
||||
use Bugzilla::User;
|
||||
use Bugzilla::Util qw(diff_arrays html_quote);
|
||||
use Bugzilla::Status qw(is_open_state);
|
||||
|
||||
# This is extensions/Example/lib/Util.pm. I can load this here in my
|
||||
# Extension.pm only because I have a Config.pm.
|
||||
|
@ -655,6 +656,44 @@ sub template_before_process {
|
|||
}
|
||||
}
|
||||
|
||||
sub bug_check_can_change_field {
|
||||
my ($self, $args) = @_;
|
||||
|
||||
my ($bug, $field, $new_value, $old_value, $priv_results)
|
||||
= @$args{qw(bug field new_value old_value priv_results)};
|
||||
|
||||
my $user = Bugzilla->user;
|
||||
|
||||
# Disallow a bug from being reopened if currently closed unless user
|
||||
# is in 'admin' group
|
||||
if ($field eq 'bug_status' && $bug->product_obj->name eq 'Example') {
|
||||
if (!is_open_state($old_value) && is_open_state($new_value)
|
||||
&& !$user->in_group('admin'))
|
||||
{
|
||||
push(@$priv_results, PRIVILEGES_REQUIRED_EMPOWERED);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
# Disallow a bug's keywords from being edited unless user is the
|
||||
# reporter of the bug
|
||||
if ($field eq 'keywords' && $bug->product_obj->name eq 'Example'
|
||||
&& $user->login ne $bug->reporter->login)
|
||||
{
|
||||
push(@$priv_results, PRIVILEGES_REQUIRED_REPORTER);
|
||||
return;
|
||||
}
|
||||
|
||||
# Allow updating of priority even if user cannot normally edit the bug
|
||||
# and they are in group 'engineering'
|
||||
if ($field eq 'priority' && $bug->product_obj->name eq 'Example'
|
||||
&& $user->in_group('engineering'))
|
||||
{
|
||||
push(@$priv_results, PRIVILEGES_REQUIRED_NONE);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
sub webservice {
|
||||
my ($self, $args) = @_;
|
||||
|
||||
|
|
|
@ -800,7 +800,6 @@ sub _remove_votes {
|
|||
$template->process("voting/votes-removed.txt.tmpl", $vars, \$msg);
|
||||
push(@messages, $msg);
|
||||
}
|
||||
Bugzilla->template_inner("");
|
||||
|
||||
my $votes = $dbh->selectrow_array("SELECT SUM(vote_count) " .
|
||||
"FROM votes WHERE bug_id = ?",
|
||||
|
|
|
@ -18,5 +18,6 @@
|
|||
# Max Kanat-Alexander <mkanat@bugzilla.org>
|
||||
#%]
|
||||
|
||||
[% field_descs.votes = "Votes" %]
|
||||
|
||||
[% IF in_template_var %]
|
||||
[% vars.field_descs.votes = "Votes" %]
|
||||
[% END %]
|
||||
|
|
|
@ -35,7 +35,7 @@ use Bugzilla::Install::CPAN;
|
|||
|
||||
use Bugzilla::Constants;
|
||||
use Bugzilla::Install::Requirements;
|
||||
use Bugzilla::Install::Util qw(bin_loc init_console vers_cmp);
|
||||
use Bugzilla::Install::Util qw(bin_loc);
|
||||
|
||||
use Data::Dumper;
|
||||
use Getopt::Long;
|
||||
|
|
|
@ -19,6 +19,7 @@
|
|||
* Joel Peshkin <bugreport@peshkin.net>
|
||||
* Erik Stambaugh <erik@dasbistro.com>
|
||||
* Marc Schumann <wurblzap@gmail.com>
|
||||
* Guy Pyrzak <guy.pyrzak@gmail.com>
|
||||
*/
|
||||
|
||||
var SUPA_JAVA_DISABLED_ERROR = 'You cannot paste images from clipboard because Java support'+
|
||||
|
@ -439,3 +440,15 @@ function normalizeComments()
|
|||
big.parentNode.removeChild(big);
|
||||
}
|
||||
}
|
||||
|
||||
function toggle_attachment_details_visibility ( )
|
||||
{
|
||||
// show hide classes
|
||||
var container = document.getElementById('attachment_info');
|
||||
if( YAHOO.util.Dom.hasClass(container, 'read') ){
|
||||
YAHOO.util.Dom.replaceClass(container, 'read', 'edit');
|
||||
}else{
|
||||
YAHOO.util.Dom.replaceClass(container, 'edit', 'read');
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -149,9 +149,8 @@ Bugzilla::User::match_field({
|
|||
if (defined $cgi->param('delta_ts'))
|
||||
{
|
||||
my $delta_ts_z = datetime_from($cgi->param('delta_ts'));
|
||||
my $first_delta_tz_z = datetime_from($first_bug->delta_ts);
|
||||
if ($first_delta_tz_z ne $delta_ts_z)
|
||||
{
|
||||
my $first_delta_tz_z = datetime_from($first_bug->delta_ts);
|
||||
if ($first_delta_tz_z ne $delta_ts_z) {
|
||||
($vars->{'operations'}) =
|
||||
Bugzilla::Bug::GetBugActivity($first_bug->id, undef,
|
||||
scalar $cgi->param('delta_ts'));
|
||||
|
@ -201,7 +200,7 @@ if (defined $cgi->param('delta_ts'))
|
|||
$vars->{'start_at'} = $cgi->param('longdesclength');
|
||||
# Always sort midair collision comments oldest to newest,
|
||||
# regardless of the user's personal preference.
|
||||
$vars->{'comments'} = $first_bug->comments({ order => "oldest_to_newest", start_at => $vars->{start_at} });
|
||||
$vars->{'comments'} = $first_bug->comments({ order => "oldest_to_newest" });
|
||||
$vars->{'bug'} = $first_bug;
|
||||
|
||||
# The token contains the old delta_ts. We need a new one.
|
||||
|
|
|
@ -166,7 +166,6 @@ elsif ($action eq 'begin-sudo') {
|
|||
my $message;
|
||||
my $mail_template = Bugzilla->template_inner($target_user->settings->{'lang'}->{'value'});
|
||||
$mail_template->process('email/sudo.txt.tmpl', { reason => $reason }, \$message);
|
||||
Bugzilla->template_inner("");
|
||||
MessageToMTA($message);
|
||||
|
||||
$vars->{'message'} = 'sudo_started';
|
||||
|
|
|
@ -220,8 +220,7 @@ sub DotInto
|
|||
# The dot mapdata lines have the following format (\nsummary is optional):
|
||||
# rectangle (LEFTX,TOPY) (RIGHTX,BOTTOMY) URLBASE/show_bug.cgi?id=BUGNUM BUGNUM[\nSUMMARY]
|
||||
|
||||
sub CreateImagemap
|
||||
{
|
||||
sub CreateImagemap {
|
||||
my ($mapfilename, $mapid, $bugtitles) = @_;
|
||||
$mapid ||= 'imagemap';
|
||||
my $map = "<map name=\"$mapid\">\n";
|
||||
|
|
|
@ -17,4 +17,25 @@
|
|||
margin-top: .5em;
|
||||
}
|
||||
|
||||
.links { display: inline; }
|
||||
form#Create #comp_desc {
|
||||
margin: .5em 1em;
|
||||
}
|
||||
|
||||
#footer #useful-links li {
|
||||
padding-bottom: 0.8ex;
|
||||
}
|
||||
|
||||
#footer .label {
|
||||
display: block;
|
||||
float: left;
|
||||
width: 8.2em;
|
||||
padding-bottom: 0.1ex;
|
||||
}
|
||||
|
||||
#footer #links-actions .label {
|
||||
padding-top: 0.35em;
|
||||
}
|
||||
|
||||
#footer .links {
|
||||
display: inline;
|
||||
}
|
||||
|
|
|
@ -14,6 +14,7 @@
|
|||
* Joel Peshkin <bugreport@peshkin.net>
|
||||
* Erik Stambaugh <erik@dasbistro.com>
|
||||
* Marc Schumann <wurblzap@gmail.com>
|
||||
* Guy Pyrzak <guy.pyrzak@gmail.com>
|
||||
*/
|
||||
|
||||
table.attachment_entry th {
|
||||
|
@ -121,10 +122,6 @@ table.attachment_info td {
|
|||
vertical-align: middle;
|
||||
}
|
||||
|
||||
#attachment_attributes {
|
||||
width: 25%;
|
||||
}
|
||||
|
||||
#attachment_attributes div {
|
||||
padding-bottom: 0.4em;
|
||||
}
|
||||
|
@ -140,8 +137,109 @@ table.attachment_info td {
|
|||
display: block;
|
||||
}
|
||||
|
||||
#attachment_attributes table#flags {
|
||||
padding-top: 1em;
|
||||
#smallCommentFrame, #attachment_flags {
|
||||
float: left;
|
||||
}
|
||||
|
||||
#smallCommentFrame {
|
||||
margin-right: 1.5em;
|
||||
}
|
||||
|
||||
#attachment_comments_and_flags, #attachment_actions {
|
||||
clear: both;
|
||||
margin-bottom: 1ex;
|
||||
}
|
||||
|
||||
#attachment_information_read_only .title {
|
||||
font-weight: bold;
|
||||
font-size: 1.5em;
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
#attachment_information_read_only .title #bz_edit {
|
||||
font-size: 0.7em;
|
||||
}
|
||||
|
||||
#attachment_information_read_only .details {
|
||||
font-family: monospace;
|
||||
}
|
||||
|
||||
#attachment_info.read #attachment_information_edit {
|
||||
display: none;
|
||||
}
|
||||
|
||||
#attachment_info.edit #attachment_information_read_only {
|
||||
display: none;
|
||||
}
|
||||
|
||||
#attachment_info.edit #attachment_view_window {
|
||||
float: left;
|
||||
width: 80%;
|
||||
}
|
||||
|
||||
#attachment_info.edit #attachment_information_edit {
|
||||
width: 20%;
|
||||
}
|
||||
|
||||
<<<<<<< HEAD:skins/standard/create_attachment.css
|
||||
#comment_textarea { width: 50em; font-size: medium; font-family: monospace; }
|
||||
=======
|
||||
#attachment_info.edit #attachment_information_edit input.text,
|
||||
#attachment_info.edit #attachment_information_edit textarea {
|
||||
width: 90%;
|
||||
}
|
||||
|
||||
#attachment_isobsolete {
|
||||
padding-right: 1em;
|
||||
}
|
||||
|
||||
#attachment_information_edit {
|
||||
float: left;
|
||||
}
|
||||
|
||||
#smallCommentFrame textarea {
|
||||
display: block;
|
||||
}
|
||||
|
||||
textarea.bz_private {
|
||||
border: 1px solid #F8C8BA;
|
||||
}
|
||||
|
||||
#update {
|
||||
clear: both;
|
||||
display: block;
|
||||
}
|
||||
|
||||
textarea {
|
||||
font-family: monospace;
|
||||
}
|
||||
|
||||
div#update_container {
|
||||
clear: both;
|
||||
padding: 1.5em 0;
|
||||
}
|
||||
|
||||
#attachment_flags {
|
||||
margin-bottom: 1em;
|
||||
}
|
||||
|
||||
#attachment_flags p {
|
||||
padding-bottom: 0;
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
#editFrame, #viewDiffFrame, #viewFrame {
|
||||
height: 400px;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.details span.bz_private{
|
||||
border-left: 1px solid darkred;
|
||||
padding-left: 0.5em;
|
||||
}
|
||||
|
||||
.no_javascript .bz_hide, .no_javascript .bz_edit {
|
||||
display: none;
|
||||
}
|
||||
>>>>>>> d5cc8b05e7f234c7cc6fe3428ad9e5928236de9a:skins/standard/attachment.css
|
|
@ -461,18 +461,44 @@ input.required, select.required, span.required_explanation {
|
|||
list-style-type: none;
|
||||
}
|
||||
|
||||
/*************/
|
||||
/* enter_bug */
|
||||
/*************/
|
||||
|
||||
form#Create table {
|
||||
border-spacing: 0;
|
||||
border-width: 0;
|
||||
}
|
||||
form#Create td, form#Create th {
|
||||
padding: .25em;
|
||||
}
|
||||
form#Create th {
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
/* This makes the "component" column as small as possible (since it
|
||||
* contains only fixed-width content) and the Reporter column
|
||||
* as large as possible, which makes the form not jump around
|
||||
* when the Component Description changes size. This works
|
||||
* pretty well on all browsers except IE 8.
|
||||
*/
|
||||
form#Create #field_container_component { width: 1px; }
|
||||
form#Create #field_container_reporter { width: 100%; }
|
||||
|
||||
form#Create .comment {
|
||||
vertical-align: top;
|
||||
overflow: auto;
|
||||
color: green;
|
||||
margin: 0 0.5em;
|
||||
padding: 0.3em;
|
||||
height: 8ex;
|
||||
}
|
||||
form#Create #comp_desc_container td { padding: 0; }
|
||||
form#Create #comp_desc { height: 11ex; }
|
||||
form#Create #os_guess_note {
|
||||
padding-top: 0;
|
||||
}
|
||||
form#Create #os_guess_note div {
|
||||
max-width: 35em;
|
||||
}
|
||||
|
||||
|
||||
.image_button {
|
||||
background-repeat: no-repeat;
|
||||
|
|
|
@ -24,26 +24,9 @@
|
|||
|
||||
<form method=post action="editclassifications.cgi">
|
||||
<table border=0 cellpadding=4 cellspacing=0>
|
||||
<tr>
|
||||
<th align="right">Classification:</th>
|
||||
<td><input size=64 maxlength=64 name="classification"></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th align="right">Description:</th>
|
||||
<td>
|
||||
[% INCLUDE global/textarea.html.tmpl
|
||||
name = 'description'
|
||||
minrows = 4
|
||||
cols = 64
|
||||
wrap = 'virtual'
|
||||
%]
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th align="right"><label for="sortkey">Sortkey:</label></th>
|
||||
<td><input id="sortkey" size="20" maxlength="20" name="sortkey"
|
||||
value=""></td>
|
||||
</tr>
|
||||
|
||||
[% PROCESS "admin/classifications/edit-common.html.tmpl" %]
|
||||
|
||||
</table>
|
||||
<hr>
|
||||
<input type=submit value="Add">
|
||||
|
|
|
@ -0,0 +1,47 @@
|
|||
[%# The contents of this file are subject to the Mozilla Public
|
||||
# License Version 1.1 (the "License"); you may not use this file
|
||||
# except in compliance with the License. You may obtain a copy of
|
||||
# the License at http://www.mozilla.org/MPL/
|
||||
#
|
||||
# Software distributed under the License is distributed on an "AS
|
||||
# IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
|
||||
# implied. See the License for the specific language governing
|
||||
# rights and limitations under the License.
|
||||
#
|
||||
# The Original Code is the Bugzilla Bug Tracking System.
|
||||
#
|
||||
# The Initial Developer of the Original Code is Netscape Communications
|
||||
# Corporation. Portions created by Netscape are
|
||||
# Copyright (C) 1998 Netscape Communications Corporation. All
|
||||
# Rights Reserved.
|
||||
#
|
||||
# Contributor(s): Tiago Rodrigues de Mello <timello@linux.vnet.ibm.com>
|
||||
#%]
|
||||
|
||||
[%# INTERFACE:
|
||||
# classification: Bugzilla::Classifiation object.
|
||||
#%]
|
||||
|
||||
<tr>
|
||||
<th align="right">Classification:</th>
|
||||
<td><input size=64 maxlength=64 name="classification"
|
||||
value="[% classification.name FILTER html %]"></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th align="right">Description:</th>
|
||||
<td>
|
||||
[% INCLUDE global/textarea.html.tmpl
|
||||
name = 'description'
|
||||
minrows = 4
|
||||
cols = 64
|
||||
defaultcontent = classification.description
|
||||
%]
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th align="right"><label for="sortkey">Sortkey:</label></th>
|
||||
<td><input id="sortkey" size="20" maxlength="20" name="sortkey"
|
||||
value="[%- classification.sortkey FILTER html %]"></td>
|
||||
</tr>
|
||||
|
||||
[% Hook.process('rows') %]
|
|
@ -24,27 +24,9 @@
|
|||
|
||||
<form method=post action="editclassifications.cgi">
|
||||
<table border=0 cellpadding=4 cellspacing=0>
|
||||
<tr>
|
||||
<th align="right">Classification:</th>
|
||||
<td><input size=64 maxlength=64 name="classification"
|
||||
value="[% classification.name FILTER html %]"></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th align="right">Description:</th>
|
||||
<td>
|
||||
[% INCLUDE global/textarea.html.tmpl
|
||||
name = 'description'
|
||||
minrows = 4
|
||||
cols = 64
|
||||
defaultcontent = classification.description
|
||||
%]
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th align="right"><label for="sortkey">Sortkey:</label></th>
|
||||
<td><input id="sortkey" size="20" maxlength="20" name="sortkey" value="
|
||||
[%- classification.sortkey FILTER html %]"></td>
|
||||
</tr>
|
||||
|
||||
[% PROCESS "admin/classifications/edit-common.html.tmpl" %]
|
||||
|
||||
<tr valign=top>
|
||||
<th align="right">
|
||||
<a href="editproducts.cgi?classification=[% classification.name FILTER url_quote %]">
|
||||
|
|
|
@ -33,92 +33,9 @@
|
|||
|
||||
<form method="post" action="editcomponents.cgi">
|
||||
<table border="0" cellpadding="4" cellspacing="0">
|
||||
<tr>
|
||||
<th align="right">Component:</th>
|
||||
<td><input size="64" maxlength="64" name="component" value=""></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th align="right">Description:</th>
|
||||
<td>
|
||||
[% INCLUDE global/textarea.html.tmpl
|
||||
name = 'description'
|
||||
minrows = 4
|
||||
cols = 64
|
||||
wrap = 'virtual'
|
||||
%]
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th align="right"><label for="initialowner">Default Assignee:</label></th>
|
||||
<td>
|
||||
[% INCLUDE global/userselect.html.tmpl
|
||||
name => "initialowner"
|
||||
id => "initialowner"
|
||||
value => ""
|
||||
size => 64
|
||||
%]
|
||||
</td>
|
||||
</tr>
|
||||
[% IF Param('useqacontact') %]
|
||||
<tr>
|
||||
<th align="right">
|
||||
<label for="initialqacontact">Default QA Contact:</label></th>
|
||||
<td>
|
||||
[% INCLUDE global/userselect.html.tmpl
|
||||
name => "initialqacontact"
|
||||
id => "initialqacontact"
|
||||
value => ""
|
||||
size => 64
|
||||
emptyok => 1
|
||||
%]
|
||||
</td>
|
||||
</tr>
|
||||
[% END %]
|
||||
<tr>
|
||||
<th align="right">
|
||||
<label for="initialcc">Default CC List:</label>
|
||||
</th>
|
||||
<td>
|
||||
[% INCLUDE global/userselect.html.tmpl
|
||||
name => "initialcc"
|
||||
id => "initialcc"
|
||||
value => ""
|
||||
size => 64
|
||||
multiple => 5
|
||||
%]
|
||||
<br>
|
||||
[% IF !Param("usemenuforusers") %]
|
||||
<em>Enter user names for the CC list as a comma-separated list.</em>
|
||||
[% END %]
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th align="right">
|
||||
<label for="default_version">Default version:</label>
|
||||
</td>
|
||||
<td>
|
||||
<select id="default_version" name="default_version">
|
||||
<option value="">---</option>
|
||||
[% FOREACH x = product.versions %]
|
||||
<option value="[% x.name FILTER html %]">[% x.name FILTER html %]</option>
|
||||
[% END %]
|
||||
</select>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td valign="top">Open for [% terms.bug %] entry:</td>
|
||||
<td><input type="checkbox" name="is_active" value="1" checked="checked" />
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th align="right">
|
||||
<label for="wiki_url">Wiki URL:</label>
|
||||
</td>
|
||||
<td>
|
||||
<input size="64" maxlength="64" name="wiki_url" value="" />
|
||||
<br><em>Or use product setting when empty.</em>
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
[% PROCESS "admin/components/edit-common.html.tmpl" %]
|
||||
|
||||
</table>
|
||||
<hr>
|
||||
<input type="submit" id="create" value="Add">
|
||||
|
|
|
@ -0,0 +1,86 @@
|
|||
[%# The contents of this file are subject to the Mozilla Public
|
||||
# License Version 1.1 (the "License"); you may not use this file
|
||||
# except in compliance with the License. You may obtain a copy of
|
||||
# the License at http://www.mozilla.org/MPL/
|
||||
#
|
||||
# Software distributed under the License is distributed on an "AS
|
||||
# IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
|
||||
# implied. See the License for the specific language governing
|
||||
# rights and limitations under the License.
|
||||
#
|
||||
# The Original Code is the Bugzilla Bug Tracking System.
|
||||
#
|
||||
# The Initial Developer of the Original Code is Netscape Communications
|
||||
# Corporation. Portions created by Netscape are
|
||||
# Copyright (C) 1998 Netscape Communications Corporation. All
|
||||
# Rights Reserved.
|
||||
#
|
||||
# Contributor(s): Tiago Rodrigues de Mello <timello@linux.vnet.ibm.com>
|
||||
#%]
|
||||
|
||||
[%# INTERFACE:
|
||||
# comp: object; Bugzilla::Component object.
|
||||
#%]
|
||||
|
||||
<tr>
|
||||
<td valign="top">Component:</td>
|
||||
<td><input size="64" maxlength="64" name="component"
|
||||
value="[%- comp.name FILTER html %]"></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td valign="top">Component Description:</td>
|
||||
<td>
|
||||
[% INCLUDE global/textarea.html.tmpl
|
||||
name = 'description'
|
||||
minrows = 4
|
||||
cols = 64
|
||||
wrap = 'virtual'
|
||||
defaultcontent = comp.description
|
||||
%]
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td valign="top"><label for="initialowner">Default Assignee:</label></td>
|
||||
<td>
|
||||
[% INCLUDE global/userselect.html.tmpl
|
||||
name => "initialowner"
|
||||
id => "initialowner"
|
||||
value => comp.default_assignee.login
|
||||
size => 64
|
||||
%]
|
||||
</td>
|
||||
</tr>
|
||||
[% IF Param('useqacontact') %]
|
||||
<tr>
|
||||
<td valign="top"><label for="initialqacontact">Default QA contact:</label></td>
|
||||
<td>
|
||||
[% INCLUDE global/userselect.html.tmpl
|
||||
name => "initialqacontact"
|
||||
id => "initialqacontact"
|
||||
value => comp.default_qa_contact.login
|
||||
size => 64
|
||||
emptyok => 1
|
||||
%]
|
||||
</td>
|
||||
</tr>
|
||||
[% END %]
|
||||
<tr>
|
||||
<td valign="top">
|
||||
<label for="initialcc">Default CC List:</label>
|
||||
</td>
|
||||
<td>
|
||||
[% INCLUDE global/userselect.html.tmpl
|
||||
name => "initialcc"
|
||||
id => "initialcc"
|
||||
value => initial_cc_names
|
||||
size => 64
|
||||
multiple => 5
|
||||
%]
|
||||
<br>
|
||||
[% IF !Param("usemenuforusers") %]
|
||||
<em>Enter user names for the CC list as a comma-separated list.</em>
|
||||
[% END %]
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
[% Hook.process('rows') %]
|
|
@ -38,68 +38,8 @@
|
|||
<form method="post" action="editcomponents.cgi">
|
||||
<table border="0" cellpadding="4" cellspacing="0">
|
||||
|
||||
<tr>
|
||||
<td valign="top">Component:</td>
|
||||
<td><input size="64" maxlength="64" name="component" value="
|
||||
[%- comp.name FILTER html %]"></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td valign="top">Component Description:</td>
|
||||
<td>
|
||||
[% INCLUDE global/textarea.html.tmpl
|
||||
name = 'description'
|
||||
minrows = 4
|
||||
cols = 64
|
||||
wrap = 'virtual'
|
||||
defaultcontent = comp.description
|
||||
%]
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td valign="top"><label for="initialowner">Default Assignee:</label></td>
|
||||
<td>
|
||||
[% INCLUDE global/userselect.html.tmpl
|
||||
name => "initialowner"
|
||||
id => "initialowner"
|
||||
value => comp.default_assignee.login
|
||||
size => 64
|
||||
%]
|
||||
</td>
|
||||
|
||||
[% IF Param('useqacontact') %]
|
||||
</tr>
|
||||
<tr>
|
||||
<td valign="top"><label for="initialqacontact">Default QA contact:</label></td>
|
||||
<td>
|
||||
[% INCLUDE global/userselect.html.tmpl
|
||||
name => "initialqacontact"
|
||||
id => "initialqacontact"
|
||||
value => comp.default_qa_contact.login
|
||||
size => 64
|
||||
emptyok => 1
|
||||
%]
|
||||
</td>
|
||||
[% END %]
|
||||
|
||||
</tr>
|
||||
<tr>
|
||||
<td valign="top">
|
||||
<label for="initialcc">Default CC List:</label>
|
||||
</td>
|
||||
<td>
|
||||
[% INCLUDE global/userselect.html.tmpl
|
||||
name => "initialcc"
|
||||
id => "initialcc"
|
||||
value => initial_cc_names
|
||||
size => 64
|
||||
multiple => 5
|
||||
%]
|
||||
<br>
|
||||
[% IF !Param("usemenuforusers") %]
|
||||
<em>Enter user names for the CC list as a comma-separated list.</em>
|
||||
[% END %]
|
||||
</td>
|
||||
</tr>
|
||||
[% PROCESS "admin/components/edit-common.html.tmpl" %]
|
||||
|
||||
<tr>
|
||||
<td valign="top">
|
||||
<label for="default_version">Default version:</label>
|
||||
|
|
|
@ -31,8 +31,8 @@
|
|||
title = title
|
||||
header = header
|
||||
subheader = subheader
|
||||
style_urls = [ 'skins/standard/create_attachment.css' ]
|
||||
javascript_urls = [ "js/attachment.js", "js/field.js" ]
|
||||
style_urls = [ 'skins/standard/attachment.css' ]
|
||||
javascript_urls = [ "js/attachment.js", "js/util.js" ]
|
||||
doc_section = "attachments.html"
|
||||
%]
|
||||
|
||||
|
|
|
@ -51,11 +51,11 @@ Interdiff of #[% oldid %] and #[% newid %] for [% terms.bug %] #[% bugid %]
|
|||
[% END %]
|
||||
[% PROCESS global/header.html.tmpl doc_section = "attachments.html#patchviewer"
|
||||
javascript_urls = "js/attachment.js"
|
||||
style_urls = ['skins/standard/create_attachment.css'] %]
|
||||
style_urls = ['skins/standard/attachment.css'] %]
|
||||
[% ELSE %]
|
||||
<html>
|
||||
<head>
|
||||
<link href="skins/standard/create_attachment.css" rel="stylesheet" type="text/css">
|
||||
<link href="skins/standard/attachment.css" rel="stylesheet" type="text/css">
|
||||
<script src="js/attachment.js" type="text/javascript"></script>
|
||||
</head>
|
||||
<body onload="[% onload FILTER html %]">
|
||||
|
|
|
@ -17,6 +17,7 @@
|
|||
#
|
||||
# Contributor(s): Myk Melez <myk@mozilla.org>
|
||||
# Frédéric Buclin <LpSolit@gmail.com>
|
||||
# Guy Pyrzak <guy.pyrzak@gmail.com>
|
||||
#%]
|
||||
|
||||
[%# Define strings that will serve as the title and header of this page %]
|
||||
|
@ -35,7 +36,8 @@
|
|||
subheader = subheader
|
||||
doc_section = "attachments.html"
|
||||
javascript_urls = ['js/attachment.js']
|
||||
style_urls = ['skins/standard/create_attachment.css']
|
||||
style_urls = ['skins/standard/attachment.css']
|
||||
bodyclasses = "no_javascript"
|
||||
%]
|
||||
|
||||
[%# No need to display the Diff button and iframe if the attachment is not a patch. %]
|
||||
|
@ -53,12 +55,38 @@
|
|||
<input type="hidden" name="token" value="[% issue_hash_token([attachment.id, attachment.modification_time]) FILTER html %]">
|
||||
[% END %]
|
||||
|
||||
<table class="attachment_info" width="100%">
|
||||
|
||||
<tr>
|
||||
<td id="attachment_attributes">
|
||||
<div id="attachment_info" class="attachment_info [% IF can_edit %] edit[% ELSE %] read[% END%]">
|
||||
<div id="attachment_attributes">
|
||||
<div id="attachment_information_read_only" class="[% "bz_private" IF attachment.isprivate %]">
|
||||
<div class="title">
|
||||
[% "[patch]" IF attachment.ispatch%]
|
||||
<span class="[% "bz_obsolete" IF attachment.isobsolete %]" title="[% "obsolete" IF attachment.isobsolete %]">
|
||||
[% attachment.description FILTER html %]
|
||||
</span>
|
||||
[% IF can_edit %]
|
||||
<span class="bz_edit">(<a href="javascript:toggle_attachment_details_visibility()">edit</a>)</span>
|
||||
[% END %]
|
||||
</div>
|
||||
[% IF NOT attachment.isurl %]
|
||||
<div class="details">
|
||||
[% attachment.filename FILTER html %] ([% attachment.contenttype FILTER html %])
|
||||
[% IF attachment.datasize %]
|
||||
[%+ attachment.datasize FILTER unitconvert %]
|
||||
[% ELSE %]
|
||||
<em>deleted</em>
|
||||
[% END %], created by [%+ INCLUDE global/user.html.tmpl who = attachment.attacher %]
|
||||
[% IF attachment.isprivate %]
|
||||
<span class="bz_private">Only visible to <strong>[% Param('insidergroup') FILTER html %]</strong></span>
|
||||
[% END %]
|
||||
</div>
|
||||
[% END %]
|
||||
</div>
|
||||
<div id="attachment_information_edit">
|
||||
<span class="bz_hide">
|
||||
(<a href="javascript:toggle_attachment_details_visibility();">hide</a>)
|
||||
</span>
|
||||
<div id="attachment_description">
|
||||
<label for="description">Description:</label>
|
||||
<label for="description">Description:</label>
|
||||
[% INCLUDE global/textarea.html.tmpl
|
||||
id = 'description'
|
||||
name = 'description'
|
||||
|
@ -76,31 +104,30 @@
|
|||
</div>
|
||||
|
||||
[% IF attachment.isurl %]
|
||||
<input type="hidden" name="filename"
|
||||
value="[% attachment.filename FILTER html %]">
|
||||
<input type="hidden" name="contenttypeentry"
|
||||
value="[% attachment.contenttype FILTER html %]">
|
||||
<input type="hidden" name="filename"
|
||||
value="[% attachment.filename FILTER html %]">
|
||||
<input type="hidden" name="contenttypeentry"
|
||||
value="[% attachment.contenttype FILTER html %]">
|
||||
[% ELSE %]
|
||||
<div id="attachment_filename">
|
||||
<label for="filename">Filename:</label>
|
||||
<input type="text" size="20" class="block[% editable_or_hide %]"
|
||||
<input type="text" size="20" class="text block[% editable_or_hide %]"
|
||||
id="filename" name="filename"
|
||||
value="[% attachment.filename FILTER html %]">
|
||||
[% IF !can_edit %]
|
||||
[%+ attachment.filename FILTER truncate(25) FILTER html %]
|
||||
[% END %]
|
||||
value="[% attachment.filename FILTER html %]">
|
||||
</div>
|
||||
|
||||
<div id="attachment_mimetype">
|
||||
<label for="contenttypeentry">MIME Type:</label>
|
||||
<input type="text" size="20" class="block[% editable_or_hide %]"
|
||||
<input type="text" size="20" class="text block[% editable_or_hide %]"
|
||||
id="contenttypeentry" name="contenttypeentry"
|
||||
value="[% attachment.contenttype FILTER html %]">
|
||||
[% IF !can_edit %]
|
||||
[%+ attachment.contenttype FILTER truncate(25) FILTER html %]
|
||||
[% END %]
|
||||
value="[% attachment.contenttype FILTER html %]">
|
||||
</div>
|
||||
|
||||
|
||||
<div id="attachment_creator">
|
||||
<span class="label">Creator:</span>
|
||||
[%+ INCLUDE global/user.html.tmpl who = attachment.attacher %]
|
||||
</div>
|
||||
|
||||
<div id="attachment_size">
|
||||
<span class="label">Size:</span>
|
||||
[% IF attachment.datasize %]
|
||||
|
@ -110,162 +137,149 @@
|
|||
[% END %]
|
||||
</div>
|
||||
|
||||
<div id="attachment_creator">
|
||||
<span class="label">Creator:</span>
|
||||
[%+ INCLUDE global/user.html.tmpl who = attachment.attacher %]
|
||||
</div>
|
||||
|
||||
<div id="attachment_ispatch">
|
||||
<input type="checkbox" id="ispatch" name="ispatch" value="1"
|
||||
[%+ IF !can_edit %]class="bz_hidden_option"[% END %]
|
||||
[%+ 'checked="checked"' IF attachment.ispatch %]>
|
||||
[% IF can_edit %]
|
||||
<label for="ispatch">patch</label>
|
||||
[% ELSE %]
|
||||
<span class="label">Is Patch:</span>
|
||||
[%+ attachment.ispatch ? "yes" : "no" %]
|
||||
[% END %]
|
||||
<label for="ispatch">patch</label>
|
||||
</div>
|
||||
[% END %]
|
||||
<div class="readonly">
|
||||
<div class="checkboxes">
|
||||
<div id="attachment_isobsolete">
|
||||
<input type="checkbox" id="isobsolete" name="isobsolete" value="1"
|
||||
[%+ 'checked="checked"' IF attachment.isobsolete %]>
|
||||
<label for="isobsolete">obsolete</label>
|
||||
</div>
|
||||
|
||||
<div id="attachment_isobsolete">
|
||||
<input type="checkbox" id="isobsolete" name="isobsolete" value="1"
|
||||
[%+ IF !can_edit %]class="bz_hidden_option"[% END %]
|
||||
[%+ 'checked="checked"' IF attachment.isobsolete %]>
|
||||
[% IF can_edit %]
|
||||
<label for="isobsolete">obsolete</label>
|
||||
[% ELSE %]
|
||||
<span class="label">Is Obsolete:</span>
|
||||
[%+ attachment.isobsolete ? "yes" : "no" %]
|
||||
[% END %]
|
||||
</div>
|
||||
|
||||
[% IF user.is_insider %]
|
||||
<div id="attachment_isprivate">
|
||||
<input type="checkbox" id="isprivate" name="isprivate" value="1"
|
||||
[%+ IF !can_edit %]class="bz_hidden_option"[% END %]
|
||||
[%+ 'checked="checked"' IF attachment.isprivate %]>
|
||||
[% IF can_edit %]
|
||||
<label for="isprivate">private (only visible to
|
||||
<strong>[% Param('insidergroup') FILTER html %]</strong>)
|
||||
</label>
|
||||
[% ELSE %]
|
||||
<span class="label">Is Private:</span>
|
||||
[%+ attachment.isprivate ? "yes" : "no" %]
|
||||
[% IF user.is_insider %]
|
||||
<div id="attachment_isprivate">
|
||||
<input type="checkbox" id="isprivate" name="isprivate" value="1"
|
||||
[%+ 'checked="checked"' IF attachment.isprivate %]>
|
||||
[% IF can_edit %]
|
||||
<label for="isprivate">private (only visible to
|
||||
<strong>[% Param('insidergroup') FILTER html %]</strong>)
|
||||
</label>
|
||||
[% ELSE %]
|
||||
<span class="label">Is Private:</span>
|
||||
[%+ attachment.isprivate ? "yes" : "no" %]
|
||||
[% END %]
|
||||
</div>
|
||||
[% END %]
|
||||
</div>
|
||||
[% END %]
|
||||
</div>
|
||||
</div>
|
||||
|
||||
[% IF attachment.flag_types.size > 0 %]
|
||||
<div id="attachment_flags">
|
||||
[% PROCESS "flag/list.html.tmpl" bug_id = attachment.bug_id
|
||||
attach_id = attachment.id
|
||||
flag_types = attachment.flag_types
|
||||
read_only_flags = !can_edit
|
||||
<div id="attachment_view_window">
|
||||
[% IF !attachment.datasize %]
|
||||
<div><b>The content of this attachment has been deleted.</b></div>
|
||||
[% ELSIF attachment.isurl %]
|
||||
<div>
|
||||
<a href="[% attachment.data FILTER html %]">
|
||||
[% IF attachment.datasize < 120 %]
|
||||
[% attachment.data FILTER html %]
|
||||
[% ELSE %]
|
||||
[% attachment.data FILTER truncate(80) FILTER html %]
|
||||
...
|
||||
[% attachment.data.match(".*(.{20})$").0 FILTER html %]
|
||||
[% END %]
|
||||
</a>
|
||||
</div>
|
||||
[% ELSIF !Param("allow_attachment_display") %]
|
||||
<div id="view_disabled" >
|
||||
<p><b>
|
||||
The attachment is not viewable in your browser due to security
|
||||
restrictions enabled by your [% terms.Bugzilla %] administrator.
|
||||
</b></p>
|
||||
<p><b>
|
||||
In order to view the attachment, you first have to
|
||||
<a href="attachment.cgi?id=[% attachment.id %]">download it</a>.
|
||||
</b></p>
|
||||
</div>
|
||||
[% ELSIF attachment.is_viewable %]
|
||||
<div >
|
||||
[% INCLUDE global/textarea.html.tmpl
|
||||
id = 'editFrame'
|
||||
name = 'comment'
|
||||
classes = 'bz_default_hidden'
|
||||
minrows = 10
|
||||
cols = 80
|
||||
wrap = 'soft'
|
||||
defaultcontent = (attachment.contenttype.match('^text\/')) ?
|
||||
attachment.data.replace('(.*\n|.+)', '>$1') : undef
|
||||
%]
|
||||
<iframe id="viewFrame" src="attachment.cgi?id=[% attachment.id %]">
|
||||
<b>You cannot view the attachment while viewing its details because your browser does not support IFRAMEs.
|
||||
<a href="attachment.cgi?id=[% attachment.id %]">View the attachment on a separate page</a>.</b>
|
||||
</iframe>
|
||||
<script type="text/javascript">
|
||||
<!--
|
||||
var patchviewerinstalled = 0;
|
||||
var attachment_id = [% attachment.id %];
|
||||
if (typeof document.getElementById == "function") {
|
||||
[% IF use_patchviewer %]
|
||||
var patchviewerinstalled = 1;
|
||||
document.write('<iframe id="viewDiffFrame" class="bz_default_hidden"><\/iframe>');
|
||||
[% END %]
|
||||
[% IF user.id %]
|
||||
document.write('<button type="button" id="editButton" onclick="editAsComment(patchviewerinstalled);">Edit Attachment As Comment<\/button>');
|
||||
document.write('<button type="button" id="undoEditButton" onclick="undoEditAsComment(patchviewerinstalled);" class="bz_default_hidden">Undo Edit As Comment<\/button>');
|
||||
document.write('<button type="button" id="redoEditButton" onclick="redoEditAsComment(patchviewerinstalled);" class="bz_default_hidden">Redo Edit As Comment<\/button>');
|
||||
[% END %]
|
||||
[% IF use_patchviewer %]
|
||||
document.write('<button type="button" id="viewDiffButton" onclick="viewDiff(attachment_id, patchviewerinstalled);">View Attachment As Diff<\/button>');
|
||||
[% END %]
|
||||
document.write('<button type="button" id="viewRawButton" onclick="viewRaw(patchviewerinstalled);" class="bz_default_hidden">View Attachment As Raw<\/button>');
|
||||
}
|
||||
//-->
|
||||
</script>
|
||||
</div>
|
||||
[% ELSE %]
|
||||
<div id="noview">
|
||||
<p><b>
|
||||
Attachment is not viewable in your browser because its MIME type
|
||||
([% attachment.contenttype FILTER html %]) is not one that your browser is
|
||||
able to display.
|
||||
</b></p>
|
||||
<p><b>
|
||||
<a href="attachment.cgi?id=[% attachment.id %]">Download the attachment</a>.
|
||||
</b></p>
|
||||
</div>
|
||||
[% END %]
|
||||
|
||||
</div>
|
||||
<div id="attachment_comments_and_flags">
|
||||
[% IF user.id %]
|
||||
<div id="smallCommentFrame">
|
||||
<div id="smallCommentFrame" >
|
||||
<label for="comment">Comment (on the [% terms.bug %]):</label>
|
||||
<input type="checkbox" name="commentsilent" value="1" /> <label for="commentsilent">Silent</label></small><br />
|
||||
[% INCLUDE global/textarea.html.tmpl
|
||||
id = 'comment_textarea'
|
||||
name = 'comment'
|
||||
minrows = 5
|
||||
cols = 25
|
||||
minrows = 10
|
||||
cols = 80
|
||||
wrap = 'soft'
|
||||
classes = 'block'
|
||||
classes = classNames
|
||||
%]
|
||||
</div>
|
||||
|
||||
<input type="submit" value="Submit" id="update" />
|
||||
<input type="button" value="Preview" onclick="showcommentpreview()" tabindex="-1" /><br><br>
|
||||
|
||||
[% PROCESS "bug/comment-preview-div.html.tmpl" %]
|
||||
|
||||
[% END %]
|
||||
</td>
|
||||
|
||||
[% IF !attachment.datasize %]
|
||||
<td width="75%"><b>The content of this attachment has been deleted.</b></td>
|
||||
[% ELSIF attachment.isurl %]
|
||||
<td width="75%">
|
||||
<a href="[% attachment.data FILTER html %]">
|
||||
[% IF attachment.datasize < 120 %]
|
||||
[% attachment.data FILTER html %]
|
||||
[% ELSE %]
|
||||
[% attachment.data FILTER truncate(80) FILTER html %]
|
||||
...
|
||||
[% attachment.data.match(".*(.{20})$").0 FILTER html %]
|
||||
[% END %]
|
||||
</a>
|
||||
</td>
|
||||
[% ELSIF !Param("allow_attachment_display") %]
|
||||
<td id="view_disabled" width="50%">
|
||||
<p><b>
|
||||
The attachment is not viewable in your browser due to security
|
||||
restrictions enabled by [% terms.Bugzilla %].
|
||||
</b></p>
|
||||
<p><b>
|
||||
In order to view the attachment, you first have to
|
||||
<a href="attachment.cgi?id=[% attachment.id %]">download it</a>.
|
||||
</b></p>
|
||||
</td>
|
||||
[% ELSIF attachment.is_viewable %]
|
||||
<td width="75%">
|
||||
[% INCLUDE global/textarea.html.tmpl
|
||||
id = 'editFrame'
|
||||
name = 'comment'
|
||||
style = 'height: 400px; width: 100%; display: none'
|
||||
minrows = 10
|
||||
cols = 80
|
||||
wrap = 'soft'
|
||||
defaultcontent = (attachment.contenttype.match('^text\/')) ?
|
||||
attachment.data.replace('(.*\n|.+)', '>$1') : undef
|
||||
%]
|
||||
<iframe id="viewFrame" src="attachment.cgi?id=[% attachment.id %]" style="height: 400px; width: 100%;">
|
||||
<b>You cannot view the attachment while viewing its details because your browser does not support IFRAMEs.
|
||||
<a href="attachment.cgi?id=[% attachment.id %]">View the attachment on a separate page</a>.</b>
|
||||
</iframe>
|
||||
<script type="text/javascript">
|
||||
<!--
|
||||
var patchviewerinstalled = 0;
|
||||
var attachment_id = [% attachment.id %];
|
||||
if (typeof document.getElementById == "function") {
|
||||
[% IF use_patchviewer %]
|
||||
var patchviewerinstalled = 1;
|
||||
document.write('<iframe id="viewDiffFrame" style="height: 400px; width: 100%; display: none;"><\/iframe>');
|
||||
[% END %]
|
||||
document.write('<button type="button" id="editButton" onclick="editAsComment(patchviewerinstalled);">Edit Attachment As Comment<\/button>');
|
||||
document.write('<button type="button" id="undoEditButton" onclick="undoEditAsComment(patchviewerinstalled);" style="display: none;">Undo Edit As Comment<\/button>');
|
||||
document.write('<button type="button" id="redoEditButton" onclick="redoEditAsComment(patchviewerinstalled);" style="display: none;">Redo Edit As Comment<\/button>');
|
||||
[% IF use_patchviewer %]
|
||||
document.write('<button type="button" id="viewDiffButton" onclick="viewDiff(attachment_id, patchviewerinstalled);">View Attachment As Diff<\/button>');
|
||||
[% END %]
|
||||
document.write('<button type="button" id="viewRawButton" onclick="viewRaw(patchviewerinstalled);" style="display: none;">View Attachment As Raw<\/button>');
|
||||
}
|
||||
//-->
|
||||
</script>
|
||||
</td>
|
||||
[% ELSE %]
|
||||
<td id="noview" width="50%">
|
||||
<p><b>
|
||||
Attachment is not viewable in your browser because its MIME type
|
||||
([% attachment.contenttype FILTER html %]) is not one that your browser is
|
||||
able to display.
|
||||
</b></p>
|
||||
<p><b>
|
||||
<a href="attachment.cgi?id=[% attachment.id %]">Download the attachment</a>.
|
||||
[% IF attachment.isOfficeDocument() == 1 %]
|
||||
<br /><a href="attachment.cgi?id=[% attachment.id %]&action=online_view" target="_blank">Online-view</a>
|
||||
[% END %]
|
||||
</b></p>
|
||||
</td>
|
||||
[% END %]
|
||||
</tr>
|
||||
</table>
|
||||
[% END %]
|
||||
<div id="attachment_flags">
|
||||
[% IF attachment.flag_types.size > 0 %]
|
||||
|
||||
[% PROCESS "flag/list.html.tmpl" bug_id = attachment.bug_id
|
||||
attach_id = attachment.id
|
||||
flag_types = attachment.flag_types
|
||||
read_only_flags = !can_edit
|
||||
%]
|
||||
|
||||
[% END %]
|
||||
</div>
|
||||
[% IF user.id %]
|
||||
<div id="update_container">
|
||||
<input type="submit" value="Submit" id="update">
|
||||
</div>
|
||||
[% END %]
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
|
||||
<div id="attachment_actions">
|
||||
|
@ -292,7 +306,14 @@
|
|||
[% " |" UNLESS loop.last() %]
|
||||
[% END %]
|
||||
</div>
|
||||
|
||||
[% IF can_edit %]
|
||||
<script type="text/javascript">
|
||||
<!--
|
||||
YAHOO.util.Dom.removeClass( document.body, "no_javascript" );
|
||||
toggle_attachment_details_visibility( );
|
||||
-->
|
||||
</script>
|
||||
[% END %]
|
||||
[% Hook.process('end') %]
|
||||
|
||||
[% PROCESS global/footer.html.tmpl %]
|
||||
|
|
|
@ -107,10 +107,22 @@ function toggle_display(link)
|
|||
<i>no flags</i>
|
||||
[% ELSE %]
|
||||
[% FOREACH flag = attachment.flags %]
|
||||
[% flag.setter.nick FILTER html %]:
|
||||
[% IF user.id %]
|
||||
<span title="[% flag.setter.identity FILTER html %]">[% flag.setter.nick FILTER html %]</span>:
|
||||
[% ELSIF flag.setter.name %]
|
||||
<span title="[% flag.setter.name FILTER html %]">[% flag.setter.nick FILTER html %]</span>:
|
||||
[% ELSE %]
|
||||
[% flag.setter.nick FILTER html %]:
|
||||
[% END %]
|
||||
[%+ flag.type.name FILTER html FILTER no_break %][% flag.status %]
|
||||
[%+ IF flag.status == "?" && flag.requestee %]
|
||||
([% flag.requestee.nick FILTER html %])
|
||||
[% IF user.id %]
|
||||
(<span title="[% flag.requestee.identity FILTER html %]">[% flag.requestee.nick FILTER html %]</span>)
|
||||
[% ELSIF flag.requestee.name %]
|
||||
(<span title="[% flag.requestee.name FILTER html %]">[% flag.requestee.nick FILTER html %]</span>)
|
||||
[% ELSE %]
|
||||
([% flag.requestee.nick FILTER html %])
|
||||
[% END %]
|
||||
[% END %]<br>
|
||||
[% END %]
|
||||
[% END %]
|
||||
|
|
|
@ -29,7 +29,7 @@
|
|||
title = title
|
||||
header = header
|
||||
subheader = filtered_summary
|
||||
style_urls = ['skins/standard/create_attachment.css']
|
||||
style_urls = ['skins/standard/attachment.css']
|
||||
%]
|
||||
|
||||
<br>
|
||||
|
|
|
@ -302,16 +302,17 @@ function checkWorktime(inp)
|
|||
|
||||
<p>(<span class="required_star">*</span> = <span class="required_explanation">Required Field</span>)</p>
|
||||
|
||||
<table cellspacing="4" cellpadding="2" border="0">
|
||||
<table>
|
||||
<tbody>
|
||||
<tr><td colspan="4"><hr /></td></tr>
|
||||
|
||||
<tr>
|
||||
<th>Product:</th>
|
||||
<td width="10%">[% product.name FILTER html %]</td>
|
||||
|
||||
<th>Reporter:</th>
|
||||
<td width="100%">[% user.login FILTER html %]</td>
|
||||
[% INCLUDE bug/field.html.tmpl
|
||||
bug = default, field = bug_fields.product, editable = 0,
|
||||
value = product.name %]
|
||||
[% INCLUDE bug/field.html.tmpl
|
||||
bug = default, field = bug_fields.reporter, editable = 0,
|
||||
value = user.login %]
|
||||
</tr>
|
||||
|
||||
[%# We can't use the select block in these two cases for various reasons. %]
|
||||
|
@ -320,9 +321,9 @@ function checkWorktime(inp)
|
|||
<a href="describecomponents.cgi?product=[% product.name FILTER url_quote %]">
|
||||
Component</a>:
|
||||
</th>
|
||||
<td>
|
||||
<select name="component" onchange="set_assign_to();" size="7"
|
||||
aria-required="true" class="required">
|
||||
<td id="field_container_component">
|
||||
<select name="component" id="component" onchange="set_assign_to();"
|
||||
size="7" aria-required="true" class="required">
|
||||
[%# Build the lists of assignees and QA contacts if "usemenuforusers" is enabled. %]
|
||||
[% IF Param("usemenuforusers") %]
|
||||
[% assignees_list = user.get_userlist.clone %]
|
||||
|
@ -344,7 +345,7 @@ function checkWorktime(inp)
|
|||
</select>
|
||||
</td>
|
||||
|
||||
<td colspan="2">
|
||||
<td colspan="2" id="comp_desc_container">
|
||||
[%# Enclose the fieldset in a nested table so that its width changes based
|
||||
# on the length on the component description. %]
|
||||
<table>
|
||||
|
@ -361,9 +362,10 @@ function checkWorktime(inp)
|
|||
</tr>
|
||||
|
||||
<tr>
|
||||
<th>Version:</th>
|
||||
<td>
|
||||
<select name="version">
|
||||
<th rowspan="3"><a href="page.cgi?id=fields.html#version">
|
||||
[%- field_descs.version FILTER html %]:</a></th>
|
||||
<td rowspan="3">
|
||||
<select name="version" size="5">
|
||||
[%- FOREACH v = version %]
|
||||
<option value="[% v FILTER html %]"
|
||||
[% ' selected="selected"' IF v == default.version %]>[% v FILTER html -%]
|
||||
|
@ -392,6 +394,22 @@ function checkWorktime(inp)
|
|||
value = default.op_sys %]
|
||||
</tr>
|
||||
[% END %]
|
||||
[% IF !Param('defaultplatform') || !Param('defaultopsys') %]
|
||||
<tr>
|
||||
<td colspan="3"> </th>
|
||||
<td id="os_guess_note" class="comment">
|
||||
<div>We've made a guess at your
|
||||
[% IF Param('defaultplatform') %]
|
||||
operating system. Please check it
|
||||
[% ELSIF Param('defaultopsys') %]
|
||||
platform. Please check it
|
||||
[% ELSE %]
|
||||
operating system and platform. Please check them
|
||||
[% END %]
|
||||
and make any corrections if necessary.</div>
|
||||
</td>
|
||||
</tr>
|
||||
[% END %]
|
||||
</tbody>
|
||||
|
||||
<tbody class="expert_fields">
|
||||
|
@ -413,25 +431,6 @@ function checkWorktime(inp)
|
|||
</tr>
|
||||
</tbody>
|
||||
|
||||
[% IF !Param('defaultplatform') || !Param('defaultopsys') %]
|
||||
<tbody>
|
||||
<tr>
|
||||
<th> </th>
|
||||
<td colspan="3" class="comment">
|
||||
We've made a guess at your
|
||||
[% IF Param('defaultplatform') %]
|
||||
operating system. Please check it
|
||||
[% ELSIF Param('defaultopsys') %]
|
||||
platform. Please check it
|
||||
[% ELSE %]
|
||||
operating system and platform. Please check them
|
||||
[% END %]
|
||||
and make any corrections if necessary.
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
[% END %]
|
||||
|
||||
<tbody class="expert_fields">
|
||||
|
||||
<tr>
|
||||
|
@ -521,8 +520,9 @@ function checkWorktime(inp)
|
|||
|
||||
[% IF Param("useqacontact") %]
|
||||
<tr>
|
||||
<th>QA Contact:</th>
|
||||
<td>
|
||||
<th><a href="page.cgi?id=fields.html#qa_contact">
|
||||
[%- field_descs.qa_contact FILTER html %]:</a></th>
|
||||
<td colspan="2">
|
||||
[% INCLUDE global/userselect.html.tmpl
|
||||
id => "qa_contact"
|
||||
name => "qa_contact"
|
||||
|
@ -538,8 +538,9 @@ function checkWorktime(inp)
|
|||
[% END %]
|
||||
|
||||
<tr>
|
||||
<th>CC:</th>
|
||||
<td>
|
||||
<th><a href="page.cgi?id=fields.html#cc">
|
||||
[%- field_descs.cc FILTER html %]:</a></th>
|
||||
<td colspan="2">
|
||||
[% INCLUDE global/userselect.html.tmpl
|
||||
id => "cc"
|
||||
name => "cc"
|
||||
|
@ -551,7 +552,17 @@ function checkWorktime(inp)
|
|||
</td>
|
||||
</tr>
|
||||
|
||||
<tr><td colspan="4"><hr /></td></tr>
|
||||
<tr>
|
||||
<th>Default [% field_descs.cc FILTER html %]:</th>
|
||||
<td colspan="2">
|
||||
<div id="initial_cc">
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td colspan="3"> </td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
[% IF user.is_timetracker %]
|
||||
|
@ -581,8 +592,12 @@ function checkWorktime(inp)
|
|||
</tr>
|
||||
|
||||
<tr>
|
||||
<th>URL:</th>
|
||||
<td colspan="2"><input name="bug_file_loc" size="40" value="[% bug_file_loc FILTER html %]"></td>
|
||||
<th><a href="page.cgi?id=fields.html#bug_file_loc">
|
||||
[%- field_descs.bug_file_loc FILTER html %]:</a></th>
|
||||
<td colspan="2">
|
||||
<input name="bug_file_loc" size="40"
|
||||
value="[% bug_file_loc FILTER html %]">
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
|
||||
|
@ -604,7 +619,8 @@ function checkWorktime(inp)
|
|||
<tr><td colspan="4"><hr /></td></tr>
|
||||
|
||||
<tr>
|
||||
<th class="required">Summary:</th>
|
||||
<th class="required"><a href="page.cgi?id=fields.html#short_desc">
|
||||
[%- field_descs.short_desc FILTER html %]:</a></th>
|
||||
<td colspan="3">
|
||||
<input name="short_desc" id="short_desc" size="70" value="[% short_desc FILTER html %]"
|
||||
maxlength="255" spellcheck="true" aria-required="true"
|
||||
|
|
|
@ -50,7 +50,7 @@
|
|||
[% END %]
|
||||
[% IF desc_url %]
|
||||
<a href="[% desc_url FILTER html %]">
|
||||
[% ELSIF !field.custom %]
|
||||
[% ELSE %]
|
||||
<a href="page.cgi?id=fields.html#[% field.name FILTER url_quote %]">
|
||||
[% END -%]
|
||||
[% field_descs.${field.name} || field.description FILTER html %]:
|
||||
|
|
|
@ -179,7 +179,7 @@
|
|||
[% FOREACH flag_type = flag_types %]
|
||||
[% NEXT UNLESS flag_type.is_active %]
|
||||
[% all_visible_flag_types.${flag_type.id} = flag_type %]
|
||||
<li resource="[% escaped_urlbase %]flag.cgi?id=[% flag_type.id FILTER url_quote
|
||||
<li resource="[% urlbase FILTER xml %]flag.cgi?id=[% flag_type.id FILTER url_quote
|
||||
%]&name=[% flag_type.name FILTER url_quote %]" />
|
||||
[% END %]
|
||||
</Seq>
|
||||
|
@ -227,7 +227,7 @@
|
|||
<Seq>
|
||||
[% FOREACH flag_type = all_visible_flag_types.values.sort('name') %]
|
||||
<li>
|
||||
<bz:flag_type rdf:about="[% escaped_urlbase %]flag.cgi?id=[% flag_type.id FILTER url_quote
|
||||
<bz:flag_type rdf:about="[% urlbase FILTER xml %]flag.cgi?id=[% flag_type.id FILTER url_quote
|
||||
%]&name=[% flag_type.name FILTER url_quote %]">
|
||||
<bz:id>[% flag_type.id FILTER html %]</bz:id>
|
||||
<bz:name>[% flag_type.name FILTER html %]</bz:name>
|
||||
|
|
|
@ -53,14 +53,18 @@
|
|||
[% FOREACH flag = type.flags %]
|
||||
<tr>
|
||||
<td>
|
||||
<a href="#[% flag.creation_date | timestamp %]">[% flag.setter.nick | html %]</a>:
|
||||
<label title="[% type.description | html %]" for="flag-[% flag.id %]" style="white-space: nowrap">[%- type.name | html -%]</label>
|
||||
<span title="[% flag.setter.identity FILTER html %]">[% flag.setter.nick FILTER html %]</span>:
|
||||
</td>
|
||||
<td>
|
||||
<label title="[% type.description FILTER html %]"
|
||||
for="flag-[% flag.id %]">
|
||||
[%- type.name FILTER html FILTER no_break -%]</label>
|
||||
</td>
|
||||
<td>
|
||||
<select id="flag-[% flag.id %]" name="flag-[% flag.id %]"
|
||||
title="[% type.description | html %]"
|
||||
onchange="toggleRequesteeField(this);"
|
||||
class="flag_select">
|
||||
class="flag_select flag_type-[% type.id %]">
|
||||
[%# Only display statuses the user is allowed to set. %]
|
||||
[% IF user.can_request_flag(type) || flag.setter_id == user.id %]
|
||||
<option value="X"></option>
|
||||
|
@ -115,10 +119,18 @@
|
|||
<p><b>Flags:</b></p>
|
||||
[% header_displayed = 1 %]
|
||||
[% END %]
|
||||
[% flag.setter.nick FILTER html %]:
|
||||
[% IF flag.setter.name %]
|
||||
<span title="[% flag.setter.name FILTER html %]">[% flag.setter.nick FILTER html %]</span>:
|
||||
[% ELSE %]
|
||||
[% flag.setter.nick FILTER html %]:
|
||||
[% END %]
|
||||
[%+ type.name FILTER html FILTER no_break %][% flag.status %]
|
||||
[% IF flag.requestee %]
|
||||
([% flag.requestee.nick FILTER html %])
|
||||
[% IF flag.requestee.name %]
|
||||
(<span title="[% flag.requestee.name FILTER html %]">[% flag.requestee.nick FILTER html %]</span>)
|
||||
[% ELSE %]
|
||||
([% flag.requestee.nick FILTER html %])
|
||||
[% END %]
|
||||
[% END %]<br>
|
||||
[% END %]
|
||||
[% END %]
|
||||
|
|
|
@ -23,80 +23,6 @@
|
|||
|
||||
[% PROCESS global/variables.none.tmpl %]
|
||||
|
||||
[% field_descs = { "[Bug creation]" => "[$terms.Bug creation]",
|
||||
"actual_time" => "Actual Hours",
|
||||
"alias" => "Alias",
|
||||
"assigned_to" => "Assignee",
|
||||
"attach_data.thedata" => "Attachment data",
|
||||
"attachments.description" => "Attachment description",
|
||||
"attachments.filename" => "Attachment filename",
|
||||
"attachments.mimetype" => "Attachment mime type",
|
||||
"attachments.ispatch" => "Attachment is patch",
|
||||
"attachments.isobsolete" => "Attachment is obsolete",
|
||||
"attachments.isprivate" => "Attachment is private",
|
||||
"attachments.isurl" => "Attachment is a URL",
|
||||
"attachments.submitter" => "Attachment creator",
|
||||
"blocked" => "Blocks",
|
||||
"bug_file_loc" => "URL",
|
||||
"bug_group" => "Group",
|
||||
"bug_id" => "$terms.Bug ID",
|
||||
"bug_severity" => "Severity",
|
||||
"bug_status" => "Status",
|
||||
"changeddate" => "Changed",
|
||||
"cc" => "CC",
|
||||
"classification" => "Classification",
|
||||
"cclist_accessible" => "CC list accessible",
|
||||
"commenter" => "Commenter",
|
||||
"component_id" => "Component ID",
|
||||
"component" => "Component",
|
||||
"content" => "Content",
|
||||
"creation_ts" => "Creation date",
|
||||
"deadline" => "Deadline",
|
||||
"delta_ts" => "Changed",
|
||||
"dependson" => "Depends on",
|
||||
"dup_id" => "Duplicate",
|
||||
"estimated_time" => "Orig. Est.",
|
||||
"everconfirmed" => "Ever confirmed",
|
||||
"flagtypes.name" => "Flags",
|
||||
"keywords" => "Keywords",
|
||||
"longdesc" => "Comment",
|
||||
"longdescs.isprivate" => "Comment is private",
|
||||
"newcc" => "CC",
|
||||
"op_sys" => "OS",
|
||||
"opendate" => "Opened",
|
||||
"owner_idle_time" => "Time Since Assignee Touched",
|
||||
"percentage_complete" => "%Complete",
|
||||
"priority" => "Priority",
|
||||
"product_id" => "Product ID",
|
||||
"product" => "Product",
|
||||
"qa_contact" => "QA Contact",
|
||||
"remaining_time" => "Hours Left",
|
||||
"rep_platform" => "Hardware",
|
||||
"reporter" => "Reporter",
|
||||
"reporter_accessible" => "Reporter accessible",
|
||||
"requestees.login_name" => "Flag Requestee",
|
||||
"resolution" => "Resolution",
|
||||
"see_also" => "See Also",
|
||||
"setters.login_name" => "Flag Setter",
|
||||
"setting" => "Setting",
|
||||
"settings" => "Settings",
|
||||
"short_desc" => "Summary",
|
||||
"status_whiteboard" => "Whiteboard",
|
||||
"target_milestone" => "Target Milestone",
|
||||
"version" => "Version",
|
||||
"work_time" => "Hours Worked"} %]
|
||||
|
||||
[%# Also include any custom fields or fields which don't have a
|
||||
Description here, by copying their Description from the
|
||||
database. If you want to override this for your language
|
||||
or your installation, just use a hook. %]
|
||||
[% UNLESS Param('shutdownhtml') %]
|
||||
[% FOREACH bz_field = bug_fields.values %]
|
||||
[% SET field_descs.${bz_field.name} = bz_field.description
|
||||
IF !field_descs.${bz_field.name}.defined %]
|
||||
[% END %]
|
||||
[% END %]
|
||||
|
||||
[% SET search_descs = {
|
||||
"noop" => "---",
|
||||
"equals" => "is equal to",
|
||||
|
@ -123,6 +49,7 @@
|
|||
"changedto" => "changed to",
|
||||
"changedby" => "changed by",
|
||||
"matches" => "matches",
|
||||
"notmatches" => "does not match",
|
||||
} %]
|
||||
|
||||
[% field_types = { ${constants.FIELD_TYPE_UNKNOWN} => "Unknown Type",
|
||||
|
@ -162,4 +89,87 @@
|
|||
[% END %]
|
||||
[% END %][% END %]
|
||||
|
||||
[% IF in_template_var %]
|
||||
[% vars.terms = terms %]
|
||||
|
||||
[%# field_descs is loaded as a global template variable and cached
|
||||
# across all templates--see VARIABLES in Bugzilla/Template.pm.
|
||||
#%]
|
||||
[% vars.field_descs = {
|
||||
"[Bug creation]" => "[$terms.Bug creation]",
|
||||
"actual_time" => "Actual Hours",
|
||||
"alias" => "Alias",
|
||||
"assigned_to" => "Assignee",
|
||||
"attach_data.thedata" => "Attachment data",
|
||||
"attachments.description" => "Attachment description",
|
||||
"attachments.filename" => "Attachment filename",
|
||||
"attachments.mimetype" => "Attachment mime type",
|
||||
"attachments.ispatch" => "Attachment is patch",
|
||||
"attachments.isobsolete" => "Attachment is obsolete",
|
||||
"attachments.isprivate" => "Attachment is private",
|
||||
"attachments.isurl" => "Attachment is a URL",
|
||||
"attachments.submitter" => "Attachment creator",
|
||||
"blocked" => "Blocks",
|
||||
"bug_file_loc" => "URL",
|
||||
"bug_group" => "Group",
|
||||
"bug_id" => "$terms.Bug ID",
|
||||
"bug_severity" => "Severity",
|
||||
"bug_status" => "Status",
|
||||
"changeddate" => "Changed",
|
||||
"cc" => "CC",
|
||||
"classification" => "Classification",
|
||||
"cclist_accessible" => "CC list accessible",
|
||||
"commenter" => "Commenter",
|
||||
"component_id" => "Component ID",
|
||||
"component" => "Component",
|
||||
"content" => "Content",
|
||||
"creation_ts" => "Creation date",
|
||||
"deadline" => "Deadline",
|
||||
"delta_ts" => "Changed",
|
||||
"dependson" => "Depends on",
|
||||
"dup_id" => "Duplicate",
|
||||
"estimated_time" => "Orig. Est.",
|
||||
"everconfirmed" => "Ever confirmed",
|
||||
"flagtypes.name" => "Flags",
|
||||
"keywords" => "Keywords",
|
||||
"longdesc" => "Comment",
|
||||
"longdescs.isprivate" => "Comment is private",
|
||||
"newcc" => "CC",
|
||||
"op_sys" => "OS",
|
||||
"opendate" => "Opened",
|
||||
"owner_idle_time" => "Time Since Assignee Touched",
|
||||
"percentage_complete" => "%Complete",
|
||||
"priority" => "Priority",
|
||||
"product_id" => "Product ID",
|
||||
"product" => "Product",
|
||||
"qa_contact" => "QA Contact",
|
||||
"remaining_time" => "Hours Left",
|
||||
"rep_platform" => "Hardware",
|
||||
"reporter" => "Reporter",
|
||||
"reporter_accessible" => "Reporter accessible",
|
||||
"requestees.login_name" => "Flag Requestee",
|
||||
"resolution" => "Resolution",
|
||||
"see_also" => "See Also",
|
||||
"setters.login_name" => "Flag Setter",
|
||||
"setting" => "Setting",
|
||||
"settings" => "Settings",
|
||||
"short_desc" => "Summary",
|
||||
"status_whiteboard" => "Whiteboard",
|
||||
"target_milestone" => "Target Milestone",
|
||||
"version" => "Version",
|
||||
"work_time" => "Hours Worked",
|
||||
} %]
|
||||
|
||||
[%# Also include any custom fields or fields which don't have a
|
||||
Description here, by copying their Description from the
|
||||
database. If you want to override this for your language
|
||||
or your installation, just use a hook. %]
|
||||
[% UNLESS Param('shutdownhtml') %]
|
||||
[% FOREACH bz_field = bug_fields.values %]
|
||||
[% SET vars.field_descs.${bz_field.name} = bz_field.description
|
||||
IF !vars.field_descs.${bz_field.name}.defined %]
|
||||
[% END %]
|
||||
[% END %]
|
||||
[% END %]
|
||||
|
||||
[% Hook.process("end") %]
|
||||
|
|
|
@ -31,10 +31,23 @@
|
|||
</p>
|
||||
|
||||
[% field_descs.short_short_desc = "Summary (first 60 characters)" %]
|
||||
[% field_descs.short_desc = "Full Summary" %]
|
||||
[% field_descs.assigned_to_realname = "Assignee Realname" %]
|
||||
[% field_descs.reporter_realname = "Reporter Realname" %]
|
||||
[% field_descs.qa_contact_realname = "QA Contact Realname" %]
|
||||
[% field_descs.short_desc = "Summary (Full)" %]
|
||||
[% field_descs.assigned_to_realname = "$field_descs.assigned_to Real Name" %]
|
||||
[% field_descs.reporter_realname = "$field_descs.reporter Real Name" %]
|
||||
[% field_descs.qa_contact_realname = "$field_descs.qa_contact Real Name" %]
|
||||
|
||||
[%# Create a mapping of field descriptions to field names, so that
|
||||
# the "Available Columns" list can be sorted alphabetically by
|
||||
# field description.
|
||||
#%]
|
||||
[% SET available_columns = {} %]
|
||||
[% FOREACH column = columns.keys %]
|
||||
[% NEXT IF collist.contains(column) %]
|
||||
[%# We lowecase the keys so that the sort happens case-insensitively. %]
|
||||
[% SET column_desc = field_descs.$column || column FILTER lower %]
|
||||
[% available_columns.$column_desc = column %]
|
||||
[% END %]
|
||||
|
||||
<form name="changecolumns" action="colchange.cgi" onsubmit="change_submit();">
|
||||
<input type="hidden" name="rememberedquery" value="[% buffer FILTER html %]" />
|
||||
<table>
|
||||
|
@ -66,12 +79,13 @@
|
|||
[% Bugzilla.COLUMNS.${column}.title || column | html %]
|
||||
</option>
|
||||
[% END %]
|
||||
[% FOREACH column = masterlist %]
|
||||
[% IF lsearch(collist, column) == -1 %]
|
||||
<option value="[% column FILTER html %]">
|
||||
[% Bugzilla.COLUMNS.${column}.title || column | html %]
|
||||
</option>
|
||||
[% END %]
|
||||
[% FOREACH key = available_columns.keys.sort %]
|
||||
[% SET column = available_columns.$key %]
|
||||
<option value="[% column FILTER html %]">
|
||||
[%# Don't display the lower-cased column description,
|
||||
# display the correct-case one. %]
|
||||
[% (field_descs.$column || column) FILTER html %]
|
||||
</option>
|
||||
[% END %]
|
||||
</select>
|
||||
</td>
|
||||
|
|
|
@ -41,6 +41,35 @@
|
|||
[% field_descs.assigned_to_realname = field_descs.assigned_to %]
|
||||
[% field_descs.reporter_realname = field_descs.reporter %]
|
||||
[% field_descs.qa_contact_realname = field_descs.qa_contact %]
|
||||
|
||||
[% abbrev =
|
||||
{
|
||||
"bug_severity" => { maxlength => 3 , title => "Sev" } ,
|
||||
"priority" => { maxlength => 3 , title => "Pri" } ,
|
||||
"rep_platform" => { maxlength => 3 , title => "Plt" } ,
|
||||
"bug_status" => { maxlength => 4 } ,
|
||||
"assigned_to" => { maxlength => 30 , ellipsis => "..." } ,
|
||||
"assigned_to_realname" => { maxlength => 20 , ellipsis => "..." } ,
|
||||
"reporter" => { maxlength => 30 , ellipsis => "..." } ,
|
||||
"reporter_realname" => { maxlength => 20 , ellipsis => "..." } ,
|
||||
"qa_contact" => { maxlength => 30 , ellipsis => "..." , title => "QAContact" } ,
|
||||
"qa_contact_realname" => { maxlength => 20 , ellipsis => "..." , title => "QAContact" } ,
|
||||
"resolution" => { maxlength => 4 } ,
|
||||
"short_desc" => { wrap => 1 } ,
|
||||
"short_short_desc" => { maxlength => 60 , ellipsis => "..." , wrap => 1 } ,
|
||||
"status_whiteboard" => { title => "Whiteboard" , wrap => 1 } ,
|
||||
"keywords" => { wrap => 1 } ,
|
||||
"flagtypes.name" => { wrap => 1 } ,
|
||||
"component" => { maxlength => 8 , title => "Comp" } ,
|
||||
"product" => { maxlength => 8 } ,
|
||||
"version" => { maxlength => 5 , title => "Vers" } ,
|
||||
"op_sys" => { maxlength => 4 } ,
|
||||
"bug_file_loc" => { maxlength => 30 } ,
|
||||
"target_milestone" => { title => "TargetM" } ,
|
||||
"percentage_complete" => { format_value => "%d %%" } ,
|
||||
}
|
||||
%]
|
||||
|
||||
[% PROCESS bug/time.html.tmpl %]
|
||||
|
||||
[% Hook.process("before_table") %]
|
||||
|
|
|
@ -25,7 +25,6 @@
|
|||
|
||||
<ul class="bz_toc">
|
||||
<li><a href="#v36_introduction">Introduction</a></li>
|
||||
<li><a href="#v36_point">Updates in this 3.6.x Release</a></li>
|
||||
<li><a href="#v36_req">Minimum Requirements</a></li>
|
||||
<li><a href="#v36_feat">New Features and Improvements</a></li>
|
||||
<li><a href="#v36_issues">Outstanding Issues</a></li>
|
||||
|
@ -57,187 +56,6 @@
|
|||
of various features and improvements in this release of
|
||||
[%+ terms.Bugzilla %].</p>
|
||||
|
||||
<h2 id="v36_point">Updates in this 3.6.x Release</h2>
|
||||
|
||||
<h3>3.6.4</h3>
|
||||
|
||||
<p>This release fixes several security issues, some of which are
|
||||
<strong>highly critical</strong>. See the
|
||||
<a href="http://www.bugzilla.org/security/3.2.9/">Security Advisory</a>
|
||||
for details.</p>
|
||||
|
||||
<p>In addition, the following important fixes/changes have been made in
|
||||
this release:</p>
|
||||
|
||||
<ul>
|
||||
<li>Due to one of the security fixes, [% terms.Bugzilla %] 3.6.4 now
|
||||
requires a newer version of the CGI.pm Perl module than previous
|
||||
releases of [% terms.Bugzilla %] did. When you run
|
||||
<kbd>checksetup.pl</kbd>, it will inform you how to upgrade your CGI.pm
|
||||
module.
|
||||
</li>
|
||||
<li>When replying to a comment with a link like "attachment 1234 [details]",
|
||||
the "[details]" link will no longer be duplicated in your reply.
|
||||
(<a href="https://bugzilla.mozilla.org/show_bug.cgi?id=474766">[% terms.Bug %] 474766</a>)
|
||||
</li>
|
||||
<li>Using Quicksearch no longer requires that the <kbd>List::MoreUtils</kbd>
|
||||
module be installed.
|
||||
(<a href="https://bugzilla.mozilla.org/show_bug.cgi?id=611129">[% terms.Bug %] 611129</a>)
|
||||
</li>
|
||||
<li>When using <a href="config.cgi?ctype=rdf">config.cgi?ctype=rdf</a>,
|
||||
information about products now includes <kbd>allows_unconfirmed</kbd>.
|
||||
(<a href="https://bugzilla.mozilla.org/show_bug.cgi?id=610217">[% terms.Bug %] 610217</a>)
|
||||
</li>
|
||||
<li>When using tabular reports, any value whose name started with a period
|
||||
or an underscore wasn't being displayed.
|
||||
(<a href="https://bugzilla.mozilla.org/show_bug.cgi?id=617684">[% terms.Bug %] 617684</a>)
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<h3>3.6.3</h3>
|
||||
|
||||
<p>This release fixes various important security issues. See the
|
||||
<a href="http://www.bugzilla.org/security/3.2.8/">Security Advisory</a>
|
||||
for details.</p>
|
||||
|
||||
<p>In addition, the following important fixes/changes have been made in
|
||||
this release:</p>
|
||||
|
||||
<ul>
|
||||
<li>Clicking the "Submit only my new comment" button on the mid-air
|
||||
collision page will no longer result in a "Form field longdesclength
|
||||
was not defined" error.
|
||||
(<a href="https://bugzilla.mozilla.org/show_bug.cgi?id=591218">[% terms.Bug %] 591218</a>)
|
||||
</li>
|
||||
<li>Saving a search with either of the deadline fields set to "Now" would
|
||||
cause that deadline field to be removed from the saved search.
|
||||
(<a href="https://bugzilla.mozilla.org/show_bug.cgi?id=590144">[% terms.Bug %] 590144</a>)
|
||||
</li>
|
||||
<li>Searching for [% terms.bugs %] "with at least X votes" was instead
|
||||
returning [% terms.bugs %] with <em>exactly</em> that many votes.
|
||||
(<a href="https://bugzilla.mozilla.org/show_bug.cgi?id=584414">[% terms.Bug %] 584414</a>)
|
||||
</li>
|
||||
<li>Typing something like "P1-5" in the quicksearch box should have
|
||||
been searching the [% field_descs.priority FILTER html %] field,
|
||||
but it was not.
|
||||
(<a href="https://bugzilla.mozilla.org/show_bug.cgi?id=585028">[% terms.Bug %] 585028</a>)
|
||||
</li>
|
||||
<li>Users who had passwords less than 6 characters long couldn't log in.
|
||||
Such users could only exist before 3.6, so it looked like after upgrading
|
||||
to 3.6, certain users couldn't log in.
|
||||
(<a href="https://bugzilla.mozilla.org/show_bug.cgi?id=575947">[% terms.Bug %] 575947</a>)
|
||||
</li>
|
||||
<li>Loading <a href="config.cgi?ctype=rdf">config.cgi?ctype=rdf</a> should
|
||||
now be faster, particularly on installations that have many flags.
|
||||
(<a href="https://bugzilla.mozilla.org/show_bug.cgi?id=553266">[% terms.Bug %] 553266</a>
|
||||
and <a href="https://bugzilla.mozilla.org/show_bug.cgi?id=605693">[% terms.Bug %] 605693</a>)
|
||||
</li>
|
||||
<li>Non-english templates were not being precompiled by checksetup.pl,
|
||||
leading to reduced performance for localized [% terms.Bugzilla %]
|
||||
installations.
|
||||
(<a href="https://bugzilla.mozilla.org/show_bug.cgi?id=605425">[% terms.Bug %] 605425</a>)
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<h3>3.6.2</h3>
|
||||
|
||||
<p>This release fixes various security issues. See the
|
||||
<a href="http://www.bugzilla.org/security/3.2.7/">Security Advisory</a>
|
||||
for details.</p>
|
||||
|
||||
<p>In addition, the following important fixes/changes have been made in
|
||||
this release:</p>
|
||||
|
||||
<ul>
|
||||
<li>[% terms.Bugzilla %] installations running on older versions of IIS
|
||||
will no longer experience the "Undef to trick_taint" errors that would
|
||||
sometimes occur.
|
||||
(<a href="https://bugzilla.mozilla.org/show_bug.cgi?id=521416">[% terms.Bug %] 521416</a>)
|
||||
</li>
|
||||
<li>Email notifications were missing the dates that comments were made.
|
||||
(<a href="https://bugzilla.mozilla.org/show_bug.cgi?id=578003">[% terms.Bug %] 578003</a>)
|
||||
</li>
|
||||
<li>Putting a phrase in quotes in the Quicksearch box now works properly,
|
||||
again.
|
||||
(<a href="https://bugzilla.mozilla.org/show_bug.cgi?id=578494">[% terms.Bug %] 578494</a>
|
||||
and <a href="https://bugzilla.mozilla.org/show_bug.cgi?id=553884">[% terms.Bug %] 553884</a>)
|
||||
</li>
|
||||
<li>Quicksearch was usually (incorrectly) being limited to 200 results.
|
||||
(<a href="https://bugzilla.mozilla.org/show_bug.cgi?id=581622">[% terms.Bug %] 581622</a>)
|
||||
</li>
|
||||
<li>On Windows, <kbd>install-module.pl</kbd> can now properly install
|
||||
DateTime and certain other Perl modules that didn't install properly
|
||||
before.
|
||||
(<a href="https://bugzilla.mozilla.org/show_bug.cgi?id=576105">[% terms.Bug %] 576105</a>)
|
||||
</li>
|
||||
<li>Searching "keywords" for "contains none of the words" or "does not
|
||||
match regular expression" now works properly.
|
||||
(<a href="https://bugzilla.mozilla.org/show_bug.cgi?id=562014">[% terms.Bug %] 562014</a>)
|
||||
</li>
|
||||
<li>Doing <kbd>collectstats.pl --regenerate</kbd> now works on installations
|
||||
using PostgreSQL.
|
||||
(<a href="https://bugzilla.mozilla.org/show_bug.cgi?id=577058">[% terms.Bug %] 577058</a>)
|
||||
</li>
|
||||
<li>The "Field Values" administrative control panel was sometimes denying
|
||||
admins the ability to delete field values when there was no reason
|
||||
to deny the deletion.
|
||||
(<a href="https://bugzilla.mozilla.org/show_bug.cgi?id=577054">[% terms.Bug %] 577054</a>)
|
||||
</li>
|
||||
<li>Eliminate the "uninitialized value" warnings that would happen when
|
||||
editing a product's components.
|
||||
(<a href="https://bugzilla.mozilla.org/show_bug.cgi?id=576911">[% terms.Bug %] 576911</a>)
|
||||
</li>
|
||||
<li>The updating of bugs_fulltext that happens during
|
||||
<kbd>checksetup.pl</kbd> for upgrades to 3.6 should now be MUCH faster.
|
||||
(<a href="https://bugzilla.mozilla.org/show_bug.cgi?id=577754">[% terms.Bug %] 577754</a>)
|
||||
</li>
|
||||
<li><kbd>email_in.pl</kbd> was not allowing the setting of time-tracking
|
||||
fields via inbound emails.
|
||||
(<a href="https://bugzilla.mozilla.org/show_bug.cgi?id=583622">[% terms.Bug %] 583622</a>)
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<h3>3.6.1</h3>
|
||||
|
||||
<p>This release fixes two security issues. See the
|
||||
<a href="http://www.bugzilla.org/security/3.2.6/">Security Advisory</a>
|
||||
for details.</p>
|
||||
|
||||
<p>In addition, the following important fixes/changes have been made in
|
||||
this release:</p>
|
||||
|
||||
<ul>
|
||||
<li>Using the "Change Columns" page would sometimes result in a
|
||||
plain-text page instead of HTML.
|
||||
(<a href="https://bugzilla.mozilla.org/show_bug.cgi?id=376044">[% terms.Bug %] 376044</a>)
|
||||
</li>
|
||||
<li>Extensions that have only templates and no code are now working.
|
||||
(<a href="https://bugzilla.mozilla.org/show_bug.cgi?id=562551">[% terms.Bug %] 562551</a>)
|
||||
</li>
|
||||
<li><kbd>install-module.pl</kbd> has been fixed so that it installs
|
||||
modules properly on both new and old versions of Perl.
|
||||
(<a href="https://bugzilla.mozilla.org/show_bug.cgi?id=560318">[% terms.Bug %] 560318</a>
|
||||
and <a href="https://bugzilla.mozilla.org/show_bug.cgi?id=560330">[% terms.Bug %] 560330</a>)
|
||||
</li>
|
||||
<li>It is now possible to upgrade from 3.4 to 3.6 when using Oracle.
|
||||
(<a href="https://bugzilla.mozilla.org/show_bug.cgi?id=561379">[% terms.Bug %] 561379</a>)
|
||||
</li>
|
||||
<li>Editing a field value's name (using the Field Values admin control
|
||||
panel) wasn't working if the value was set as the default for that
|
||||
field.
|
||||
(<a href="https://bugzilla.mozilla.org/show_bug.cgi?id=561296">[% terms.Bug %] 561296</a>)
|
||||
</li>
|
||||
<li>If you had the <kbd>noresolveonopenblockers</kbd> parameter set,
|
||||
[%+ terms.bugs %] couldn't be edited at all if they were marked FIXED
|
||||
and had any open blockers. (The parameter is only supposed to prevent
|
||||
<em>changing</em> [% terms.bugs %] to FIXED, not modifying already-FIXED
|
||||
[%+ terms.bugs %].)
|
||||
(<a href="https://bugzilla.mozilla.org/show_bug.cgi?id=565314">[% terms.Bug %] 565314</a>)
|
||||
</li>
|
||||
<li>Some minor issues with Perl 5.12 were fixed (mostly warnings that Perl
|
||||
5.12 was throwing). [% terms.Bugzilla %] now supports Perl 5.12.</li>
|
||||
</ul>
|
||||
|
||||
<h2 id="v36_req">Minimum Requirements</h2>
|
||||
|
||||
<p>Any requirements that are new since 3.4.5 will look like
|
||||
|
@ -266,7 +84,7 @@
|
|||
<h3 id="v36_req_modules">Required Perl Modules</h3>
|
||||
|
||||
[% INCLUDE req_table reqs = REQUIRED_MODULES
|
||||
new = [] updated = ['CGI.pm'] %]
|
||||
new = [] updated = [] %]
|
||||
|
||||
<h3 id="v36_req_optional_mod">Optional Perl Modules</h3>
|
||||
|
||||
|
@ -274,7 +92,7 @@
|
|||
features of [% terms.Bugzilla %]:</p>
|
||||
|
||||
[% INCLUDE req_table reqs = OPTIONAL_MODULES
|
||||
new = ['JSON-RPC', 'Test-Taint', 'Math-Random-Secure']
|
||||
new = ['JSON-RPC', 'Test-Taint']
|
||||
updated = ['Chart']
|
||||
include_feature = 1 %]
|
||||
|
||||
|
@ -298,7 +116,7 @@
|
|||
<p>A <a href="https://wiki.mozilla.org/Bugzilla:CMU_HCI_Research_2008">scientific
|
||||
usability study</a> was done on [% terms.Bugzilla %] by researchers
|
||||
from Carnegie-Mellon University. As a result of this study,
|
||||
<a href="https://bugzilla.mozilla.org/showdependencytree.cgi?id=490786&hide_resolved=0">several
|
||||
<a href="https://bugzilla.mozilla.org/showdependencytree.cgi?id=490786&hide_resolved=0">several
|
||||
usability issues</a> were prioritized to be fixed, based on specific data
|
||||
from the study.</p>
|
||||
|
||||
|
@ -379,7 +197,7 @@
|
|||
on shared hosting). SUExec support shows up as an option
|
||||
in the <kbd>localconfig</kbd> file during installation.</p>
|
||||
|
||||
<h3 id="v36_feat_mpwindows">Experimental mod_perl Support on Windows</h3>
|
||||
<h3 id="36_feat_mpwindows">Experimental mod_perl Support on Windows</h3>
|
||||
|
||||
<p>There is now experimental support for running [% terms.Bugzilla %]
|
||||
under mod_perl on Windows, for a significant performance enhancement
|
||||
|
@ -456,12 +274,6 @@
|
|||
<li><b>[% terms.Bug %] Editing:</b> The "Collapse All Comments"
|
||||
and "Expand All Comments" links now appear to the right of the
|
||||
comment list instead of above it.</li>
|
||||
<li><b>[% terms.Bug %] Editing:</b> The See Also field now supports
|
||||
URLs for Google Code Issues and the Debian B[% %]ug-Tracking System.</li>
|
||||
<li><b>[% terms.Bug %] Editing:</b> There have been significant performance
|
||||
improvements in <kbd>show_bug.cgi</kbd> (the script that displays the
|
||||
[% terms.bug %]-editing form), particularly for [% terms.bugs %] that
|
||||
have lots of comments or attachments.</li>
|
||||
|
||||
<li><b>Attachments:</b> The "Details" page of an attachment
|
||||
now displays itself as uneditable if you can't edit the fields
|
||||
|
@ -474,9 +286,6 @@
|
|||
<li><b>Attachments:</b> When you click on an "attachment 12345" link
|
||||
in a comment, if the attachment is a patch, you will now see the
|
||||
formatted "Diff" view instead of the raw patch.</li>
|
||||
<li><b>Attachments</b>: For text attachments, we now let the browser
|
||||
auto-detect the character encoding, instead of forcing the browser to
|
||||
always assume the attachment is in UTF-8.</li>
|
||||
|
||||
<li><b>Search:</b> You can now display [% terms.bug %] flags as a column
|
||||
in search results.</li>
|
||||
|
@ -573,11 +382,6 @@
|
|||
faster at upgrading installations, particularly older installations.
|
||||
Also, it's been made faster to run for the case where it's not
|
||||
doing an upgrade.</li>
|
||||
<li><b>Installation:</b> If you install [% terms.Bugzilla %] using the
|
||||
tarball, the <kbd>CGI.pm</kbd> module from CPAN is now included in
|
||||
the <kbd>lib/</kbd> dir. If you would rather use the CGI.pm from your
|
||||
global Perl installation, you can delete <kbd>CGI.pm</kbd> and the
|
||||
<kbd>CGI</kbd> directory from the <kbd>lib/</kbd> directory.</li>
|
||||
|
||||
<li>When editing a group, you can now specify that members of a group
|
||||
are allowed to grant others membership in that group itself.</li>
|
||||
|
@ -588,12 +392,14 @@
|
|||
words instead of P1, P2, etc.</li>
|
||||
<li>There is now a system in place so that all field values can be
|
||||
localized. See the <kbd>value_descs</kbd> variable in
|
||||
<kbd>template/en/default/global/field-descs.none.tmpl</kbd>.</li>
|
||||
<li><kbd>config.cgi</kbd> now returns an ETag header and understands
|
||||
the If-None-Match header in HTTP requests.</li>
|
||||
<li>The XML format of <kbd>show_bug.cgi</kbd> now returns more information:
|
||||
the numeric id of each comment, whether an attachment is a URL,
|
||||
the modification time of an attachment, the numeric id of a flag,
|
||||
and the numeric id of a flag's type.</li>
|
||||
|
||||
<li><b>Parameters:</b> Parameters that aren't actually required are no longer
|
||||
in the "Required" section of the Parameters page. Instead, some are in the
|
||||
new "General" section, and some are in the new "Advanced" section.</li>
|
||||
|
@ -664,9 +470,6 @@
|
|||
that parameter will be ignored. Mostly this just affects
|
||||
customizers--[% terms.Bugzilla %]'s WebService is not functionally
|
||||
affected by these changes.</li>
|
||||
<li>In previous versions of [% terms.Bugzilla %], error messages were
|
||||
sent word-wrapped to the client, from the WebService. Error messages
|
||||
are now sent as one unbroken line.</li>
|
||||
</ul>
|
||||
|
||||
<h2 id="v36_issues">Outstanding Issues</h2>
|
||||
|
@ -718,9 +521,6 @@
|
|||
<h2 id="v36_code_changes">Code Changes Which May Affect Customizations</h2>
|
||||
|
||||
<ul>
|
||||
<li>There is no longer a SendBugMail method in the templates, and bugmail
|
||||
is no longer sent by processing a template. Instead, it is sent
|
||||
by using <kbd>Bugzilla::BugMail::Send</kbd>.</li>
|
||||
<li>Comments are now represented as a
|
||||
<a href="[% docs_urlbase FILTER html %]api/Bugzilla/Comment.html">Bugzilla::Comment</a>
|
||||
object instead of just being hashes.</li>
|
||||
|
@ -733,13 +533,13 @@
|
|||
<li>All of the various template header information required to display
|
||||
the [% terms.bug %] form is now in one template,
|
||||
<kbd>template/en/default/bug/show-header.html.tmpl</kbd>.</li>
|
||||
<li><s>You should now use <kbd>display_value</kbd> instead of
|
||||
<li>You should now use <kbd>display_value</kbd> instead of
|
||||
<kbd>get_status</kbd> or <kbd>get_resolution</kbd> in templates.
|
||||
<kbd>display_value</kbd> should be used anywhere that a
|
||||
<select>-type field has its values displayed.</s>
|
||||
Долбанутое решение убрано.</li>
|
||||
<select>-type field has its values displayed.</li>
|
||||
</ul>
|
||||
|
||||
|
||||
<h1 id="v36_previous">[% terms.Bugzilla %] 3.4 Release Notes</h1>
|
||||
|
||||
<ul class="bz_toc">
|
||||
|
@ -776,6 +576,52 @@
|
|||
|
||||
<h2 id="v34_point">Updates In This 3.4.x Release</h2>
|
||||
|
||||
<h3>3.4.6</h3>
|
||||
|
||||
<ul>
|
||||
<li>When doing a search that involves "not equals" or "does not contain the
|
||||
string" or similar "negative" search types, the search description that
|
||||
appears at the top of the resulting [% terms.bug %] list will indicate
|
||||
that the search was of that type.
|
||||
(<a href="https://bugzilla.mozilla.org/show_bug.cgi?id=474738">[% terms.Bug %] 474738</a>)
|
||||
</li>
|
||||
<li>In Internet Explorer, users couldn't easily mark a RESOLVED DUPLICATE
|
||||
[%+ terms.bug %] as REOPENED, due to a JavaScript error.
|
||||
(<a href="https://bugzilla.mozilla.org/show_bug.cgi?id=546719">[% terms.Bug %] 546719</a>)
|
||||
</li>
|
||||
<li>If you use a "bookmarkable template" to pre-fill forms on
|
||||
the [% terms.bug %]-filing page, and you have custom fields
|
||||
that are only supposed to appear (or only supposed to have certain
|
||||
values) based on the values of other fields, those custom fields will
|
||||
now work properly.
|
||||
(<a href="https://bugzilla.mozilla.org/show_bug.cgi?id=538211">[% terms.Bug %] 538211</a>)
|
||||
</li>
|
||||
<li>If you have a custom field that's only supposed to appear when
|
||||
a [% terms.bug %]'s resolution is FIXED, it will now behave properly
|
||||
on the [% terms.bug %]-editing form when a user sets the [% terms.bug %]'s
|
||||
status to RESOLVED.
|
||||
(<a href="https://bugzilla.mozilla.org/show_bug.cgi?id=520993">[% terms.Bug %] 520993</a>)
|
||||
</li>
|
||||
<li>If you are logged-out and using <kbd>request.cgi</kbd>, the Requester
|
||||
and Requestee fields no longer respect the <kbd>usermatching</kbd>
|
||||
parameter--they always require full usernames.
|
||||
(<a href="https://bugzilla.mozilla.org/show_bug.cgi?id=533018">[% terms.Bug %] 533018</a>)
|
||||
</li>
|
||||
<li>If you tried to do a search with too many terms (resulting in a URL
|
||||
that was longer than about 7000 characters), Apache would return a
|
||||
500 error instead of your search results.
|
||||
(<a href="https://bugzilla.mozilla.org/show_bug.cgi?id=513989">[% terms.Bug %] 513989</a>)
|
||||
</li>
|
||||
<li>[% terms.Bugzilla %] would sometimes lose fields from your sort order
|
||||
when you added new fields to your sort order.
|
||||
(<a href="https://bugzilla.mozilla.org/show_bug.cgi?id=470214">[% terms.Bug %] 470214</a>)
|
||||
</li>
|
||||
<li>The Atom format of search results would sometimes be missing the
|
||||
Reporter or Assignee field for some [% terms.bugs %].
|
||||
(<a href="https://bugzilla.mozilla.org/show_bug.cgi?id=537834">[% terms.Bug %] 537834</a>)
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<h3>3.4.5</h3>
|
||||
|
||||
<p>This release contains fixes for multiple security issues. See the
|
||||
|
@ -929,20 +775,19 @@
|
|||
|
||||
<p>Perl v5.8.1</p>
|
||||
|
||||
[% INCLUDE db_req db='mysql' %]
|
||||
<h3 id="v34_req_mysql">For MySQL Users</h3>
|
||||
|
||||
<ul>
|
||||
<li>MySQL v4.1.2</li>
|
||||
<li><strong>perl module:</strong> DBD::mysql v4.00</li>
|
||||
</ul>
|
||||
|
||||
[% INCLUDE db_req db='pg' %]
|
||||
|
||||
[% INCLUDE db_req db='oracle' %]
|
||||
|
||||
<h3 id="v34_req_modules">Required Perl Modules</h3>
|
||||
|
||||
[% INCLUDE req_table reqs = REQUIRED_MODULES
|
||||
new = ['URI', 'DateTime', 'DateTime-TimeZone',
|
||||
'Digest-SHA']
|
||||
updated = ['Template-Toolkit'] %]
|
||||
|
||||
<h3 id="v34_req_optional_mod">Optional Perl Modules</h3>
|
||||
<h3 id="v34_req_pg">For PostgreSQL Users</h3>
|
||||
|
||||
<ul>
|
||||
<li>PostgreSQL v8.00.0000</li>
|
||||
<li><strong>perl module:</strong> DBD::Pg v1.45</li>
|
||||
</ul>
|
||||
|
||||
<h3 id="v34_req_oracle">For Oracle Users</h3>
|
||||
|
||||
|
@ -1012,10 +857,118 @@
|
|||
<p>The following perl modules, if installed, enable various
|
||||
features of [% terms.Bugzilla %]:</p>
|
||||
|
||||
[% INCLUDE req_table reqs = OPTIONAL_MODULES
|
||||
new = ['TheSchwartz', 'Daemon-Generic']
|
||||
updated = []
|
||||
include_feature = 1 %]
|
||||
<table class="req_table" border="0" cellspacing="0" cellpadding="0">
|
||||
<tr>
|
||||
<th>Module</th>
|
||||
<th>Version</th>
|
||||
<th>Enables Feature</th>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>LWP::UserAgent</td>
|
||||
<td>(Any)</td>
|
||||
<td>Automatic Update Notifications</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Template::Plugin::GD::Image</td>
|
||||
<td>(Any)</td>
|
||||
<td>Graphical Reports</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>GD::Text</td>
|
||||
<td>(Any)</td>
|
||||
<td>Graphical Reports</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>GD::Graph</td>
|
||||
<td>(Any)</td>
|
||||
<td>Graphical Reports</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>GD</td>
|
||||
<td>1.20</td>
|
||||
<td>Graphical Reports, New Charts, Old Charts</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Email::MIME::Attachment::Stripper</td>
|
||||
<td>(Any)</td>
|
||||
<td>Inbound Email</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Email::Reply</td>
|
||||
<td>(Any)</td>
|
||||
<td>Inbound Email</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Net::LDAP</td>
|
||||
<td>(Any)</td>
|
||||
<td>LDAP Authentication</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="req_new">TheSchwartz</td>
|
||||
<td class="req_new">(Any)</td>
|
||||
<td>Mail Queueing</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="req_new">Daemon::Generic</td>
|
||||
<td class="req_new">(Any)</td>
|
||||
<td>Mail Queueing</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>HTML::Parser</td>
|
||||
<td>3.40</td>
|
||||
<td>More HTML in Product/Group Descriptions</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>HTML::Scrubber</td>
|
||||
<td>(Any)</td>
|
||||
<td>More HTML in Product/Group Descriptions</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>XML::Twig</td>
|
||||
<td>(Any)</td>
|
||||
<td>Move [% terms.Bugs %] Between Installations</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>MIME::Parser</td>
|
||||
<td>5.406</td>
|
||||
<td>Move [% terms.Bugs %] Between Installations</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Chart::Base</td>
|
||||
<td>1.0</td>
|
||||
<td>New Charts, Old Charts</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Image::Magick</td>
|
||||
<td>(Any)</td>
|
||||
<td>Optionally Convert BMP Attachments to PNGs</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>PatchReader</td>
|
||||
<td>0.9.4</td>
|
||||
<td>Patch Viewer</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Authen::Radius</td>
|
||||
<td>(Any)</td>
|
||||
<td>RADIUS Authentication</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Authen::SASL</td>
|
||||
<td>(Any)</td>
|
||||
<td>SMTP Authentication</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>SOAP::Lite</td>
|
||||
<td>0.710.06</td>
|
||||
<td>XML-RPC Interface</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>mod_perl2</td>
|
||||
<td>1.999022</td>
|
||||
<td>mod_perl</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
<h2 id="v34_feat">New Features and Improvements</h2>
|
||||
|
||||
|
@ -3119,7 +3072,7 @@ sub y { $var++ }</pre>
|
|||
|
||||
[% BLOCK db_req %]
|
||||
[% SET m = DB_MODULE.$db %]
|
||||
<h3 id="v34_req_[% db FILTER html %]">For [% m.name FILTER html %] Users</h3>
|
||||
<h3 id="v36_req_[% db FILTER html %]">For [% m.name FILTER html %] Users</h3>
|
||||
|
||||
<ul>
|
||||
<li>[% m.name FILTER html %]
|
||||
|
|
|
@ -46,6 +46,7 @@
|
|||
"changedto",
|
||||
"changedby",
|
||||
"matches",
|
||||
"notmatches",
|
||||
] %]
|
||||
|
||||
<h3 id="chart">
|
||||
|
|
|
@ -85,7 +85,7 @@ sub SaveAccount {
|
|||
my $pwd1 = $cgi->param('new_password1');
|
||||
my $pwd2 = $cgi->param('new_password2');
|
||||
|
||||
my $old_login_name = $user->login;
|
||||
my $old_login_name = $cgi->param('old_login');
|
||||
my $new_login_name = trim($cgi->param('new_login_name'));
|
||||
|
||||
if ($user->authorizer->can_change_password
|
||||
|
|
1
whine.pl
1
whine.pl
|
@ -395,7 +395,6 @@ sub mail {
|
|||
$template->process("whine/multipart-mime.txt.tmpl", $args, \$msg)
|
||||
or die($template->error());
|
||||
|
||||
Bugzilla->template_inner("");
|
||||
MessageToMTA($msg);
|
||||
|
||||
delete $args->{'boundary'};
|
||||
|
|
|
@ -89,7 +89,6 @@ foreach my $email (sort (keys %bugs)) {
|
|||
$template->process("email/whine.txt.tmpl", $vars, \$msg)
|
||||
or die($template->error());
|
||||
|
||||
Bugzilla->template_inner("");
|
||||
MessageToMTA($msg);
|
||||
|
||||
print "$email " . join(" ", @{$bugs{$email}}) . "\n";
|
||||
|
|
Loading…
Reference in New Issue