Commit 5fc80f94 authored by mkanat%bugzilla.org's avatar mkanat%bugzilla.org

Bug 430014: Re-write the code hooks system so that it uses modules instead of individual .pl files

Patch by Max Kanat-Alexander <mkanat@bugzilla.org> (module owner) a=mkanat
parent 78413d85
......@@ -40,9 +40,11 @@ use Bugzilla::Constants;
use Bugzilla::Auth;
use Bugzilla::Auth::Persist::Cookie;
use Bugzilla::CGI;
use Bugzilla::Extension;
use Bugzilla::DB;
use Bugzilla::Install::Localconfig qw(read_localconfig);
use Bugzilla::Install::Requirements qw(OPTIONAL_MODULES);
use Bugzilla::Install::Util;
use Bugzilla::Template;
use Bugzilla::User;
use Bugzilla::Error;
......@@ -55,9 +57,6 @@ use File::Spec::Functions;
use DateTime::TimeZone;
use Safe;
# This creates the request cache for non-mod_perl installations.
our $_request_cache = {};
#####################################################################
# Constants
#####################################################################
......@@ -171,8 +170,6 @@ sub init_page {
}
}
init_page() if !$ENV{MOD_PERL};
#####################################################################
# Subroutines and Methods
#####################################################################
......@@ -193,6 +190,27 @@ sub template_inner {
return $class->request_cache->{"template_inner_$lang"};
}
our $extension_packages;
sub extensions {
my ($class) = @_;
my $cache = $class->request_cache;
if (!$cache->{extensions}) {
# Under mod_perl, mod_perl.pl populates $extension_packages for us.
if (!$extension_packages) {
$extension_packages = Bugzilla::Extension->load_all();
}
my @extensions;
foreach my $package (@$extension_packages) {
my $extension = $package->new();
if ($extension->enabled) {
push(@extensions, $extension);
}
}
$cache->{extensions} = \@extensions;
}
return $cache->{extensions};
}
sub feature {
my ($class, $feature) = @_;
my $cache = $class->request_cache;
......@@ -538,12 +556,6 @@ sub has_flags {
return $class->request_cache->{has_flags};
}
sub hook_args {
my ($class, $args) = @_;
$class->request_cache->{hook_args} = $args if $args;
return $class->request_cache->{hook_args};
}
sub local_timezone {
my $class = shift;
......@@ -554,6 +566,12 @@ sub local_timezone {
return $class->request_cache->{local_timezone};
}
# This creates the request cache for non-mod_perl installations.
# This is identical to Install::Util::_cache so that things loaded
# into Install::Util::_cache during installation can be read out
# of request_cache later in installation.
our $_request_cache = $Bugzilla::Install::Util::_cache;
sub request_cache {
if ($ENV{MOD_PERL}) {
require Apache2::RequestUtil;
......@@ -586,6 +604,8 @@ sub END {
_cleanup() unless $ENV{MOD_PERL};
}
init_page() if !$ENV{MOD_PERL};
1;
__END__
......@@ -821,11 +841,6 @@ The current Parameters of Bugzilla, as a hashref. If C<data/params>
does not exist, then we return an empty hashref. If C<data/params>
is unreadable or is not valid perl, we C<die>.
=item C<hook_args>
If you are running inside a code hook (see L<Bugzilla::Hook>) this
is how you get the arguments passed to the hook.
=item C<local_timezone>
Returns the local timezone of the Bugzilla installation,
......
......@@ -561,7 +561,7 @@ sub _check_data {
$data = <$fh>;
}
}
Bugzilla::Hook::process('attachment-process_data', { data => \$data,
Bugzilla::Hook::process('attachment_process_data', { data => \$data,
attributes => $params });
# Do not validate the size if we have a filehandle. It will be checked later.
......
......@@ -35,7 +35,7 @@ sub new {
my $list = shift;
my %methods = map { $_ => "Bugzilla/Auth/Login/$_.pm" } split(',', $list);
lock_keys(%methods);
Bugzilla::Hook::process('auth-login_methods', { modules => \%methods });
Bugzilla::Hook::process('auth_login_methods', { modules => \%methods });
$self->{_stack} = [];
foreach my $login_method (split(',', $list)) {
......
......@@ -30,7 +30,7 @@ sub new {
my $self = $class->SUPER::new(@_);
my %methods = map { $_ => "Bugzilla/Auth/Verify/$_.pm" } split(',', $list);
lock_keys(%methods);
Bugzilla::Hook::process('auth-verify_methods', { modules => \%methods });
Bugzilla::Hook::process('auth_verify_methods', { modules => \%methods });
$self->{_stack} = [];
foreach my $verify_method (split(',', $list)) {
......
......@@ -107,7 +107,7 @@ sub DB_COLUMNS {
$dbh->sql_date_format('deadline', '%Y-%m-%d') . ' AS deadline',
@custom_names);
Bugzilla::Hook::process("bug-columns", { columns => \@columns });
Bugzilla::Hook::process("bug_columns", { columns => \@columns });
return @columns;
}
......@@ -543,7 +543,7 @@ sub create {
$dbh->do('INSERT INTO longdescs (' . join(',', @columns) . ")
VALUES ($qmarks)", undef, @values);
Bugzilla::Hook::process('bug-end_of_create', { bug => $bug,
Bugzilla::Hook::process('bug_end_of_create', { bug => $bug,
timestamp => $timestamp,
});
......@@ -613,7 +613,7 @@ sub run_create_validators {
delete $params->{lastdiffed};
delete $params->{bug_id};
Bugzilla::Hook::process('bug-end_of_create_validators',
Bugzilla::Hook::process('bug_end_of_create_validators',
{ params => $params });
return $params;
......@@ -870,7 +870,7 @@ sub update {
$changes->{'dup_id'} = [$old_dup || undef, $cur_dup || undef];
}
Bugzilla::Hook::process('bug-end_of_update', { bug => $self,
Bugzilla::Hook::process('bug_end_of_update', { bug => $self,
timestamp => $delta_ts,
changes => $changes,
});
......@@ -1779,7 +1779,7 @@ sub fields {
# Custom Fields
map { $_->name } Bugzilla->active_custom_fields
);
Bugzilla::Hook::process("bug-fields", {'fields' => \@fields} );
Bugzilla::Hook::process('bug_fields', {'fields' => \@fields} );
return @fields;
}
......
......@@ -68,7 +68,7 @@ sub _load_params {
}
# This hook is also called in editparams.cgi. This call here is required
# to make SetParam work.
Bugzilla::Hook::process('config-modify_panels',
Bugzilla::Hook::process('config_modify_panels',
{ panels => \%hook_panels });
}
# END INIT CODE
......@@ -84,7 +84,7 @@ sub param_panels {
$param_panels->{$module} = "Bugzilla::Config::$module" unless $module eq 'Common';
}
# Now check for any hooked params
Bugzilla::Hook::process('config-add_panels',
Bugzilla::Hook::process('config_add_panels',
{ panel_modules => $param_panels });
return $param_panels;
}
......
......@@ -1635,7 +1635,7 @@ sub _initialize {
if exists $abstract_schema->{$table};
}
unlock_keys(%$abstract_schema);
Bugzilla::Hook::process('db_schema-abstract_schema',
Bugzilla::Hook::process('db_schema_abstract_schema',
{ schema => $abstract_schema });
unlock_hash(%$abstract_schema);
}
......
......@@ -107,7 +107,7 @@ sub _throw_error {
# Clone the hash so we aren't modifying the constant.
my %error_map = %{ WS_ERROR_CODE() };
require Bugzilla::Hook;
Bugzilla::Hook::process('webservice-error_codes',
Bugzilla::Hook::process('webservice_error_codes',
{ error_map => \%error_map });
my $code = $error_map{$error};
if (!$code) {
......
......@@ -533,7 +533,7 @@ sub update_flags {
my @new_summaries = $class->snapshot($self->flags);
my @changes = $class->update_activity(\@old_summaries, \@new_summaries);
Bugzilla::Hook::process('flag-end_of_update', { object => $self,
Bugzilla::Hook::process('flag_end_of_update', { object => $self,
timestamp => $timestamp,
old_flags => \@old_summaries,
new_flags => \@new_summaries,
......
......@@ -590,7 +590,7 @@ sub update_table_definitions {
# New --TABLE-- changes should go *** A B O V E *** this point #
################################################################
Bugzilla::Hook::process('install-update_db');
Bugzilla::Hook::process('install_update_db');
# We do this here because otherwise the foreign key from
# products.classification_id to classifications.id will fail
......
......@@ -26,7 +26,8 @@ package Bugzilla::Install::Requirements;
use strict;
use Bugzilla::Constants;
use Bugzilla::Install::Util qw(vers_cmp install_string);
use Bugzilla::Install::Util qw(vers_cmp install_string
extension_requirement_packages);
use List::Util qw(max);
use Safe;
use Term::ANSIColor;
......@@ -138,9 +139,9 @@ sub REQUIRED_MODULES {
},
);
my $all_modules = _get_extension_requirements(
'REQUIRED_MODULES', \@modules);
return $all_modules;
my $extra_modules = _get_extension_requirements('REQUIRED_MODULES');
push(@modules, @$extra_modules);
return \@modules;
};
sub OPTIONAL_MODULES {
......@@ -291,9 +292,9 @@ sub OPTIONAL_MODULES {
},
);
my $all_modules = _get_extension_requirements(
'OPTIONAL_MODULES', \@modules);
return $all_modules;
my $extra_modules = _get_extension_requirements('OPTIONAL_MODULES');
push(@modules, @$extra_modules);
return \@modules;
};
# This maps features to the files that require that feature in order
......@@ -312,31 +313,20 @@ use constant FEATURE_FILES => (
updates => ['Bugzilla/Update.pm'],
);
# This implements the install-requirements hook described in Bugzilla::Hook.
# This implements the REQUIRED_MODULES and OPTIONAL_MODULES stuff
# described in in Bugzilla::Extension.
sub _get_extension_requirements {
my ($function, $base_modules) = @_;
my @all_modules;
# get a list of all extensions
my @extensions = glob(bz_locations()->{'extensionsdir'} . "/*");
foreach my $extension (@extensions) {
my $file = "$extension/code/install-requirements.pl";
if (-e $file) {
my $safe = new Safe;
# This is a very liberal Safe.
$safe->permit(qw(:browse require entereval caller));
$safe->rdo($file);
if ($@) {
warn $@;
next;
}
my $modules = eval { &{$safe->varglob($function)}($base_modules) };
next unless $modules;
push(@all_modules, @$modules);
my ($function) = @_;
my $packages = extension_requirement_packages();
my @modules;
foreach my $package (@$packages) {
if ($package->can($function)) {
my $extra_modules = $package->$function;
push(@modules, @$extra_modules);
}
}
unshift(@all_modules, @$base_modules);
return \@all_modules;
return \@modules;
};
sub check_requirements {
......
......@@ -37,6 +37,8 @@ use base qw(Exporter);
our @EXPORT_OK = qw(
bin_loc
get_version_and_os
extension_code_files
extension_requirement_packages
indicate_progress
install_string
include_languages
......@@ -79,6 +81,96 @@ sub get_version_and_os {
os_ver => $os_details[3] };
}
sub _extension_paths {
my $dir = bz_locations()->{'extensionsdir'};
my @extension_items = glob("$dir/*");
my @paths;
foreach my $item (@extension_items) {
my $basename = basename($item);
# Skip CVS directories and any hidden files/dirs.
next if ($basename eq 'CVS' or $basename =~ /^\./);
if (-d $item) {
if (!-e "$item/disabled") {
push(@paths, $item);
}
}
elsif ($item =~ /\.pm$/i) {
push(@paths, $item);
}
}
return @paths;
}
sub extension_code_files {
my ($requirements_only) = @_;
my @files;
foreach my $path (_extension_paths()) {
my @load_files;
if (-d $path) {
my $extension_file = "$path/Extension.pm";
my $config_file = "$path/Config.pm";
if (-e $extension_file) {
push(@load_files, $extension_file);
}
if (-e $config_file) {
push(@load_files, $config_file);
}
# Don't load Extension.pm if we just want Config.pm and
# we found both.
if ($requirements_only and scalar(@load_files) == 2) {
shift(@load_files);
}
}
else {
push(@load_files, $path);
}
next if !scalar(@load_files);
# We know that these paths are safe, because they came from
# extensionsdir and we checked them specifically for their format.
# Also, the only thing we ever do with them is pass them to "require".
trick_taint($_) foreach @load_files;
push(@files, \@load_files);
}
return \@files;
}
# Used by _get_extension_requirements in Bugzilla::Install::Requirements.
sub extension_requirement_packages {
# If we're in a .cgi script or some time that's not the requirements phase,
# just use Bugzilla->extensions. This avoids running the below code during
# a normal Bugzilla page, which is important because the below code
# doesn't actually function right if it runs after
# 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 }) {
return Bugzilla->extensions;
}
my $packages = _cache()->{extension_requirement_packages};
return $packages if $packages;
$packages = [];
my %package_map;
my $extension_files = extension_code_files('requirements only');
foreach my $file_set (@$extension_files) {
my $file = shift @$file_set;
my $name = require $file;
if ($name =~ /^\d+$/) {
die install_string('extension_must_return_name',
{ file => $file, returned => $name });
}
my $package = "Bugzilla::Extension::$name";
$package_map{$file} = $package;
push(@$packages, $package);
}
_cache()->{extension_requirement_packages} = $packages;
# Used by Bugzilla::Extension->load if it's called after this method
# (which only happens during checksetup.pl, currently).
_cache()->{extension_requirement_package_map} = \%package_map;
return $packages;
}
sub indicate_progress {
my ($params) = @_;
my $current = $params->{current};
......@@ -93,8 +185,8 @@ sub indicate_progress {
sub install_string {
my ($string_id, $vars) = @_;
_cache()->{template_include_path} ||= template_include_path();
my $path = _cache()->{template_include_path};
_cache()->{install_string_path} ||= template_include_path();
my $path = _cache()->{install_string_path};
my $string_template;
# Find the first template that defines this string.
......@@ -134,10 +226,10 @@ sub include_languages {
# function in Bugzilla->request_cache. This is done to improve the
# performance of the template processing.
my $to_be_cached = 0;
if (exists $ENV{'SERVER_SOFTWARE'} and not @_) {
my $cache = Bugzilla->request_cache;
if (not @_) {
my $cache = _cache();
if (exists $cache->{include_languages}) {
return @{$cache->{include_languages}}
return @{ $cache->{include_languages} };
}
$to_be_cached = 1;
}
......@@ -202,8 +294,7 @@ sub include_languages {
# 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) {
my $cache = Bugzilla->request_cache;
$cache->{include_languages} = \@usedlanguages;
_cache()->{include_languages} = \@usedlanguages;
}
return @usedlanguages;
......@@ -241,12 +332,8 @@ sub template_base_directories {
# First, we add extension template directories, because extension templates
# override standard templates. Extensions may be localized in the same way
# that Bugzilla templates are localized.
my @template_dirs;
my @extensions = glob(bz_locations()->{'extensionsdir'} . "/*");
foreach my $extension (@extensions) {
next if (-e "$extension/disabled" or !-d "$extension/template");
push(@template_dirs, "$extension/template");
}
my @extensions = grep { -d "$_/template" } _extension_paths();
my @template_dirs = map { "$_/template" } @extensions;
push(@template_dirs, bz_locations()->{'templatedir'});
return \@template_dirs;
}
......@@ -384,12 +471,13 @@ sub init_console {
}
# This is like request_cache, but it's used only by installation code
# for setup.cgi and things like that.
# for checksetup.pl and things like that.
our $_cache = {};
sub _cache {
if ($ENV{MOD_PERL}) {
require Apache2::RequestUtil;
return Apache2::RequestUtil->request->pnotes();
# If the normal request_cache is available (which happens any time
# after the requirements phase) then we should use that.
if (eval { Bugzilla->request_cache; }) {
return Bugzilla->request_cache;
}
return $_cache;
}
......
......@@ -171,7 +171,7 @@ sub MessageToMTA {
Debug => Bugzilla->params->{'smtp_debug'};
}
Bugzilla::Hook::process('mailer-before_send', { email => $email });
Bugzilla::Hook::process('mailer_before_send', { email => $email });
if ($method eq "Test") {
my $filename = bz_locations()->{'datadir'} . '/mailer.testfile';
......
......@@ -279,7 +279,7 @@ sub set {
superclass => __PACKAGE__,
function => 'Bugzilla::Object->set' });
Bugzilla::Hook::process('object-before_set',
Bugzilla::Hook::process('object_before_set',
{ object => $self, field => $field,
value => $value });
......@@ -303,7 +303,7 @@ sub set_all {
my $method = "set_$key";
$self->$method($params->{$key});
}
Bugzilla::Hook::process('object-end_of_set_all', { object => $self,
Bugzilla::Hook::process('object_end_of_set_all', { object => $self,
params => $params });
}
......@@ -348,7 +348,7 @@ sub update {
$dbh->do("UPDATE $table SET $columns WHERE $id_field = ?", undef,
@values, $self->id) if @values;
Bugzilla::Hook::process('object-end_of_update',
Bugzilla::Hook::process('object_end_of_update',
{ object => $self, old_object => $old_self,
changes => \%changes });
......@@ -412,7 +412,7 @@ sub check_required_create_fields {
# This hook happens here so that even subclasses that don't call
# SUPER::create are still affected by the hook.
Bugzilla::Hook::process('object-before_create', { class => $class,
Bugzilla::Hook::process('object_before_create', { class => $class,
params => $params });
foreach my $field ($class->REQUIRED_CREATE_FIELDS) {
......@@ -445,7 +445,7 @@ sub run_create_validators {
$field_values{$field} = $value;
}
Bugzilla::Hook::process('object-end_of_create_validators',
Bugzilla::Hook::process('object_end_of_create_validators',
{ class => $class, params => \%field_values });
return \%field_values;
......
......@@ -170,7 +170,7 @@ sub COLUMNS {
# The short_short_desc column is identical to short_desc
$columns{'short_short_desc'} = $columns{'short_desc'};
Bugzilla::Hook::process("buglist-columns", { columns => \%columns });
Bugzilla::Hook::process('buglist_columns', { columns => \%columns });
$cache->{search_columns} = \%columns;
return $cache->{search_columns};
......
......@@ -86,9 +86,9 @@ sub process {
my $self = shift;
my ($file, $vars) = @_;
Bugzilla::Hook::process("template-before_process",
{ vars => $vars, file => $file,
template => $self });
#Bugzilla::Hook::process('template_before_process',
# { vars => $vars, file => $file,
# template => $self });
return $self->SUPER::process(@_);
}
......@@ -188,7 +188,7 @@ sub quoteUrls {
my $tmp;
my @hook_regexes;
Bugzilla::Hook::process('bug-format_comment',
Bugzilla::Hook::process('bug_format_comment',
{ text => \$text, bug => $bug, regexes => \@hook_regexes,
comment => $comment });
......@@ -793,7 +793,7 @@ sub create {
},
};
Bugzilla::Hook::process('template-before_create', { config => $config });
Bugzilla::Hook::process('template_before_create', { config => $config });
my $template = $class->new($config)
|| die("Template creation failed: " . $class->error());
return $template;
......
......@@ -222,7 +222,7 @@ Bugzilla::Install::reset_password($switch{'reset-password'})
Bugzilla::Install::create_default_product();
Bugzilla::Hook::process('install-before_final_checks', {'silent' => $silent });
Bugzilla::Hook::process('install_before_final_checks', { silent => $silent });
###########################################################################
# Final checks
......
......@@ -88,7 +88,7 @@ my @custom_fields = grep { $_->type != FIELD_TYPE_MULTI_SELECT }
Bugzilla->active_custom_fields;
push(@masterlist, map { $_->name } @custom_fields);
Bugzilla::Hook::process("colchange-columns", {'columns' => \@masterlist} );
Bugzilla::Hook::process('colchange_columns', {'columns' => \@masterlist} );
$vars->{'masterlist'} = \@masterlist;
......
......@@ -74,7 +74,7 @@ foreach my $panel (keys %$param_panels) {
my %hook_panels = map { $_->{name} => { params => $_->{param_list} } }
@panels;
# Note that this hook is also called in Bugzilla::Config.
Bugzilla::Hook::process('config-modify_panels', { panels => \%hook_panels });
Bugzilla::Hook::process('config_modify_panels', { panels => \%hook_panels });
$vars->{panels} = \@panels;
......
......@@ -218,7 +218,7 @@ if ($action eq 'del') {
$vars->{'product'} = $product;
$vars->{'token'} = issue_session_token('delete_product');
Bugzilla::Hook::process("product-confirm_delete", { vars => $vars });
Bugzilla::Hook::process('product_confirm_delete', { vars => $vars });
$template->process("admin/products/confirm-delete.html.tmpl", $vars)
|| ThrowTemplateError($template->error());
......
......@@ -604,7 +604,7 @@ foreach my $row (@$grouplist) {
$vars->{'group'} = \@groups;
Bugzilla::Hook::process("enter_bug-entrydefaultvars", { vars => $vars });
Bugzilla::Hook::process('enter_bug_entrydefaultvars', { vars => $vars });
$vars->{'default'} = \%default;
......
# -*- Mode: perl; indent-tabs-mode: nil -*-
#
# The contents of this file are subject to the Mozilla Public
# License Version 1.1 (the "License"); you may not use this file
# except in compliance with the License. You may obtain a copy of
# the License at http://www.mozilla.org/MPL/
#
# Software distributed under the License is distributed on an "AS
# IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
# implied. See the License for the specific language governing
# rights and limitations under the License.
#
# The Original Code is the Bugzilla Bug Tracking System.
#
# The Initial Developer of the Original Code is Everything Solved, Inc.
# Portions created by the Initial Developer are Copyright (C) 2009
# the Initial Developer. All Rights Reserved.
#
# Contributor(s):
# Max Kanat-Alexander <mkanat@bugzilla.org>
package Bugzilla::Extension::BmpConvert;
use strict;
use constant NAME => 'BmpConvert';
use constant REQUIRED_MODULES => [
{
package => 'PerlMagick',
module => 'Image::Magick',
version => 0,
},
];
__PACKAGE__->NAME;
# -*- Mode: perl; indent-tabs-mode: nil -*-
#
# The contents of this file are subject to the Mozilla Public
# License Version 1.1 (the "License"); you may not use this file
# except in compliance with the License. You may obtain a copy of
# the License at http://www.mozilla.org/MPL/
#
# Software distributed under the License is distributed on an "AS
# IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
# implied. See the License for the specific language governing
# rights and limitations under the License.
#
# The Original Code is the Bugzilla Bug Tracking System.
#
# The Initial Developer of the Original Code is Frédéric Buclin.
# Portions created by Frédéric Buclin are Copyright (C) 2009
# Frédéric Buclin. All Rights Reserved.
#
# Contributor(s):
# Frédéric Buclin <LpSolit@gmail.com>
# Max Kanat-Alexander <mkanat@bugzilla.org>
package Bugzilla::Extension::BmpConvert;
use strict;
use base qw(Bugzilla::Extension);
use Image::Magick;
our $VERSION = '1.0';
sub attachment_process_data {
my ($self, $params) = @_;
return unless $params->{attributes}->{mimetype} eq 'image/bmp';
my $data = ${$params->{data}};
my $img = Image::Magick->new(magick => 'bmp');
# $data is a filehandle.
if (ref $data) {
$img->Read(file => \*$data);
$img->set(magick => 'png');
$img->Write(file => \*$data);
}
# $data is a blob.
else {
$img->BlobToImage($data);
$img->set(magick => 'png');
$data = $img->ImageToBlob();
}
undef $img;
${$params->{data}} = $data;
$params->{attributes}->{mimetype} = 'image/png';
$params->{attributes}->{filename} =~ s/^(.+)\.bmp$/$1.png/i;
}
__PACKAGE__->NAME;
# -*- Mode: perl; indent-tabs-mode: nil -*-
#
# The contents of this file are subject to the Mozilla Public
# License Version 1.1 (the "License"); you may not use this file
# except in compliance with the License. You may obtain a copy of
# the License at http://www.mozilla.org/MPL/
#
# Software distributed under the License is distributed on an "AS
# IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
# implied. See the License for the specific language governing
# rights and limitations under the License.
#
# The Original Code is the Bugzilla Bug Tracking System.
#
# The Initial Developer of the Original Code is Everything Solved, Inc.
# Portions created by the Initial Developers are Copyright (C) 2009 the
# Initial Developer. All Rights Reserved.
#
# Contributor(s):
# Max Kanat-Alexander <mkanat@bugzilla.org>
package Bugzilla::Extension::Example;
use strict;
use constant NAME => 'Example';
use constant REQUIRED_MODULES => [
{
package => 'Data-Dumper',
module => 'Data::Dumper',
version => 0,
},
];
use constant OPTIONAL_MODULES => [
{
package => 'Acme',
module => 'Acme',
version => 1.11,
feature => ['example_acme'],
},
];
__PACKAGE__->NAME;
# -*- Mode: perl; indent-tabs-mode: nil -*-
#
# The contents of this file are subject to the Mozilla Public
# License Version 1.1 (the "License"); you may not use this file
# except in compliance with the License. You may obtain a copy of
# the License at http://www.mozilla.org/MPL/
#
# Software distributed under the License is distributed on an "AS
# IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
# implied. See the License for the specific language governing
# rights and limitations under the License.
#
# The Original Code is the Bugzilla Example Plugin.
#
# The Initial Developer of the Original Code is Canonical Ltd.
# Portions created by Canonical are Copyright (C) 2008 Canonical Ltd.
# All Rights Reserved.
#
# Contributor(s): Max Kanat-Alexander <mkanat@bugzilla.org>
package extensions::Example::lib::AuthLogin;
use strict;
use base qw(Bugzilla::Auth::Login);
use constant user_can_create_account => 0;
use Bugzilla::Constants;
# Always returns no data.
sub get_login_info {
return { failure => AUTH_NODATA };
}
1;
# -*- Mode: perl; indent-tabs-mode: nil -*-
#
# The contents of this file are subject to the Mozilla Public
# License Version 1.1 (the "License"); you may not use this file
# except in compliance with the License. You may obtain a copy of
# the License at http://www.mozilla.org/MPL/
#
# Software distributed under the License is distributed on an "AS
# IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
# implied. See the License for the specific language governing
# rights and limitations under the License.
#
# The Original Code is the Bugzilla Example Plugin.
#
# The Initial Developer of the Original Code is Canonical Ltd.
# Portions created by Canonical are Copyright (C) 2008 Canonical Ltd.
# All Rights Reserved.
#
# Contributor(s): Max Kanat-Alexander <mkanat@bugzilla.org>
package extensions::Example::lib::AuthVerify;
use strict;
use base qw(Bugzilla::Auth::Verify);
use Bugzilla::Constants;
# A verifier that always fails.
sub check_credentials {
return { failure => AUTH_NO_SUCH_USER };
}
1;
# -*- Mode: perl; indent-tabs-mode: nil -*-
#
# The contents of this file are subject to the Mozilla Public
# License Version 1.1 (the "License"); you may not use this file
# except in compliance with the License. You may obtain a copy of
# the License at http://www.mozilla.org/MPL/
#
# Software distributed under the License is distributed on an "AS
# IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
# implied. See the License for the specific language governing
# rights and limitations under the License.
#
# The Original Code is the Bugzilla Example Plugin.
#
# The Initial Developer of the Original Code is Canonical Ltd.
# Portions created by Canonical Ltd. are Copyright (C) 2008
# Canonical Ltd. All Rights Reserved.
#
# Contributor(s): Max Kanat-Alexander <mkanat@bugzilla.org>
# Bradley Baetz <bbaetz@acm.org>
package extensions::Example::lib::ConfigExample;
use strict;
use warnings;
use Bugzilla::Config::Common;
sub get_param_list {
my ($class) = @_;
my @param_list = (
{
name => 'example_string',
type => 't',
default => 'EXAMPLE',
},
);
return @param_list;
}
1;
# -*- Mode: perl; indent-tabs-mode: nil -*-
#
# The contents of this file are subject to the Mozilla Public
# License Version 1.1 (the "License"); you may not use this file
# except in compliance with the License. You may obtain a copy of
# the License at http://www.mozilla.org/MPL/
#
# Software distributed under the License is distributed on an "AS
# IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
# implied. See the License for the specific language governing
# rights and limitations under the License.
#
# The Original Code is the Bugzilla Bug Tracking System.
#
# The Initial Developer of the Original Code is Everything Solved, Inc.
# Portions created by Everything Solved, Inc. are Copyright (C) 2007
# Everything Solved, Inc. All Rights Reserved.
#
# Contributor(s): Max Kanat-Alexander <mkanat@bugzilla.org>
package extensions::Example::lib::WSExample;
use strict;
use warnings;
use base qw(Bugzilla::WebService);
use Bugzilla::Error;
# This can be called as Example.hello() from the WebService.
sub hello { return 'Hello!'; }
sub throw_an_error { ThrowUserError('example_my_error') }
1;
[%#
# 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 Example Plugin.
#
# The Initial Developer of the Original Code is Canonical Ltd.
# Portions created by Canonical Ltd. are Copyright (C) 2008
# Canonical Ltd. All Rights Reserved.
#
# Contributor(s): Bradley Baetz <bbaetz@acm.org>
#%]
[%
title = "Example Extension"
desc = "Configure example extension"
%]
[% param_descs = {
example_string => "Example string",
}
%]
[%#
# 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 Example Plugin.
#
# The Initial Developer of the Original Code is Canonical Ltd.
# Portions created by Canonical Ltd. are Copyright (C) 2009
# Canonical Ltd. All Rights Reserved.
#
# Contributor(s):
# Max Kanat-Alexander <mkanat@bugzilla.org>
#%]
[% PROCESS global/header.html.tmpl
title = "Example Page"
%]
<p>Here's what you passed me:</p>
[% USE Dumper %]
<pre>
[% Dumper.dump_html(cgi_variables) %]
</pre>
[% PROCESS global/footer.html.tmpl %]
# 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 Initial Developer of the Original Code is Everything Solved, Inc.
# Portions created by the Initial Developer are Copyright (C) 2009 the
# Initial Developer. All Rights Reserved.
#
# The Original Code is the Bugzilla Bug Tracking System.
#
# Contributor(s):
# Max Kanat-Alexander <mkanat@bugzilla.org>
%strings = (
feature_example_acme => 'Example Extension: Acme Feature',
);
1;
[%# -*- Mode: perl; indent-tabs-mode: nil -*-
#
# The contents of this file are subject to the Mozilla Public
# License Version 1.1 (the "License"); you may not use this file
# except in compliance with the License. You may obtain a copy of
# the License at http://www.mozilla.org/MPL/
#
# Software distributed under the License is distributed on an "AS
# IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
# implied. See the License for the specific language governing
# rights and limitations under the License.
#
# The Original Code is the Bugzilla Example Plugin.
#
# The Initial Developer of the Original Code is ITA Software
# Portions created by the Initial Developer are Copyright (C) 2009
# the Initial Developer. All Rights Reserved.
#
# Contributor(s): Bradley Baetz <bbaetz@everythingsolved.com>
#%]
[% IF san_tag == "example_check_au_user" %]
<em>EXAMPLE PLUGIN</em> - Checking for non-Australian users.
[% ELSIF san_tag == "example_check_au_user_alert" %]
User &lt;[% login FILTER html %]&gt; isn't Australian.
[% IF user.in_group('editusers') %]
<a href="editusers.cgi?id=[% userid FILTER none %]">Edit this user</a>.
[% END %]
[% ELSIF san_tag == "example_check_au_user_prompt" %]
<a href="sanitycheck.cgi?example_repair_au_user=1">Fix these users</a>.
[% ELSIF san_tag == "example_repair_au_user_start" %]
<em>EXAMPLE PLUGIN</em> - OK, would now make users Australian.
[% ELSIF san_tag == "example_repair_au_user_end" %]
<em>EXAMPLE PLUGIN</em> - Users would now be Australian.
[% END %]
[%# Note that error messages should generally be indented four spaces, like
# below, because when Bugzilla translates an error message into plain
# text, it takes four spaces off the beginning of the lines.
#
# Note also that I prefixed my error name with "example", the name of my
# extension, so that I wouldn't conflict with other error names in
# Bugzilla or other extensions.
#%]
[% IF error == "example_my_error" %]
[% title = "Example Error Title" %]
This is the error message! It contains <em>some html</em>.
[% END %]
......@@ -20,8 +20,8 @@ package Bugzilla::ModPerl;
use strict;
# If you have an Apache2::Status handler in your Apache configuration,
# you need to load Apache2::Status *here*, so that Apache::DBI can
# report information to Apache2::Status.
# you need to load Apache2::Status *here*, so that any later-loaded modules
# can report information to Apache2::Status.
#use Apache2::Status ();
# We don't want to import anything into the global scope during
......@@ -41,6 +41,7 @@ Template::Config->preload();
use Bugzilla ();
use Bugzilla::Constants ();
use Bugzilla::CGI ();
use Bugzilla::Extension ();
use Bugzilla::Install::Requirements ();
use Bugzilla::Mailer ();
use Bugzilla::Template ();
......@@ -87,6 +88,8 @@ foreach my $file (glob "$cgi_path/*.cgi") {
$rl->handler($file, $file);
}
# And now pre-load all extensions
$Bugzilla::extension_packages = Bugzilla::Extension->load_all();
package Bugzilla::ModPerl::ResponseHandler;
use strict;
......
......@@ -52,7 +52,7 @@ if ($id) {
}
my %vars;
Bugzilla::Hook::process('page-before_template',
Bugzilla::Hook::process('page_before_template',
{ page_id => $id, vars => \%vars });
my $format = $template->get_format("pages/$1", undef, $2);
......
......@@ -254,7 +254,7 @@ $vars->{'mailrecipients'} = {'changer' => $user->login};
$vars->{'id'} = $id;
$vars->{'bug'} = $bug;
Bugzilla::Hook::process("post_bug-after_creation", { vars => $vars });
Bugzilla::Hook::process('post_bug_after_creation', { vars => $vars });
ThrowCodeError("bug_error", { bug => $bug }) if $bug->error;
......
......@@ -388,7 +388,7 @@ if ($cgi->param('remove_old_whine_targets')) {
# Repair hook
###########################################################################
Bugzilla::Hook::process("sanitycheck-repair", { status => \&Status });
Bugzilla::Hook::process('sanitycheck_repair', { status => \&Status });
###########################################################################
# Checks
......@@ -1075,7 +1075,7 @@ Status('whines_obsolete_target_fix') if $display_repair_whines_link;
# Check hook
###########################################################################
Bugzilla::Hook::process("sanitycheck-check", { status => \&Status });
Bugzilla::Hook::process('sanitycheck_check', { status => \&Status });
###########################################################################
# End
......
......@@ -143,6 +143,33 @@
An error occurred processing hook [% name FILTER html %] in
extension [% extension FILTER html %]: [% errstr FILTER html %]
[% ELSIF error == "extension_must_be_subclass" %]
<code>[% package FILTER html %]</code> from
<code>[% filename FILTER html %]</code> is not a subclass of
<code>[% class FILTER html %]</code>.
[% ELSIF error == "extension_must_return_name" %]
<code>[% extension FILTER html %]</code> returned
<code>[% returned FILTER html %]</code>, which is not a valid name
for an extension. Extensions must return their name, not <code>1</code>
or a number. See the documentation of
<a href="[% docs_urlbase %]api/Bugzilla/Extension.html">Bugzilla::Extension</a>
for details.
[% ELSIF error == "extension_no_name" %]
We did not find a <code>NAME</code> method in
<code>[% package FILTER html %]</code> (loaded from
<code>[% filename FILTER html %]</code>). This means that
the extension has one or more of the following problems:
<ul>
<li><code>[% filename FILTER html %]</code> did not define a
<code>[% package FILTER html %]</code> package.</li>
<li><code>[% package FILTER html %]</code> did not define a
<code>NAME</code> method (or the <code>NAME</code> method
returned an empty string).</li>
</ul>
[% ELSIF error == "extern_id_conflict" %]
The external ID '[% extern_id FILTER html %]' already exists
in the database for '[% username FILTER html %]', but your
......
......@@ -45,7 +45,11 @@ COMMANDS TO INSTALL REQUIRED MODULES (You *must* run all these commands
and then re-run this script):
EOT
done => 'done.',
extension_must_return_name => <<END,
##file## returned ##returned##, which is not a valid name for an extension.
Extensions must return their name, not <code>1</code> or a number. See
the documentation of Bugzilla::Extension for details.
END
feature_auth_ldap => 'LDAP Authentication',
feature_auth_radius => 'RADIUS Authentication',
feature_graphical_reports => 'Graphical Reports',
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment